使用 Jest 模拟带有 props 的 React 组件

Posted

技术标签:

【中文标题】使用 Jest 模拟带有 props 的 React 组件【英文标题】:Using Jest to mock a React component with props 【发布时间】:2017-11-08 05:55:49 【问题描述】:

我有一个 React 组件,其中包含一些其他组件,这些组件依赖于对 Redux 存储等的访问,这在执行完整的 Enzyme 装载时会导致问题。让我们说一个这样的结构:

import ComponentToMock from './ComponentToMock';

<ComponentToTest>
  ...some stuff
  <ComponentToMock testProp="This throws a warning" />
</ComponentToTest>

我想使用 Jest 的 .mock() 方法来模拟出子组件,这样就不用担心测试了。

我知道我可以用类似这样的东西来模拟一个直接的组件:

jest.mock('./ComponentToMock', () =&gt; 'ComponentToMock');

但是,由于该组件通常会接收 props,因此 React 会感到不安,并发出警告,提示未知 props(在本例中为 testProp)被传递给 &lt;ComponentToMock /&gt;

我尝试返回一个函数,但是你不能在 Jest 模拟中返回 JSX(据我所知),因为它被提升了。在这种情况下会引发错误。

所以我的问题是我该怎么做

a) 让ComponentToMock 忽略传递给它的道具,或者

b) 返回一个 React 组件,该组件可用于模拟我不担心测试的子组件。

或者...有更好的方法吗?

【问题讨论】:

我自己遇到了很多麻烦,但在这里得到了回答:SO Question 【参考方案1】:

docs for jest.mock()底部有一个注意防止吊装行为:

注意:使用babel-jest 时,对mock 的调用将自动 提升到代码块的顶部。如果你想使用doMock 明确避免这种行为。

然后您可以按照您的描述进行操作:返回一个函数,该函数是您不需要测试的组件的存根。

jest.doMock('./ComponentToMock', () => 
  const ComponentToMock = () => <div />;
  return ComponentToMock;
);

const ComponentToTest = require('./ComponentToTest').default;

命名存根组件会很有帮助,因为它会在快照中呈现。

【讨论】:

这很高兴知道!文档提到它有点不经意。但是,我尝试了这个,但仍然没有成功。因为 的导入是在引入 的时候发生的,除非 Jest 的 mock 被提升为 first,否则是事后发生的,并且 mock 不起作用。 我更新了 sn-p:你必须做模拟,然后要求组件进行测试。 我已经设法让这个工作在基本意义上发挥作用。它确实需要使用... require,ahem,而不是 import。对于任何有类似情况的人来说,这可能值得考虑。我有一个更复杂的设置,似乎无法使用该修复程序,但这可能只是一些干扰 HOC。感谢您的帮助! 同样,这个解决方案行不通,它会抛出一个Invariant Violation: getNodeFromInstance: Invalid argument. 似乎我们应该接受测试输出时的警告。 根据组件导出/导入的方式,您可能需要执行return ComponentToMock【参考方案2】:

自从我提出这个问题后,我学到了更多。这是处理需要传递道具的模拟组件的另一种(更好的?)方法:使用模块模拟文件

首先在组件文件夹下的__mocks__文件夹中创建一个与要模拟的组件同名的文件,例如

.
|- /ComponentToMock.js
└- /__mocks__/ComponentToMock.js <-- create this folder/file!

注意:在撰写本文时,文件夹必须被称为__mocks__(您需要在您需要的每个文件夹中创建__mocks__模拟组件。如果下划线让你不高兴,就假装它们不存在;))

接下来,在这个mock文件中,你可以随意写文件,例如

// This code would live in ./__mocks__/ComponentToMock.js
import React from 'react';
const ComponentToMock = ( testProp ) => <div>A mock with 'testProp' passed!</div>;
export default ComponentToMock;

然后在测试文件中,将Jest mock语句改为:jest.mock('./ComponentToMock');

当 Jest 遇到没有第二个函数参数的 .mock() 时,它会自动查找 __mocks__ 文件夹。然而,即使 mock 语句在被测试的组件中被提升,这不会影响 mock 本身的导入 - 因此它能够导入和编译 React 组件!

这似乎适用于需要传递 props 的模拟组件,否则如果返回 null 函数会产生 prop 警告(但如果组件没有接收到 props 则继续使用是完全可以接受的)。我希望这可以帮助一些人。

【讨论】:

关于假装看不到下划线的部分非常有帮助。我会的!【参考方案3】:

除了接受的答案,如果您使用多个导出,则可以按如下方式进行模拟:

// Component.jsx

export  A, B ;
// Component-test.js

jest.mock("../src/Component", () => 
  return 
    A: true,
    B: () => 
      return <></>;
    ,
  ;
)

参考博客:https://thoughtbot.com/blog/mocking-react-components-with-jest

【讨论】:

【参考方案4】:

就我而言,我无法使模拟工作。

原来是区分大小写的问题:

模块文件名:Autosuggest.js

我是如何嘲笑它的:jest.mock('./AutoSuggest', ...);

【讨论】:

【参考方案5】:
const mockComponent = ComponentName => ( children, ...props ) => (
  <ComponentName ... '[mockComponent]': true  ...props>
    children
  </ComponentName>
);

export default mockComponent;
jest.mock('../ComponentToMock', () => 
  const mockComponent = require('./mockComponent').default;

  return mockComponent('ComponentToMock');
);

【讨论】:

以上是关于使用 Jest 模拟带有 props 的 React 组件的主要内容,如果未能解决你的问题,请参考以下文章

如何用 Jest 模拟/替换对象的 getter 函数?

开玩笑:模拟 console.error - 测试失败

如何在带有 Jest 的 react-native 中使用模拟的 fetch() 对 API 调用进行单元测试

Jest 模拟内部函数

在 React 应用程序中使用 Jest 模拟导入/模块

Jest : 模拟导入 JSON 文件