What is fetch-mock?
fetch-mock is a library for mocking HTTP requests made using the Fetch API. It allows developers to simulate different responses and behaviors for fetch calls, which is particularly useful for testing and development purposes.
What are fetch-mock's main functionalities?
Mocking a simple GET request
This feature allows you to mock a simple GET request. The code sample demonstrates how to mock a GET request to 'https://api.example.com/data' and return a JSON object with sample data.
const fetchMock = require('fetch-mock');
fetchMock.get('https://api.example.com/data', { data: 'sample data' });
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data));
Mocking a POST request with specific body
This feature allows you to mock a POST request with a specific request body. The code sample demonstrates how to mock a POST request to 'https://api.example.com/submit' and return different responses based on the request body.
const fetchMock = require('fetch-mock');
fetchMock.post('https://api.example.com/submit', (url, options) => {
if (options.body === JSON.stringify({ key: 'value' })) {
return { status: 'success' };
} else {
return { status: 'error' };
}
});
fetch('https://api.example.com/submit', {
method: 'POST',
body: JSON.stringify({ key: 'value' })
})
.then(response => response.json())
.then(data => console.log(data));
Mocking with delay
This feature allows you to mock a request with a delay. The code sample demonstrates how to mock a GET request to 'https://api.example.com/delayed' and return a response after a 1-second delay.
const fetchMock = require('fetch-mock');
fetchMock.get('https://api.example.com/delayed', new Promise(resolve => setTimeout(() => resolve({ data: 'delayed data' }), 1000)));
fetch('https://api.example.com/delayed')
.then(response => response.json())
.then(data => console.log(data));
Mocking with different response statuses
This feature allows you to mock requests with different HTTP response statuses. The code sample demonstrates how to mock a GET request to 'https://api.example.com/not-found' and return a 404 status.
const fetchMock = require('fetch-mock');
fetchMock.get('https://api.example.com/not-found', 404);
fetch('https://api.example.com/not-found')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.catch(error => console.error('Fetch error:', error));
Other packages similar to fetch-mock
nock
Nock is a HTTP mocking and expectations library for Node.js. It intercepts HTTP requests and allows you to define custom responses. Compared to fetch-mock, Nock is more focused on Node.js and works with any HTTP library, not just fetch.
msw
Mock Service Worker (MSW) is a library for mocking network requests in both browser and Node.js environments. It uses Service Workers to intercept requests in the browser, making it more versatile for front-end testing compared to fetch-mock.
axios-mock-adapter
Axios Mock Adapter is a library specifically designed for mocking requests made with the Axios HTTP client. It provides a simple API for defining request handlers and responses. While fetch-mock is designed for the Fetch API, axios-mock-adapter is tailored for Axios.
fetch-mock
![Coverage Status](https://coveralls.io/repos/wheresrhys/fetch-mock/badge.svg)
Mock http requests made using fetch (or isomorphic-fetch). As well as shorthand methods for the simplest use cases, it offers a flexible API for customising mocking behaviour, and can also be persisted (with resettable state) over a series of tests.
Which version to require
- Browser tests:
require('fetch-mock')
- Server side tests running in nodejs 4 or higher:
require('fetch-mock/src/server')
- Server side tests running in nodejs 0.12 or lower:
require('fetch-mock/es5/server')
You will need to ensure fetch
and Promise
are already available as globals in your environment
To output useful messages for debugging export DEBUG=fetch-mock
require('fetch-mock')
exports a singleton with the following methods
Basic usage
mock(matcher, response)
or mock(matcher, method, response)
Replaces fetch()
with a stub which records it's calls, grouped by route, and optionally returns a mocked Response
object or passes the call through to fetch()
.
matcher
[required]: Condition for selecting which requests to mock Accepts any of the following
method
[optional]: only matches requests using this http methodresponse
[required]: Configures the http response returned by the mock. Can take any of the following values
number
: Creates a response with this statusstring
: Creates a 200 response with the string as the response bodyobject
: As long as the object does not contain any of the properties below it is converted into a json string and returned as the body of a 200 response. If any of the properties below are defined it is used to configure a Response
object
body
: Set the response body (string
or object
)status
: Set the response status (defaut 200
)headers
: Set the response headers. (object
)throws
: If this property is present then a Promise
rejected with the value of throws
is returned
Function(url, opts)
: A function that is passed the url and opts fetch()
is called with and that returns any of the responses listed above
restore()
Restores fetch()
to its unstubbed state and clears all data recorded for its calls
reMock()
Normally calling mock()
twice without restoring inbetween will throw an error. reMock()
calls restore()
internally before calling mock()
again. This allows you to put a generic call to mock()
in a beforeEach()
while retaining the flexibility to vary the responses for some tests
reset()
Clears all data recorded for fetch()
's calls
calls()
Returns an array of arrays of the arguments passed to fetch()
for mocked calls.
Advanced usage
mock(routeConfig)
Use a configuration object to define a route to mock.
* name
[required]: A unique string naming the route. Used to subsequently retrieve references to the calls, grouped by name
* method
[optional]: http method
* matcher
[required]: as specified above
* response
[required]: as specified above
mock(routes)
Pass in an array of route configuration objects
mock(config)
Pas in an object containing more complex config for fine grained control over every aspect of mocking behaviour. May have the following properties
- routes
: Either a single route config object or an array of them (see above)
- responses
: When registerRoute()
(see below) has already been used to register some routes then responses
can be used to override the default response. Its value should be an object mapping route names to responses, which should be similar to those provided in the response
property of stanadard route configurations e.g.
```javascript
responses: {
session: function (url, opts) {
if (opts.headers.authorized) {
return {user: 'dummy-authorized-user'};
} else {
return {user: 'dummy-unauthorized-user'};
}
}
}
```
- `greed`: Determines how the mock handles unmatched requests
- 'none': all unmatched calls get passed through to `fetch()`
- 'bad': all unmatched calls result in a rejected promise
- 'good': all unmatched calls result in a resolved promise with a 200 status
calls(routeName)
Returns an array of arrays of the arguments passed to fetch()
that matched the given route. '__unmatched' can be passed in to return results for calls not matching any route.
called(routeName)
Returns a Boolean denoting whether any calls matched the given route. '__unmatched' can be passed in to return results for calls not matching any route. If no routeName is passed it returns true
if any fetch calls were made
registerRoute()
Often your application/module will need a mocked response for some http requests in order to initialise properly, even if the content of those calls are not the subject of a given test e.g. a mock response from an authentication service and a multi-variant testing service might be necessary in order to test the UI for a version of a log in form. It's helpful to be able to define some default responses for these services which will exist throughout all or a large subset of your tests. registerRoute()
aims to fulfil this need. All these predefined routes can be overridden when mock(config)
is called.
registerRoute(object)
: An object similar to the route objects accepted by mock()
registerRoute(array)
: An array of the above objectsregisterRoute(name, matcher, response)
: The 3 properties of the route object spread across 3 parameters
unregisterRoute(name)
Unregisters one or more previously registered routes. Accepts either a string or an array of strings
useNonGlobalFetch(func)
When using isomorphic-fetch or node-fetch ideally fetch
should be added as a global. If not possible to do so you can still use fetch-mock in combination with mockery in nodejs. To use fetch-mock with with mockery you will need to use this function to prevent fetch-mock trying to mock the function globally.
func
Optional reference to fetch
(or any other function you may want to substitute for fetch
in your tests).
Mockery example
var fetch = require('node-fetch');
var fetchMock = require('fetch-mock');
var mockery = require('mockery');
fetchMock.useNonGlobalFetch(fetch);
fetchMock.registerRoute([
...
])
it('should make a request', function (done) {
mockery.registerMock('fetch', fetchMock.mock());
mockery.deregisterMock('fetch');
done();
});
Examples
var fetchMock = require('fetch-mock');
it('should pretend to be Rambo', done => {
fetchMock.mock('http://rambo.was.ere', 301);
fetch('http://rambo.was.ere')
.then(res => {
expect(fetchMock.calls().length).to.equal(1);
expect(res.status).to.equal(301);
fetchMock.restore();
done();
});
})
fetchMock.registerRoute([
{
name: 'session',
matcher: 'https://sessionservice.host.com',
response: {
body: 'user-12345',
opts: {
headers: {
'x-status': 'unsubscribed'
},
status: 401
}
}
},
{
name: 'geo',
matcher: /^https\:\/\/geoservice\.host\.com/,
response: {
body: {
country: 'uk'
}
}
}
])
it('should do A', function () {
fetchMock.mock({
greed: 'none'
});
thingToTest.exec();
fetchMock.calls('session')
fetchMock.called('geo')
fetchMock.reset()
fetchMock.calls('session')
fetchMock.called('geo')
fetch.calledWith('thing')
fetchMock.restore();
})
describe('content', function () {
before(function () {
fetchMock.registerRoute('content', function (url, opts) {
return opts.headers.get('x-api-key') && url.test(/^https\:\/\/contentservice\.host\.com/);
}, {body: 'I am an article'});
});
after(function () {
fetchMock.unregisterRoute('content');
})
it('should do B', function () {
fetchMock.mock({
routes: ['session', 'content', {
name: 'enhanced-content',
matcher: /^https\:\/\/enhanced-contentservice\.host\.com/,
response: function (url, opts) {
return {body: 'enhanced-article-' + url.split('article-id/')[1]};
}
}]
});
thingToTest.exec();
fetchMock.calls('content')
fetchMock.called('enhanced-content')
fetchMock.restore();
})
it('should do C', function () {
fetchMock.mock({
responses: {
'session': 'invalid-user'
}
});
thingToTest.exec();
fetchMock.restore();
})
});