使用 Jest 模拟带有 props 的 React 组件
Using Jest to mock a React component with props
我有一个 React 组件,其中包含一些依赖于访问 Redux 存储等的其他组件,这在执行完整的 Enzyme 挂载时会导致问题。让我们说一个这样的结构:
import ComponentToMock from './ComponentToMock';
<ComponentToTest>
...some stuff
<ComponentToMock testProp="This throws a warning" />
</ComponentToTest>
我想用Jest的.mock()
方法mock出子组件,这样就不用担心测试了
我知道我可以用类似的东西模拟出一个直接组件:
jest.mock('./ComponentToMock', () => 'ComponentToMock');
然而,由于该组件通常会接收 props,React 会感到不安,发出警告,告知未知的 props(在本例中为 testProp
)被传递给 <ComponentToMock />
。
我试过 return 一个函数,但是你不能 return Jest 模拟中的 JSX(据我所知),因为它被提升了。在这种情况下会抛出错误。
所以我的问题是我怎样才能
a) 让 ComponentToMock
忽略传递给它的道具,或者
b) return 一个 React 组件,可用于模拟我不担心测试的子组件。
或者...有更好的方法吗?
docs for jest.mock()
底部有一个注释,用于防止提升行为:
Note: When using babel-jest
, calls to mock
will automatically be
hoisted to the top of the code block. Use doMock
if you want to
explicitly avoid this behavior.
然后你可以按照你描述的那样做:return一个函数,它是你不需要测试的组件的存根。
jest.doMock('./ComponentToMock', () => {
const ComponentToMock = () => <div />;
return ComponentToMock;
});
const ComponentToTest = require('./ComponentToTest').default;
命名存根组件很有帮助,因为它会在快照中呈现。
自从我问了这个问题后,我又学到了一些东西。这是处理需要传递道具的模拟组件的另一种(更好?)方法:使用模块 mock 文件.
首先在组件文件夹下的 __mocks__
文件夹中创建一个与要模拟的组件同名的文件,例如
.
|- /ComponentToMock.js
└- /__mocks__/ComponentToMock.js <-- create this folder/file!
注意:在撰写本文时,文件夹 必须 被称为 __mocks__
(您将需要在您需要模拟组件的每个文件夹中创建 __mocks__
。如果下划线让您不高兴,就假装它们不存在 ;) )
接下来,在这个模拟文件中,你可以随意编写文件,例如
// 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 的模拟组件,否则会在返回空函数时产生 prop 警告(但如果组件没有收到 props 则继续使用是完全可以接受的)。我希望这可以帮助一些人。
就我而言,我无法进行模拟工作。
结果是 case-sensitivity 问题:
模块文件名:Autosuggest.js
我是如何嘲笑它的:jest.mock('./AutoSuggest', ...);
<-- 错误案例
除了已接受的答案外,如果您使用多个导出,则可以按如下方式进行模拟:
// 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
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');
});
我有一个 React 组件,其中包含一些依赖于访问 Redux 存储等的其他组件,这在执行完整的 Enzyme 挂载时会导致问题。让我们说一个这样的结构:
import ComponentToMock from './ComponentToMock';
<ComponentToTest>
...some stuff
<ComponentToMock testProp="This throws a warning" />
</ComponentToTest>
我想用Jest的.mock()
方法mock出子组件,这样就不用担心测试了
我知道我可以用类似的东西模拟出一个直接组件:
jest.mock('./ComponentToMock', () => 'ComponentToMock');
然而,由于该组件通常会接收 props,React 会感到不安,发出警告,告知未知的 props(在本例中为 testProp
)被传递给 <ComponentToMock />
。
我试过 return 一个函数,但是你不能 return Jest 模拟中的 JSX(据我所知),因为它被提升了。在这种情况下会抛出错误。
所以我的问题是我怎样才能
a) 让 ComponentToMock
忽略传递给它的道具,或者
b) return 一个 React 组件,可用于模拟我不担心测试的子组件。
或者...有更好的方法吗?
docs for jest.mock()
底部有一个注释,用于防止提升行为:
Note: When using
babel-jest
, calls tomock
will automatically be hoisted to the top of the code block. UsedoMock
if you want to explicitly avoid this behavior.
然后你可以按照你描述的那样做:return一个函数,它是你不需要测试的组件的存根。
jest.doMock('./ComponentToMock', () => {
const ComponentToMock = () => <div />;
return ComponentToMock;
});
const ComponentToTest = require('./ComponentToTest').default;
命名存根组件很有帮助,因为它会在快照中呈现。
自从我问了这个问题后,我又学到了一些东西。这是处理需要传递道具的模拟组件的另一种(更好?)方法:使用模块 mock 文件.
首先在组件文件夹下的 __mocks__
文件夹中创建一个与要模拟的组件同名的文件,例如
.
|- /ComponentToMock.js
└- /__mocks__/ComponentToMock.js <-- create this folder/file!
注意:在撰写本文时,文件夹 必须 被称为 __mocks__
(您将需要在您需要模拟组件的每个文件夹中创建 __mocks__
。如果下划线让您不高兴,就假装它们不存在 ;) )
接下来,在这个模拟文件中,你可以随意编写文件,例如
// 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 的模拟组件,否则会在返回空函数时产生 prop 警告(但如果组件没有收到 props 则继续使用是完全可以接受的)。我希望这可以帮助一些人。
就我而言,我无法进行模拟工作。
结果是 case-sensitivity 问题:
模块文件名:Autosuggest.js
我是如何嘲笑它的:jest.mock('./AutoSuggest', ...);
<-- 错误案例
除了已接受的答案外,如果您使用多个导出,则可以按如下方式进行模拟:
// 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
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');
});