101 lines
4.1 KiB
JavaScript
101 lines
4.1 KiB
JavaScript
// Color Together mode socket test.
|
|
const { io } = require("socket.io-client");
|
|
const URL = "http://localhost:3000";
|
|
const TIMEOUT_MS = 20000;
|
|
|
|
const results = [];
|
|
let exitCode = 0;
|
|
const pass = (n) => { results.push({ name: n, status: "pass" }); console.log("PASS:", n); };
|
|
const fail = (n, e) => { results.push({ name: n, status: "fail", error: String(e) }); console.log("FAIL:", n, "-", e); exitCode = 1; };
|
|
|
|
function waitFor(socket, event, predicate = () => true, timeout = 6000) {
|
|
return new Promise((resolve, reject) => {
|
|
const t = setTimeout(() => reject(new Error(`timeout waiting for ${event}`)), timeout);
|
|
const handler = (data) => {
|
|
if (predicate(data)) {
|
|
clearTimeout(t);
|
|
socket.off(event, handler);
|
|
resolve(data);
|
|
}
|
|
};
|
|
socket.on(event, handler);
|
|
});
|
|
}
|
|
function emitAck(s, event, payload) {
|
|
return new Promise((resolve, reject) => {
|
|
const t = setTimeout(() => reject(new Error(`ack timeout for ${event}`)), 5000);
|
|
s.emit(event, payload, (resp) => { clearTimeout(t); resolve(resp); });
|
|
});
|
|
}
|
|
|
|
const killer = setTimeout(() => { console.log("FAIL: Global timeout"); process.exit(1); }, TIMEOUT_MS);
|
|
killer.unref();
|
|
|
|
(async () => {
|
|
let a, b, c;
|
|
try {
|
|
a = io(URL, { transports: ["websocket"], forceNew: true });
|
|
b = io(URL, { transports: ["websocket"], forceNew: true });
|
|
await Promise.all([
|
|
new Promise((r) => a.on("connect", r)),
|
|
new Promise((r) => b.on("connect", r)),
|
|
]);
|
|
pass("color: clients A,B connected");
|
|
|
|
const create = await emitAck(a, "room:create", {
|
|
nickname: "Alice", avatar: "🐱", mode: "color",
|
|
settings: { canvasType: "blank" },
|
|
});
|
|
if (!create || !create.ok) throw new Error("create failed: " + JSON.stringify(create));
|
|
const code = create.code;
|
|
pass("color: room created, code=" + code);
|
|
|
|
const j = await emitAck(b, "room:join", { code, nickname: "Bob", avatar: "🐶" });
|
|
if (!j || !j.ok) throw new Error("join failed");
|
|
pass("color: B joined");
|
|
|
|
// listen FIRST, then trigger
|
|
const stateAfterStartP = waitFor(a, "room:state", (s) => s.color !== null && s.phase === "playing", 4000);
|
|
const start = await emitAck(a, "game:start", {});
|
|
if (!start || !start.ok) throw new Error("game:start failed: " + JSON.stringify(start));
|
|
pass("color: game:start ok");
|
|
|
|
const stateAfterStart = await stateAfterStartP;
|
|
pass("color: room transitioned to playing with color state");
|
|
|
|
// A emits color:stroke; B should receive color:strokeBroadcast
|
|
const strokePayload = {
|
|
points: [{ x: 10, y: 10 }, { x: 20, y: 20 }],
|
|
color: "#FF0000",
|
|
size: 5,
|
|
tool: "brush",
|
|
};
|
|
const bRecv = waitFor(b, "color:strokeBroadcast", (d) => d && d.color === "#FF0000", 4000);
|
|
a.emit("color:stroke", strokePayload);
|
|
const got = await bRecv;
|
|
if (!got || !Array.isArray(got.points) || got.points.length !== 2) throw new Error("stroke broadcast malformed: " + JSON.stringify(got));
|
|
pass("color: B received color:strokeBroadcast with same payload");
|
|
|
|
// C joins mid-game and should receive color:state with the existing stroke
|
|
c = io(URL, { transports: ["websocket"], forceNew: true });
|
|
await new Promise((r) => c.on("connect", r));
|
|
const cStateP = waitFor(c, "color:state", (s) => s && Array.isArray(s.strokes), 5000);
|
|
const j2 = await emitAck(c, "room:join", { code, nickname: "Carol", avatar: "🦊" });
|
|
if (!j2 || !j2.ok) throw new Error("C join failed");
|
|
pass("color: C joined mid-game");
|
|
const cState = await cStateP;
|
|
if (!cState.strokes || cState.strokes.length < 1) throw new Error("color:state to new joiner missing strokes: " + JSON.stringify(cState));
|
|
pass("color: new joiner C received color:state with " + cState.strokes.length + " stroke(s)");
|
|
|
|
} catch (e) {
|
|
fail("color flow", e && e.message ? e.message : String(e));
|
|
} finally {
|
|
try { a && a.disconnect(); } catch (_) {}
|
|
try { b && b.disconnect(); } catch (_) {}
|
|
try { c && c.disconnect(); } catch (_) {}
|
|
clearTimeout(killer);
|
|
console.log("__RESULTS__ " + JSON.stringify(results));
|
|
setTimeout(() => process.exit(exitCode), 200);
|
|
}
|
|
})();
|