or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

certificate-management.mdevent-monitoring.mdhttp-request-mocking.mdindex.mdmock-server-setup.mdresponse-actions.mdwebsocket-mocking.md

websocket-mocking.mddocs/

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