跳到主要內容
版本:v18.0.0

使用預載查詢測試 Relay

使用預載查詢(useQueryLoaderusePreloadedQuery hook)的組件需要稍微不同且更複雜的測試設定。

簡而言之,需要在 **渲染組件之前** 執行兩個步驟

  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) 呼叫完成,但要正確設定可能很棘手。

此呼叫的關鍵是以非常特定的格式(確切來說是 MockResolvers 類型)返回模擬的 graphql 結果。這透過 generate 的第二個參數完成 - 它是一個物件,其鍵是我們想要模擬的 GraphQL 類型。(請參閱 mock-payload-generator)。

繼續上面的範例

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

這裡的棘手之處在於取得要傳回的 GraphQL 類型和欄位的名稱。這可以透過兩種方式完成

  • 呼叫 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,但未觸發「之後」的 usePreloadedQuery - 查詢會暫停。本指南的撰寫目的就是要解決這個問題 - 您可能需要重新閱讀它。但最有可能的原因是
    • 使用了不同的查詢 - 將不會呼叫查詢解析器,currentOperation 將會是 null
    • 查詢變數不相符 - 將不會呼叫查詢解析器,currentOperation 將會是 null(請確保檢查 variables)。
      • 另外,請確保陣列的順序相同(如果有的話),或者如果可能的話,最好使用集合。
  • 如果從查詢傳回的資料不是您預期的,請確保您正在產生正確的 graphql 類型。
    • 如果傳回值看起來像 <mock-value-for-field-"formatted_amount">,您就知道您正在模擬錯誤的類型
注意

請確保組件和測試使用相同的環境(也就是說,在您的測試 React 樹中的某處沒有巢狀的 <RelayEnvironmentProvider environment={RelayFBEnvironment}>)。

結語

這裡的範例使用 testing-library-react,但它也適用於 react-test-renderer


此頁面是否有用?

透過以下方式協助我們讓網站變得更好 回答幾個快速問題.