Socket.IO mock library with full room · namespace · broadcast support.
Sweet setup, rocket speed.
Status: pre-1.0. The delivery core (rooms, namespaces, broadcasts, acks, disconnect) is complete and checked against real socket.io by a dual-run conformance suite. The idiomatic
io.on('connection')entry point and URL-basedconnect(url, { auth, query })now work (see Usage), populatingsocket.handshake; thenextConnectionpairing helper stays for tests that drive a connection directly. The public API can still change before 1.0.0.
Socket.IO delivery is more than event propagation. Room membership, namespace isolation, and broadcast exclusion rules interact to decide a single question: who actually receives this event?
smocket aims to reproduce that delivery logic faithfully. Every behavior is specified by a conformance suite that runs against a real Socket.IO server first — smocket is implemented to match it. It fills the gap left by existing mock libraries, none of which support rooms, namespaces, and broadcasts in full.
npm install -D smocketimport { connect, Server } from 'smocket';
const io = new Server('http://localhost:3000');
// The server-side entry point, exactly as in real socket.io: wire per-socket
// handlers as each client connects. `socket.handshake` carries the client's auth
// and query, so the same code an app runs on socket.io runs here.
io.on('connection', (socket) => {
console.log('connected as', socket.handshake.auth.name);
socket.on('join', (room) => {
socket.join(room);
socket.to(room).emit('user-joined', socket.id);
});
});
// Clients connect by URL, resolved to the server through smocket's origin registry.
// A second argument passes auth and query through, socket.io-client's `io(url, opts)`.
const a = connect('http://localhost:3000', { auth: { name: 'a' } });
const b = connect('http://localhost:3000', { auth: { name: 'b' } });
a.on('user-joined', (id) => console.log('a saw', id));
// Emits sent before the connection completes are buffered and flushed in order,
// so a joins room-1 before b does.
a.emit('join', 'room-1');
b.emit('join', 'room-1');
// b joins after a, so a receives 'user-joined' (b's id); b does not, since it is the sender.- Socket ID assignment and tracking
emit/on/ acknowledgements- Room
join/leavewith bidirectional membership - Broadcasts:
io.to·socket.to·socket.broadcast·except - Namespace isolation
- Multi-client simulation
- Membership cleanup on
disconnect
smocket reproduces the delivery and routing layer of Socket.IO. The following are out of scope:
- Reconnection
- Transport fallback
- Heartbeat
- Multi-server setups via the Redis adapter
- Binary encoding
These belong to the transport layer, which has no meaning in an in-memory mock.
- v0.1.0 (2026-07-30). Core delivery layer: socket lifecycle, emit/on with acknowledgements, room join/leave, broadcast variants, and namespace isolation, verified against a real Socket.IO server.
- v0.2.0 (2026-07-30). Extensibility: public adapter API with a working example, multi-client simulation helpers, and a stable public surface for 1.0.
- v0.3.0 (2026-08-03). App-facing entry points:
io.on('connection'),connect(url), and theioalias, so code written for socket.io runs against smocket. - v0.4.0 (2026-08-06). The remaining public API surface: connection middleware, acknowledgement timeouts,
volatile, catch-all listeners,socket.data, listener removal, andexceptchaining, plus packaging verification and a browser run in CI. - v1.0.0 (planned). First stable release: complete documentation, usage examples, and a published conformance test report.
Beyond 1.0, extensions such as a devtools panel and a Storybook addon are under consideration.
smocket's conformance suite also serves as a close look at how Socket.IO actually behaves — anything worth reporting, we hope to contribute back upstream.
See the milestones for progress and open items. The API is subject to change until 1.0.
Contributions are welcome. The most useful ones encode how Socket.IO actually behaves, so tests that pin smocket to real Socket.IO matter most here.
Good places to start:
- Issues labelled
good first issueare scoped to not need the whole codebase. None open yet as of July 2026 — they'll appear as the core lands. - The milestones show what each release is aiming for.
See CONTRIBUTING.md for branch naming, commit conventions, and how pull requests are merged.
MIT License