【问题标题】:Jest mocking default exports - require vs import开玩笑模拟默认导出 - 需要与导入
【发布时间】:2018-04-13 21:05:47
【问题描述】:

我在这里看到了关于用 jest 模拟默认导出的问题,但我认为这已经被问过了:

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

在我的理解中,import module from location 直接翻译成const module = require(location).default,所以我很困惑为什么会这样。我宁愿保持我的代码风格一致,而不是在原始模块中使用require 调用。

有办法吗?

使用模拟测试文件:

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();
});

依赖.js

export default () => console.log('do something');

module.js(不工作)

import dependency from './dependency.js';
dependency();

module.js(工作)

const dependency = require('./dependency.js').default;
dependency();

【问题讨论】:

  • dependency 调用是否发生在与jest.mock 调用不同的模块上?
  • 不应该jest.mock('./dependecy', () => jest.fn()); 在这两种情况下都有效吗?
  • 我更新了测试文件的代码,显示模块正在通过简单的导入和运行进行测试。

标签: javascript jestjs es6-modules


【解决方案1】:

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

jest.mock('dependency', () => ({
  ...jest.requireActual('dependency'),
  __esModule: true,
  default: jest.fn(),
}))

【讨论】:

  • 虽然接受的答案提供了关于发生了什么以及为什么会发生这种情况的详细信息,但我发现这实际上是一个更清洁的解决方案。不知道为什么它被否决了,但是在像我这样的场景中,代码库没有完全迁移到 ES6/Typescript 以进行导入,将 __esModule 选项设置为 false 就可以了,它允许在使用 es6 而不是的模块中使用导入必须在较新的文件中混合 require js。
  • 如果您想同时拥有默认导出和其他导出,您可以这样做。 __esModule: true 是正确处理 default 所需要的。
【解决方案2】:

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

jest.mock('./dependency', () => () => jest.fn());

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

【讨论】:

    【解决方案3】:

    您可以使用es6 importrequire js 在您的笑话测试中导入您的js 文件。

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

    我还应该补充一点,正如here jest 默认情况下会将任何 jest.mocks 提升到文件顶部,因此您放置导入的顺序并不重要。

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

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

    当您使用require js 导入文件时,它的结构如下:

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

    const test = require('../Test');
    test.default.doSomething();
    

    当使用es6 import 导入它时,您应该以不同的方式进行。使用相同的示例:

    import Test from '../Test';
    Test.doSomething();
    

    编辑:如果您想使用es6 import,请将您的模拟函数更改为:

    jest.mock('./dependecy', () => jest.fn());
    

    【讨论】:

    • 我正在测试的模块根本没有导出类或任何东西。我更新了代码以显示那是什么。然而,它正在导入/需要一个具有默认导出的模块。
    • 所以我的模块应该导入依赖 es6 样式。如果模拟期望require js,我怎样才能让它期望es6 import
    • @AnnaMelzer 我已经用你的模拟函数应该如何编辑我的答案。
    • 我只是好奇,但是_esModule: true是什么,我如何打印导入文件的结构? (不是从所需文件返回的对象)
    • @KevinChandra __esModule 让导入模块知道这是一个转译的 ES 模块(这对于默认导出尤其重要)。
    猜你喜欢
    • 2021-09-25
    • 1970-01-01
    • 2020-05-27
    • 2018-07-25
    • 2018-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    相关资源
    最近更新 更多