Частично издеваться над модулем React с помощью Jest - PullRequest
4 голосов
/ 24 марта 2019

Я пытаюсь смоделировать только одну функцию в импортированном модуле React, оставляя оставшуюся часть модуля неизменной и делаю это на верхнем уровне для всех тестов.

Я использую свежее приложение create-реагировать-приложениепроект с единственным тестом для наблюдения за проблемой.

Шаги для воспроизведения:

  • create-react-app test
  • используйте предоставленный src/App.test.js в качестве единственного файла теста
  • 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 любым способом.Вот файл для переноса:

"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');
...

Это может быть связано с установкой Jest + Babel create-Reaction-app, поскольку мне не удалось заставить jest.dontMock некорректно работать с vanilla Jest и require. * 1033.*

Почему статический React импорт импровизирован, а React2, а остальные нет?Что именно происходит внутри?

Как можно исправить текущее поведение jest.dontMock, чтобы частично высмеивать модуль на верхнем уровне?

1 Ответ

1 голос
/ 25 марта 2019

Импорт по умолчанию:

Простым решением было бы издеваться над React.lazy в setupTest.js:

import React from 'react';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });

jest.spyOn(React.lazy);

Любые последующие require/imports из react будут частично проверяться для каждого тестового файла.

Рабочий пример : https://github.com/mattcarlotta/react-lazy-mocked (я не использую create-react-app, но jest можно настроить так же, как он у меня)

Установка:

  • git clone git@github.com:mattcarlotta/react-lazy-mocked.git
  • cd react-lazy-mocked
  • yarn install
  • yarn test

корень / __ тесты __ / 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);
  });
});

страниц / Home / __ тесты __ / 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
  • yarn install
  • yarn test

Utils / __ издевается __ / react.js

jest.mock('react', () => ({
  ...require.requireActual('react'),
  lazy: jest.fn(),
}));
module.exports = require.requireMock('react');

utils / setup / setupTest.js (опционально, вы можете добавить смоделированный файл react как функцию global jest, чтобы вам не приходилось писать import * as React from 'react' для каждого теста) :

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.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);
  });
});
...