Mock WebSocket Connections: Real-Time Application Testing

Learn WebSocket mocking techniques for real-time apps. Test bidirectional communication, subscriptions, and live data flow with practical examples.

WebSockets are bidirectional: after an initial handshake, both client and server can send messages at any time.

This requires different testing approaches.

Why WebSocket Testing is Different

REST API testing is simple: send request, check response. WebSocket testing is harder because:

  • Connections persist over time
  • Either side can initiate messages
  • Timing matters
  • Connection failures need handling
  • Subscriptions and unsubscriptions are important

WebSocket Testing Strategies

1. Unit Test the Message Handlers

describe('Chat message handler', () => {
  it('broadcasts message to all clients', () => {
    const handler = createMessageHandler();
    const mockClients = [
      { send: jest.fn() },
      { send: jest.fn() }
    ];
    
    handler.onMessage('Hello!', mockClients);
    
    expect(mockClients[0].send).toHaveBeenCalledWith('Hello!');
    expect(mockClients[1].send).toHaveBeenCalledWith('Hello!');
  });
});

2. Mock WebSocket Objects

import WS from 'jest-websocket-mock';

let server;
beforeEach(() => {
  server = new WS('ws://localhost:1234');
});

it('connects and sends message', async () => {
  const client = new WebSocket('ws://localhost:1234');
  await server.connected;
  
  client.send('Hello');
  await expect(server).toReceiveMessage('Hello');
  
  server.send('Hi back!');
});

afterEach(() => WS.clean());

3. Integration Test with Real Server

const WebSocket = require('ws');

describe('WebSocket integration', () => {
  let wss;
  
  beforeEach((done) => {
    wss = new WebSocket.Server({ port: 8080 });
    wss.on('connection', (ws) => {
      ws.on('message', (msg) => {
        ws.send(`Echo: ${msg}`);
      });
    });
    done();
  });
  
  it('receives echo response', (done) => {
    const ws = new WebSocket('ws://localhost:8080');
    ws.on('message', (data) => {
      expect(data).toBe('Echo: test');
      done();
    });
    ws.send('test');
  });
  
  afterEach(() => wss.close());
});

Testing Subscriptions

Many real-time apps use subscriptions. Test this by verifying clients only receive messages from subscribed channels:

it('only sends to subscribed clients', async () => {
  const client1 = connectClient();
  const client2 = connectClient();
  
  client1.subscribe('news');
  client2.subscribe('weather');
  
  server.publish('news', 'Breaking news!');
  
  expect(client1.received).toContain('Breaking news!');
  expect(client2.received).not.toContain('Breaking news!');
});

Testing Connection Failures

Real-world connections fail. Test how your app handles it:

it('reconnects on disconnection', async () => {
  const client = new ReconnectingWebSocket('ws://localhost:8080');
  
  // Close connection
  client.socket.close();
  
  // Verify reconnection is attempted
  await wait(100);
  expect(client.isConnected).toBe(true);
});

Tools for WebSocket Testing

  • jest-websocket-mock - Mock WebSockets in Jest
  • socket.io testing utilities - Built-in Socket.io helpers
  • WebSocket Test Server - Node.js WebSocket test server
  • Postman - Can test WebSocket APIs
  • MockWebSocket - Browser-based mocking

Conclusion

WebSocket testing requires different tools than REST API testing, but it's absolutely necessary for real-time applications. Start with unit tests for message handlers, add mock WebSocket tests, and finish with integration tests using real servers.