Skip to content

WebSocketRoute ​

DANGER

WebSocket interception only supports application code that uses globalThis.WebSocket. It does not intercept npm ws clients or custom WebSocket stacks.

BackendWebSocketRoute is passed to backendMocks.routeWebSocket().

ts
await backendMocks.routeWebSocket("wss://events.example.test/socket", async (ws) => {
  ws.send("connected");

  ws.onMessage((message) => {
    if (message === "ping") {
      ws.send("pong");
    }
  });
});

ws.url() ​

Returns the WebSocket URL.

ts
expect(ws.url()).toBe("wss://events.example.test/socket");

ws.protocols() ​

Returns requested protocols.

ts
expect(ws.protocols()).toContain("graphql-transport-ws");

ws.onMessage(handler) ​

Handles messages from the app side. Messages are string or Buffer.

ts
ws.onMessage((message) => {
  ws.send(`echo:${String(message)}`);
});

On the server-side route returned by connectToServer(), onMessage() handles messages from the real upstream server.

ws.onClose(handler) ​

Handles close events.

ts
ws.onClose((code, reason) => {
  console.log("closed", code, reason);
});

ws.send(message) ​

Sends a text or binary message to the opposite side.

ts
ws.send(JSON.stringify({ type: "ready" }));
ws.send(Buffer.from([1, 2, 3]));

ws.close(options?) ​

Closes the opposite side.

ts
await ws.close({ code: 4001, reason: "closed by test" });
OptionTypeDescription
codenumberClose code.
reasonstringClose reason.

ws.connectToServer() ​

Connects to the real upstream server and returns a route for the server side.

ts
await backendMocks.routeWebSocket("wss://events.example.test/socket", async (ws) => {
  const server = ws.connectToServer();

  ws.onMessage((message) => {
    server.send(message);
  });

  server.onMessage((message) => {
    ws.send(message);
  });
});

Calling connectToServer() twice throws.

Matching behavior ​

routeWebSocket() accepts glob string, RegExp, predicate, and URLPattern URL matchers.

Within one test, the newest matching WebSocket route is used. Across tests, more than one claiming test fails with ambiguous_route.

unrouteAll() does not remove WebSocket routes.

Type ​

ts
interface BackendWebSocketRoute {
  url(): string;
  protocols(): string[];
  onMessage(handler: (message: string | Buffer) => unknown): void;
  onClose(
    handler: (code: number | undefined, reason: string | undefined) => unknown,
  ): void;
  send(message: string | Buffer): void;
  close(options?: { code?: number; reason?: string }): Promise<void>;
  connectToServer(): BackendWebSocketRoute;
}

Mock the outside world. Keep the real app.