WebSocket and Socket.IO Mocking Library
mock-socket is a JavaScript library designed for mocking WebSocket and Socket.IO connections, facilitating isolated testing of client-side code that interacts with these protocols. The current stable version is 9.3.1. Releases appear to be driven by feature additions, bug fixes, and dependency updates, with major versions typically indicating breaking API changes or significant environment requirements (like Node.js version bumps). Key differentiators include its ability to intercept and control WebSocket and Socket.IO traffic, allowing developers to simulate server responses, connection states, and various network conditions without needing a real backend. It also offers the flexibility to globally stub the `WebSocket` object or manually inject its mocks, and ships with comprehensive TypeScript definitions for improved developer experience. While it supports Socket.IO, this support is explicitly noted as limited.
Common errors
-
Error: WebSocket is not defined
cause When running client-side code (e.g., a React app test) that uses the global `WebSocket` object in a Node.js environment (like Jest), the `WebSocket` global might not be present unless explicitly polyfilled or mocked by `mock-socket`.fixEnsure that `mock-socket`'s global stubbing is active by creating a `new Server(url)` instance before the client code runs. If using `{ mock: false }`, manually assign `global.WebSocket = WebSocket;` (or `window.WebSocket` in a browser-like test environment) to the mock `WebSocket` from `mock-socket`. -
Cannot find name 'USVString'.
cause This error typically occurs in TypeScript projects when the TypeScript environment or `lib` settings are not correctly configured to include DOM types that define `USVString`.fixEnsure your `tsconfig.json` includes `"lib": ["dom", "es2017"]` (or appropriate ES version) to provide standard DOM type definitions. This was a known issue in older `mock-socket` versions that was fixed in 8.0.5. -
TypeError: app.connection.on is not a function
cause This error usually happens when attempting to use Socket.IO-style event listeners (`.on('event', ...)`) on a standard `WebSocket` mock, or vice versa, or if `window.io` was not correctly stubbed for a Socket.IO client.fixVerify that you are using the correct mock for the client type: `WebSocket` for raw WebSockets and `SocketIO` (assigned to `window.io`) for Socket.IO clients. Ensure your client-side code is calling the appropriate methods (`.onmessage` for `WebSocket`, `.on('event')` for Socket.IO).
Warnings
- breaking In version 8.0.0, the `connection` event listener on the `Server` instance changed its signature. The first argument is now a `socket` reference (the individual client connection) instead of the `server` instance. This allows direct communication with the connected client.
- breaking Node.js 6 support was dropped in version 8.1.0, and subsequently in 9.0.0, which now requires Node.js >= 8.
- gotcha By default, creating a `new Server()` instance will automatically stub out the global `WebSocket` object, which is restored when the server stops. This can lead to unexpected behavior if multiple `Server` instances are created without proper management or if you need to use the real `WebSocket` in parallel.
- gotcha Socket.IO support in `mock-socket` is noted as limited. Not all Socket.IO features or complex scenarios may be fully supported or behave identically to a real Socket.IO server.
Install
-
npm install mock-socket -
yarn add mock-socket -
pnpm add mock-socket
Imports
- Server
const Server = require('mock-socket').Server;import { Server } from 'mock-socket'; - WebSocket
import WebSocket from 'mock-socket';
import { WebSocket } from 'mock-socket'; - SocketIO
import { io } from 'mock-socket';import { SocketIO } from 'mock-socket';
Quickstart
import { Server } from 'mock-socket';
// Simulate a client-side application that uses WebSocket
class WebSocketClientApp {
constructor(url) {
this.messages = [];
this.connection = new WebSocket(url);
this.connection.onopen = () => {
console.log('Client connected to:', url);
};
this.connection.onmessage = event => {
console.log('Client received:', event.data);
this.messages.push(event.data);
};
this.connection.onclose = () => {
console.log('Client disconnected');
};
this.connection.onerror = error => {
console.error('Client error:', error.message);
};
}
sendMessage(message) {
this.connection.send(message);
}
}
async function runMockTest() {
const fakeURL = 'ws://localhost:8080';
// Create a mock server instance
const mockServer = new Server(fakeURL);
// Listen for connections to the mock server
mockServer.on('connection', socket => {
console.log('Mock server: client connected!');
// Listen for messages from the connected client
socket.on('message', data => {
console.log('Mock server received from client:', data);
if (data === 'hello server') {
socket.send('hello client from mock server!');
}
});
// Simulate the server closing the connection after a delay
setTimeout(() => {
socket.close();
}, 500);
});
// Instantiate the client app, which will attempt to connect to the fakeURL
const app = new WebSocketClientApp(fakeURL);
app.sendMessage('hello server');
// Wait for some asynchronous operations to complete
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('Messages received by client:', app.messages);
// Assertions would go here in a real test runner
if (app.messages.includes('hello client from mock server!')) {
console.log('Test passed: Client received expected message.');
} else {
console.error('Test failed: Client did not receive expected message.');
}
// Clean up the mock server
mockServer.stop();
console.log('Mock server stopped.');
}
// To run this example in a Node.js environment, you might need to globally stub WebSocket
// If running in a browser environment or a testing framework that stubs globals, this might be optional.
// For Node.js, ensure `global.WebSocket` is available or pass `{ mock: false }` to Server
// and manually assign `global.WebSocket = WebSocket;`
// In a test runner like Jest, you might do:
// beforeAll(() => { global.WebSocket = require('mock-socket').WebSocket; });
// afterAll(() => { delete global.WebSocket; });
// For this standalone example, we'll assume a context where WebSocket is available or shimmed.
// Or, if your client code explicitly imports WebSocket:
// const { WebSocket } = require('mock-socket'); // or import { WebSocket } from 'mock-socket';
runMockTest();