
Research
/Security News
Toptal’s GitHub Organization Hijacked: 10 Malicious Packages Published
Threat actors hijacked Toptal’s GitHub org, publishing npm packages with malicious payloads that steal tokens and attempt to wipe victim systems.
jest-fetch-mock
Advanced tools
The jest-fetch-mock npm package is a Jest plugin that allows you to easily mock fetch calls in your tests. It provides a simple and flexible way to control the behavior of fetch requests, making it easier to test code that relies on network requests.
Mocking fetch responses
This feature allows you to mock the response of a fetch call. In the example, the fetch call to '/some-endpoint' is mocked to return a JSON object with data '12345'.
const fetchMock = require('jest-fetch-mock');
fetchMock.enableMocks();
// Mock a simple fetch response
fetchMock.mockResponseOnce(JSON.stringify({ data: '12345' }));
// Example test
it('fetches data successfully', async () => {
const response = await fetch('/some-endpoint');
const data = await response.json();
expect(data).toEqual({ data: '12345' });
});
Mocking fetch errors
This feature allows you to mock fetch errors. In the example, the fetch call to '/error-endpoint' is mocked to throw an error with the message 'Failed to fetch'.
const fetchMock = require('jest-fetch-mock');
fetchMock.enableMocks();
// Mock a fetch error
fetchMock.mockRejectOnce(new Error('Failed to fetch'));
// Example test
it('handles fetch error', async () => {
try {
await fetch('/error-endpoint');
} catch (error) {
expect(error).toEqual(new Error('Failed to fetch'));
}
});
Mocking multiple fetch calls
This feature allows you to mock multiple fetch calls in sequence. In the example, the first fetch call to '/first-endpoint' returns a JSON object with data 'first', and the second fetch call to '/second-endpoint' returns a JSON object with data 'second'.
const fetchMock = require('jest-fetch-mock');
fetchMock.enableMocks();
// Mock multiple fetch responses
fetchMock.mockResponses(
[JSON.stringify({ data: 'first' }), { status: 200 }],
[JSON.stringify({ data: 'second' }), { status: 200 }]
);
// Example test
it('fetches multiple data successfully', async () => {
const response1 = await fetch('/first-endpoint');
const data1 = await response1.json();
expect(data1).toEqual({ data: 'first' });
const response2 = await fetch('/second-endpoint');
const data2 = await response2.json();
expect(data2).toEqual({ data: 'second' });
});
fetch-mock is a comprehensive library for mocking fetch requests. It provides a wide range of features for controlling fetch behavior, including matching requests based on various criteria, delaying responses, and more. Compared to jest-fetch-mock, fetch-mock offers more advanced and granular control over fetch requests, but it may require more setup and configuration.
nock is a powerful HTTP mocking library for Node.js. It allows you to intercept and mock HTTP requests made by any HTTP client, including fetch. While nock is not specifically designed for fetch, it can be used to mock fetch requests in a Node.js environment. Compared to jest-fetch-mock, nock provides broader HTTP mocking capabilities but may be overkill if you only need to mock fetch requests.
msw (Mock Service Worker) is a library for mocking network requests in both browser and Node.js environments. It uses service workers to intercept and mock requests, providing a realistic simulation of network behavior. Compared to jest-fetch-mock, msw offers a more realistic and flexible approach to mocking network requests, but it may require more setup and understanding of service workers.
Fetch is the new way to do HTTP requests in the browser, and it can be used in other environments such as React Native. Jest Fetch Mock allows you to easily mock your fetch
calls and return the response you need to fake the HTTP requests. It's easy to setup and you don't need a library like nock
to get going and it uses Jest's built-in support for mocking under the surface. This means that any of the jest.fn()
methods are also available. For more information on the jest mock API, check their docs here
It currently supports the mocking with the cross-fetch
polyfill, so it supports Node.js and any browser-like runtime.
To setup your fetch mock you need to do the following things:
$ npm install --save-dev jest-fetch-mock
Create a setupJest
file to setup the mock or add this to an existing setupFile
. :
//setupJest.js or similar file
global.fetch = require('jest-fetch-mock')
Add the setupFile to your jest config in package.json
:
"jest": {
"automock": false,
"setupFiles": [
"./setupJest.js"
]
}
If you are using Create-React-App (CRA), the code for setupTest.js
above should be placed into src/setupTests.js
in the root of your project. CRA automatically uses this filename by convention in the Jest configuration it generates. Similarly, changing to your package.json
is not required as CRA handles this when generating your Jest configuration.
Note: Keep in mind that if you decide to "eject" before creating src/setupTests.js, the resulting package.json file won't contain any reference to it, so you should manually create the property setupTestFrameworkScriptFile in the configuration for Jest, something like the following:
"jest": {
"setupTestFrameworkScriptFile": "<rootDir>/src/setupTests.js"
}
fetch.mockResponse(body, init): fetch
- Mock all fetch callsfetch.mockResponseOnce(body, init): fetch
- Mock each fetch call independentlyfetch.once(body, init): fetch
- Alias for mockResponseOncefetch.mockResponses(...responses): fetch
- Mock multiple fetch calls independently
[body, init]
fetch.mockReject(error): fetch
- Mock all fetch calls, letting them fail directlyfetch.mockRejectOnce(error): fetch
- Let the next fetch call fail directlyfetch.resetMocks()
- Clear previously set mocks so they do not bleed into other mocksfetch.mock
- The mock state for your fetch calls. Make assertions on the arguments given to fetch
when called by the functions you are testing. For more information check the Jest docsFor information on the arguments body and init can take, you can look at the MDN docs on the Response Constructor function, which jest-fetch-mock
uses under the surface.
https://developer.mozilla.org/en-US/docs/Web/API/Response/Response
Each mocked response or err
or will return a Mock Function. You can use methods like .toHaveBeenCalledWith
to ensure that the mock function was called with specific arguments. For more methods detail, take a look at this.
In most of the complicated examples below, I am testing my action creators in Redux, but it doesn't have to be used with Redux.
In this simple example I won't be using any libraries. It is a simple fetch request, in this case to google.com. First we setup the beforeEach
callback to reset our mocks. This isn't strictly necessary in this example, but since we will probably be mocking fetch more than once, we need to reset it across our tests to assert on the arguments given to fetch.
Once we've done that we can start to mock our response. We want to give it an objectwith a data
property and a string value of 12345
and wrap it in JSON.stringify
to JSONify it. Here we use mockResponseOnce
, but we could also use once
, which is an alias.
We then call the function that we want to test with the arguments we want to test with. In the then
callback we assert we have got the correct data back.
Finally we can assert on the .mock
state that Jest provides for us to test what arguments were given to fetch and how many times it was called
//api.js
export function APIRequest(who) {
if (who === 'google') {
return fetch('https://google.com').then(res => res.json())
} else {
return 'no argument provided'
}
}
//api.test.js
import { APIRequest } from './api'
describe('testing api', () => {
beforeEach(() => {
fetch.resetMocks()
})
it('calls google and returns data to me', () => {
fetch.mockResponseOnce(JSON.stringify({ data: '12345' }))
//assert on the response
APIRequest('google').then(res => {
expect(res.data).toEqual('12345')
})
//assert on the times called and arguments given to fetch
expect(fetch.mock.calls.length).toEqual(1)
expect(fetch.mock.calls[0][0]).toEqual('https://google.com')
})
})
In this example I am mocking just one fetch call. Any additional fetch calls in the same function will also have the same mock response. For more complicated functions with multiple fetch calls, you can check out example 3.
import configureMockStore from 'redux-mock-store' // mock store
import thunk from 'redux-thunk'
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
import { getAccessToken } from './accessToken'
describe('Access token action creators', () => {
it('dispatches the correct actions on successful fetch request', () => {
fetch.mockResponse(JSON.stringify({ access_token: '12345' }))
const expectedActions = [
{ type: 'SET_ACCESS_TOKEN', token: { access_token: '12345' } }
]
const store = mockStore({ config: { token: '' } })
return (
store
.dispatch(getAccessToken())
//getAccessToken contains the fetch call
.then(() => {
// return of async actions
expect(store.getActions()).toEqual(expectedActions)
})
)
})
})
In this example I am mocking just one fetch call but this time using the mockReject
function to simulate a failed request. Any additional fetch calls in the same function will also have the same mock response. For more complicated functions with multiple fetch calls, you can check out example 3.
import configureMockStore from 'redux-mock-store' // mock store
import thunk from 'redux-thunk'
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
import { getAccessToken } from './accessToken'
describe('Access token action creators', () => {
it('dispatches the correct actions on a failed fetch request', () => {
fetch.mockReject(new Error('fake error message'))
const expectedActions = [
{ type: 'SET_ACCESS_TOKEN_FAILED', error: { status: 503 } }
]
const store = mockStore({ config: { token: '' } })
return (
store
.dispatch(getAccessToken())
//getAccessToken contains the fetch call
.then(() => {
// return of async actions
expect(store.getActions()).toEqual(expectedActions)
})
)
})
})
In this next example, the store does not yet have a token, so we make a request to get an access token first. This means that we need to mock two different responses, one for each of the fetches. Here we can use fetch.mockResponseOnce
or fetch.once
to mock the response only once and call it twice. Because we return the mocked function, we can chain this jQuery style. It internally uses Jest's mockImplementationOnce
. You can read more about it on the Jest documentation
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
import { getAnimeDetails } from './animeDetails'
describe('Anime details action creators', () => {
it('dispatches requests for an access token before requesting for animeDetails', () => {
fetch
.once(JSON.stringify({ access_token: '12345' }))
.once(JSON.stringify({ name: 'naruto' }))
//once is an alias for .mockResponseOnce
//
const expectedActions = [
{ type: 'SET_ACCESS_TOKEN', token: { access_token: '12345' } },
{ type: 'SET_ANIME_DETAILS', animeDetails: { name: 'naruto' } }
]
const store = mockStore({ config: { token: null } })
return (
store
.dispatch(getAnimeDetails('21049'))
//getAnimeDetails contains the 2 fetch calls
.then(() => {
// return of async actions
expect(store.getActions()).toEqual(expectedActions)
})
)
})
})
fetch.mockResponses
fetch.mockResponses
takes as many arguments as you give it, all of which are arrays representing each Response Object. It will then call the mockImplementationOnce
for each response object you give it. This reduces the amount of boilerplate code you need to write. An alternative is to use .once
and chain it multiple times if you don't like wrapping each response arguments in a tuple/array.
In this example our actionCreator calls fetch
4 times, once for each season of the year and then concatenates the results into one final array. You'd have to write fetch.mockResponseOnce
4 times to achieve the same thing:
describe('getYear action creator', () => {
it('dispatches the correct actions on successful getSeason fetch request', () => {
fetch.mockResponses(
[
JSON.stringify([{ name: 'naruto', average_score: 79 }]),
{ status: 200 }
],
[
JSON.stringify([{ name: 'bleach', average_score: 68 }]),
{ status: 200 }
],
[
JSON.stringify([{ name: 'one piece', average_score: 80 }]),
{ status: 200 }
],
[
JSON.stringify([{ name: 'shingeki', average_score: 91 }]),
{ status: 200 }
]
)
const expectedActions = [
{
type: 'FETCH_ANIMELIST_REQUEST'
},
{
type: 'SET_YEAR',
payload: {
animes: [
{ name: 'naruto', average_score: 7.9 },
{ name: 'bleach', average_score: 6.8 },
{ name: 'one piece', average_score: 8 },
{ name: 'shingeki', average_score: 9.1 }
],
year: 2016
}
},
{
type: 'FETCH_ANIMELIST_COMPLETE'
}
]
const store = mockStore({
config: {
token: { access_token: 'wtw45CmyEuh4P621IDVxWkgVr5QwTg3wXEc4Z7Cv' }
},
years: []
})
return (
store
.dispatch(getYear(2016))
//This calls fetch 4 times, once for each season
.then(() => {
// return of async actions
expect(store.getActions()).toEqual(expectedActions)
})
)
})
})
fetch.resetMocks
fetch.resetMocks
resets the fetch
mock to give fresh mock data in between tests. It only resets the fetch
calls as to not disturb any other mocked functionality.
describe('getYear action creator', () => {
beforeEach(() => {
fetch.resetMocks();
});
it('dispatches the correct actions on successful getSeason fetch request', () => {
fetch.mockResponses(
[
JSON.stringify([ {name: 'naruto', average_score: 79} ]), { status: 200}
],
[
JSON.stringify([ {name: 'bleach', average_score: 68} ]), { status: 200}
]
)
const expectedActions = [
{
type: 'FETCH_ANIMELIST_REQUEST'
},
{
type: 'SET_YEAR',
payload: {
animes: [
{name: 'naruto', average_score: 7.9},
{name: 'bleach', average_score: 6.8}
],
year: 2016,
}
},
{
type: 'FETCH_ANIMELIST_COMPLETE'
}
]
const store = mockStore({
config: { token: { access_token: 'wtw45CmyEuh4P621IDVxWkgVr5QwTg3wXEc4Z7Cv' }},
years: []
})
return store.dispatch(getYear(2016))
//This calls fetch 2 times, once for each season
.then(() => { // return of async actions
expect(store.getActions()).toEqual(expectedActions)
})
});
it('dispatches the correct actions on successful getSeason fetch request', () => {
fetch.mockResponses(
[
JSON.stringify([ {name: 'bleach', average_score: 68} ]), { status: 200}
],
[
JSON.stringify([ {name: 'one piece', average_score: 80} ]), { status: 200}
],
[
JSON.stringify([ {name: 'shingeki', average_score: 91} ]), { status: 200}
]
)
const expectedActions = [
{
type: 'FETCH_ANIMELIST_REQUEST'
},
{
type: 'SET_YEAR',
payload: {
animes: [
{name: 'bleach', average_score: 6.8},
{name: 'one piece', average_score: 8},
{name: 'shingeki', average_score: 9.1}
],
year: 2016,
}
},
{
type: 'FETCH_ANIMELIST_COMPLETE'
}
]
const store = mockStore({
config: { token: { access_token: 'wtw45CmyEuh4P621IDVxWkgVr5QwTg3wXEc4Z7Cv' }},
years: []
})
return store.dispatch(getYear(2016))
//This calls fetch 3 times, once for each season
.then(() => { // return of async actions
expect(store.getActions()).toEqual(expectedActions)
})
,
})
})
fetch.mock
to inspect the mock state of each fetch callfetch.mock
by default uses Jest's mocking functions. Therefore you can make assertions on the mock state. In this example we have an arbitrary function that makes a different fetch request based on the argument you pass to it. In our test, we run Jest's beforeEach()
and make sure to reset our mock before each it()
block as we will make assertions on the arguments we are passing to fetch()
. The most uses property is the fetch.mock.calls
array. It can give you information on each call, and their arguments which you can use for your expect()
calls. Jest also comes with some nice aliases for the most used ones.
// api.js
import 'cross-fetch'
export function APIRequest(who) {
if (who === 'facebook') {
return fetch('https://facebook.com')
} else if (who === 'twitter') {
return fetch('https://twitter.com')
} else {
return fetch('https://google.com')
}
}
// api.test.js
import { APIRequest } from './api'
describe('testing api', () => {
beforeEach(() => {
fetch.resetMocks()
})
it('calls google by default', () => {
fetch.mockResponse(JSON.stringify({ secret_data: '12345' }))
APIRequest()
expect(fetch.mock.calls.length).toEqual(1)
expect(fetch.mock.calls[0][0]).toEqual('https://google.com')
})
it('calls facebook', () => {
fetch.mockResponse(JSON.stringify({ secret_data: '12345' }))
APIRequest('facebook')
expect(fetch.mock.calls.length).toEqual(2)
expect(fetch.mock.calls[0][0]).toEqual(
'https://facebook.com/someOtherResource'
)
expect(fetch.mock.calls[1][0]).toEqual('https://facebook.com')
})
it('calls twitter', () => {
fetch.mockResponse(JSON.stringify({ secret_data: '12345' }))
APIRequest('twitter')
expect(fetch).toBeCalled() // alias for expect(fetch.mock.calls.length).toEqual(1);
expect(fetch).toBeCalledWith('https://twitter.com') // alias for expect(fetch.mock.calls[0][0]).toEqual();
})
})
FAQs
fetch mock for jest
The npm package jest-fetch-mock receives a total of 1,096,490 weekly downloads. As such, jest-fetch-mock popularity was classified as popular.
We found that jest-fetch-mock demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Threat actors hijacked Toptal’s GitHub org, publishing npm packages with malicious payloads that steal tokens and attempt to wipe victim systems.
Research
/Security News
Socket researchers investigate 4 malicious npm and PyPI packages with 56,000+ downloads that install surveillance malware.
Security News
The ongoing npm phishing campaign escalates as attackers hijack the popular 'is' package, embedding malware in multiple versions.