1
0
Fork 0
polaris-task-force/tests/int/poker-tables.int.spec.ts
Z8MB1E f7bb8f1e9f feat(poker): mark leavers immediately and auto-end when one player remains
Leavers now flip a left flag on the very next snapshot, the felt announces who left, and a game left with a single seated player resolves at once with a bell notification instead of waiting out the hand timer.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 17:06:57 -04:00

101 lines
3.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
createTable,
getSnapshotFor,
joinTable,
leaveTable,
startGame,
} from "@/lib/minigames/poker/tables";
/**
* Regression tests for the registry's game-start path. Guards against the
* seat-map aliasing bug that once spawned phantom "Player null" engine seats
* when a table started with fewer than four players.
*/
describe("poker table registry: startGame", () => {
it("starts a heads-up game with exactly the two seated players", () => {
const tableId = createTable(9001, "Host");
joinTable(tableId, 9002, "Guest");
const snapshot = startGame(tableId, 9001);
const seatedIds = snapshot.seats.filter((id) => id !== null);
expect(seatedIds).toHaveLength(2);
const players = snapshot.you?.players ?? [];
expect(players).toHaveLength(2);
for (const player of players) {
expect(player.name).not.toBe("Player null");
expect(player.name.length).toBeGreaterThan(0);
expect(player.eliminated).toBe(false);
}
});
it("starts a three-handed game with exactly the three seated players", () => {
const tableId = createTable(9101, "Host");
joinTable(tableId, 9102, "Second");
joinTable(tableId, 9103, "Third");
const snapshot = startGame(tableId, 9101);
const seatedIds = snapshot.seats.filter((id) => id !== null);
expect(seatedIds).toHaveLength(3);
const players = snapshot.you?.players ?? [];
expect(players).toHaveLength(3);
const names = players.map((player) => player.name);
expect(names).not.toContain("Player null");
expect(new Set(names).size).toBe(3);
});
it("keeps every engine player backed by a real seated user", () => {
const tableId = createTable(9201, "Host");
joinTable(tableId, 9202, "Second");
const snapshot = startGame(tableId, 9201);
const players = snapshot.you?.players ?? [];
for (const player of players) {
const userId = snapshot.seats[player.seatId];
expect(userId).not.toBeNull();
expect(typeof userId).toBe("number");
}
});
});
describe("poker table registry: last player standing", () => {
it("ends the game immediately when everyone else leaves mid-hand", () => {
const tableId = createTable(9301, "Host");
joinTable(tableId, 9302, "Guest");
startGame(tableId, 9301);
leaveTable(tableId, 9302);
const remaining = getSnapshotFor(tableId, 9301);
expect(remaining.you?.phase).toBe("game-complete");
const players = remaining.you?.players ?? [];
const hostPlayer = players.find((player) => player.seatId === remaining.you?.viewerSeat);
const guestPlayer = players.find((player) => player.seatId !== remaining.you?.viewerSeat);
expect(hostPlayer?.eliminated).toBe(false);
expect(hostPlayer?.left).toBe(false);
// The leaver's committed blind is forfeited (leavers take nothing from
// the pot), so the host only receives their own small blind back.
expect(hostPlayer?.stack).toBe(1000);
expect(guestPlayer?.eliminated).toBe(true);
expect(guestPlayer?.left).toBe(true);
});
it("does not end the game while two or more players remain seated", () => {
const tableId = createTable(9401, "Host");
joinTable(tableId, 9402, "Second");
joinTable(tableId, 9403, "Third");
startGame(tableId, 9401);
leaveTable(tableId, 9403);
const snapshot = getSnapshotFor(tableId, 9401);
expect(snapshot.you?.phase).not.toBe("game-complete");
const third = getSnapshotFor(tableId, 9403);
expect(third.you).toBeNull();
});
});