React/Jestでのテストで「要素が存在しない」を確認する
これはスペースマーケット Engineer Blog の記事です。
書き手はfumink7です。
不揃いバームクーヘンを食べながら書いています。
おいしいね 🙌
なんの記事?
React/Jest(Testing-library)で「要素が存在しない」を確認する方法についてです。
ほぼここ↓に載っている内容なのでこちら見れば済む話なのですが、ちょっと整理しておこうかと。
あったものが存在しなくなったことを確認したい
たとえば非同期処理が実行された結果、要素が削除されたことを確認するようなテストですね。
waitForで要素が存在しなくなるまで待つ
以下のようにwaitForを使うことで要素がなくなったことを確認できます。
正確に言うと、expectをwaitForのタイムアウトまで実行し続けて期待値が返ってきたら(エラーが発生しなくなったら)テスト成功になりますね。
await waitFor(() => {
expect(screen.queryByAltText('テストだよ')).not.toBeInTheDocument()
})
余談ですが.not.toBeInTheDocument()
をtoHaveLength(0)
みたいに書いても問題ないですがテストの意味がわかりやすいよね、とのこと。
waitForElementToBeRemovedで要素がなくなったことをキャッチ
waitForElementToBeRemovedを使って要素がなくなったことをキャッチアップする方法もあります。
MutationObserverを利用しているので、DOMに変更があった場合にのみチェックが走るため効率的とのこと。
await waitForElementToBeRemoved(() => queryByText('テストだよ'))
最初存在しない → 処理の結果、やっぱり存在しないことを確認したい
レンダリング→非同期でのAPIへのデータ取得→View反映というコンポーネント表示の確認のテストで
- 取得したデータがある場合、List表示されること
- 取得したデータがなかった場合、List表示されないこと
という確認を行いたかった場合、2はどうすべきなんだ?と迷いました。
というのも、waitForで要素がなかったことを確認しようとしてもそれがデータ取得処理の前なのか後なのか確認できないということです。
render(<TargetComponent />)
// render直後はListが表示されておらず、非同期でのデータ取得をおこないデータが存在すれば表示、無ければListは表示されないまま
// ↓リストがないことを確認できた時(成功時)、それがデータ取得処理後に行われたという保証がない
await waitFor(() => {
expect(screen.queryByAltText('テストだよ')).not.toBeInTheDocument()
})
非同期処理が完了する(であろう)時間を確保する
シンプルなやり方ですが、データ取得処理が終わるまで待ってからfindBy
が失敗することを期待するテストです。
↓この例だとあくまで「100ms待てば終わっているだろう」というものでデータ取得処理が確実に終わったことを保証するものではないので、時間設定が難しいかも?
await expect(
screen.findByRole('list', {}, { timeout: 100 }),
).rejects.toThrow()
非同期処理の完了を検知する方法はあるのか??
もちろんコードにもよると思うのですが、コンポーネント内のこの非同期処理完了を検知したらアサーションを実行、みたいなことが書けるのでしょうか?
SpyOn
とか利用すればできそうな気がするのですが、結局よくわからず…
続報を待て🕵🏾
参考:実行環境
テスティングフレームワークはJest、UIテストのためにTesting Libraryを使用しています
- typescript@4.9.4
- React@18.2.0
- jest@28.1.0
- @testing-library/react@13.3.0
(いつもの宣伝)スペースマーケットはエンジニアを募集しています!
もちろんエンジニア大募集中です!
スペースを簡単に貸し借りできるサービス「スペースマーケット」のエンジニアによる公式ブログです。 弊社採用技術スタックはこちら -> whatweuse.dev/company/spacemarket
Discussion