はじめに
かなり苦労しました。
問題
TypeError: Cannot read properties of null (reading 'length')のエラーが発生する。
エラーメッセージ
TypeError: Cannot read properties of null (reading 'length')
49 | // console.log("newRecordCount", newRecordCount);
50 |
> 51 | await expect(recordCount + 1).toBe(newRecords.length);
| ^
52 | });
53 |
at length (src/tests/componenteSample.spec.jsx:51:50)
at call (src/tests/componenteSample.spec.jsx:2:1)
at Generator.tryCatch (src/tests/componenteSample.spec.jsx:2:1)
at Generator._invoke [as next] (src/tests/componenteSample.spec.jsx:2:1)
at asyncGeneratorStep (src/tests/componenteSample.spec.jsx:2:1)
at asyncGeneratorStep (src/tests/componenteSample.spec.jsx:2:1)
解決方法
エラーのコード
const newRecords = await waitFor(() => {
const elements = screen.getAllByTestId('record');
if (elements.length > recordCount) {
return elements;
}
return null;
});
const newRecordCount = newRecords.length;
await expect(recordCount + 1).toBe(newRecords.length);
await
await は、Promise が解決される(resolve または reject される)まで待機する演算子です。非同期関数内で使用され、処理を一時停止します。(copilot)
awaitを付けても、await expect(recordCount + 1).toBe(newRecordCount);は、expectの結果が返るまで待機するという意味にはならない。
console.logで確認したところ、undefinedが返ってきていた。
awaitの場合、undefinedが返ってきたら再計算することはない。
await waitFor
waitFor は、特定の条件が満たされるまで繰り返し実行される関数です。React Testing Library で使用され、非同期にレンダリングされる要素や状態の変化を待つために使用されます。デフォルトの間隔は50msで、デフォルトのタイムアウトは1000msです。(copilot)
expectを同期的に待機するためには、waitFor関数の中でexpectを使用する必要がある。
waitFor内でexpectを使用することで、条件が満たされるまで待機することができる。
Testing Libraryのドキュメントによると、waitForはタイムアウトに達するまで何度でもコールバックを実行する。デフォルトの間隔は50msで、デフォルトのタイムアウトは1000ms。
await waitFor(() => {
const newRecords = screen.getAllByTestId('record');
const newRecordCount = newRecords.length;
console.log("newRecordCount", newRecordCount);
expect(recordCount + 1).toBe(newRecordCount);
});
参考
async function内でPromiseの結果(resolve、reject)が返されるまで待機する(処理を一時停止する)演算子のこと。
https://qiita.com/soarflat/items/1a9613e023200bbebcb3#await%E3%81%A8%E3%81%AF
testing-libraryのドキュメント
https://testing-library.com/docs/dom-testing-library/api-async/#waitfor