Testing WebSocket Applications
1. Writing Unit Tests
| Target | Mock |
|---|---|
| Message handler | Pass parsed object |
| Encoder/decoder | Test pure function |
| Validator | Valid/invalid fixtures |
| Reducer | State transitions |
2. Mocking WebSocket API
Example: mock-socket
import { Server, WebSocket as MockWS } from "mock-socket";
const URL = "ws://localhost:9999/ws";
const server = new Server(URL);
globalThis.WebSocket = MockWS;
server.on("connection", (s) => s.on("message", (m) => s.send(`echo:${m}`)));
| Library | Use |
|---|---|
| mock-socket | Browser-side WS mock |
| jest-websocket-mock | Jest matchers |
| MSW | WebSocket handlers (MSW 2.0+) |
3. Testing Message Handlers
| Pattern | Detail |
|---|---|
| Inject dispatcher | Call directly with parsed msg |
| Assert side effects | State / outbound message |
| Snapshot | Reducer output |
4. Testing Reconnection Logic
Example: Simulate disconnect
const server = new Server(URL);
const client = createClient(URL);
await waitFor(() => client.state === "open");
server.close();
await waitFor(() => client.reconnectAttempts > 0);
| Scenario | Assert |
|---|---|
| Server drops | Backoff schedule respected |
| Network offline | Pauses attempts |
| Auth 4401 | Stops retrying |
5. Writing Integration Tests
| Layer | Detail |
|---|---|
| Real server | Spin up on random port |
| Real ws client | Node ws in test |
| Cleanup | Close server in afterEach |
6. Using WebSocket Test Server
| Tool | Use |
|---|---|
| ws + ephemeral port | Lightweight harness |
| Autobahn TestSuite | RFC compliance |
| Echo server (postman-echo) | Quick manual checks |
7. Testing Error Scenarios
| Scenario | Expected |
|---|---|
| Malformed JSON | Log + drop, no crash |
| Oversize message | Close 1009 |
| Bad UTF-8 | Close 1007 |
| Server crash mid-msg | Client reconnects |
8. Load Testing
Example: k6 script
import ws from "k6/ws";
export const options = { vus: 1000, duration: "5m" };
export default function () {
ws.connect("wss://api.example.com/ws", (socket) => {
socket.on("open", () => socket.send(JSON.stringify({ "type":"ping" })));
socket.setTimeout(() => socket.close(), 30000);
});
}
| Metric | Watch |
|---|---|
| Connection success rate | > 99% |
| Avg open time | < 500ms |
| Server CPU/mem | Stable |
9. Testing Security
| Test | Detail |
|---|---|
| Origin spoofing | Server rejects unknown |
| Invalid token | Close 4401 |
| IDOR via topic | Forbidden access denied |
| Replay attack | Nonce/id enforcement |
| Fuzz payload | No server crash |
10. Implementing E2E Tests
| Tool | Detail |
|---|---|
| Playwright | Built-in WS interception |
| Cypress + cy-websocket | Plugin support |
| Puppeteer | Chrome DevTools Protocol |