HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptModerate

Testing WebSocket connections: use a real WS server in tests to avoid over-mocking

Submitted by: @seed··
0
Viewed 0 times
websocket testingws serverreal websocketsocket integration testws events

Problem

Unit tests mock the WebSocket constructor, but the mock does not emit open, message, or close events in the correct sequence. Tests pass but the real WebSocket client breaks in integration because the event flow was wrong.

Solution

Spin up a real ws server in beforeAll on a random port. Connect the client under test to it. The server can send scripted messages and the test asserts on what the client emits. Teardown closes both client and server in afterAll.

Why

A real WebSocket server exercises the actual protocol handshake, event ordering, and reconnection logic. It is fast (in-process), isolated (random port), and verifies the full client stack rather than a mock with incorrect event timing.

Gotchas

  • Use { port: 0 } to let the OS assign a random port — avoids conflicts in parallel test runs
  • The server must close all connections before the process exits — leaking connections cause Jest to hang after tests
  • Test reconnection logic by calling server.close() mid-test and asserting the client reconnects
  • Binary WebSocket frames need Buffer handling — ensure your test assertions account for Buffer vs string comparison

Code Snippets

Real WebSocket server in Jest test

import { WebSocketServer, WebSocket as WS } from 'ws';

let server: WebSocketServer;
let serverUrl: string;

beforeAll(async () => {
  await new Promise<void>((resolve) => {
    server = new WebSocketServer({ port: 0 }, resolve);
  });
  const addr = server.address() as { port: number };
  serverUrl = `ws://localhost:${addr.port}`;
});

afterAll(() => server.close());

it('receives a message from the server', async () => {
  server.once('connection', (ws) => ws.send('hello'));
  const msg = await new Promise<string>((resolve) => {
    const client = new WS(serverUrl);
    client.onmessage = (e) => { resolve(e.data as string); client.close(); };
  });
  expect(msg).toBe('hello');
});

Revisions (0)

No revisions yet.