mswMock Service Worker

Browser

Setup

Mock Service Worker operates client-side by registering a Service Worker responsible for requests interception. However, we don't have to write any of the worker's code by ourselves, but rather copy the worker file distributed by the library. Mock Service Worker provides a dedicated CLI to help us do that.

Execute the init command of the Mock Service Worker CLI:

1$ npx msw init <PUBLIC_DIR> --save

Replace the <PUBLIC_DIR> placeholder with the relative path to your server's public directory. For example, in a Create React App project this command would be:

1$ npx msw init public/ --save

Note that we are using the --save option to save the given worker directory ("public") in the package.json. That way any updates to the worker script will be automatically applied when updating the msw package in the future.

Where is my "public" directory?

A public directory is usually a root directory of your server (i.e. ./build, ./public, or ./dist). This directory is often committed to Git, and so should be the Mock Service Worker.

Common public directories

Below you can find a list of public directories in most used JavaScript project starters.

Project namePublic directory
Create React App./public
GatsbyJS./static
NextJS./public
VueJS./public
Angular./src (and add it to the assets of the angular.json file)
Preact./src/static
Not sure where is your public directory? Reach out to the maintainers of the development stack that you are using, they should be able to help.

Configure worker

Let's create a file in our mock definition directory (src/mocks) where we would configure and start our Service Worker.

Create a src/mocks/browser.js file:

1$ touch src/mocks/browser.js

In the browser.js file we are going to create a worker instance with our request handlers defined earlier.

Import setupWorker function from the msw package and create a worker instance with previously defined request handlers

1// src/mocks/browser.js
2import { setupWorker } from 'msw'
3import { handlers } from './handlers'
4
5// This configures a Service Worker with the given request handlers.
6export const worker = setupWorker(...handlers)

Start worker

In order for our mock definition to execute during the runtime, it needs to be imported into our application's code. However, since mocking is a development-oriented technique, we will be importing our src/mocks/browser.js file conditionally, depending on the current environment.

It's not recommended to include Mock Service Worker in production. Doing so may lead to a distorted experience for your users.

Import the src/mocks/browser.js file conditionally following one of the examples below:

1// src/index.js
2import React from 'react'
3import ReactDOM from 'react-dom'
4import App from './App'
5
6if (process.env.NODE_ENV === 'development') {
7 const { worker } = require('./mocks/browser')
8 worker.start()
9}
10
11ReactDOM.render(<App />, document.getElementById('root'))

Verify & Inspect

After importing the mock definition, you should see a successful activation message from Mock Service Worker in your browser's console:

[MSW] Mocking enabled

Any requests that match previously defined handlers will now be intercepted and mocked.

Troubleshooting

Create React App (version 3)

If you have created a project using previous Create React App (version 3) you should remove the following line

1serviceWorker.unregister()

in your src/index.js file. Create React App unregisters all Service Workers by default, which would also unregister the mock Service Worker, resulting into broken requests interception.

Using homepage property in package.json

If your project uses homepage relative path configuration, you have to make sure that your url is rewriten to use / at the end of the pathname, and the serviceWorker url should be adjusted as well.

Let's say that your package.json has the following line:

"homepage": "/login/"

Your development environment will automatically open using localhost:3000/login, without / at the end and your service worker will not work as expected. For this reason we have to update our src/index.js or src/index.tsx where we rewrite windows.location.pathname string with / at the end:

1// src/index.js
2import React from 'react'
3import ReactDOM from 'react-dom'
4import App from './App'
5
6async function main() {
7 if (process.env.NODE_ENV === 'development') {
8 if (window.location.pathname === '/login') {
9 window.location.pathname = '/login/'
10 return
11 }
12
13 const { worker } = require('./mocks/browser')
14
15 await worker.start({
16 serviceWorker: {
17 url: '/login/mockServiceWorker.js',
18 },
19 })
20 }
21
22 ReactDOM.render(
23 <React.StrictMode>
24 <App />
25 </React.StrictMode>,
26 document.getElementById('root'),
27 )
28}
29
30main()

Related discussions: 1, 2