Testing
Run the stage and phones in one process with inMemory(), no WebRTC and no browser.
On this page
One process, many apps
inMemory() is a signaling adapter that also opens an in-process channel. Share one instance
between apps, and real frames flow through the real engines. It needs no DOM.
import { controllerPlugin, createApp, inMemory, stagePlugin } from "@moku-labs/room";
async function untilRead(read: () => unknown): Promise<unknown> {
while (read() === undefined) await new Promise(resolve => setTimeout(resolve, 10));
return read();
}
const transport = { signaling: inMemory(), iceServers: [] };
const stage = createApp({
plugins: [stagePlugin],
pluginConfigs: { transport, session: { generateQr: false } }
});
await stage.start();
stage.sync.registerSlice("round", { number: 1 });
const { code } = stage.stage.createRoom();
const phone = createApp({ plugins: [controllerPlugin], pluginConfigs: { transport } });
await phone.start();
await phone.controller.joinRoom(code);
console.log(await untilRead(() => phone.controller.read("round"))); // { number: 1 }
await phone.stop();
await stage.stop();- Skips the QR encoder.
- Stop both apps, or the timers keep the runner alive.
- Each
inMemory()is its own bus. Two calls never connect. Share one instance. - Deltas wait for a tick.
mutatedoes not send. Wait up to one tick (33 ms at 30 Hz), or callapp.sync.broadcast(). - Timeouts are configurable. Lower
reconnectTimeoutMs,heartbeatIntervalMsandheartbeatTimeoutMsto test failure paths quickly. - It proves no WebRTC. ICE, relays and iOS behavior need real devices.
inMemory({ server: true }) also simulates the hub protocol: sessions are persistent and expose
onEvict.
Related
- transport plugin: the adapters and the timing config.