メインコンテンツにスキップ
バージョン: v18.0.0

プリロードされたクエリを使った Relay のテスト

プリロードされたクエリ (`useQueryLoader` および `usePreloadedQuery` フック) を使用するコンポーネントでは、少し異なる、より複雑なテスト設定が必要です。

要するに、**コンポーネントをレンダリングする前に**実行する必要がある 2 つのステップがあります

  1. `environment.mock.queueOperationResolver` を介してレスポンスを生成するようにクエリリゾルバーを設定する
  2. `environment.mock.queuePendingOperation` を介して保留中のキュー呼び出しを記録する

問題がある場合の症状

  1. テストが期待どおりに動作しない。
  2. クエリが実行されるのではなく、ブロックしているように見える
    1. 例: `Suspend` が「待機中」から「データ読み込み済み」状態に切り替わらない
  3. `usePreloadedQuery` の前後に `console.log` を追加した場合、「前」の呼び出しのみがヒットする

要約

const {RelayEnvironmentProvider} = require('react-relay');
const {MockPayloadGenerator, createMockEnvironment} = require('relay-test-utils');
const {act, render} = require('@testing-library/react');
test("...", () => {
// arrange
const environment = createMockEnvironment();
environment.mock.queueOperationResolver(operation => {
return MockPayloadGenerator.generate(operation, {
CurrencyAmount() {
return {
formatted_amount: "1234$",
};
},
});
});
const query = YourComponentGraphQLQueryGoesHere; // can be the same, or just identical
const variables = {
// ACTUAL variables for the invocation goes here
};
environment.mock.queuePendingOperation(YourComponentGraphQLQuery, variables);

// act
const {getByTestId, ..otherStuffYouMightNeed} = render(
<RelayEnvironmentProvider environment={environment}>
<YourComponent data-testid="1234" {...componentPropsIfAny}/>
</RelayEnvironmentProvider>
);
// trigger the loading - click a button, emit an event, etc. or ...
act(() => jest.runAllImmediates()); // ... if loadQuery is in the useEffect()
// assert
// your assertions go here
});

レスポンスを生成するようにクエリリゾルバーを設定する

これは `environment.mock.queueOperationResolver(operation)` 呼び出しを介して行われますが、正しく行うのは難しい場合があります。

この呼び出しの核心は、モックされた GraphQL 結果を非常に特定の形式 (正確には `MockResolvers` 型) で返すことです。これは、`generate` の 2 番目のパラメーターを介して行われます。これは、モックしたい GraphQL 型をキーとするオブジェクトです。(`mock-payload-generator` を参照してください)。

上記の例を続けると

return MockPayloadGenerator.generate(operation, {
CurrencyAmount() { // <-- the GraphQL type
return {
formatted_amount: "response_value" <-- CurrencyAmount fields, selected in the query
};
}
});

ここで難しいのは、返す GraphQL 型とフィールドの名前を取得することです。これは、次の 2 つの方法で実行できます

  • `console.log(JSON.stringify(operation, null, 2))` を呼び出し、モックしたいものに対応する `concreteType` を探します。次に、兄弟の `selections` 配列を見て、そのオブジェクトから選択されているフィールドを記述します。

モックリゾルバーコンテキストを介して、異なるクエリ変数に対して異なるデータを返すことが**可能**です。クエリ変数は `context.args` で利用可能ですが、_最も内側の関数呼び出し_に対してのみ利用可能です(上記のクエリの場合、`offer_ids` のみが利用可能です)

CurrencyAmount(context) {
console.log(JSON.stringify(context, null, 2)); // <--
return { formatted_amount: mockResponse }
}
// <-- logs { ...snip..., "name": "subtotal_price_for_offers", args: { offer_ids: [...] } }

保留中のキュー呼び出しを記録する

これはより簡単です。これは `environment.mock.queuePendingOperation(query, variables)` の呼び出しを介して行われます

  • `Query` はコンポーネントによって発行されたクエリと一致する必要があります。最も簡単な(そしてクエリの変更に対して最も堅牢な)方法は、コンポーネントモジュールからクエリをエクスポートし、テストで使用することですが、_同一_(ただし同じではない)クエリも同様に機能します。
  • `variables` は、このテスト呼び出しで使用される変数と一致する必要があります。
    • ネストされたオブジェクトと配列に注意してください。これらは `areEqual` (呼び出しコード) を介して比較されます
      • 配列は値で比較されます(参照ではなく)が、要素の順序が重要です
      • ネストされたオブジェクト - 深い比較を実行します。キーの順序は関係ありません(これは確認されていません。graphql クエリで「深い」構造を使用した場合は、このドキュメントを更新してください)。

トラブルシューティング

  • `console.log`、どこでも `console.log`!推奨される場所
    • コンポーネント:`useQueryLoader, usePreloadedQuery, loadQuery` の前と後
    • テスト:`queueOperationResolver` コールバック内
    • ライブラリ:`RelayModernMockEnvironment.execute` 内、`const currentOperation = ...` 呼び出しの後 (ここ)
  • `loadQuery` が呼び出されない場合は、トリガーイベントを発行してください。コンポーネントの実装によっては、ユーザーアクション(ボタンクリックやキー押下など)、javascript イベント(イベントエミッターメカニズムを介して)、または `useEffect` を使用した単純な「遅延実行」の場合があります。
    • `useEffect` の場合は見落としやすい可能性があります。コンポーネントをレンダリング**した後**に `act(() => jest.runAllImmediates())` を呼び出すようにしてください
  • `usePreloadedQuery` の「前」はヒットするが、「後」はヒットしない場合、クエリは一時停止します。このガイド全体はそれを解決するために書かれています。再読してください。ただし、ほとんどの場合、次のいずれかです。
    • 異なるクエリを使用した - クエリリゾルバーは呼び出されず、`currentOperation` は `null` になります
    • クエリ変数が一致しない - クエリリゾルバーは呼び出されず、`currentOperation` は `null` になります(`variables` を必ず調べてください)。
      • また、配列がある場合は同じ順序になっていることを確認してください(または、可能であれば、セットを使用することをお勧めします)。
  • クエリから返されたデータが期待どおりでない場合は、正しい graphql 型を生成していることを確認してください。
    • 返り値が `<mock-value-for-field-"formatted_amount">` のように見える場合は、間違ったものをモックしていることがわかります

コンポーネントとテストが同じ環境を使用していることを確認してください(つまり、テストの React ツリーのどこかに `<RelayEnvironmentProvider environment={RelayFBEnvironment}>` がネストされていないことを確認してください)。

エピローグ

ここでの例では `testing-library-react` を使用していますが、`react-test-renderer` でも同様に機能します。


このページは役に立ちましたか?

サイトをさらに改善するためにご協力ください いくつかの簡単な質問に答えてください.