警告の原因となる状態の更新後にアサートするものが何もない場合に、Jest/testing-library によってスローされる「act(...) にラップされていません」という警告を防ぐ方法があるかどうかを調べようとしています。または、この警告を無視する必要がある場合。
次の単純なコンポーネントがあるとします。
import React, {useEffect, useState} from 'react';
import {getData} from 'services';
const MyComponent = () => {
const [arr, setArr] = useState([]);
useEffect(() => {
(async () => {
const {items} = await getData();
setArr(items);
})();
}, []);
return (
<div>
{!(arr.length > 0) && <p>no array items</p>}
{arr.length > 0 && (
<ul>
{arr.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)}
</div>
);
};
export default MyComponent;
getData()
このコンポーネントがデータを返さなくても正常にレンダリングされることを簡単にテストしたいとします。
だから私はこのようなテストを持っています:
import React from 'react';
import {getData} from 'services';
import {render, screen} from 'testUtils';
import MyComponent from './MyComponent';
jest.mock('services', () => ({
getData: jest.fn(),
}));
it('renders', () => {
getData.mockResolvedValue({items: []});
render(<MyComponent />);
expect(screen.getByText('no array items')).toBeInTheDocument();
});
このテストはパスしますが、「act(...) にラップされていません」という警告が表示されます。これは、テストが終了する前に終了するgetData()
ためです。
この場合、からの応答は、最初にコンポーネントの上部にgetData()
設定arr
した値 (空の配列) に設定されます。そのため、非同期関数が完了した後も UI は変更されません。まだ「配列項目なし」と書かれている段落を見ているだけなので、状態の更新を待つと主張できるものは何もありません。完了します。
できますがexpect(getData).toHaveBeenCalledTimes(1)
、関数呼び出し後に状態が実際に更新されるのを待ちません。
setArr(items)
発生する時間を確保するために、テストで任意の一時停止を試みました。
it('renders', async () => {
getData.mockResolvedValue({items: []});
render(<MyComponent />);
expect(screen.getByText('no array items')).toBeInTheDocument();
await new Promise(resolve => setTimeout(resolve, 2000));
expect(screen.getByText('no array items')).toBeInTheDocument();
});
しかし、それは役に立たないようです。正直なところ、その理由はわかりません。
テストのみを変更して、この状況を処理する方法はありますか?
MyComponent をリファクタリングすることで問題を解決できると確信しています。たとえば、arr
MyComponent を prop として渡し、呼び出しを親コンポーネントに移動するか、呼び出しを完全にgetData()
スキップするテスト専用のカスタム prop を作成しますが、私はしません。getData()
テストでの警告を避けるためだけにコンポーネントを変更したくない。
私はtesting-library/react v11.2.2 を使用しています。