Jest テストパターンとモックの連動関係

Jest でテストしている間は、次のパターンと実践に従って動作を分離し、単体テストの効率を最大化します。

簡単なプロパティ変更を見てみましょう。プロパティ変更後のコンポーネントの表示は非同期なので、DOM に何かが追加される順序は、いつも予測どおりとは限りません。テストは、期待される動作を確認する前に、値の変更が DOM に反映されるまで待機することをお勧めします。Promise.resolve() ステートメントを使用して、ページ要素が変更された後に値を確認する手法を次に示します。

  1. コンポーネントを DOM に追加する。
  2. プロパティ値を変更する。
  3. Promise.resolve() 値を返して、コンポーネントが表示されるのを待機する。

詳細は、Vlocity の Matt Goldspink 氏によるブログ投稿「Testing Lightning Web Components (Lightning Web コンポーネントのテスト)」を参照してください。

先ほどの例を発展させて、属性を追加してみましょう。属性を使えば、テストである値を変更して、その変更がどのようにレンダリングされるかを確認できます。Object.assign() ステートメントを使用して、次のように appendChild のコールの前に属性を設定します。

たとえば、次のコードでは、最初のテストの背景色を赤に設定しています。

単体テストは、単純な UI 要素を更新するだけでは恐らく十分ではありません。コードによっては、インポートされたモジュール、Lightning 基本コンポーネント、イベントハンドラーなど、特定の連動関係の動作に依存するものがあります。ただし、コードには、サーバーへのコール、データベース要求、またはリモートアクセス API の不確定な動作やタイミングの影響を受けない一貫した環境が必要です。以下のセクションでは、単体テストでのこれらの連動関係のモッキング動作について説明します。モッキングは、テストするコードの動作を切り離す一般的なテスト方法です。

sfdx-lwc-jest リポジトリには Salesforce が提供するモックコンポーネントがあります。コンポーネントのソースは lightning-stubs ディレクトリにあります。Lightning 基本コンポーネントを含む、これらのモックコンポーネントをテストに使用します。モックコンポーネントは実際のコンポーネントの API と一致しますが、すべての機能を備えているわけではなく、テスト用のリソースとして機能します。これらのモックコンポーネントによってイベントが起動されることはありませんが、それらのイベントハンドラーを呼びだすことができます。

たとえば、lwc-recipes リポジトリにある miscToastNotification.js の例を見てみましょう。ユーザー入力をシミュレーションするために、inputTitleEl 定数は sfdx-lwc-jest で提供されるモック <lightning-input> 要素を参照します。また DOM でこの要素を照会してイベントをディスパッチし、この要素に結び付けた change ハンドラーを呼び出すこともできます。通知の動作をテストするだけなので、モックコンポーネントを使用して入力値の制御を維持します。

モックコンポーネントを使用するときには、次の点に留意してください。

  • テストが、スロットが表示される順序に依存しないようにすることをお勧めします。たとえば、actionstodos という名前の 2 つのスロットがあるとします。期待どおりのコンテンツがある場合は、モック (または実際の) コンポーネントでこれらのスロットが表示される順序が入れ替わったとしても、テストは合格します。
  • Lightning 基本コンポーネントには、DOM では属性として反映されないプロパティがいくつかあります。たとえば、<lightning-button> ではプロパティ iconPosition を設定できます。これは、ボタンに使用する SLDS クラスを判断するために使用され、表示される値ではありません。すべてのプロパティが属性として反映されるものと思い込まず、この動作を考慮に入れたテストケースを設計してください。
  • これらのモックコンポーネントからイベントは起動されませんが、これらに対して dispatchEvent() をコールできます。

同じ miscToastNotification.js の例を見ると、モックイベントハンドラーもあることがわかります。このテストではまずいくつかの定数値を定義し、次に ShowToastEventName イベントによって jest.fn() がトリガーされ、lightning-input 要素に定数が挿入されます。

テストの最後に、イベントハンドラーが期待どおりにコールされ、正しいパラメーターが使用されていることを確認します。

コンポーネントの動作をより詳細に制御するためにモックコンポーネントへの参照を作成するには、jest.config.js ファイルに moduleNameMapper 設定を追加します。例として、lwc-recipes リポジトリにある jest.config.js では、次のようにモックコンポーネントがモジュール名で参照されています。

では、この設定が lwc-recipes リポジトリの miscToastNotification.test.js でどのように使用されているのかを見てみましょう。import ステートメントがあります。

moduleNameMapper エントリがない場合、この import ステートメントはスタブ https://github.com/salesforce/sfdx-lwc-jest/blob/master/src/lightning-stubs/platformShowToastEvent/platformShowToastEvent.js に解決されます。

moduleNameMapper エントリがある場合、この import ステートメントは jest-mocks カスタムスタブ https://github.com/trailheadapps/lwc-recipes/blob/master/force-app/test/jest-mocks/lightning/platformShowToastEvent.js に解決されます。モックスタブには、他のプロパティをイベントオブジェクトに追加するカスタムロジックがあります。

デフォルトの jest.config.js ファイルをカスタム setupFilesAfterEnv オプションで上書きする場合は、その値を @salesforce/sfdx-lwc-jest/config で定義されている値とマージします。

テスト環境では、コンポーネントが本番スキーマにアクセスできない可能性があります。名前空間への参照をインポートする場合、テスト中は戻り値をプレースホルダーとしてモックします。

Jest テストでは、jest-transformer を使用して @salesforce/label インポートステートメントを変数宣言に変換します。値は label パスに設定されます。デフォルトで、myImport には c.specialLabel の文字列値が割り当てられます。jest.mock() を使用して、インポートに独自の値を指定できます。次の例では、c.specialLabel の代わりに文字列 value set in test が返されます。

lwc-recipes リポジトリの lwc ディレクトリを参照してください。多数のレシピに、コメント付きの jest テストを含む __tests__ ディレクトリがあります。

関連トピック