Jest模拟默认导出 - 需要vs导入

Ann*_*zer 7 javascript jestjs es6-modules

我在这里看到有关嘲笑默认出口的问题,但我不认为这已经被问到:

在模拟正在测试的模块的依赖项的默认导出TypeError: (0 , _dependency.default) is not a function时,如果模块使用ES6 import语句导入依赖项,则测试套件无法运行,但是,如果模块使用require().default调用,则说明它成功.

根据我的理解,import module from location直接转换为const module = require(location).default,所以我很困惑为什么会发生这种情况.我宁愿保持我的代码风格一致,也不要require在原始模块中使用调用.

有办法吗?

使用mock测试文件:

import './modules.js';
import dependency from './dependency';

jest.mock('./dependency', () => {
   return {
      default: jest.fn()
   };
});

// This is what I would eventually like to call
it('calls the mocked function', () => {
   expect(dependency).toHaveBeenCalled();
});
Run Code Online (Sandbox Code Playgroud)

Dependency.js

export default () => console.log('do something');
Run Code Online (Sandbox Code Playgroud)

module.js(不工作)

import dependency from './dependency.js';
dependency();
Run Code Online (Sandbox Code Playgroud)

module.js(工作)

const dependency = require('./dependency.js').default;
dependency();
Run Code Online (Sandbox Code Playgroud)

小智 52

如果你想使用 ES 模块的简短答案 import dependency from 'dependency'

jest.mock('dependency', () => ({
  ...jest.requireActual('dependency'),
  __esModule: true,
  default: jest.fn(),
}))
Run Code Online (Sandbox Code Playgroud)


小智 21

你尝试过这样的事情吗?我处理默认导出模拟了几个月,直到我发现了这个。

jest.mock('./dependency', () => () => jest.fn());
Run Code Online (Sandbox Code Playgroud)

这行代码背后的想法是,您正在导出一个作为函数的模块。所以你需要让 Jest 知道它必须将你的所有./dependency文件模拟为一个函数,该函数返回一个jest.fn()


Sot*_*sis 9

您可以在jest测试中使用es6 importrequire js导入js文件.

使用时,es6 import您应该知道jest正在尝试解析所有依赖项,并且还会调用要导入的类的构造函数.在此步骤中,您无法模拟它.必须成功解决依赖关系,然后才能继续进行模拟.

我还应该补充一点,这里可以看到jest默认情况下将任何jest.mocks提升到文件的顶部,这样放置导入的顺序并不重要.

你的问题虽然不同.您的模拟函数假定您已使用包含js文件require js.

jest.mock('./dependecy', () => {
   return {
      default: jest.fn()
   };
});
Run Code Online (Sandbox Code Playgroud)

使用时导入文件时require js,这是它具有的结构:

在此输入图像描述

因此,假设我已经导入了名为"Test"的类require js,并且它具有名为"doSomething"的方法,我可以在我的测试中通过执行以下操作来调用它:

const test = require('../Test');
test.default.doSomething();
Run Code Online (Sandbox Code Playgroud)

使用时导入它es6 import,你应该采用不同的方式.使用相同的例子:

import Test from '../Test';
Test.doSomething();
Run Code Online (Sandbox Code Playgroud)

编辑:如果你想使用es6 import更改你的模拟功能:

jest.mock('./dependecy', () => jest.fn());
Run Code Online (Sandbox Code Playgroud)


小智 7

我必须在 vue 和 jest 中执行此操作:

尽管在代码中我使用了默认导入,但在单元测试中我必须像这样命名导入:

import * as someName from 'dependency';
Run Code Online (Sandbox Code Playgroud)

然后我使用奇怪的属性“__esModule”来允许 jest 使用默认构造函数,如下所示:

jest.mock('dependency', () => ({
  __esModule: true,
  default: jest.fn(),
}));
Run Code Online (Sandbox Code Playgroud)

最后在我的单元测试中,我在默认构造函数上使用了间谍功能:

const mySpy = jest.spyOn(someName, 'default').mockImplementation(params => {
 params.doSomeThing();
});
...
expect(mySpy).toBeCalledWith({...})
Run Code Online (Sandbox Code Playgroud)

它有效,而且这是唯一有效的方法