Как протестировать снимки с помощью 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()
Ответ Рейна каким-то образом не работал с нашим агентом сборки, но работал в среде разработки.