DEV Community

Alex Spinov
Alex Spinov

Posted on

MSW Has a Free API Mocking Library — Here's How to Use It

Mocking APIs with jest.mock() or nock is fragile and tightly coupled to implementation. MSW (Mock Service Worker) intercepts actual network requests — your app doesn't know it's being mocked.

What Is MSW?

MSW intercepts HTTP requests at the network level using Service Workers (browser) or custom interceptors (Node.js). Your application code makes real fetch/axios calls — MSW catches them and returns your mock responses.

Quick Start

npm install msw --save-dev
Enter fullscreen mode Exit fullscreen mode
// mocks/handlers.ts
import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('/api/users', () => {
    return HttpResponse.json([
      { id: 1, name: 'John', email: 'john@example.com' },
      { id: 2, name: 'Jane', email: 'jane@example.com' },
    ]);
  }),

  http.post('/api/users', async ({ request }) => {
    const body = await request.json();
    return HttpResponse.json(
      { id: 3, ...body },
      { status: 201 }
    );
  }),

  http.delete('/api/users/:id', ({ params }) => {
    return new HttpResponse(null, { status: 204 });
  }),
];
Enter fullscreen mode Exit fullscreen mode

Browser Setup

// mocks/browser.ts
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';

export const worker = setupWorker(...handlers);
Enter fullscreen mode Exit fullscreen mode
// main.tsx
if (process.env.NODE_ENV === 'development') {
  const { worker } = await import('./mocks/browser');
  await worker.start();
}
Enter fullscreen mode Exit fullscreen mode

Test Setup (Vitest/Jest)

// mocks/server.ts
import { setupServer } from 'msw/node';
import { handlers } from './handlers';

export const server = setupServer(...handlers);

// setup.ts
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Enter fullscreen mode Exit fullscreen mode

Testing Example

import { server } from '../mocks/server';
import { http, HttpResponse } from 'msw';

test('shows error when API fails', async () => {
  // Override handler for this test only
  server.use(
    http.get('/api/users', () => {
      return HttpResponse.json(
        { message: 'Server error' },
        { status: 500 }
      );
    })
  );

  render(<UserList />);

  expect(await screen.findByText('Failed to load users')).toBeInTheDocument();
});
Enter fullscreen mode Exit fullscreen mode

Why MSW Over Alternatives

Feature MSW jest.mock nock
Network level Yes No Node only
Framework agnostic Yes Jest only Node only
Browser support Yes No No
TypeScript First-class Manual Basic
Reusable mocks Yes Per-test Per-test
Dev server mocking Yes No No

Advanced Patterns

Simulating Delays

http.get('/api/data', async () => {
  await delay(2000); // 2 second delay
  return HttpResponse.json({ data: 'loaded' });
});
Enter fullscreen mode Exit fullscreen mode

Network Errors

http.get('/api/data', () => {
  return HttpResponse.error(); // Simulates network failure
});
Enter fullscreen mode Exit fullscreen mode

Streaming Responses

http.get('/api/stream', () => {
  const stream = new ReadableStream({
    start(controller) {
      controller.enqueue(new TextEncoder().encode('chunk 1'));
      controller.enqueue(new TextEncoder().encode('chunk 2'));
      controller.close();
    },
  });
  return new HttpResponse(stream);
});
Enter fullscreen mode Exit fullscreen mode

Get Started


Testing APIs that consume scraped data? My Apify actors deliver reliable test data. Custom solutions: spinov001@gmail.com

Top comments (0)