smocket

Application case study · Smocket 1.0.0

Socket.IO mocking without a separate Node.js server

The drawing game keeps one server-side event flow and runs it with either a Node.js mock server built with Socket.IO or Smocket.

Application
Three-player drawing game
Shared code
Server event handlers
Runtimes
Node.js mock + Smocket
Working ruleSmocket runs your Socket.IO server logic in memory.

Use a Node.js mock server when the network connection belongs in the local setup. Use Smocket when the application flow is the work.

01

Two jobs, one application

Smocket replaces a separate Node.js mock server in focused frontend development and application tests. It does not replace the production backend.

Node.js Socket.IO mock server

Run a separate mock server process

Build backend-like events with the Socket.IO server package. The mock needs its own process, port, lifecycle, and browser network connection.

Use when the network connection should remain part of the local setup.
Smocket

Run mock server behavior in memory

Run the same handlers in memory for server-driven UI, rooms, broadcasts, acknowledgements, and multi-client application tests.

Use for focused development and application tests.
02

Where Smocket runs

Choose a context to see who hosts the server and how clients connect.

Node tests

Application tests in Node.js

Create a Smocket server inside the test, connect multiple clients, and assert the application event flow without opening a port.

Host
Vitest or another Node.js test runner
Connection
In-memory client and server
Use it for
Best for repeatable tests of rooms, broadcasts, acknowledgements, and server-driven state.
03

One application, two bootstraps

The drawing game registers one application function. Only the code that creates and connects the server changes.

Shared application

Register the drawing-game event flow once

export function registerDrawingGameApplication(io: GameServer) {
  const state = new DrawingGameState();

  io.on('connection', (socket) => {
    const actions: GameActions = {
      join(current, room) {
        return state.join(current, room);
      },
      stroke(current, segment) {
        return state.rememberStroke(current, segment);
      },
      // Chat, guess, and disconnect use the same state.
    };

    registerGameHandler(io, socket, actions);
  });
}

Join, stroke, chat, guess, room state, and disconnect rules live behind this boundary.

Node.js mock server bootstrap

Attach the application to the Node HTTP server

const io = new SocketIoServer(httpServer);

registerDrawingGameApplication(io, {
  countdownMs,
});

The Node.js mock owns a separate process, port, and network connection.

Smocket bootstrap

Attach the application to a SharedWorker

const io = new Server(GAME_URL);

registerDrawingGameApplication(io, {
  countdownMs,
});

workerScope.onconnect = ({ ports: [port] }) => {
  if (port) attachSharedWorker(io, port);
};

The demo uses this browser runtime so three tabs can share one in-memory server.

Selected workflow

A three-tab drawing round

Follow the same selected workflow through either runtime, then open the browser demo to try the SharedWorker path.

CONNECT ×3

Open three player tabs

On screen
Player A opens Players B and C. Each page receives a distinct socket ID.
Event flow
Three clients connect to the selected server runtime.
Live demoDraw in A. Guess in B or C. See the same result in all three.

The demo uses the SharedWorker runtime shown above.

Open the 3-tab demo
04

Observed behavior and boundaries

The table covers the drawing-game workflow, then separates what still belongs to the production backend.

Selected behaviorNode.js Socket.IO mock serverSmocket
Three clients connect with distinct socket IDsObservedObserved
All clients join one room and receive shared stateObservedObserved
A stroke reaches the other two clients, not its senderObservedObserved
Wrong and correct guesses return acknowledgementsObservedObserved
A correct guess ends the round on all three clientsObservedObserved
Closing a client removes it from the sessionObservedObserved
Still use the production backend

Production network and integration behavior

  • Transport, authentication, reconnection, and deployment
  • Persistence and integration with the production backend
  • Behavior outside Smocket’s documented API surface
SharedWorker conditions

One browser profile and origin

  • Tabs share the same profile, origin, worker script URL, and worker name
  • Worker restarts clear its in-memory sockets, rooms, and application state
  • The automated browser run currently uses desktop Chromium