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 all aspects of mocking behaviour.
npm install fetch-mock
then require('fetch-mock')
in most environments.
Replaces fetch()
with a stub which records its calls, grouped by route, and optionally returns a mocked Response
object or passes the call through to fetch()
. Calls to .mock()
can be chained.
matcher
: Condition for selecting which requests to mock Accepts any of the followingstring
: Either- an exact url to match e.g. 'http://www.site.com/page.html'
- if the string begins with a
^
, the string following the^
must begin the url e.g. '^http://www.site.com' would match 'http://www.site.com' or 'http://www.site.com/page.html' - '*' to match any url
RegExp
: A regular expression to test the url againstFunction(url, opts)
: A function (returning a Boolean) that is passed the url and optsfetch()
is called with (or, iffetch()
was called with one, theRequest
instance)
response
: Configures the http response returned by the mock. Can take any of the following values (or be aPromise
for any of them, enabling full control when testing race conditions etc.)Response
: AResponse
instance - will be used unalterednumber
: 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 aResponse
objectbody
: Set the response body (string
orobject
)status
: Set the response status (defaut200
)headers
: Set the response headers. (object
)throws
: If this property is present then aPromise
rejected with the value ofthrows
is returnedsendAsJson
: This property determines whether or not the request body should be JSON.stringified before being sent (defaults to true).
Function(url, opts)
: A function that is passed the url and optsfetch()
is called with and that returns any of the responses listed above (or aPromise
for any of them)
options
: A configuration object with all/additional properties to define a route to mockname
: A unique string naming the route. Used to subsequently retrieve references to the calls, grouped by name. If not specified defaults tomatcher.toString()
Note: If a non-unique name is provided no error will be thrown (because names are optional, so auto-generated ones may legitimately clash)method
: http method to matchmatcher
: as specified aboveresponse
: as specified above
Shorthands for mock()
restricted to a particular method Tip: if you use some other method a lot you can easily define your own shorthands e.g.:
fetchMock.purge = function (matcher, response, options) {
return this.mock(matcher, response, Object.assign({}, options, {method: 'PURGE'}));
}
Chainable method that restores fetch()
to its unstubbed state and clears all data recorded for its calls.
Chainable method that clears all data recorded for fetch()
's calls
Note that restore()
and reset()
are both bound to fetchMock, and can be used directly as callbacks e.g. afterEach(fetchMock.restore)
will work just fine. There is no need for afterEach(function () {fetchMock.restore()})
For the methods below matcherName
, if given, should be either the name of a route (see advanced usage below) or equal to matcher.toString()
for any unnamed route
Returns an object {matched: [], unmatched: []}
containing arrays of all calls to fetch, grouped by whether fetch-mock matched them or not. If matcherName
is specified then only calls to fetch matching that route are returned.
Returns a Boolean indicating whether fetch was called and a route was matched. If matcherName
is specified it only returns true
if that particular route was matched.
Returns the arguments for the last matched call to fetch
Returns the url for the last matched call to fetch
Returns the options for the last matched call to fetch
Set some global config options, which include
sendAsJson
[defaulttrue
] - by default fetchMock will convert objects to JSON before sending. This is overrideable fro each call but for some scenarios e.g. when dealing with a lot of array buffers, it can be useful to default tofalse
fetchMock
.mock('http://domain1', 200)
.mock('http://domain2', 'PUT', {
affectedRecords: 1
});
myModule.onlyCallDomain2()
.then(() => {
expect(fetchMock.called('http://domain2')).to.be.true;
expect(fetchMock.called('http://domain1')).to.be.false;
expect(fetchMock.calls().unmatched.length).to.equal(0);
expect(JSON.parse(fetchMock.lastUrl('http://domain2'))).to.equal('http://domain2/endpoint');
expect(JSON.parse(fetchMock.lastOptions('http://domain2').body)).to.deep.equal({prop: 'val'});
})
.then(fetchMock.restore)
First of all, consider whether you could just use fetch
as a global. Here are 3 reasons why this is a good idea:
- The
fetch
standard defines it as a global (and in some cases it won't work unless bound towindow
), so to write isomorphic code it's probably best to stick to this pattern isomorphic-fetch
takes care of installing it as a global in nodejs or the browser, so there's no effort on your part to do so.fetch-mock
is primarily designed to work withfetch
as a global and your experience of using it will be far more straightforward if you follow this pattern
Still not convinced?
In that case fetchMock.fetchMock
gives you access to the mock implementation of fetch
which you can pass in to a mock loading library such as mockery
var fetch = require('node-fetch');
var fetchMock = require('fetch-mock');
var mockery = require('mockery');
it('should make a request', function (done) {
mockery.registerMock('node-fetch', fetchMock.fetchMock);
fetchMock.mock('http://domain.com/', 200)
const myModule = require('./src/my-mod'); // this module requires node-fetch and assigns to a variable
// test code goes in here
mockery.deregisterMock('fetch');
done();
});
If using a mock loading library such as mockery
, are you requiring the module you're testing after registering fetch-mock
with the mock loader? You probably should be (Example incorrect usage). If you're using ES6 import
it may not be possible to do this without reverting to using require()
sometimes. I did warn you about not using fetch
as a global (...sigh)
- If your client-side code or tests do not use a loader that respects the browser field of package.json use
require('fetch-mock/es5/client')
. - If you need to use fetch-mock without commonjs, you can include the precompiled
node_modules/fetch-mock/es5/client-browserified.js
in a script tag. This loads fetch-mock into thefetchMock
global variable. - For server side tests running in nodejs 0.12 or lower use
require('fetch-mock/es5/server')
In node, if using npm at a version less than 2 the Request
constructor used by fetch-mock
won't necessarily be the same as the one used by isomorphic-fetch
. To fix this upgrade to npm@3.
- In nodejs
require('isomorphic-fetch')
before any of your tests. - In the browser
require('isomorphic-fetch')
can also be used, but it may be easier tonpm install whatwg-fetch
(the module isomorphic-fetch is built around) and load./node_modules/whatwg-fetch/fetch.js
directly into the page, either in a script tag or by referencing it your test runner config. - When using karma-webpack it's best not to use the
webpack.ProvidePlugin
for this. Instead just addnode_modules/whatwg-fetch/fetch.js
to your list of files to include, or require it directly into your tests before requiring fetch-mock.