or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

browser-setup.mdcli.mdgraphql-handlers.mdhttp-handlers.mdindex.mdnodejs-setup.mdreact-native-setup.mdresponse-creation.mdutilities.mdwebsocket-handlers.md

websocket-handlers.mddocs/

0

# WebSocket Handlers

1

2

WebSocket handlers provide event-based interception and mocking of WebSocket connections with support for connection lifecycle management, message broadcasting, and client management.

3

4

## Capabilities

5

6

### WebSocket Link Creation

7

8

Create WebSocket handlers for specific WebSocket server URLs.

9

10

```typescript { .api }

11

/**

12

* Creates a WebSocket link handler for intercepting connections to a specific URL

13

* @param url - WebSocket server URL to intercept (string, RegExp, or path pattern)

14

* @returns WebSocketLink instance with event handling and broadcast capabilities

15

*/

16

function link(url: string | RegExp): WebSocketLink;

17

18

interface WebSocketLink {

19

/** Set of all WebSocket clients connected to this link */

20

clients: Set<WebSocketClientConnectionProtocol>;

21

22

/** Add event listener for WebSocket connection events */

23

addEventListener<EventType extends keyof WebSocketHandlerEventMap>(

24

event: EventType,

25

listener: WebSocketEventListener<EventType>

26

): WebSocketHandler;

27

28

/** Broadcast data to all connected WebSocket clients */

29

broadcast(data: WebSocketData): void;

30

31

/** Broadcast data to all clients except specified ones */

32

broadcastExcept(

33

clients: WebSocketClientConnectionProtocol | WebSocketClientConnectionProtocol[],

34

data: WebSocketData

35

): void;

36

}

37

38

const ws: {

39

link: typeof link;

40

};

41

```

42

43

**Usage Examples:**

44

45

```typescript

46

import { ws } from "msw";

47

48

// Create WebSocket link for chat application

49

const chatServer = ws.link('wss://chat.example.com');

50

51

// Handle new connections

52

chatServer.addEventListener('connection', ({ client }) => {

53

console.log('Client connected:', client.id);

54

55

// Send welcome message to new client

56

client.send(JSON.stringify({

57

type: 'welcome',

58

message: 'Welcome to the chat!'

59

}));

60

61

// Notify other clients about new user

62

chatServer.broadcastExcept(client, JSON.stringify({

63

type: 'user_joined',

64

userId: client.id

65

}));

66

});

67

68

// Create WebSocket link with RegExp pattern

69

const gameServer = ws.link(/wss:\/\/game\.example\.com\/room\/\d+/);

70

71

gameServer.addEventListener('connection', ({ client }) => {

72

// Extract room ID from URL

73

const roomId = client.url.match(/\/room\/(\d+)/)?.[1];

74

75

client.send(JSON.stringify({

76

type: 'room_joined',

77

roomId

78

}));

79

});

80

81

// Development WebSocket server

82

const devServer = ws.link('ws://localhost:8080');

83

84

devServer.addEventListener('connection', ({ client }) => {

85

// Echo server - send back any received message

86

client.addEventListener('message', (event) => {

87

client.send(`Echo: ${event.data}`);

88

});

89

});

90

```

91

92

### Event Handling

93

94

Handle WebSocket connection lifecycle events.

95

96

```typescript { .api }

97

type WebSocketEventListener<EventType extends keyof WebSocketHandlerEventMap> =

98

(...args: WebSocketHandlerEventMap[EventType]) => void;

99

100

interface WebSocketHandlerEventMap {

101

/** Fired when a client connects to the WebSocket server */

102

connection: [event: { client: WebSocketClientConnectionProtocol; server: WebSocketLink }];

103

/** Fired when a client disconnects from the WebSocket server */

104

disconnect: [event: { client: WebSocketClientConnectionProtocol; server: WebSocketLink }];

105

}

106

107

interface WebSocketClientConnectionProtocol {

108

/** Unique client identifier */

109

id: string;

110

/** WebSocket URL the client connected to */

111

url: string;

112

/** Connection protocol (if specified) */

113

protocol?: string;

114

/** Send data to this specific client */

115

send(data: WebSocketData): void;

116

/** Close the connection to this client */

117

close(code?: number, reason?: string): void;

118

/** Add event listener for client-specific events */

119

addEventListener(event: string, listener: (event: any) => void): void;

120

/** Remove event listener from client */

121

removeEventListener(event: string, listener: (event: any) => void): void;

122

}

123

```

124

125

**Usage Examples:**

126

127

```typescript

128

// Handle connection events

129

const server = ws.link('wss://api.example.com');

130

131

server.addEventListener('connection', ({ client, server }) => {

132

console.log(`Client ${client.id} connected to ${client.url}`);

133

134

// Set up client-specific message handler

135

client.addEventListener('message', (event) => {

136

console.log(`Message from ${client.id}:`, event.data);

137

138

// Parse and handle different message types

139

try {

140

const message = JSON.parse(event.data);

141

142

switch (message.type) {

143

case 'chat':

144

// Broadcast chat message to all clients

145

server.broadcast(JSON.stringify({

146

type: 'chat',

147

from: client.id,

148

message: message.text,

149

timestamp: Date.now()

150

}));

151

break;

152

153

case 'ping':

154

// Respond with pong

155

client.send(JSON.stringify({ type: 'pong' }));

156

break;

157

158

case 'join_room':

159

// Handle room joining logic

160

client.send(JSON.stringify({

161

type: 'room_joined',

162

room: message.room

163

}));

164

break;

165

}

166

} catch (error) {

167

client.send(JSON.stringify({

168

type: 'error',

169

message: 'Invalid message format'

170

}));

171

}

172

});

173

174

// Handle client errors

175

client.addEventListener('error', (event) => {

176

console.error(`Client ${client.id} error:`, event);

177

});

178

179

// Handle client disconnect

180

client.addEventListener('close', (event) => {

181

console.log(`Client ${client.id} disconnected:`, event.code, event.reason);

182

183

// Notify other clients

184

server.broadcastExcept(client, JSON.stringify({

185

type: 'user_left',

186

userId: client.id

187

}));

188

});

189

});

190

191

// Handle disconnect events at server level

192

server.addEventListener('disconnect', ({ client }) => {

193

console.log(`Server: Client ${client.id} disconnected`);

194

195

// Clean up any server-side state associated with this client

196

// removeUserFromRooms(client.id);

197

});

198

```

199

200

### Broadcasting Messages

201

202

Send messages to multiple clients with flexible targeting.

203

204

```typescript { .api }

205

/**

206

* Broadcast data to all connected WebSocket clients

207

* @param data - Data to send (string, ArrayBuffer, or Blob)

208

*/

209

broadcast(data: WebSocketData): void;

210

211

/**

212

* Broadcast data to all clients except specified ones

213

* @param clients - Client or array of clients to exclude from broadcast

214

* @param data - Data to send (string, ArrayBuffer, or Blob)

215

*/

216

broadcastExcept(

217

clients: WebSocketClientConnectionProtocol | WebSocketClientConnectionProtocol[],

218

data: WebSocketData

219

): void;

220

221

type WebSocketData = string | ArrayBuffer | Blob;

222

```

223

224

**Usage Examples:**

225

226

```typescript

227

const chatServer = ws.link('wss://chat.example.com');

228

229

chatServer.addEventListener('connection', ({ client, server }) => {

230

client.addEventListener('message', (event) => {

231

const message = JSON.parse(event.data);

232

233

switch (message.type) {

234

case 'broadcast_message':

235

// Send message to all connected clients

236

server.broadcast(JSON.stringify({

237

type: 'message',

238

from: client.id,

239

text: message.text,

240

timestamp: Date.now()

241

}));

242

break;

243

244

case 'private_message':

245

// Send message to all clients except sender

246

server.broadcastExcept(client, JSON.stringify({

247

type: 'message',

248

from: client.id,

249

text: message.text,

250

timestamp: Date.now()

251

}));

252

break;

253

254

case 'admin_announcement':

255

// Send to all clients except specific ones

256

const excludedClients = Array.from(server.clients).filter(

257

c => c.id.startsWith('guest_')

258

);

259

260

server.broadcastExcept(excludedClients, JSON.stringify({

261

type: 'announcement',

262

text: message.text,

263

priority: 'high'

264

}));

265

break;

266

267

case 'server_stats':

268

// Broadcast server statistics

269

server.broadcast(JSON.stringify({

270

type: 'stats',

271

connectedClients: server.clients.size,

272

uptime: process.uptime(),

273

timestamp: Date.now()

274

}));

275

break;

276

}

277

});

278

});

279

280

// Periodic broadcasts

281

const gameServer = ws.link('wss://game.example.com');

282

283

gameServer.addEventListener('connection', ({ server }) => {

284

// Send game state updates every second

285

setInterval(() => {

286

if (server.clients.size > 0) {

287

server.broadcast(JSON.stringify({

288

type: 'game_state',

289

players: server.clients.size,

290

timestamp: Date.now()

291

}));

292

}

293

}, 1000);

294

});

295

296

// Binary data broadcasting

297

const dataServer = ws.link('wss://data.example.com');

298

299

dataServer.addEventListener('connection', ({ client, server }) => {

300

client.addEventListener('message', (event) => {

301

if (event.data instanceof ArrayBuffer) {

302

// Echo binary data to all other clients

303

server.broadcastExcept(client, event.data);

304

}

305

});

306

});

307

```

308

309

### Client Management

310

311

Access and manage connected WebSocket clients.

312

313

```typescript { .api }

314

interface WebSocketLink {

315

/** Set of all WebSocket clients connected to this link */

316

clients: Set<WebSocketClientConnectionProtocol>;

317

}

318

```

319

320

**Usage Examples:**

321

322

```typescript

323

const server = ws.link('wss://monitoring.example.com');

324

325

server.addEventListener('connection', ({ client, server }) => {

326

console.log(`Total clients: ${server.clients.size}`);

327

328

// Send client list to new client

329

client.send(JSON.stringify({

330

type: 'client_list',

331

clients: Array.from(server.clients).map(c => ({

332

id: c.id,

333

url: c.url,

334

protocol: c.protocol

335

}))

336

}));

337

338

client.addEventListener('message', (event) => {

339

const message = JSON.parse(event.data);

340

341

switch (message.type) {

342

case 'get_stats':

343

client.send(JSON.stringify({

344

type: 'stats',

345

totalClients: server.clients.size,

346

clientIds: Array.from(server.clients).map(c => c.id)

347

}));

348

break;

349

350

case 'kick_client':

351

// Find and disconnect specific client

352

const targetClient = Array.from(server.clients).find(

353

c => c.id === message.clientId

354

);

355

356

if (targetClient) {

357

targetClient.close(1000, 'Kicked by admin');

358

}

359

break;

360

361

case 'message_client':

362

// Send message to specific client

363

const recipient = Array.from(server.clients).find(

364

c => c.id === message.targetId

365

);

366

367

if (recipient) {

368

recipient.send(JSON.stringify({

369

type: 'private_message',

370

from: client.id,

371

text: message.text

372

}));

373

}

374

break;

375

}

376

});

377

});

378

379

// Connection limiting

380

const limitedServer = ws.link('wss://limited.example.com');

381

382

limitedServer.addEventListener('connection', ({ client, server }) => {

383

if (server.clients.size > 10) {

384

client.close(1013, 'Server full');

385

return;

386

}

387

388

client.send(JSON.stringify({

389

type: 'welcome',

390

position: server.clients.size,

391

maxClients: 10

392

}));

393

});

394

```

395

396

### Advanced WebSocket Patterns

397

398

Handle complex WebSocket scenarios and patterns.

399

400

```typescript

401

// Room-based messaging

402

const roomServer = ws.link('wss://rooms.example.com');

403

const rooms = new Map<string, Set<WebSocketClientConnectionProtocol>>();

404

405

roomServer.addEventListener('connection', ({ client, server }) => {

406

let currentRoom: string | null = null;

407

408

client.addEventListener('message', (event) => {

409

const message = JSON.parse(event.data);

410

411

switch (message.type) {

412

case 'join_room':

413

// Leave current room

414

if (currentRoom && rooms.has(currentRoom)) {

415

rooms.get(currentRoom)!.delete(client);

416

}

417

418

// Join new room

419

currentRoom = message.room;

420

if (!rooms.has(currentRoom)) {

421

rooms.set(currentRoom, new Set());

422

}

423

rooms.get(currentRoom)!.add(client);

424

425

// Notify room members

426

rooms.get(currentRoom)!.forEach(roomClient => {

427

if (roomClient !== client) {

428

roomClient.send(JSON.stringify({

429

type: 'user_joined_room',

430

userId: client.id,

431

room: currentRoom

432

}));

433

}

434

});

435

break;

436

437

case 'room_message':

438

// Send message to all clients in current room

439

if (currentRoom && rooms.has(currentRoom)) {

440

rooms.get(currentRoom)!.forEach(roomClient => {

441

roomClient.send(JSON.stringify({

442

type: 'room_message',

443

from: client.id,

444

room: currentRoom,

445

text: message.text

446

}));

447

});

448

}

449

break;

450

}

451

});

452

453

client.addEventListener('close', () => {

454

// Clean up room membership

455

if (currentRoom && rooms.has(currentRoom)) {

456

rooms.get(currentRoom)!.delete(client);

457

if (rooms.get(currentRoom)!.size === 0) {

458

rooms.delete(currentRoom);

459

}

460

}

461

});

462

});

463

464

// Protocol-specific handling

465

const multiProtocolServer = ws.link('wss://protocols.example.com');

466

467

multiProtocolServer.addEventListener('connection', ({ client }) => {

468

switch (client.protocol) {

469

case 'chat':

470

client.send(JSON.stringify({ type: 'chat_ready' }));

471

break;

472

case 'game':

473

client.send(JSON.stringify({ type: 'game_ready' }));

474

break;

475

default:

476

client.send(JSON.stringify({ type: 'generic_ready' }));

477

}

478

});

479

```

480

481

## Types

482

483

```typescript { .api }

484

// Handler types

485

interface WebSocketHandler {

486

url: string | RegExp;

487

eventHandlers: Map<string, Function[]>;

488

}

489

490

// Client types

491

interface WebSocketClientConnectionProtocol {

492

id: string;

493

url: string;

494

protocol?: string;

495

send(data: WebSocketData): void;

496

close(code?: number, reason?: string): void;

497

addEventListener(event: string, listener: (event: any) => void): void;

498

removeEventListener(event: string, listener: (event: any) => void): void;

499

}

500

501

// Data types

502

type WebSocketData = string | ArrayBuffer | Blob;

503

504

// Event types

505

interface WebSocketHandlerEventMap {

506

connection: [event: {

507

client: WebSocketClientConnectionProtocol;

508

server: WebSocketLink

509

}];

510

disconnect: [event: {

511

client: WebSocketClientConnectionProtocol;

512

server: WebSocketLink

513

}];

514

}

515

516

type WebSocketEventListener<EventType extends keyof WebSocketHandlerEventMap> =

517

(...args: WebSocketHandlerEventMap[EventType]) => void;

518

519

// Connection types

520

interface WebSocketHandlerConnection {

521

client: WebSocketClientConnectionProtocol;

522

server: WebSocketLink;

523

}

524

```