新しい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>, + ]
それで、それを行うための最良の方法はどれですか?
すべてのテストスイートを<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 {
//...
}
遅延ロードされたコンポーネントはpromiseのようなものであることを忘れないでください。それらをテストにインポートし、解決するまで待ってから、スナップショットが一致することを確認します。
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();
});
});
ネストされたコンポーネントとレイジーロードされたコンポーネントの1つをスナップショットテストしたいという同様の問題がありました。ネストは次のようになりました。
_SalesContainer -> SalesAreaCard -> SalesCard -> AreaMap
_
ここで、SalesContainer
は最上位のコンポーネントです。 AreaMap
- componentはSalesCard
によってReact lazy and 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();
});
});
_