使用預載查詢測試 Relay
使用預載查詢(useQueryLoader
和 usePreloadedQuery
hook)的組件需要稍微不同且更複雜的測試設定。
簡而言之,需要在 **渲染組件之前** 執行兩個步驟
- 設定查詢解析器以透過
environment.mock.queueOperationResolver
產生回應 - 透過
environment.mock.queuePendingOperation
記錄一個待處理的佇列調用
錯誤徵兆
- 測試沒有達到預期的效果。
- 查詢似乎正在阻塞而不是執行
- 例如,
Suspend
沒有從「等待中」切換到「資料已載入」狀態
- 例如,
- 如果在
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
。
此頁面是否有用?
透過以下方式協助我們讓網站變得更好 回答幾個快速問題.