Mock Fetch in a Jest Test
This is a way to mock the fetch
function in a Jest test.
Why Mock Fetch
We are probably using test fakes to avoid testing dependencies. In the case of fetch
, we want to avoid the dependency of the network and whatever endpoints we might be making requests to.
Avoiding the network will make our test less real-life and provide less ROI in general. It'll also make our test easier to control, allow a precise assertion, avoid testing the world, and make it faster to run.
Set up a Fetch Stub
To use a more precise term than "mock", we will set up a fetch
"stub" implementation. This is the fake version of fetch
that we'll use instead of the real deal:
function setupFetchStub(data) {
return function fetchStub(_url) {
return new Promise((resolve) => {
resolve({
json: () =>
Promise.resolve({
data,
}),
})
})
}
}
This fetchStub
will always return a json response of the data that we set it up to return.
Mock Global Fetch
fetch
exists on the global
object, usually window
in the browser. Before the test, we want to replace the real fetch
with the fake/stub one:
jest.spyOn(global, "fetch").mockImplementation(setupFetchStub(fakeData))
Then at the end of the test, we want to make sure we undo that action so that any other test that may need to real/native fetch
implementation in tact, has it to use.
global.fetch.mockClear()
There is the potential that those functions won't work as described. You may get an error like:
Cannot spy the fetch property because it is not a function; undefined given instead
You'd get this if your test environment's global
object doesn't have fetch
defined on it. Since you're not running Jest in a browser, it's using a jsdom implementation that may not have it.
In this case, as an alternative, you can run setup with:
global.fetch = jest.fn().mockImplementation(setupFetchStub(fakeData))
And cleanup with:
global.fetch.mockClear()
delete global.fetch
A Jest Test with Fetch
All together, that Jest test that stubs out fetch
might look like:
it('doesnt really fetch', async () => {
const fakeData = { fake: 'data' }
jest.spyOn(global, "fetch").mockImplementation(setupFetchStub(fakeData))
const res = await fetch('anyUrl')
const json = await res.json()
expect(json).toEqual({ data: fakeData })
global.fetch.mockClear()
})
Do you have a better way to accomplish the same job here?