Как протестировать снимки с помощью Jest и нового React lazy 16.6 API

Я должен компоненты, импортированные с новым React lazy API (16.6).

import React, {PureComponent, lazy} from 'react';

const Component1 = lazy(() => import('./Component1'));
const Component2 = lazy(() => import('./Component2'));

class CustomComponent extends PureComponent {
  ...
  render() {

  return (
    <div>
      <Component1 />
      <Component2 />
    </div>
  );
 }
}

В своих тестах я делаю снимки этого компонента. Это очень простой тест:

import { create } from 'react-test-renderer';

const tree = await create(<CustomComponent />).toJSON();

expect(tree).toMatchSnapshot();

В журналах тест не пройден с этой ошибкой:

A React component suspended while rendering, but no fallback UI was specified.

Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.

Должен ли я обернуть в каждом тестовом наборе с <Suspense>...?

it('should show the component', async () => {
  const component = await create(
    <React.Suspense fallback={<div>loading</div>}>
     <CustomComponent /> 
    </React.Suspense> 
  ); 
  const tree = component.toJSON(); 

  expect(tree).toMatchSnapshot(); 

};

Если я это сделаю, я только вижу в снимке fallback составная часть.

+ Array [ + <div> + loading + </div>, + ]

Итак, какой лучший способ сделать это?

5 ответов

Решение

Должен ли я обернуть в каждом тестовом наборе с <Suspense> ?

Да, Suspense компонент необходим для ленивой загрузки дочерних компонентов, в частности, для обеспечения резервирования и для согласования, когда доступны ленивые компоненты.

экспорт Component1 а также Component2 в CustomComponent так что они могут быть импортированы в тестах.

import React, {PureComponent, lazy} from 'react';

export const Component1 = lazy(() => import('./Component1'));
export const Component2 = lazy(() => import('./Component2'));

export default class CustomComponent extends PureComponent {
  //...
}

Помните, что лениво загруженные компоненты похожи на обещания. Импортируйте их в тест и дождитесь их разрешения, прежде чем проверять соответствие снимка.

import { create } from 'react-test-renderer';
import React, {Suspense} from 'react';
import CustomComponent, {Component1, Component2} from './LazyComponent';

describe('CustomComponent', () => {
  it('rendered lazily', async()=> {
    const root = create(
      <Suspense fallback={<div>loading...</div>}>
        <CustomComponent/>
      </Suspense>
    );

    await Component1;
    await Component2;
    expect(root).toMatchSnapshot();
  })
})

Согласно этому комментарию в github, вы можете издеваться над ленивыми компонентами с помощью Jest, чтобы вместо этого возвращать фактические компоненты, хотя вам нужно будет перемещать и экспортировать ленивые операторы в их собственные файлы, чтобы они работали.

// LazyComponent1.ts
import { lazy } from 'react';

export default lazy(() => import('./Component1'));
// CustomComponent.tsx
import React, { PureComponent } from 'react';
import Component1 from './LazyComponent1';
import Component2 from './LazyComponent2';

class CustomComponent extends PureComponent {
  ...
  render() {

  return (
    <div>
      <Component1 />
      <Component2 />
    </div>
  );
 }
}
// CustomComponent.spec.tsx
import React, { Suspense } from 'react';
import { create } from 'react-test-renderer';
import CustomComponent from './CustomComponent';

jest.mock('./LazyComponent1', () => require('./Component1'));
jest.mock('./LazyComponent2', () => require('./Component2'));

describe('CustomComponent', () => {
  it('should show the component', () => {
    const component = await create(
      <Suspense fallback={<div>loading</div>}>
       <CustomComponent /> 
      </Suspense> 
    ); 
    const tree = component.toJSON(); 

    expect(tree).toMatchSnapshot(); 
  });
});

С Enzyme и mount это сработало для меня. Это не требует изменения каких-либо экспортов.

      // wait for lazy components
await import('./Component1')
await import('./Component2')

jest.runOnlyPendingTimers()
wrapper.update()

Благодаря комментарию Эндрю Ферка к принятому ответу.

У меня была аналогичная проблема, когда я хотел сделать тестирование снимков вложенных компонентов, и один из них загружался лениво. Вложенность выглядела примерно так:

SalesContainer -> SalesAreaCard -> SalesCard -> AreaMap

где SalesContainerэто верхний компонент. ВAreaMap-компонент лениво загружается SalesCardиспользуя React lazy и Suspense. Тесты прошли локально сAreaMapвизуализируется в снимке для большинства разработчиков. Но тесты всегда с треском проваливались в Jenkins CI сAreaMapникогда не отображался. Слабый, мягко говоря.

Чтобы тесты прошли, я добавил волшебную строку await testRenderer.getInstance().loadingPromise;на тесты. Это пример теста:

import React from 'react';
import renderer from 'react-test-renderer';
import wait from 'waait';
import SalesContainer from './index';

describe('<SalesContainer />', () => {
it('should render correctly', async () => {
    const testRenderer = renderer.create(
      <SalesContainer />
    );
    await wait(0);
    await testRenderer.getInstance().loadingPromise;
    expect(testRenderer).toMatchSnapshot();
  });
});

В некотором смысле комбинация двух ответов - единственное, что сработало для меня (используя ферментное крепление)

Мне пришлось использовать логику экспорта принятого ответа и логику ожидания ответа Рейна.

      //use at own risk
await (Component1 as any)._ctor();
wrapper.update()

Ответ Рейна каким-то образом не работал с нашим агентом сборки, но работал в среде разработки.

Другие вопросы по тегам