0
# WebSocket Mocking
1
2
WebSocket connection interception and mocking with support for message echoing, forwarding, and custom handling for testing real-time applications.
3
4
## Capabilities
5
6
### WebSocket Rule Builder
7
8
Create rules for matching and handling WebSocket upgrade requests.
9
10
```typescript { .api }
11
interface Mockttp {
12
/**
13
* Create a rule builder for matching WebSocket connections.
14
* Matches the initial HTTP upgrade request that establishes the WebSocket.
15
*/
16
forAnyWebSocket(): WebSocketRuleBuilder;
17
}
18
19
interface WebSocketRuleBuilder {
20
/**
21
* Match WebSocket upgrades for specific paths.
22
* Supports string paths, full URLs, and regular expressions.
23
*/
24
withPath(path: string | RegExp): this;
25
26
/**
27
* Match WebSocket upgrades with specific headers.
28
* Useful for matching custom protocols or authentication.
29
*/
30
withHeaders(headers: Headers): this;
31
32
/**
33
* Match WebSocket upgrades with specific query parameters.
34
*/
35
withQuery(query: {[key: string]: string | string[] | undefined}): this;
36
37
/**
38
* Match WebSocket requests to specific hostname.
39
*/
40
withHostname(hostname: string | RegExp): this;
41
42
/**
43
* Match WebSocket requests to specific host (hostname:port).
44
*/
45
withHost(host: string | RegExp): this;
46
47
/**
48
* Match WebSocket requests to specific host (hostname:port).
49
* Alternative method name for withHost.
50
*/
51
forHost(host: string): this;
52
53
/**
54
* Match WebSocket requests to specific hostname only.
55
* Alternative method name for withHostname.
56
*/
57
forHostname(hostname: string): this;
58
59
/**
60
* Match WebSocket requests on specific port number.
61
*/
62
withPort(port: number): this;
63
64
/**
65
* Match WebSocket requests on specific port number.
66
* Alternative method name for withPort.
67
*/
68
forPort(port: number): this;
69
70
/**
71
* Match WebSocket requests with specific protocol (ws/wss).
72
*/
73
withProtocol(protocol: "ws" | "wss"): this;
74
75
/**
76
* Match WebSocket requests where URL matches regular expression.
77
*/
78
withUrlMatching(pattern: RegExp): this;
79
80
/**
81
* Match WebSocket requests with specific body content.
82
* Less common for WebSockets but available from inherited base.
83
*/
84
withBody(content: string | RegExp): this;
85
86
/**
87
* Match WebSocket requests with exact JSON body content.
88
* Less common for WebSockets but available from inherited base.
89
*/
90
withJsonBody(json: object): this;
91
92
/**
93
* Match WebSocket requests with partial JSON body content.
94
* Less common for WebSockets but available from inherited base.
95
*/
96
withJsonBodyIncluding(json: object): this;
97
98
/**
99
* Match WebSocket requests with specific cookie values.
100
*/
101
withCookie(cookie: {[key: string]: string}): this;
102
103
/**
104
* Match WebSocket upgrades using custom matching logic.
105
*/
106
matching(callback: (request: CompletedRequest) => boolean | Promise<boolean>): this;
107
}
108
```
109
110
**Usage Examples:**
111
112
```typescript
113
import { getLocal } from "mockttp";
114
115
const mockServer = getLocal();
116
await mockServer.start();
117
118
// Match any WebSocket connection
119
await mockServer.forAnyWebSocket()
120
.thenEcho();
121
122
// Match specific path
123
await mockServer.forAnyWebSocket()
124
.withPath("/chat")
125
.thenEcho();
126
127
// Match with custom headers
128
await mockServer.forAnyWebSocket()
129
.withPath("/secure-chat")
130
.withHeaders({
131
"Sec-WebSocket-Protocol": "chat-v1",
132
"Authorization": /^Bearer .+/
133
})
134
.thenPassivelyListen();
135
136
// Match with query parameters
137
await mockServer.forAnyWebSocket()
138
.withPath("/notifications")
139
.withQuery({ userId: "123", token: "abc" })
140
.thenEcho();
141
142
// Custom matching logic
143
await mockServer.forAnyWebSocket()
144
.matching((request) => {
145
const protocols = request.headers['sec-websocket-protocol'];
146
return protocols && protocols.includes('myapp-v2');
147
})
148
.thenPassThrough();
149
```
150
151
### WebSocket Response Actions
152
153
Actions for handling WebSocket connections after they're matched.
154
155
```typescript { .api }
156
interface WebSocketRuleBuilder {
157
/**
158
* Accept the WebSocket and echo all received messages back to the client.
159
* Useful for testing WebSocket client implementations.
160
*/
161
thenEcho(): Promise<MockedEndpoint>;
162
163
/**
164
* Accept the WebSocket and listen passively without sending messages.
165
* Useful for testing message sending without interference.
166
*/
167
thenPassivelyListen(): Promise<MockedEndpoint>;
168
169
/**
170
* Forward the WebSocket to the original target server.
171
* Enables selective WebSocket mocking while preserving real connections.
172
*/
173
thenPassThrough(options?: PassThroughWebSocketStepOptions): Promise<MockedEndpoint>;
174
175
/**
176
* Forward the WebSocket to a specific target URL.
177
* Enables WebSocket proxying and redirection.
178
*/
179
thenForwardTo(
180
target: string,
181
options?: PassThroughWebSocketStepOptions
182
): Promise<MockedEndpoint>;
183
184
/**
185
* Reject the WebSocket upgrade request with an HTTP error response.
186
* Useful for testing connection failure scenarios.
187
*/
188
thenRejectConnection(
189
statusCode?: number,
190
statusMessage?: string,
191
headers?: Headers,
192
body?: Buffer | string
193
): Promise<MockedEndpoint>;
194
195
/**
196
* Close the connection immediately without accepting the WebSocket.
197
* Simulates server crashes or network failures.
198
*/
199
thenCloseConnection(): Promise<MockedEndpoint>;
200
201
/**
202
* Reset the connection with a TCP RST packet.
203
* Simulates aggressive connection termination.
204
*/
205
thenResetConnection(): Promise<MockedEndpoint>;
206
207
/**
208
* Hold the connection open indefinitely without responding.
209
* Simulates server timeouts during WebSocket upgrade.
210
*/
211
thenTimeout(): Promise<MockedEndpoint>;
212
213
/**
214
* Add a delay before processing the WebSocket connection.
215
* Can be chained with other WebSocket actions.
216
*/
217
delay(ms: number): this;
218
}
219
220
interface PassThroughWebSocketStepOptions {
221
/**
222
* Custom DNS lookup options for the target server.
223
*/
224
lookupOptions?: PassThroughLookupOptions;
225
226
/**
227
* Connection options for the upstream WebSocket.
228
*/
229
connectionOptions?: PassThroughStepConnectionOptions;
230
231
/**
232
* Forwarding configuration for the WebSocket.
233
*/
234
forwardingOptions?: ForwardingOptions;
235
}
236
```
237
238
**Usage Examples:**
239
240
```typescript
241
import { getLocal } from "mockttp";
242
243
const mockServer = getLocal();
244
await mockServer.start();
245
246
// Echo server for testing
247
await mockServer.forAnyWebSocket()
248
.withPath("/echo")
249
.thenEcho();
250
251
// Silent listener for one-way testing
252
await mockServer.forAnyWebSocket()
253
.withPath("/send-only")
254
.thenPassivelyListen();
255
256
// Forward to real WebSocket server
257
await mockServer.forAnyWebSocket()
258
.withPath("/chat")
259
.thenForwardTo("wss://chat.example.com/socket");
260
261
// Reject unauthorized connections
262
await mockServer.forAnyWebSocket()
263
.withPath("/admin")
264
.matching((req) => !req.headers.authorization)
265
.thenRejectConnection(401, "Unauthorized", {
266
"WWW-Authenticate": "Bearer"
267
});
268
269
// Accept authorized connections
270
await mockServer.forAnyWebSocket()
271
.withPath("/admin")
272
.matching((req) => req.headers.authorization === "Bearer valid-token")
273
.thenPassThrough();
274
275
// Simulate connection failure
276
await mockServer.forAnyWebSocket()
277
.withPath("/unreliable")
278
.thenCloseConnection();
279
280
// Delayed WebSocket handling
281
await mockServer.forAnyWebSocket()
282
.withPath("/slow")
283
.delay(2000)
284
.thenEcho();
285
```
286
287
### WebSocket Event Monitoring
288
289
Monitor WebSocket connections and messages through the event system.
290
291
```typescript { .api }
292
interface Mockttp {
293
/**
294
* Subscribe to WebSocket upgrade requests (before acceptance/rejection).
295
*/
296
on(event: 'websocket-request', callback: (req: CompletedRequest) => void): Promise<void>;
297
298
/**
299
* Subscribe to WebSocket upgrade acceptances (after successful upgrade).
300
*/
301
on(event: 'websocket-accepted', callback: (res: CompletedResponse) => void): Promise<void>;
302
303
/**
304
* Subscribe to messages received from WebSocket clients.
305
*/
306
on(event: 'websocket-message-received', callback: (msg: WebSocketMessage) => void): Promise<void>;
307
308
/**
309
* Subscribe to messages sent to WebSocket clients.
310
*/
311
on(event: 'websocket-message-sent', callback: (msg: WebSocketMessage) => void): Promise<void>;
312
313
/**
314
* Subscribe to WebSocket connection closures.
315
*/
316
on(event: 'websocket-close', callback: (close: WebSocketClose) => void): Promise<void>;
317
}
318
319
interface WebSocketMessage {
320
/**
321
* ID of the WebSocket stream (matches request/response IDs).
322
*/
323
streamId: string;
324
325
/**
326
* Direction of the message from Mockttp's perspective.
327
*/
328
direction: 'sent' | 'received';
329
330
/**
331
* Message content as raw bytes (already decompressed).
332
*/
333
content: Uint8Array;
334
335
/**
336
* Whether this is a binary message or text message.
337
*/
338
isBinary: boolean;
339
340
/**
341
* High-precision timestamp of when the message was processed.
342
*/
343
eventTimestamp: number;
344
345
/**
346
* Timing information for the WebSocket connection.
347
*/
348
timingEvents: TimingEvents;
349
350
/**
351
* Tags associated with this WebSocket connection.
352
*/
353
tags: string[];
354
}
355
356
interface WebSocketClose {
357
/**
358
* ID of the WebSocket stream (matches request/response IDs).
359
*/
360
streamId: string;
361
362
/**
363
* WebSocket close code (1000 = normal closure, etc.).
364
*/
365
closeCode: number | undefined;
366
367
/**
368
* Human-readable close reason.
369
*/
370
closeReason: string;
371
372
/**
373
* Timing information for the WebSocket connection.
374
*/
375
timingEvents: TimingEvents;
376
377
/**
378
* Tags associated with this WebSocket connection.
379
*/
380
tags: string[];
381
}
382
```
383
384
**Usage Examples:**
385
386
```typescript
387
import { getLocal } from "mockttp";
388
389
const mockServer = getLocal({ debug: true });
390
await mockServer.start();
391
392
// Monitor all WebSocket activity
393
await mockServer.on('websocket-request', (req) => {
394
console.log(`WebSocket requested: ${req.url}`);
395
});
396
397
await mockServer.on('websocket-accepted', (res) => {
398
console.log(`WebSocket accepted: ${res.id}`);
399
});
400
401
await mockServer.on('websocket-message-received', (msg) => {
402
const text = msg.isBinary ?
403
`<${msg.content.length} bytes>` :
404
new TextDecoder().decode(msg.content);
405
console.log(`Received: ${text}`);
406
});
407
408
await mockServer.on('websocket-message-sent', (msg) => {
409
const text = msg.isBinary ?
410
`<${msg.content.length} bytes>` :
411
new TextDecoder().decode(msg.content);
412
console.log(`Sent: ${text}`);
413
});
414
415
await mockServer.on('websocket-close', (close) => {
416
console.log(`WebSocket closed: ${close.closeCode} - ${close.closeReason}`);
417
});
418
419
// Set up WebSocket mock
420
await mockServer.forAnyWebSocket()
421
.withPath("/chat")
422
.thenEcho();
423
```
424
425
### Manual WebSocket Rule Management
426
427
Advanced methods for programmatic WebSocket rule management.
428
429
```typescript { .api }
430
interface Mockttp {
431
/**
432
* Add multiple WebSocket rules to the server.
433
*/
434
addWebSocketRules(...ruleData: WebSocketRuleData[]): Promise<MockedEndpoint[]>;
435
436
/**
437
* Add a single WebSocket rule to the server.
438
*/
439
addWebSocketRule(ruleData: WebSocketRuleData): Promise<MockedEndpoint>;
440
441
/**
442
* Replace all existing WebSocket rules with the given rules.
443
* HTTP request rules are left untouched.
444
*/
445
setWebSocketRules(...ruleData: WebSocketRuleData[]): Promise<MockedEndpoint[]>;
446
}
447
448
interface WebSocketRuleData {
449
// Complex internal rule data structure
450
// Use fluent builder API when possible
451
}
452
```
453
454
### WebSocket Protocol Matching
455
456
WebSocket connections can be matched on various aspects of the initial HTTP upgrade request:
457
458
**Path Matching**: Same patterns as HTTP requests - relative paths, full URLs, wildcards, regex
459
**Header Matching**: Match WebSocket-specific headers like `Sec-WebSocket-Protocol`, `Sec-WebSocket-Extensions`
460
**Query Parameters**: Match connection parameters passed in the upgrade URL
461
**Custom Logic**: Use callback functions for complex matching requirements
462
463
### WebSocket Testing Patterns
464
465
Common patterns for testing WebSocket applications:
466
467
**Echo Testing**: Use `thenEcho()` to test client message sending and receiving
468
**Send-Only Testing**: Use `thenPassivelyListen()` to test client sending without server responses
469
**Protocol Testing**: Match specific protocols and subprotocols using header matching
470
**Authentication Testing**: Reject connections without proper authentication headers
471
**Error Handling**: Test client error handling with `thenRejectConnection()` and connection control methods
472
**Performance Testing**: Use `delay()` to simulate slow WebSocket upgrades
473
474
### WebSocket vs HTTP Mocking
475
476
WebSocket mocking differs from HTTP request mocking in several ways:
477
478
- **Connection Lifecycle**: WebSockets maintain persistent connections, unlike HTTP's request-response model
479
- **Bidirectional**: Both client and server can send messages at any time
480
- **Message Types**: Support both text and binary message types
481
- **Protocol Upgrade**: WebSocket connections start as HTTP requests with specific upgrade headers
482
- **Event-Driven**: WebSocket testing relies heavily on event monitoring rather than simple request-response verification