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:
1npx 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:
1npx 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 themsw
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 name | Public 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 |
Ember.js | ./public |
Svelte.js | ./public |
SvelteKit | ./static |
Vite | ./public |
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:
1touch 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.js2import { setupWorker } from 'msw'3import { handlers } from './handlers'45// 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.
Import the src/mocks/browser.js
file conditionally following one of the examples below:
1// src/index.js2import React from 'react'3import ReactDOM from 'react-dom'4import App from './App'56if (process.env.NODE_ENV === 'development') {7 const { worker } = require('./mocks/browser')8 worker.start()9}1011ReactDOM.render(<App />, document.getElementById('root'))
Starting the worker is an asynchronous action, which may create a race condition with your application making requests on mount. If that's the case, please refer to the Deferred mounting recipe to enforce your application mount when the worker is ready.
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 window.location.pathname
string with /
at the end:
1// src/index.js2import React from 'react'3import ReactDOM from 'react-dom'4import App from './App'56async function main() {7 if (process.env.NODE_ENV === 'development') {8 if (window.location.pathname === '/login') {9 window.location.pathname = '/login/'10 return11 }1213 const { worker } = require('./mocks/browser')1415 await worker.start({16 serviceWorker: {17 url: '/login/mockServiceWorker.js',18 },19 })20 }2122 ReactDOM.render(23 <React.StrictMode>24 <App />25 </React.StrictMode>,26 document.getElementById('root'),27 )28}2930main()