Jest: 模拟同时具有默认导出和命名导出的ES6模块

20

我有一个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'
    });
});

这个行为对我来说真的很奇怪,因为当仅模拟默认导入或命名导入中的一个时,这个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,是否可以模拟命名导入和默认导入?我是否可以使用不同的语法来实现我想要的结果,即从模块中导入命名和默认值,并能够模拟它们两个?

2个回答

24

另一种解决方案对我没用。这是我做的方法:

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

另一种方法:

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

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

1
对于其他查看此答案的人,请注意 __esModule 属性中的驼峰式大小写——如果全部使用小写,则无法正常工作。 - Alexander Nied
1
这只对我使用Babel有效,例如此示例。没有Babel,此示例有效。 - ggorlen

3

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

import mainFunction, { utilityFunction } from './dependency';

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

我不确定你是怎么让测试运行的,但我在本地尝试了一下,测试通过了。


嗨,djfdev,感谢你的回答!事实证明你是正确的,我提供的示例代码在我的环境中确实有效。我在问题中写的内容实际上是我遇到的问题过于简单化了 - 在我的用例中,默认导入是一个React组件。是否值得编辑问题以提供实际代码?否则,我可以将此问题标记为已解决并打开一个新问题。 - bean
经过再次思考,我将把你的答案标记为正确,并开一个新问题。再次感谢! - bean
我的更新问题在这里:https://dev59.com/_FUM5IYBdhLWcg3wc_2c - bean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接