A tool for helping upgrade to fetch-mock@12.
- Install
npm i -D @fetch-mock/codemods jscodeshift fetch-mock@12
; - Manually modify any code using
.sandbox()
according to the example at the bottom of this page. - Run
jscodeshift -t node_modules/@fetch-mock/codemods/src/index.js --ignore-pattern="node_modules/**/*" .
to run over your entire project, or replace.
with the directory/file paths you wish to modify. The jscodeshift CLI has many options - adjust them to suit your project. Note that the parser option should not be used as @fetch-mock/codemods forces use of the TSX parser in order to ensure compatibility with teh greatest range of projects. - For scenarios where the codemod is unable to detect which variable contains a fetch-mock instance (e.g. when it is required in a global set up file, or when using
jest.mock()
or fetch-mock-jest) you may pass in one or more variable names using theFM_VARIABLES
environment variable e.g.FM_VARIABLES=fm,fetch
- After the codemods have executed:
a) If mocking global
fetch
you will probably need to add a call to.mockGlobal()
at least once per test suite, possibly in abeforeAll
/beforeEach
block. b) Correct all the errors inserted by the codemod related to use offallbackToNetwork
,.calls()
or.lastCall()
usage. c) Run all your tests and fix any issues. If you believe the codemods have made any errors, or have missed any easy to modify patterns, please raise an issue. - Once all your tests are fixed you should be able to uninstall the codemods:
npm uninstall @fetch-mock/codemods jscodeshift
If you're using fetch-mock-jest, you should migrate to @fetch-mock/jest, which is built around fetch-mock@12. While these codemods have not been tested on fetch-mock-jest, in principle you should be able use them by making similar adjustments to those described below about use with the sandbox()
method, and by using the FM_VARIABLES
environment variable to help the codemod identify which variables contain instances of fetch-mock.
For everyt variable containing an instance of fetch-mock imported using require
or import
it will:
- Rewrite
.mock()
to.route()
- Rewrite
.reset()
,.restore()
,.resetBehavior()
and.resetHistory()
to their equivalents in fetch-mock@12 - Rewrite
.lastUrl()
,.lastOptions()
andlastResponse()
to their equivalents in fetch-mock@12 - Adds an informative error whenever
.lastCall()
or.calls()
are used with advice on how to manually correct these - Converts
.getOnce()
,.getAnyOnce()
,.postOnce()
etc... - which have been removed - to calls to the underlying.get()
method with additional options passed in. - Removes uses of the deprecated options
overwriteRoutes
,warnOnFallback
,sendAsJson
- Removes uses of the deprecated
fallbackToNetwork
option, and adds an informative error with details of how to replace with thespyGlobal()
method
- Javascript is a language with multiple ways to do the same thing. While these codemods attempt to cover a few different patterns, it's likely that they don't cover all the ways fetch-mock is being used. Please raise an issue if you think they can be improved.
- fetch-mock@12 no longer has the
.mock()
method which combines defining a route and setting up global mocking. All calls to.mock()
are replaced by.route()
. If using globalfetch
you will also need to call.mockGlobal()
at least once per test suite. - The
.sandbox()
method previously created afetch
function that also had all the fetch-mock methods attached. This is no longer the case, but pulling it apart is complex and deliberately left out of scope for this codemod. - Any uses of fetch-mock prior to assigning to a variable will not be modified e.g.
require('fetch-mock').mock('a', 'b')
will not be converted torequire('fetch-mock').route('a', 'b')
- When using a pattern such as
jest.mock('node-fetch', () => require('fetch-mock').sandbox())
, the codemod is unable to identify thatrequire('node-fetch')
will be an instance of fetch-mock. - On the server side fetch-mock was previously built around node-fetch's classes, but now uses native
fetch
. In most cases, even if your application code still uses node-fetch, your mocks will still work. However, if you explicitly create instances ofRequest
orHeaders
using node-fetch's classes, you may need to provide these to fetch-mock.
Taking the last 4 points together, this example illustrates the kind of manual modifications required:
jest.mock('node-fetch', () => require('fetch-mock').sandbox());
const nodeFetch = require('node-fetch');
it('runs a test', () => {
nodeFetch.get('http://a.com', 200);
myAPI.call();
expect(nodeFetch.called()).toBe(true);
});
const fetchMock = require('fetch-mock');
jest.mock('node-fetch', () => {
const nodeFetch = jest.requireActual('node-fetch');
// only needed if your application makes use of Response, Request
// or Headers classes directly
Object.assign(fetchMock.config, {
fetch: nodeFetch,
Response: nodeFetch.Response,
Request: nodeFetch.Request,
Headers: nodeFetch.Headers,
});
return fetchMock.fetchHandler;
});
const nodeFetch = require('node-fetch');
it('runs a test', () => {
fetchMock.get('http://a.com', 200);
myAPI.call();
expect(fetchMock.called()).toBe(true);
});