Seamless REST/GraphQL API mocking library for browser and Node.js.
npx @tessl/cli install tessl/npm-msw@2.11.00
# Mock Service Worker (MSW)
1
2
Mock Service Worker (MSW) is an API mocking library that intercepts HTTP, GraphQL, and WebSocket requests at the network level using Service Workers in browsers and low-level interception in Node.js. Unlike traditional mocking libraries that stub fetch or axios functions, MSW operates transparently without modifying application code, allowing developers to reuse the same mock definitions across unit tests, integration tests, end-to-end tests, and local development.
3
4
## Package Information
5
6
- **Package Name**: msw
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install msw`
10
11
## Core Imports
12
13
```typescript
14
import { http, HttpResponse, setupWorker } from "msw";
15
import { setupServer } from "msw/node";
16
```
17
18
For CommonJS:
19
20
```javascript
21
const { http, HttpResponse, setupWorker } = require("msw");
22
const { setupServer } = require("msw/node");
23
```
24
25
Environment-specific imports:
26
27
```typescript
28
// Browser-specific
29
import { setupWorker } from "msw/browser";
30
31
// Node.js-specific
32
import { setupServer } from "msw/node";
33
34
// React Native-specific
35
import { setupServer } from "msw/native";
36
37
// Core-only imports
38
import { http } from "msw/core/http";
39
import { graphql } from "msw/core/graphql";
40
import { ws } from "msw/core/ws";
41
```
42
43
## Basic Usage
44
45
```typescript
46
import { http, HttpResponse, setupWorker } from "msw";
47
48
// Define request handlers
49
const handlers = [
50
// REST API handlers
51
http.get('/api/user', () => {
52
return HttpResponse.json({ name: 'John Doe', id: 123 });
53
}),
54
55
http.post('/api/login', async ({ request }) => {
56
const { username, password } = await request.json();
57
58
if (username === 'admin' && password === 'secret') {
59
return HttpResponse.json({ token: 'abc123' });
60
}
61
62
return HttpResponse.json(
63
{ error: 'Invalid credentials' },
64
{ status: 401 }
65
);
66
}),
67
68
// GraphQL handlers
69
graphql.query('GetUser', () => {
70
return HttpResponse.json({
71
data: { user: { name: 'John Doe' } }
72
});
73
}),
74
];
75
76
// Browser setup
77
const worker = setupWorker(...handlers);
78
worker.start();
79
80
// Node.js setup (for testing)
81
const server = setupServer(...handlers);
82
server.listen();
83
```
84
85
## Architecture
86
87
MSW is built around several key components:
88
89
- **Request Handlers**: Define how to intercept and respond to specific requests using Express-like routing
90
- **Setup APIs**: Platform-specific APIs (`setupWorker`, `setupServer`) that configure and control request interception
91
- **Response Utilities**: `HttpResponse` class and utilities for creating realistic mock responses
92
- **Network Interception**: Service Workers (browser) or low-level interceptors (Node.js) that capture requests transparently
93
- **Multi-Environment Support**: Same handler definitions work across browser, Node.js, and React Native environments
94
95
## Capabilities
96
97
### HTTP Request Handling
98
99
Intercept and mock HTTP requests using Express-like routing syntax with support for parameters, wildcards, and custom predicates.
100
101
```typescript { .api }
102
interface HttpRequestHandler {
103
<Params, RequestBodyType, ResponseBodyType>(
104
predicate: string | RegExp | ((info: { request: Request; parsedResult: any }) => boolean),
105
resolver: (info: {
106
request: Request;
107
params: Params;
108
cookies: Record<string, string>;
109
}) => Response | Promise<Response>,
110
options?: { once?: boolean }
111
): HttpHandler;
112
}
113
114
const http: {
115
all: HttpRequestHandler;
116
get: HttpRequestHandler;
117
post: HttpRequestHandler;
118
put: HttpRequestHandler;
119
delete: HttpRequestHandler;
120
patch: HttpRequestHandler;
121
head: HttpRequestHandler;
122
options: HttpRequestHandler;
123
};
124
```
125
126
[HTTP Handlers](./http-handlers.md)
127
128
### GraphQL Request Handling
129
130
Intercept and mock GraphQL operations by query/mutation name or operation type, with support for typed responses and scoped endpoints.
131
132
```typescript { .api }
133
interface GraphQLRequestHandler {
134
<Query, Variables>(
135
predicate: string | DocumentNode | ((info: { query: any; variables: any }) => boolean),
136
resolver: (info: {
137
query: Query;
138
variables: Variables;
139
request: Request;
140
}) => Response | Promise<Response>,
141
options?: { once?: boolean }
142
): GraphQLHandler;
143
}
144
145
const graphql: {
146
query: GraphQLRequestHandler;
147
mutation: GraphQLRequestHandler;
148
operation: (resolver: any) => GraphQLHandler;
149
link: (url: string) => typeof graphql;
150
};
151
```
152
153
[GraphQL Handlers](./graphql-handlers.md)
154
155
### WebSocket Connection Handling
156
157
Intercept and mock WebSocket connections with event-based API for handling connection lifecycle and message broadcasting.
158
159
```typescript { .api }
160
interface WebSocketLink {
161
clients: Set<WebSocketClient>;
162
addEventListener<EventType extends keyof WebSocketHandlerEventMap>(
163
event: EventType,
164
listener: (...args: WebSocketHandlerEventMap[EventType]) => void
165
): WebSocketHandler;
166
broadcast(data: WebSocketData): void;
167
broadcastExcept(
168
clients: WebSocketClient | WebSocketClient[],
169
data: WebSocketData
170
): void;
171
}
172
173
const ws: {
174
link: (url: string) => WebSocketLink;
175
};
176
```
177
178
[WebSocket Handlers](./websocket-handlers.md)
179
180
### Browser Environment Setup
181
182
Service Worker-based request interception for browser environments with lifecycle control and runtime handler management.
183
184
```typescript { .api }
185
interface SetupWorker {
186
start(options?: StartOptions): Promise<ServiceWorkerRegistration | undefined>;
187
stop(): void;
188
use(...handlers: RequestHandler[]): void;
189
resetHandlers(...handlers?: RequestHandler[]): void;
190
restoreHandlers(): void;
191
listHandlers(): ReadonlyArray<RequestHandler>;
192
events: LifeCycleEventEmitter;
193
}
194
195
function setupWorker(...handlers: RequestHandler[]): SetupWorker;
196
```
197
198
[Browser Setup](./browser-setup.md)
199
200
### Node.js Environment Setup
201
202
Low-level request interception for Node.js environments using HTTP/HTTPS module patching, ideal for testing scenarios.
203
204
```typescript { .api }
205
interface SetupServer {
206
listen(options?: { onUnhandledRequest?: 'bypass' | 'warn' | 'error' }): void;
207
close(): void;
208
use(...handlers: RequestHandler[]): void;
209
resetHandlers(...handlers?: RequestHandler[]): void;
210
restoreHandlers(): void;
211
listHandlers(): ReadonlyArray<RequestHandler>;
212
events: LifeCycleEventEmitter;
213
}
214
215
function setupServer(...handlers: RequestHandler[]): SetupServer;
216
```
217
218
[Node.js Setup](./nodejs-setup.md)
219
220
### React Native Environment Setup
221
222
Request interception for React Native applications using fetch and XMLHttpRequest interceptors, compatible with popular HTTP libraries.
223
224
```typescript { .api }
225
interface SetupServerCommonApi {
226
listen(options?: { onUnhandledRequest?: 'bypass' | 'warn' | 'error' }): void;
227
close(): void;
228
use(...handlers: RequestHandler[]): void;
229
resetHandlers(...handlers?: RequestHandler[]): void;
230
restoreHandlers(): void;
231
listHandlers(): ReadonlyArray<RequestHandler>;
232
events: LifeCycleEventEmitter;
233
}
234
235
function setupServer(...handlers: RequestHandler[]): SetupServerCommonApi;
236
```
237
238
[React Native Setup](./react-native-setup.md)
239
240
### Response Creation
241
242
Enhanced Response class with convenience methods for creating various response types with proper headers and content handling.
243
244
```typescript { .api }
245
class HttpResponse<BodyType> extends Response {
246
constructor(body?: BodyType | null, init?: HttpResponseInit);
247
248
static text(body?: string, init?: HttpResponseInit): HttpResponse<string>;
249
static json<T>(body?: T, init?: HttpResponseInit): HttpResponse<T>;
250
static xml(body?: string, init?: HttpResponseInit): HttpResponse<string>;
251
static html(body?: string, init?: HttpResponseInit): HttpResponse<string>;
252
static arrayBuffer(body?: ArrayBuffer, init?: HttpResponseInit): HttpResponse<ArrayBuffer>;
253
static formData(body?: FormData, init?: HttpResponseInit): HttpResponse<FormData>;
254
static error(): HttpResponse<any>;
255
}
256
257
interface HttpResponseInit extends ResponseInit {
258
type?: ResponseType;
259
}
260
```
261
262
[Response Creation](./response-creation.md)
263
264
### Command Line Interface
265
266
CLI tool for initializing and managing MSW Service Worker files in browser environments.
267
268
```bash { .api }
269
# Initialize MSW in project
270
msw init [publicDir] [--save] [--cwd <directory>]
271
272
# Examples:
273
msw init public/ --save
274
msw init ./static
275
msw init --cwd /path/to/project
276
```
277
278
[CLI Documentation](./cli.md)
279
280
### Request Utilities
281
282
Utilities for handling request flow, including delays, bypassing MSW interception, and passthrough behavior.
283
284
```typescript { .api }
285
function delay(duration?: number | 'real' | 'infinite'): Promise<void>;
286
function bypass(input: string | URL | Request, init?: RequestInit): Request;
287
function passthrough(): HttpResponse<any>;
288
function getResponse(
289
handlers: Array<RequestHandler>,
290
request: Request,
291
resolutionContext?: ResponseResolutionContext
292
): Promise<Response | undefined>;
293
```
294
295
[Request Utilities](./utilities.md)
296
297
## Types
298
299
```typescript { .api }
300
// Core handler types
301
type RequestHandler = HttpHandler | GraphQLHandler | WebSocketHandler;
302
303
interface RequestHandlerOptions {
304
once?: boolean;
305
}
306
307
// HTTP types
308
interface HttpHandler {
309
predicate: string | RegExp | HttpCustomPredicate;
310
resolver: HttpResponseResolver;
311
options: RequestHandlerOptions;
312
}
313
314
type HttpCustomPredicate = (info: {
315
request: Request;
316
parsedResult: HttpRequestParsedResult;
317
}) => boolean;
318
319
interface HttpRequestParsedResult {
320
match: Match;
321
query: RequestQuery;
322
}
323
324
type RequestQuery = Record<string, string | string[]>;
325
326
// GraphQL types
327
interface GraphQLHandler {
328
operationType: 'query' | 'mutation' | 'all';
329
predicate: string | DocumentNode | GraphQLCustomPredicate;
330
resolver: GraphQLResponseResolver;
331
}
332
333
type GraphQLCustomPredicate = (info: {
334
query: any;
335
variables: Record<string, any>;
336
operationType: string;
337
operationName?: string;
338
}) => boolean;
339
340
// WebSocket types
341
interface WebSocketHandler {
342
url: string | RegExp;
343
eventHandlers: Map<string, Function[]>;
344
}
345
346
type WebSocketData = string | ArrayBuffer | Blob;
347
348
// Setup types
349
interface StartOptions {
350
serviceWorker?: {
351
url?: string;
352
options?: RegistrationOptions;
353
};
354
quiet?: boolean;
355
onUnhandledRequest?: 'bypass' | 'warn' | 'error';
356
}
357
358
// Path matching types
359
type Path = string | RegExp;
360
type PathParams<T extends string = string> = Record<T, string>;
361
362
interface Match {
363
matches: boolean;
364
params: Record<string, string>;
365
}
366
367
// Response types
368
type DefaultBodyType = string | number | boolean | null | undefined | ArrayBuffer | Blob | FormData | ReadableStream;
369
type JsonBodyType = Record<string, any> | any[];
370
371
// Lifecycle types
372
interface LifeCycleEventsMap {
373
'request:start': [args: { request: Request; requestId: string }];
374
'request:match': [args: { request: Request; requestId: string }];
375
'request:unhandled': [args: { request: Request; requestId: string }];
376
'request:end': [args: { request: Request; requestId: string }];
377
'response:mocked': [args: { response: Response; request: Request; requestId: string }];
378
'response:bypass': [args: { response: Response; request: Request; requestId: string }];
379
'unhandledException': [args: { error: Error; request: Request; requestId: string }];
380
}
381
382
type LifeCycleEventEmitter = {
383
on<EventType extends keyof LifeCycleEventsMap>(
384
event: EventType,
385
listener: (...args: LifeCycleEventsMap[EventType]) => void
386
): void;
387
removeListener<EventType extends keyof LifeCycleEventsMap>(
388
event: EventType,
389
listener: (...args: LifeCycleEventsMap[EventType]) => void
390
): void;
391
removeAllListeners(event?: keyof LifeCycleEventsMap): void;
392
};
393
394
// Utility types
395
type DelayMode = 'real' | 'infinite';
396
type ResponseResolutionContext = {
397
baseUrl?: string;
398
};
399
400
// Deprecated types (for backward compatibility)
401
/** @deprecated Use HttpResponse instead */
402
type StrictResponse<BodyType> = HttpResponse<BodyType>;
403
404
// Legacy type aliases
405
type DefaultRequestMultipartBody = Record<string, string | File>;
406
```