MSW for TypeScript: Complete Guide with Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

MSW for TypeScript: Complete Guide with Examples

What Is MSW and Why Use It?

Mock Service Worker (MSW) is a library for intercepting and mocking network requests at the Service Worker API level. Unlike traditional solutions (e.g., axios-mock-adapter or nock), MSW works at the browser or Node.js level, intercepting real HTTP requests and returning predefined responses. This lets you test applications without running a real server or modifying your application code.

The main goal of MSW is to provide a unified tool for API mocking in both browser tests (using a real Service Worker) and server-side tests (Node.js). The library is especially useful for TypeScript developers, as it offers strict typing for all requests and responses. MSW is ideal for unit tests, integration tests, and frontend development in isolation from the backend.

A key advantage of MSW is that mocks work at the network level, not the code level. This means any HTTP request library (fetch, axios, graphql-request, etc.) will be automatically intercepted without additional configuration. The library supports REST APIs, GraphQL, and can even handle WebSocket connections through extensions.

Installation

To install MSW in a TypeScript project, run one of the following commands:

# npm
npm install msw --save-dev

# yarn
yarn add msw --dev

# pnpm
pnpm add msw --save-dev

After installation, initialize the Service Worker for browser use:

npx msw init public/ --save

For server-side use (Node.js), no additional initialization is required.

Quick Start — Minimal Working Example

Let's create a simple mock for a REST API. This example includes defining a handler, setting up the server, and making a test request.

// handlers.ts
import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('https://api.example.com/user', () => {
    return HttpResponse.json({
      id: 'c7b3d8e0-5e0b-4b0f-8b3a-3b9f4b3d3b3f',
      firstName: 'John',
      lastName: 'Maverick',
    });
  }),
];

// server.ts (for Node.js)
import { setupServer } from 'msw/node';
import { handlers } from './handlers';

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

// test.ts
import { server } from './server';

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

test('should fetch user', async () => {
  const response = await fetch('https://api.example.com/user');
  const data = await response.json();
  expect(data.firstName).toBe('John');
});

Core Methods and Functions

1. http.get()

Signature: http.get(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Description: Creates a handler for GET requests to the specified URL. Supports exact strings, regular expressions, and parameterized patterns.

import { http, HttpResponse } from 'msw';

export const handler = http.get('https://api.example.com/users/:id', ({ params }) => {
  const { id } = params;
  return HttpResponse.json({ id, name: 'User ' + id });
});

2. http.post()

Signature: http.post(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Description: Creates a handler for POST requests. Allows reading the request body via request.json().

import { http, HttpResponse } from 'msw';

export const handler = http.post('https://api.example.com/users', async ({ request }) => {
  const body = await request.json();
  return HttpResponse.json({ id: 'new-id', ...body }, { status: 201 });
});

3. http.put()

Signature: http.put(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Description: Creates a handler for PUT requests. Works similarly to POST but is semantically used for updates.

import { http, HttpResponse } from 'msw';

export const handler = http.put('https://api.example.com/users/:id', async ({ params, request }) => {
  const { id } = params;
  const updates = await request.json();
  return HttpResponse.json({ id, ...updates });
});

4. http.delete()

Signature: http.delete(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Description: Creates a handler for DELETE requests. Typically returns a 200 or 204 status code.

import { http, HttpResponse } from 'msw';

export const handler = http.delete('https://api.example.com/users/:id', ({ params }) => {
  const { id } = params;
  return HttpResponse.json({ message: `User ${id} deleted` });
});

5. http.patch()

Signature: http.patch(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Description: Creates a handler for PATCH requests. Used for partial updates to a resource.

import { http, HttpResponse } from 'msw';

export const handler = http.patch('https://api.example.com/users/:id', async ({ params, request }) => {
  const { id } = params;
  const partialUpdate = await request.json();
  return HttpResponse.json({ id, ...partialUpdate });
});

6. http.all()

Signature: http.all(url: string | RegExp, resolver: (info: HttpRequestInfo) => HttpResponse)

Description: Creates a handler that matches any HTTP method for the specified URL. Useful for catching all requests to a particular endpoint.

import { http, HttpResponse } from 'msw';

export const handler = http.all('https://api.example.com/*', () => {
  return HttpResponse.json({ message: 'Mocked response for any method' });
});

7. HttpResponse.json()

Signature: HttpResponse.json(body: any, init?: ResponseInit)

Description: Creates a JSON response. The second parameter allows setting status codes, headers, and other response options.

import { HttpResponse } from 'msw';

// Simple JSON response
const response1 = HttpResponse.json({ data: 'test' });

// JSON response with custom status and headers
const response2 = HttpResponse.json(
  { error: 'Not found' },
  { status: 404, headers: { 'X-Custom': 'value' } }
);

8. HttpResponse.text()

Signature: HttpResponse.text(body: string, init?: ResponseInit)

Description: Creates a plain text response. Useful for mocking endpoints that return HTML, CSV, or other text formats.

import { HttpResponse } from 'msw';

const response = HttpResponse.text('Hello, world!', {
  headers: { 'Content-Type': 'text/plain' }
});

9. HttpResponse.xml()

Signature: HttpResponse.xml(body: string, init?: ResponseInit)

Description: Creates an XML response. Automatically sets the Content-Type header to application/xml.

import { HttpResponse } from 'msw';

const response = HttpResponse.xml('value');

10. HttpResponse.arrayBuffer()

Signature: HttpResponse.arrayBuffer(body: ArrayBuffer, init?: ResponseInit)

Description: Creates a response with binary data. Useful for mocking file downloads or image responses.

import { HttpResponse } from 'msw';

const buffer = new ArrayBuffer(8);
const response = HttpResponse.arrayBuffer(buffer);

Recommendations