使用 Jest 部分模拟 React 模块 [英] Partially mock React module with Jest
问题描述
我试图在导入的 React 模块中只模拟一个函数,保持模块的其余部分不被模拟,并在所有测试的顶层执行此操作.
I'm trying to mock only one function in imported React module, keep the rest of the module unmocked and do this at top level for all tests.
我正在使用新的 create-react-app 项目和单个测试来观察问题.
I'm using fresh create-react-app project with a single test to observe the problem.
重现步骤:
create-react-app 测试
- 使用提供的
src/App.test.js
作为唯一的测试文件 npm 运行测试
create-react-app test
- use provided
src/App.test.js
as the only test file npm run test
App.test.js
jest.mock('react', () => {
jest.dontMock('react');
const React = require('react');
const lazy = jest.fn();
return {
...React,
lazy
};
});
import * as React from 'react';
const React2 = require('react');
it('should partially mock React module', async () => {
expect(jest.isMockFunction(React.lazy)).toBe(true); // passes
expect(jest.isMockFunction(React2.lazy)).toBe(true); // fails
expect(jest.isMockFunction(require('react').lazy)).toBe(true); // fails
expect(jest.isMockFunction((await import('react')).lazy)).toBe(true); // fails
});
这里的问题似乎是 jest.dontMock
因为它阻止了 require
和动态 import
被模拟,但目前尚不清楚为什么可以通过这种方式模拟静态 import
,因为它以任何方式使用 require
.这是转译的文件:
The problem here seems to be jest.dontMock
as it prevents require
and dynamic import
from being mocked, but it remains unclear why it was possible to mock static import
this way, as it uses require
any way. Here's transpiled file:
"use strict";
jest.mock('react', () => {
jest.dontMock('react');
const React = require('react');
const lazy = jest.fn();
return (0, _objectSpread2.default)({}, React, {
lazy
});
});
var _interopRequireWildcard3 = require("...\node_modules\@babel\runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("...\node_modules\@babel\runtime/helpers/interopRequireDefault");
var _interopRequireWildcard2 = _interopRequireDefault(require("...\node_modules\@babel\runtime/helpers/interopRequireWildcard"));
var _objectSpread2 = _interopRequireDefault(require("...\node_modules\@babel\runtime/helpers/objectSpread"));
var React = _interopRequireWildcard3(require("react"));
const React2 = require('react');
...
这可能与 create-react-app Jest+Babel 设置有关,因为我无法使 jest.dontMock
与 vanilla Jest 和 require
错误地工作.
This may have something to do with create-react-app Jest+Babel setup because I was unable to make jest.dontMock
work incorrectly with vanilla Jest and require
.
为什么静态 React
导入被模拟,而 React2
和其余的不是?里面到底发生了什么?
Why is static React
import mocked but React2
and the rest aren't? What exactly is going on inside?
如何修复 jest.dontMock
当前行为以在顶层部分模拟模块?
How can jest.dontMock
current behaviour be fixed to partially mock a module at top level?
推荐答案
默认导入:
一个简单的解决方案是在 setupTest.js
中模拟 React.lazy
:
import React from 'react';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
jest.spyOn(React.lazy);
对于每个测试文件,react
的任何后续 require/imports
都将被部分模拟.
Any subsequent require/imports
of react
will be partially mocked for each test file.
工作示例:https://github.com/mattcarlotta/react-lazy-mocked(我不使用 create-react-app
,但是 jest
可以像我一样设置)
Working example: https://github.com/mattcarlotta/react-lazy-mocked (I don't use the create-react-app
, but jest
can be set up the same way as I have it)
安装:
git clone git@github.com:mattcarlotta/react-lazy-mocked.git
cd react-lazy-mocked
纱线安装
纱线测试
root/__tests__/root.test.js
import React from 'react';
import App from '../index.js';
const React2 = require('react');
describe('App', () => {
const wrapper = mount(<App />);
it('renders without errors', () => {
const homeComponent = wrapper.find('.app');
expect(homeComponent).toHaveLength(1);
});
it('should partially mock React module', async () => {
expect(jest.isMockFunction(await require('react').lazy)).toBe(true); // eslint-disable-line global-require
expect(jest.isMockFunction(React)).toBe(false);
expect(jest.isMockFunction(React.lazy)).toBe(true);
expect(jest.isMockFunction(React2)).toBe(false);
expect(jest.isMockFunction(React2.lazy)).toBe(true);
});
it('should no longer be partially mocked within the test file', () => {
React.lazy.mockRestore();
expect(jest.isMockFunction(React.lazy)).toBe(false);
});
});
pages/Home/__tests__/Home.test.js
import React from 'react';
import Home from '../index.js';
describe('Home', () => {
const wrapper = shallow(<Home />);
it('renders without errors', () => {
const homeComponent = wrapper.find('.app');
expect(homeComponent).toHaveLength(1);
});
it('should partially mock React module', async () => {
expect(jest.isMockFunction(React.lazy)).toBe(true);
});
});
<小时>
命名导入:
工作示例:https://github.com/mattcarlotta/named-react-lazy-mocked
安装:
git clone git@github.com:mattcarlotta/named-react-lazy-mocked.git
cd named-react-lazy-mocked
纱线安装
纱线测试
utils/__mocks__/react.js
jest.mock('react', () => ({
...require.requireActual('react'),
lazy: jest.fn(),
}));
module.exports = require.requireMock('react');
utils/setup/setupTest.js(或者,您可以将模拟的 react
文件添加为 global
玩笑函数,这样您就不会不必为每个测试编写 import * as React from 'react'
:
utils/setup/setupTest.js (optionally, you can add the mocked react
file as a global
jest function so you won't have to write import * as React from 'react'
for every test):
import { JSDOM } from 'jsdom';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
// import React from '../__mocks__/react';
configure({ adapter: new Adapter() });
// global.React = React;
root/__tests__/root.test.js
import * as React from 'react';
import App from '../index.js';
const React2 = require('react');
describe('App', () => {
const wrapper = mount(<App />);
it('renders without errors', () => {
const homeComponent = wrapper.find('.app');
expect(homeComponent).toHaveLength(1);
});
it('should partially mock React module', async () => {
expect(jest.isMockFunction(await require('react').lazy)).toBe(true); // eslint-disable-line global-require
expect(jest.isMockFunction(React)).toBe(false);
expect(jest.isMockFunction(React.lazy)).toBe(true);
expect(jest.isMockFunction(React2)).toBe(false);
expect(jest.isMockFunction(React2.lazy)).toBe(true);
});
});
这篇关于使用 Jest 部分模拟 React 模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!