FAQ

Common questions about Mock Service Worker.

How is it different than library XYZ?

Please see the Comparison page for detailed technical and conceptual comparison between Mock Service Worker and other popular API mocking libraries.

In a nutshell, most solutions provide requests interception on the application level, while Mock Service Worker intercepts requests on the network level. It also allows you to use the same mock definition not only for testing, but for development and debugging as well, integrating across different tools without configurations, adapters, or plugins.

Does it support request library XYZ?

Yes. Mock Service Worker supports all request libraries, both existing and those about to be released in the future. This is one of the benefits you get by mocking your API at the network level.

Can I use it in Node.js?

Yes. Although there’s no Service Worker in Node.js, MSW provides you with a designated API to reuse the same request handlers in Node.js. Follow the integration below to learn how to use MSW in Node.js:

Node.js integration

Learn how to integrate Mock Service Worker in any Node.js process.

Can I use it in React Native?

Yes, you can use MSW while developing and testing your React Native application. The setup would be similar to that in Node.js, and you can learn more about it following this guide:

Node.js integration

Learn how to integrate Mock Service Worker in a Node.js process.

ReferenceError: fetch is not defined in Node.js

This error means that the version of Node.js you’re using doesn’t support the global Fetch API.

Resolve this by upgrading to Node.js version 18 or higher. MSW does not support Node.js versions below version 18.

Request/Response/TextEncoder is not defined (Jest)

This issue is caused by your environment not having the Node.js globals for one reason or another. This commonly happens in Jest because it intentionally robs you of Node.js globals and fails to re-add them in their entirely. As the result, you have to explicitly add them yourself.

Create a jest.polyfills.js file next to your jest.config.js with the following content:

// jest.polyfills.js
/**
 * @note The block below contains polyfills for Node.js globals
 * required for Jest to function when running JSDOM tests.
 * These HAVE to be require's and HAVE to be in this exact
 * order, since "undici" depends on the "TextEncoder" global API.
 *
 * Consider migrating to a more modern test runner if
 * you don't want to deal with this.
 */
 
const { TextDecoder, TextEncoder } = require('node:util')
 
Object.defineProperties(globalThis, {
  TextDecoder: { value: TextDecoder },
  TextEncoder: { value: TextEncoder },
})
 
const { Blob, File } = require('node:buffer')
const { fetch, Headers, FormData, Request, Response } = require('undici')
 
Object.defineProperties(globalThis, {
  fetch: { value: fetch, writable: true },
  Blob: { value: Blob },
  File: { value: File },
  Headers: { value: Headers },
  FormData: { value: FormData },
  Request: { value: Request },
  Response: { value: Response },
})

Make sure to install undici. It’s the official fetch implementation in Node.js.

Then, set the setupFiles option in jest.config.js to point to the newly created jest.polyfills.js:

// jest.config.js
module.exports = {
  setupFiles: ['./jest.polyfills.js'],
}

If you find this setup cumbersome, consider migrating to a modern testing framework, like Vitest, which has none of the Node.js globals issues and provides native ESM support out of the box.

Why should I drop query parameters from the request handler URL?

Query parameters do not describe RESTful resources. Instead, they provide additional data to the server. Query parameters will be automatically stripped by MSW during the request matching and will have no effect.

It’s easier to understand this by thinking of request handlers as server-side route handlers: you do not include query parameters when routing on the server, so neither should you when routing with MSW.

Note that you can access query parameters in the request handler by using the URL API:

// Describe the resource path: "/post".
http.get('/post', ({ request }) => {
  // Convert the request URL string to a URL instance
  // so the browser would parse query parameters for you.
  const url = new URL(request.url)
 
  // Access the query parameters from the URL instance.
  // For example: GET /post/id=abc-123 → id: "abc-123"
  const id = url.searchParams.get('id')
 
  return HttpResponse.json({
    id,
    title: 'The Empowering Limitation',
  })
})

Why do I get stale responses with react-query/SWR/Apollo/etc.?

Caching mechanism of some request clients may produce stale responses in your tests. Make sure you clear the cache before/after each test suite for your tests to remain predictable.

react-query

import { QueryCache } from 'react-query'
 
const queryCache = new QueryCache()
 
afterEach(() => {
  queryCache.clear()
})

SWR

import { cache } from 'swr'
 
beforeEach(() => {
  cache.clear()
})

Apollo Client

The Apollo Client team recommends creating a new client instance for each test.

// src/apollo-client.js
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'
 
const httpLink = new HttpLink({
  uri: 'https://example.com/graphql',
})
 
export function makeClient() {
  return new ApolloClient({
    cache: new InMemoryCache(),
    link: httpLink,
  })
}
// test/Component.test.jsx
import { makeClient } from '../src/apollo-client'
 
it('renders the component', async () => {
  const client = makeClient()
  // ...use your client in test.
})

Learn more in the Apollo Client documentation.

Light theme when?

Whenever you have time to open a pull request.

MSW doesn’t work in concurrent tests

If your test suite features multiple concurrent test that modify the network behavior (i.e. have .use() calls), you must scope the network to each test by using the server.boundary() API.

server.boundary()

Scope the network interception to the given boundary.