Reactで非同期処理をテストする中で、「ローディング中の表示が出るか」を確認をするためにモック関数(仮の処理)を使いました。
Supabase のような実際の通信は行なわず、代わりに非同期処理やPromiseを使用する手順をまとめました。
開発環境
- React(ViteまたはCreate React App)
- TypeScript
- Jest(React Testing Library)
- Supabase
テスト内容
- データ取得中に"読み込み中..."という表示があることをテストする
Promiseとは何か
Promise オブジェクトは非同期処理の完了(もしくは失敗)の結果およびその結果の値を表します。
JavaScriptでは時間がかかる処理(例:API呼び出し)はすぐに終わりません。
そのため「あとで結果が返ってくるよ」という約束をするのがPromiseです。
const promise = new Promise((resolve) => {
setTimeout(() => {
resolve("データが取れた!");
}, 1000); // 1秒後に結果を返す
});
Promise の状態には3つあります
- pending(保留中)
- fulfilled(成功)
- rejected(失敗)
resolve(...)
を呼ぶと fulfilled 状態になります。
setTimeoutで擬似的に遅延させる
テストでは Supabase のような実際の通信は行いません。
代わりにモック関数(仮の処理)を使います。
ローディング表示をテストするには、意図的にPromiseを少し遅延させることで"読み込み中..."が表示される瞬間を観測します。
mockFetchRecord.mockImplementationOnce(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ data: [], error: null });
}, 100); // 100ms 待ってから返す
});
});
このとき、mockImplementationOnce
を使うことで「このテストのときだけ動作を変える」という一時的なモックが可能になります。
mockImplementationOnce とは
Jest で定義されたモック関数に対して「次の1回だけこの実装で動かして」と命令できるメソッドです。
これにより、テストごとに異なる動作を定義することができ、特定の状態を意図的に再現できます。
遅延させた上でテストで"読み込み中"を探す
test("ローディング画面をみることができる", async () => {
render(<App />);
// データ取得中の文言が一瞬でも表示されることを確認
expect(screen.getByText("読み込み中...")).toBeInTheDocument();
// 念のためデータ取得完了も待つ
await waitFor(() => screen.getByTestId("table"));
});
なぜこうしないといけないのか
デフォルトのモック(mockResolvedValue(...))は即座に値を返してしまうため、ローディング表示の"瞬間"を通り過ぎてしまいます。
意図的にPromiseの完了を少し遅らせることで、"読み込み中..."という表示が画面に現れている状態をテストできます。
一時的に行われるので、各テスト内で毎回 mockImplementationOnce
を呼び出す必要があ離ます。
参考リンク