使用 Jest 部分模拟 React 模块 [英] Partially mock React module with Jest

查看:31
本文介绍了使用 Jest 部分模拟 React 模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在导入的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆