笑话:当同一个模块也有命名导出时,如何模拟默认导出组件?

Posted

技术标签:

【中文标题】笑话:当同一个模块也有命名导出时,如何模拟默认导出组件?【英文标题】:Jest: How to mock default export Component when same module also has named export? 【发布时间】:2018-07-27 15:41:23 【问题描述】:

我有一个 ES6 模块,它默认导出一个 React 组件类,但也导出一个普通的 JS 函数作为命名导出。在测试使用此模块的其他包时,我想模拟默认导出的组件和命名的导出函数,以保持我的单元测试纯净。

模块看起来像这样:

import React,  Component  from 'react';

export default class MyComponent extends Component 
  render() 
    return <div>Hello</div>
  


export function myUtilityFunction()  return 'foo' ;

我想使用以下语法来模拟导出:

import React from 'react';
import MyComponent,  myUtilityFunction  from './module';

jest.mock('./module');
MyComponent.mockImplementation(() => 'MockComponent');
myUtilityFunction.mockImplementation(() => 'foo');

但是,当我尝试使用此语法时,在其他组件中使用时,MyComponent 似乎没有被模拟。当我尝试像这样模拟 MyComponent 并自行渲染时,它会渲染为 null。

这种行为很奇怪,因为如果我使用完全相同的语法,但两个导入都是 javascript 函数,则模拟按预期工作。请参阅我在此处打开的 *** 问题,该问题确认当导入都是函数时语法有效。

这里是一个演示问题的 GitHub 存储库,以及我尝试过的几个解决方案:https://github.com/zpalexander/jest-enzyme-problem

您可以构建 repo 并使用 yarn install && yarn test 运行测试

谢谢!

【问题讨论】:

【参考方案1】:

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

  jest.mock('./module', () => (
    __esModule: true,
    myUtilityFunction: 'myUtilityFunction',
    default: 'MyComponent'
  ));

另一种方法:

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

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

【讨论】:

这在大多数情况下都有效,尽管要在我的示例仓库中通过测试,您需要将 myUtilityFunction: 'myUtilityFunction 更改为 myUtilityFunction: () =&gt; 'myUtilityFunction'【参考方案2】:

我认为问题在于 ShallowWrapper 类的 getElement 方法需要传递一个包含渲染方法的类。为此,您的 MyComponent.mockImplementation 需要更全面地模拟类构造函数。

有关如何模拟类构造函数的详细信息,请参阅从“mockImplementation 也可用于模拟类构造函数:”https://facebook.github.io/jest/docs/en/mock-function-api.html#mockfnmockimplementationfn

开始的 Jest 文档

使用 Jest 文档作为模型,我们可以模拟 MyComponent 类构造函数使其可通过酶进行浅层渲染,如下所示:

MyComponent.mockImplementation(() => 
  return 
    render: () => <div>MockComponent</div>
  ;
);

现在当 getElement 去寻找渲染方法时,它会找到它。

以下是在您的存储库中的 App.mockImplementation.test.js 文件上实现此更改的要点:https://gist.github.com/timothyjellison/a9c9c2fdfb0b30aab5698dd92e901b24

【讨论】:

这个解决方案对我有用。感谢您的回复。我希望有一种方法可以用更少的样板来做到这一点,但根据 Jest 维护者的说法,一切都按预期工作:github.com/facebook/jest/issues/5579#event-1477087994

以上是关于笑话:当同一个模块也有命名导出时,如何模拟默认导出组件?的主要内容,如果未能解决你的问题,请参考以下文章

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

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

将 CommonJS 默认导出导入为命名导出/无法加载 ES 模块

无法从非 EcmaScript 模块导入命名的导出 XXXX(只有默认导出可用)

为啥导出/导入默认 ES 模块属性比命名模块属性更快?

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