Mock Service Worker
Mock Service Worker (MSW) is a powerful and seamless library for intercepting and mocking REST and GraphQL API requests directly at the network level, in both browser and Node.js environments. Unlike traditional mocking libraries that patch client-side request utilities, MSW leverages the Service Worker API in browsers and a custom `http` interception module in Node.js. This approach allows applications to run against mock data without any code changes, making it ideal for consistent mocking across development, unit, integration, and end-to-end testing, as well as debugging. The current stable version is 2.13.4, with frequent minor and patch releases, often several times a month, indicating active development. Its key differentiator is providing deviation-free mocking by intercepting actual network requests, ensuring a high fidelity simulation of real API interactions.
Common errors
-
SyntaxError: Named export 'setupWorker' not found. The requested module 'msw' does not provide an export named 'setupWorker'
cause Attempting to use CommonJS `require` or incorrect ESM import syntax for MSW v2, which is ESM-only, or importing `setupWorker` from the wrong entry point (`msw` instead of `msw/browser`).fixEnsure you are using `import { setupWorker } from 'msw/browser'` and that your project is configured for ESM. For Node.js, use `import { setupServer } from 'msw/node'`. -
Failed to register a Service Worker: A bad HTTP response code (404) was received when fetching the script.
cause The `mockServiceWorker.js` file is not found at the expected path (usually the public root) by the browser when `worker.start()` is called.fixVerify that `mockServiceWorker.js` is present in your public directory and accessible. Run `npx msw init <PUBLIC_DIR_PATH>` to re-initialize it. Check your web server configuration to ensure it serves static files correctly from the root path. If using a custom path, specify it in `setupWorker({ serviceWorker: { url: '/custom/path/mockServiceWorker.js' } })`. -
TypeError: Cannot read properties of undefined (reading 'listen') at server.listen
cause The `server` object returned by `setupServer` is either undefined or not properly instantiated, often due to incorrect import or setup in a Node.js environment.fixEnsure `setupServer` is correctly imported as `import { setupServer } from 'msw/node'` and that the `server` variable is assigned the result of `setupServer(...)`. -
Error: [MSW] The 'rest' handler is deprecated and will be removed in the next major version. Please use 'http' instead.
cause Using the deprecated `rest` object from MSW v1 instead of the `http` object for defining request handlers in an MSW v2 environment.fixReplace `rest.get`, `rest.post`, `rest.put`, `rest.patch`, `rest.delete` with their `http` equivalents (e.g., `http.get`, `http.post`).
Warnings
- breaking MSW v2 is an ESM-only package and no longer supports CommonJS (`require`). All imports must use ESM syntax (`import`).
- breaking The `rest` object for defining HTTP handlers was renamed to `http` in MSW v2. Similarly, the `graphql` object also underwent changes in its API.
- breaking The package entry points for browser and Node.js setups changed in MSW v2. Browser setup now imports from `msw/browser` and Node.js from `msw/node`.
- gotcha Ensuring the Service Worker script (`mockServiceWorker.js`) is correctly served at the root of your application's public directory is crucial for browser environments. Incorrect paths or server configurations can prevent the worker from registering.
- gotcha When using MSW in Node.js test environments (e.g., Jest, Vitest), it's important to properly set up the lifecycle hooks (`beforeAll`, `afterAll`, `afterEach`) to start and stop the server and reset handlers.
Install
-
npm install msw -
yarn add msw -
pnpm add msw
Imports
- setupWorker
const { setupWorker } = require('msw')import { setupWorker } from 'msw/browser' - setupServer
import { setupServer } from 'msw'import { setupServer } from 'msw/node' - http
import { rest } from 'msw'import { http } from 'msw' - HttpResponse
import { HttpResponse } from 'msw'
Quickstart
import { setupWorker, http, HttpResponse } from 'msw';
// Define handlers for your API requests
const handlers = [
http.get('https://example.com/api/user/:userId', ({ params }) => {
const { userId } = params;
if (userId === '123') {
return HttpResponse.json(
{ id: '123', name: 'John Doe', email: 'john.doe@example.com' },
{ status: 200 }
);
}
return HttpResponse.json({ message: 'User not found' }, { status: 404 });
}),
http.post('https://example.com/api/users', async ({ request }) => {
const newUser = await request.json();
console.log('New user creation request:', newUser);
return HttpResponse.json({ id: 'new-id', ...newUser }, { status: 201 });
})
];
// Create a service worker instance
const worker = setupWorker(...handlers);
// Register the Service Worker in the browser
worker.start({
onUnhandledRequest: 'warn' // Configure behavior for unhandled requests
});
console.log('MSW service worker started.');
// Example usage: Make a fetch request that will be intercepted by MSW
async function demonstrateMocking() {
try {
console.log('Fetching user 123...');
const userResponse = await fetch('https://example.com/api/user/123');
const userData = await userResponse.json();
console.log('Fetched user (mocked):', userData);
console.log('Creating a new user...');
const createUserResponse = await fetch('https://example.com/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Jane Smith', email: 'jane.smith@example.com' })
});
const newUserData = await createUserResponse.json();
console.log('Created user (mocked):', newUserData);
} catch (error) {
console.error('Fetch error:', error);
}
}
demonstrateMocking();