import { MockHelper, EventHook } from "@/testing"; import { NetworkMessage, LocalClient, ChatMessage } from "@/network"; const sampleRoom = () => ({ max_players: 3, password: "" }); function messageKind(kind: string): (msg: NetworkMessage) => void { return msg => { expect(msg.kind).toEqual(kind); }; } describe("network/PeerServer", () => { test("A server can be created", () => { const mox = new MockHelper(); mox.createServer(sampleRoom()); }); test("Clients can join servers and receive data", async () => { const mox = new MockHelper(); const hook = new EventHook(); mox.createServer(sampleRoom()); const client = mox.createClient(); hook.hookEmitter(client, "data", "client-data"); client.connect("test-server"); await hook.expect("client-data", 1000, messageKind("room-info")); await hook.expect("client-data", 1000, messageKind("player-joined")); }); test("Servers handle multiple clients and resolve name collisions", async () => { const mox = new MockHelper(); const hook = new EventHook(); mox.createServer(sampleRoom()); const client1 = mox.createClient(); const client2 = mox.createClient(); hook.hookEmitter(client1, "data", "client1-data"); hook.hookEmitter(client2, "data", "client2-data"); client1.connect("test-server"); await hook.expect("client1-data", 1000, messageKind("room-info")); await hook.expect("client1-data", 1000, messageKind("player-joined")); client2.connect("test-server"); await hook.expect("client2-data", 1000, messageKind("rename")); await hook.expect("client2-data", 1000, messageKind("room-info")); await hook.expect("client2-data", 1000, messageKind("player-joined")); await hook.expect("client1-data", 1000, messageKind("player-joined")); }); test("Local server clients receives client events", async () => { const mox = new MockHelper(); const hook = new EventHook(); const local = new LocalClient({ name: "server-player" }); const server = mox.createServer(sampleRoom(), "test-server", local); const client = mox.createClient(); hook.hookEmitter(local, "player-joined", "local-joined"); client.connect("test-server"); await hook.expect("local-joined", 1000); }); test("Server enforces password protection", async () => { const mox = new MockHelper(); const hook = new EventHook(); const room = sampleRoom(); const roomPassword = "test-pwd"; room.password = roomPassword; const server = mox.createServer(room, "test-server"); // This client will try the right password const client1 = mox.createClient(); hook.hookEmitter(client1, "data", "client1-data"); client1.connect("test-server"); await hook.expect("client1-data", 1000, messageKind("password-req")); client1.password(roomPassword); await hook.expect("client1-data", 1000, messageKind("room-info")); await hook.expect("client1-data", 1000, messageKind("player-joined")); // This client will try an incorrect password const client2 = mox.createClient("test-client2", "another-client"); hook.hookEmitter(client2, "data", "client2-data"); client2.connect("test-server"); await hook.expect("client2-data", 1000, messageKind("password-req")); client2.password("not the right password"); await hook.expect("client2-data", 1000, messageKind("error")); }); }); describe("network/PeerClient", () => { test("Client handles forced name change", async () => { const mox = new MockHelper(); const hook = new EventHook(); mox.createServer(sampleRoom()); const client1 = mox.createClient(); const client2 = mox.createClient(); hook.hookEmitter(client2, "rename", "client-rename"); client1.connect("test-server"); client2.connect("test-server"); await hook.expect("client-rename", 1000); // Client must have changed its internal data to match the new name expect(client1.name).not.toEqual(client2.name); }); test("Client can leave the room", async () => { const mox = new MockHelper(); const hook = new EventHook(); const local = new LocalClient({ name: "server-player" }); const server = mox.createServer(sampleRoom(), "test-server", local); const client = mox.createClient(); hook.hookEmitter(local, "player-joined", "client-joined"); hook.hookEmitter(local, "player-left", "client-left"); client.connect("test-server"); await hook.expect("client-joined", 1000); client.leave(); await hook.expect("client-left", 1000); }); test("Clients can chat", async () => { const mox = new MockHelper(); const hook = new EventHook(); const local = new LocalClient({ name: "server-player" }); const server = mox.createServer(sampleRoom(), "test-server", local); const client = mox.createClient(); hook.hookEmitter(local, "player-joined", "client-joined"); hook.hookEmitter(local, "chat", "client-chat"); client.connect("test-server"); await hook.expect("client-joined", 1000); const hellomsg = "Hello everyone"; client.say("", hellomsg); await hook.expect("client-chat", 1000, (msg: ChatMessage) => { expect(msg.from).toEqual("client-peer"); expect(msg.message).toEqual(hellomsg); }); }); test("Client internal player list gets correctly updated", async () => { const mox = new MockHelper(); const hook = new EventHook(); const local = new LocalClient({ name: "server-player" }); const server = mox.createServer(sampleRoom(), "test-server", local); const client = mox.createClient(); hook.hookEmitter(local, "player-joined", "client-joined"); hook.hookEmitter(local, "player-left", "client-left"); client.connect("test-server"); await hook.expect("client-joined", 1000); expect(local.players).toHaveLength(2); client.leave(); await hook.expect("client-left", 1000); expect(local.players).toHaveLength(1); }); });