テスト環境
このドキュメントではあなたの環境に影響する要素や、いくつかのシナリオにおける推奨事項について概説します。
テストランナー
Jest、mocha、ava のようなテストランナーを使えば、標準的な JavaScript を使ってテストスイートを書き、開発プロセスの一環として実行できるようにできます。加えて、テストスイートは継続的インテグレーションの一部としても実行されます。
- Jest は React プロジェクトとの広範な互換性を有しており、モジュールやタイマーのモック、
jsdom
のサポートを有しています。Create React App を使っている場合、Jest は有用なデフォルト値とともに追加設定なしでインストールされます。 - mocha のようなライブラリは実際のブラウザ環境でうまく動作するため、それが必要なテストでは有用でしょう。
- End-to-end テストは複数のページにまたがる長いフローのテストに使用され、異なったセットアップが必要です。
描画画面のモック
しばしばテストは、ブラウザのような実際の描画用の画面にアクセスできない環境で実行されます。このような環境では、Node.js 内で実行される軽量のブラウザ実装である jsdom
を使ってブラウザ環境をシミュレートすることをお勧めします。
多くの場合、jsdom は普通のブラウザの挙動と同様に動作しますが、レイアウトやナビゲーションのような機能は有していません。それでも、個々のテストでブラウザを立ち上げるよりも高速に動作するので、ほとんどのウェブベースのコンポーネントのテストでは有用です。また、jsdom はあなたのテストと同一のプロセスで動作するため、描画された DOM に対して内容を調べたりアサーションを行うコードを書くことができます。
本物のブラウザと全く同様に、jsdom ではユーザ操作をモデルすることができます。テストは DOM ノードに対してイベントをディスパッチして、そのアクションに対する副作用を観察したり検証したりすることができます(例)。
UI テストの大部分は上記のようなセットアップを行って書くことができます。すなわちテストランナーとして Jest を使い、jsdom にレンダーし、ブラウザイベントの羅列としてユーザ操作を定義し、act()
ヘルパを活用します(例)。例えば、React 自体のテストの多くもこの組み合わせで書かれています。
主にブラウザ特有の動作をテストする必要があるライブラリを書いており、レイアウトや本物のユーザ入力などネイティブなブラウザの挙動が必要な場合は、mocha のようなフレームワークを利用できます。
DOM をシミュレートできない環境(例えば Node.js で React Native のコンポーネントをテストする場合など)では、イベントシミュレーションヘルパを使って要素とのインタラクションをシミュレーションできます。あるいは、@testing-library/react-native
の fireEvent
ヘルパを利用することもできます。
Cypress、puppeteer、webdriver のようなフレームワークは end-to-end テストを実行するのに有用です。
関数のモック
テストを書く際は、テスト環境に同等物がないコード(例えば navigator.onLine
の状態を Node.js 内で確認する、など)のモック化をしたくなります。テストではいくつかの関数を監視し、テストの他の部位がその関数とどう作用するのかを観察することもできます。そのような場合に、これらの関数をテストしやすいバージョンで選択的にモック化できれば有用です。
これはデータを取得する場面では特に有用です。本物の API エンドポイントからデータを取得することによって遅くなったり不安定になったりするのを避けるため、通常はフェイクデータを利用することが望まれます(例)。これによりテストが予想可能になります。Jest や sinon などのライブラリはモック関数をサポートしています。End-to-end テストの場合、ネットワークのモックはより困難ですが、いずれにせよそのようなテストでは本物の API エンドポイントを使ってテストをしたいでしょう。
モジュールのモック
コンポーネントによってはテスト環境でうまく動作しないか、テストにとって本質的ではないモジュールに依存していることがあります。このようなモジュールを選択的にモック化して適切な代替物で置き換えることは有用です(例)。
Node.js では、Jest のようなテストランナーはモジュールのモックをサポートしています。mock-require
のようなライブラリを使用することもできます。
タイマーのモック
コンポーネントは setTimeout
、setInterval
や Date.now
のような時間に依存する関数を使っているかもしれません。テスト環境では、これらの関数をモック版で置き換えて、手動で時間を「進められる」ようにすることが有用です。これはテストを高速に実行させるためにも役立ちます! タイマーに依存しているテストは順番通りに処理されますが、より高速になるのです(例)。Jest、sinon や lolex を含むほとんどのフレームワークにおいて、テストでモックタイマーを利用できます。
時には、タイマーのモックをやりたくない場合があります。例えばアニメーションや、タイミングに依存するエンドポイント(API レートリミッタなど)をテストしているのかもしれません。タイマーのモックが利用できるライブラリでは、テストあるいはスイートごとにモックを有効化・無効化できるようになっているため、どのようにテストを実行するかを明示的に選択できます。
End-to-end テスト
End-to-end テストは長いワークフロー、特にあなたの業務にとってとても重要なワークフロー(例えば支払いやサインアップ)をテストするのに有用です。これらのテストをする際は、本物のブラウザがアプリケーション全体をいかに描画し、本物の API エンドポイントからいかにデータを取得し、セッションやクッキーをいかに使い、さまざまなリンク間でいかにナビゲーションするかをすべて試験したいでしょう。また、おそらく DOM の状態だけではなく、バックエンドのデータに対する検証(例えばデータベースに更新が正しく永続化されているかの確認)も行いたいかもしれません。
このようなシナリオの場合は、Cypress、Playwright のようなフレームワークや Puppeteer のようなライブラリを使うことで、複数のルート間をナビゲートし、ブラウザのみならず、必要に応じてバックエンド側の副作用についても検証を行うことができるでしょう。