Unit Testing a Colyseus Project¶
The @colyseus/testing
package provides a few utility methods for testing your Colyseus application. It can be used along with your favorite testing framework, such as Mocha, or Jest.
Recommendations and best practices¶
- Make assertions on both server-side and client-side structures after simulating an exchange of messages between them.
- Room instances are disposed between tests - make sure each test you declare is creating the room you're going to perform tests and don't re-use room instances between tests.
- Always declare your test cases with
async
. - Before running assertions make sure you await for the server or client to process pending actions
import { ColyseusTestServer, boot } from "@colyseus/testing";
// import your "arena.config.ts" file here.
import appConfig from "../src/arena.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 server-side Room instance reference.
const room = await colyseus.createRoom("my_room", {});
// `client1` is the client-side `Room` instance reference (same as JavaScript SDK)
const client1 = await colyseus.connectTo(room);
// make your assertions
assert.strictEqual(client1.sessionId, room.clients[0].sessionId);
});
});
import { ColyseusTestServer, boot } from "@colyseus/testing";
// import your "arena.config.ts" file here.
import appConfig from "../src/arena.config";
describe("testing your Colyseus app", () => {
let colyseus: ColyseusTestServer;
beforeAll(async () => colyseus = await boot(appConfig));
afterAll(async () => await colyseus.shutdown());
beforeEach(async () => await colyseus.cleanup());
it("connecting into a room", async() => {
// `room` is the server-side Room instance reference.
const room = await colyseus.createRoom("my_room", {});
// `client1` is the client-side `Room` instance reference (same as JavaScript SDK)
const client1 = await colyseus.connectTo(room);
// make your assertions
expect(client1.sessionId).toEqual(room.clients[0].sessionId);
});
});
Waiting for asynchronous actions to process¶
room.waitForMessage(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 specific a message
const [ client, message ] = await room.waitForMessage("foo");
// ... message "foo" has been received and processed
assert.strictEqual(client.sessionId, client1.sessionId);
assert.strictEqual("payload", message);
});
room.waitForNextMessage()
¶
Wait for any next message to arrive in the server.
Parameters
additionalDelay: number
- additional delay afteronMessage
has been called in the server-side, 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);
});
room.waitForNextPatch()
¶
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();
// server and client's state must match after the patch
assert.deepStrictEqual(client1.state.toJSON(), room.state.toJSON());
});
room.waitForNextSimulationTick()
¶
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();
// (this is just an illustration scenario)
// (assuming the room's state has a "tick" property that updates during setSimulationInterval())
assert.strictEqual(room.state.tick, 1);
});
Client-side SDK methods & utilities¶
From your test-cases, you may call any of the client-side SDK methods through colyseus.sdk
Example
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);
});
client.waitForNextPatch()
¶
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
});
client.waitForMessage(type)
¶
Wait for a particular message type
to arrive in the client-side.
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.
});
client.waitForNextMessage()
¶
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
also offers an HTTP client for requesting 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)
Example
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']);
});