問題描述
使用 Jest 測試框架調用 fetch(url) 時如何根據 url 模擬變量響應? (How to mock variable responses based on the url when fetch(url) is called using the Jest testing framework?)
我有一個如下所示的模塊:
calculate‑average.js
const fetch = require('node‑fetch') const stats = require('stats‑lite') const BASE_URL = 'https://www.example.com/api' const calculateAverage = async(numApiCalls) => { const importantData = [] for (let i = 0; i < numApiCalls; i++) { const url = `${BASE_URL}/${i}` // will make requests to https://www.example.com/api/0, https://www.example.com/api/1 and so on.... const res = await fetch(url) const jsonRes = await res.json() importantData.push(jsonRes.importantData) } return stats.mean(importantData) } module.exports = calculateAverage
我試過測試它按照以下思路,但我顯然遠離解決方案:
calculate‑average.test.js
const calculateAverage = require('../calculate‑average') jest.mock( 'node‑fetch', () => { return jest.fn(() => {}) } ) test('Should calculate stats for liquidation open interest delatas', async() => { const stats = await calculateAverage(100) // Should make 100 API calls. console.log(stats) })
我需要做的是:
- 能夠為每個 API 調用指定自定義的變化響應。例如,我應該能夠指定對
https://www.example.com/api/0
的調用返回{importantData: 0 }
,對https://www.example.com/api/1
返回{ importantData: 1 }
以此類推... - 如果向我未指定響應的
url
發出請求,則會提供默認響應。例如,如果對https://www.example.com/api/101
做出響應,則發送默認響應{importantData: 1000 }
。
我希望只使用 Jest 而不依賴於像 mock‑fetch
和 jest‑mock‑fetch
這樣的模塊。但是,如果不使用的解決方案過於復雜,那麼我很樂意使用它們。只是不想在不需要時創建不必要的依賴項。
https://www.example.com/api/101
做出響應,則發送默認響應 {importantData: 1000 }
。 我希望只使用 Jest 而不依賴於像 mock‑fetch
和 jest‑mock‑fetch
這樣的模塊。但是,如果不使用的解決方案過於復雜,那麼我很樂意使用它們。只是不想在不需要時創建不必要的依賴項。
https://www.example.com/api/101
做出響應,則發送默認響應 {importantData: 1000 }
。 我希望只使用 Jest 而不依賴於像 mock‑fetch
和 jest‑mock‑fetch
這樣的模塊。但是,如果不使用的解決方案過於復雜,那麼我很樂意使用它們。只是不想在不需要時創建不必要的依賴項。
mock‑fetch
和 jest‑mock‑fetch
等模塊來執行此操作。但是,如果不使用的解決方案過於復雜,那麼我很樂意使用它們。只是不想在不需要時創建不必要的依賴項。 我最好只使用 Jest 而不依賴於 mock‑fetch
和 jest‑mock‑fetch
等模塊來執行此操作。但是,如果不使用的解決方案過於復雜,那麼我很樂意使用它們。只是不想在不需要時創建不必要的依賴項。參考解法
方法 1:
Sure you can! You can use mock function mockResolvedValueOnce
method to return a result for a specific call and mockResolvedValue
to return the default result.
jest.mock('node‑fetch', () => {
const generateResponse = (value) => {
return { json: () => ({ importantData: value }) };
};
return jest
.fn()
.mockResolvedValue(generateResponse(1000)) // default response
.mockResolvedValueOnce(generateResponse(0)) // response for first call
.mockResolvedValueOnce(generateResponse(1)) // response for second call
.mockResolvedValueOnce(generateResponse(2)); // response for third call
});
Note that we are returning an object with the json
property so that it returns the json data when you call res.json()
in calculate‑average.js
.
If you want to return a specific response based on the
url
parameter, you will have to mock the desired behaviour in the returned mock function for node‑fetch
. The following example will mock the returned value so that for URLs where the counter is greater than 100 it will return 1000. Otherwise, it will return the same value present in the url
:jest.mock('node‑fetch', () => {
return jest.fn((url) => {
// Get and parse the URL parameter.
const value = parseInt(url.split('/').slice(‑1)[0], 10);
return Promise.resolve({
json: () => ({ importantData: value > 100 ? 1000 : value })
});
});
});
(by philosopher、mgarcia)