Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】How to fix the error that import.meta.env cannot be used in Jest (Vite + Supabase)

2025年09月19日に「Dev.to」が公開したITニュース「How to fix the error that import.meta.env cannot be used in Jest (Vite + Supabase)」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Jestテストでローディングスピナーの表示確認時、モックが速すぎてスピナーがすぐ消え、テストが失敗することがある。初期表示確認は`getByRole`を使い、ローディングから消えるまでをテストする際は、モックに遅延を追加し`findByRole`で確認すると良い。

ITニュース解説

システム開発において、プログラムが期待通りに動作するかを確認する作業を「テスト」と呼ぶ。これは製品の品質を保証するために不可欠な工程であり、特にユーザーが直接操作する「ユーザーインターフェース(UI)」の動作確認は、利用者の体験に直結するため非常に重要だ。

今回の解説では、JavaScriptのテストフレームワークであるJestを用いたUIテスト中に発生した具体的な問題と、その解決策について説明する。問題の焦点は、非同期処理の待機中に表示される「ローディングスピナー」と呼ばれるアニメーション要素のテストにある。

ローディングスピナーは、ウェブアプリケーションなどで、データ取得や複雑な計算など時間がかかる処理が行われている最中に表示されるUI要素だ。ユーザーに「今、システムが動作している」ことを伝え、アプリケーションがフリーズしていないことを視覚的に知らせる役割を果たす。例えば、データベースからデータを取得する際、ネットワークの状況によっては時間がかかるため、その間スピナーを表示しておくことで、ユーザーは待ち時間を認識し、不必要な操作を避けられる。

このようなローディングスピナーが正しく表示され、そしてデータ取得後に適切に消えることを確認するために、私たちはテストコードを書く。今回問題が発生したのは、このローディングスピナーの動作を検証するテストだ。

テストシナリオはこうである。アプリケーションがデータを取得する処理を開始すると、ローディングスピナーが表示される。データ取得が完了したら、スピナーは消えて、取得したデータが表示される。この一連の流れが正しく行われることをテストで検証したかった。

しかし、テストを実行すると、「findByRole("status")が見つからない」というエラーが発生した。findByRole("status")とは、Jestと共にUI要素をテストするために使われるライブラリの機能で、画面上に「status」というロールを持つ要素(今回の場合はスピナー)が出現するまで待機し、見つかったらその要素をテストコードに返す役割を持つ。スピナーは表示されるはずなのに、テストでは見つけられなかったのだ。

なぜこのような事態になったのか。原因は、テストのために用意された「モック」の動作にあった。モックとは、テスト対象のプログラムが依存する外部のシステムやコンポーネント(例:データベース)を、テスト専用に置き換えた「偽物」のことだ。実際の外部システムと通信する代わりに、あらかじめ決められたデータを即座に返すようなモックを用意することで、テストを高速かつ安定して実行できるメリットがある。

今回のケースでは、Supabaseというウェブデータベースサービスからのデータ取得をシミュレーションするためにモックを使用していた。このモックが、現実のデータ取得処理よりもはるかに高速に動作しすぎたことが問題を引き起こした。実際のデータ取得はネットワークの遅延などで時間がかかるものだが、モックはそうした制約を無視し、データを「瞬時に」返してしまったのだ。

この結果、アプリケーションはデータ取得処理を開始すると同時にスピナーを表示するが、モックがデータを一瞬で返してしまうため、スピナーを表示するロジック(setLoading(true))の直後に、スピナーを非表示にするロジック(setLoading(false))がすぐに実行されてしまった。つまり、スピナーはほんの一瞬だけ表示された後、ほとんどすぐに画面から消えてしまったことになる。

findByRole("status")は、スピナーが出現するのを待っていたわけだが、スピナーは表示された直後に消えてしまったため、findByRoleが「見つけようと待っている」間にすでに画面からいなくなってしまっていた。そのため、テストツールはスピナーが「見つからなかった」と判断し、エラーを発生させたのだ。しかし、実際にはスピナーは初期描画の瞬間に確かに存在していたのである。この、テストコードの認識と実際の表示状況のズレが、テスト失敗の根本原因だった。

この問題を解決するためには、状況に応じた2つのアプローチが考えられる。

一つ目の解決策は、findByRole("status")の代わりにgetByRole("status")を使用する方法だ。getByRole("status")は、findByRoleのように要素が出現するまで待つのではなく、テスト実行時点の画面の状態から指定された要素を「即座に」探し出す。もし要素が見つからなければエラーとなる。今回のケースでは、スピナーは初期描画の瞬間に確実に存在していたため、getByRoleを使ってその瞬間を捉えることで、スピナーの存在をテストで確認できるようになった。これにより、「アプリケーションの起動時にスピナーが表示されること」という、最も基本的な表示状態のテストはパスできるようになった。

しかし、この方法だけでは、「スピナーが一定時間表示され、その後データ取得後に適切に消える」という、ユーザーが実際に体験する一連の動作を完全にテストすることは難しい。初期表示の確認はできても、スピナーが表示され続けることや、最終的に消えることを検証するためには、別の工夫が必要だ。

そこで二つ目の解決策として、モックに「遅延」を追加する方法が有効となる。モックがデータを瞬時に返すのではなく、意図的に数秒間の待ち時間(例えばJavaScriptのsetTimeout関数を使って)を設けるのだ。これにより、実際のデータ取得処理に近い、ある程度の時間を要する非同期処理をシミュレーションできる。モックがデータを返すまでに時間がかかるようになれば、その間スピナーは画面上に表示され続ける状態となる。この状態であれば、findByRole("status")がスピナーを見つけ出し、その存在を確認できる。さらに、スピナーが一定時間表示された後に消えることまで含めて、一連の動作をより現実的な形でテストすることが可能になるのだ。

今回の経験は、システムエンジニアとしてテストを書く上で重要な教訓となる。テストは、単にプログラムがエラーなく動くかを見るだけでなく、現実世界でのユーザーの利用状況や、非同期処理による時間差、UIの状態変化といった複雑な要素を考慮に入れる必要がある。状況に応じて適切なテストメソッドを選び、モックの動作も現実世界に近づけることで、より信頼性の高い、質の良いソフトウェアを開発できるようになるだろう。