玩笑:使用默认和命名导出模拟 ES6 模块

Posted

技术标签:

【中文标题】玩笑:使用默认和命名导出模拟 ES6 模块【英文标题】:Jest: Mock ES6 Module with both default and named export 【发布时间】:2018-07-25 15:30:42 【问题描述】:

我有一个带有默认导出和命名导出的 ES6 模块:

/** /src/dependency.js **/

export function utilityFunction()  return false; 

export default function mainFunction()  return 'foo'; 

它被第二个 ES6 模块使用:

/** /src/myModule.js **/

import mainFunction,  utilityFunction  from './dependency';

// EDIT: Fixed syntax error in code sample
// export default myModule() 
export default function myModule() 
    if (!utilityFunction()) return 2;
    return mainFunction();

我正在尝试使用 Jest 为 myModule.js 编写单元测试。但是当我尝试模拟命名和默认导入时,Jest 似乎只模拟命名导入。它继续使用默认导入的实际实现,并且不允许我模拟它,即使在我调用 .mockImplementation() 之后也是如此。这是我正在尝试使用的代码:

/** 
  * Trying to mock both named and default import. 
  * THIS DOESN'T WORK.
  */

/** /tests/myModule.test.js **/

import mainFunction,  utilityFunction  from '../src/dependency';
import myModule from '../src/myModule';

jest.mock('../src/dependency');

mainFunction.mockImplementation(() => 1);
utilityFunction.mockImplementation(() => true);

describe('myModule', () => 
    it('should return the return value of mainFunction when the result of utilityFunction is true', () => 
        expect(myModule()).toEqual(1); // FAILS - actual result is 'foo'
    );
);

这种行为对我来说似乎很奇怪,因为在模拟 JUST 默认导入或 JUST 命名导入时,此 API 工作正常。例如,在 myModule.js 只导入默认导入的情况下,这很容易做到:

/**
  * Trying to mock just the default import. 
  * THIS WORKS.
  */

/** /src/myModule.js **/

import mainFunction from './dependency';

// EDIT: Fixed syntax error in code sample
// export default myModule() 
export default function myModule() 
    return mainFunction();



/** /tests/myModule.test.js **/
// If only mainFunction is used by myModule.js

import mainFunction from '../src/dependency';
import myModule from '../src/myModule';

jest.mock('../src/dependency');
mainFunction.mockImplementation(() => 1);

describe('myModule', () => 
    it('should return the return value of mainFunction', () => 
        expect(myModule()).toEqual(1); // Passes
    );
);

在只使用命名的“utilityFunction”导出的情况下,模拟导入也很容易:

/**
  * Trying to mock both named and default import. 
  * THIS WORKS.
  */
/** /src/myModule.js **/

import  utililtyFunction  from './dependency';

// EDIT: Fixed syntax error in code sample
// export default myModule()
export default function myModule() 
    return utilityFunction();



/** /tests/myModule.test.js **/
// If only utilityFunction is used by myModule.js

import  utilityFunction  from '../src/dependency';
import myModule from '../src/myModule';

jest.mock('../src/dependency);
utilityFunction.mockImplementation(() => 'bar');

describe('myModule', () => 
    it('should return the return value of utilityFunction', () => 
        expect(myModule()).toEqual('bar'); // Passes
    );
);

是否可以使用 Jest 模拟命名和默认导入?是否有不同的语法可以用来实现我想要的结果,我从模块中导入命名值和默认值并能够模拟它们?

【问题讨论】:

嗨,你试过我的回答了吗?我想这就是你要找的。另外,如果可行,您能否给出最佳答案? 【参考方案1】:

您有一个语法错误...在 myModule.js 的默认导出中省略了 function 关键字。应该是这样的:

import mainFunction,  utilityFunction  from './dependency';

export default function myModule() 
    if (!utilityFunction()) return 2;
    return mainFunction();

我不确定你是如何让测试运行的,但我只是在本地尝试过,它通过了。

【讨论】:

您好 djfdev,感谢您的回答!事实证明你是对的,我提供的示例代码确实在我的环境中工作。我在问题中写的结果是对我遇到的问题的过度简化 - 在我的用例中,默认导入是一个 React 组件。编辑问题以提供实际代码是否值得?否则,我可以将此问题标记为已回答并打开一个新问题。 在考虑了更多之后,我会将您的答案标记为正确并打开一个新问题。再次感谢! 我更新的问题在这里:***.com/questions/48831701/…【参考方案2】:

其他解决方案对我不起作用。我就是这样做的:

  jest.mock('../src/dependency', () => (
    __esModule: true,
    utilityFunction: 'utilityFunction',
    default: 'mainFunction'
  ));

另一种方法:

jest.unmock('../src/dependency');

const myModule = require('../src/dependency');
myModule.utilityFunction = 'your mock'

【讨论】:

以上是关于玩笑:使用默认和命名导出模拟 ES6 模块的主要内容,如果未能解决你的问题,请参考以下文章

ES6 命名导出和默认导出之间的可变差异

使用 ES5 语法在 Node 中混合默认和命名导出

简明 ES6 模块

在开玩笑的模拟模块工厂中模拟一个承诺

如何从命名空间导出,访问默认值? [复制]

如何从 ES6 模块导入默认和命名