Files
sternboard/server/test/helpers.ts
T

86 lines
2.8 KiB
TypeScript
Raw Normal View History

import { buildServer, type BuiltServer } from "../src/app.js";
import { io as ioc, type Socket } from "socket.io-client";
import type { BoardState } from "../src/room.js";
export type TestServer = BuiltServer & { port: number; url: string };
export async function startTestServer(): Promise<TestServer> {
const server = buildServer({ cleanup: false });
const port = await server.listen(0); // puerto efímero
return Object.assign(server, { port, url: `http://localhost:${port}` });
}
export async function createBoard(
url: string,
body: Record<string, unknown> = {},
): Promise<{ boardId: string; moderatorToken: string; expiresAt: string | null }> {
const res = await fetch(`${url}/api/boards`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ templateId: "mad-sad-glad", votesPerUser: 3, ...body }),
});
return res.json();
}
// Cliente de test: mantiene el último estado recibido para evitar carreras
// (el estado buscado puede haber llegado antes de adjuntar el listener).
export class Client {
last: BoardState | null = null;
constructor(public socket: Socket) {
socket.on("board:state", (s: BoardState) => (this.last = s));
}
emit(event: string, payload: Record<string, unknown>) {
this.socket.emit(event, payload);
}
// Resuelve cuando el último estado (presente o futuro) cumple el predicado.
waitFor(predicate: (s: BoardState) => boolean, timeoutMs = 10000): Promise<BoardState> {
if (this.last && predicate(this.last)) return Promise.resolve(this.last);
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
this.socket.off("board:state", handler);
reject(new Error("waitFor timeout"));
}, timeoutMs);
const handler = (s: BoardState) => {
if (predicate(s)) {
clearTimeout(timer);
this.socket.off("board:state", handler);
resolve(s);
}
};
this.socket.on("board:state", handler);
});
}
close() {
this.socket.close();
}
}
// Conecta, hace join y devuelve un Client ya con su primer estado.
export function join(
url: string,
boardId: string,
participantId: string,
name: string,
): Promise<Client> {
return new Promise((resolve, reject) => {
const socket = ioc(url, { transports: ["websocket"], forceNew: true });
const client = new Client(socket);
const timer = setTimeout(() => reject(new Error("join timeout")), 10000);
socket.on("connect", () => socket.emit("board:join", { boardId, participantId, name }));
socket.once("error", (e) => {
clearTimeout(timer);
reject(new Error(`join error: ${JSON.stringify(e)}`));
});
const ready = (s: BoardState) => {
clearTimeout(timer);
socket.off("board:state", ready);
client.last = s;
resolve(client);
};
socket.on("board:state", ready);
});
}