Unit Testing Your Server
The @colyseus/testing package provides utility methods for testing your Colyseus application. It simulates client connections and message exchange using the JavaScript SDK, so you can validate both server and client behavior in a single test.
Installation
This package is installed by default on new projects created via npm create colyseus-app.
npm install --save-dev @colyseus/testingGetting Started
Boot the test server with your app.config.ts, then create rooms and connect simulated clients inside each test case.
import { ColyseusTestServer, boot } from "@colyseus/testing";
// import your "app.config.ts" file here.
import appConfig from "../src/app.config";
describe("testing your Colyseus app", () => {
let colyseus: ColyseusTestServer;
before(async () => colyseus = await boot(appConfig));
after(async () => colyseus.shutdown());
beforeEach(async () => await colyseus.cleanup());
it("connecting into a room", async() => {
// `room` is the backend Room instance reference.
const room = await colyseus.createRoom("my_room", {});
// `client1` is the frontend `Room` instance reference (from the JavaScript SDK)
const client1 = await colyseus.connectTo(room);
// make your assertions
assert.strictEqual(client1.sessionId, room.clients[0].sessionId);
});
});Then run your tests:
npx vitestBest Practices
- Assert on both server and client state after simulating message exchange.
- Create a fresh room in each test — rooms are disposed between tests via
colyseus.cleanup(), so do not reuse room instances. - Always declare test cases with
async. - Await for the server or client to process pending actions before running assertions.
Server-side Utilities
When sending messages between server and client, wait for the server to process the message before making assertions.
Wait For Message Type
Wait for a particular message type to arrive in the server.
it("should receive message", async() => {
const room = await colyseus.createRoom("my_room");
const client1 = await colyseus.connectTo(room);
client1.send("foo", "payload");
// wait for a specific message
const [ client, message ] = await room.waitForMessage("foo");
assert.strictEqual(client.sessionId, client1.sessionId);
assert.strictEqual("payload", message);
});Wait For Next Message
Wait for any next message to arrive in the server.
Parameters
delay: number- additional delay afteronMessagehas been called in the backend, in milliseconds (optional)
it("should receive message", async() => {
const room = await colyseus.createRoom("my_room");
const client1 = await colyseus.connectTo(room);
let received = false;
room.onMessage("foo", (client, message) => {
received = true;
});
client1.send("foo");
await room.waitForNextMessage();
assert.ok(received);
});Wait For Next Patch
Wait for the server to send the latest patched state to all clients.
it("client state must match server's after patch is received", async() => {
const room = await colyseus.createRoom("my_room");
const client1 = await colyseus.connectTo(room);
await room.waitForNextPatch();
assert.deepStrictEqual(client1.state.toJSON(), room.state.toJSON());
});Wait For Next Simulation Tick
Wait for the next simulation tick to complete.
it("should assert something after room's simulation tick", async() => {
const room = await colyseus.createRoom("my_room");
const client1 = await colyseus.connectTo(room);
await room.waitForNextSimulationTick();
// assuming the room's state has a "tick" property that updates during setSimulationInterval()
assert.strictEqual(room.state.tick, 1);
});Client-side Utilities
You can call any frontend SDK methods through colyseus.sdk to simulate client behavior:
it("should connect into battle_room with options x, y, z", async () => {
const client = await colyseus.sdk.joinOrCreate("battle_room", {
a: "a",
b: "b",
c: "c"
});
assert.ok(client.sessionId);
});Wait for Next Patch
Wait for client state to be in sync with the server.
it("should do xyz after receiving message 'x'", async () => {
const client = await colyseus.sdk.joinOrCreate("battle_room");
await client.waitForNextPatch();
// perform assertions after client has received a message
});Wait for Message Type
Wait for a particular message type to arrive in the client.
it("should do xyz after receiving message 'x'", async () => {
const client = await colyseus.sdk.joinOrCreate("battle_room");
client.send("ask-for-x");
await client.waitForMessage("received-x");
// perform assertions after client has received "received-x" message type.
});Wait for Next Message
Wait for any next message to arrive in the client.
it("should do xyz after receiving message 'x'", async () => {
const client = await colyseus.sdk.joinOrCreate("battle_room");
client.send("ask-for-x");
await client.waitForNextMessage();
// perform assertions after client has received a message
});Testing HTTP Routes
The @colyseus/testing package also provides an HTTP client for testing your custom HTTP routes:
colyseus.http.get(url, opts)colyseus.http.post(url, opts)colyseus.http.patch(url, opts)colyseus.http.delete(url, opts)colyseus.http.put(url, opts)
it("should get json data", async () => {
const response = await colyseus.http.get("/");
// "data" is the response body
assert.deepStrictEqual({ success: true }, response.data);
// access to response headers.
assert.strictEqual('header value', response.headers['some-header']);
});