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.