Files
two-keys/server/test/helpers.ts
T
joshuaandClaude Opus 5.5 0de6617c82 V1.0.0
Two Keys: co-op mystery games for couples. Eight games on four engines (story, defuse, sync, labyrinth), two-device and couch play, mobile-first UI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:36:12 +02:00

41 lines
1.6 KiB
TypeScript

import { loadGames } from '../src/content/loader';
import type { DefuseGame, Game, LabyrinthGame, StoryGame, SyncGame } from '../src/content/schemas';
import { initEngine } from '../src/engines/index';
import { createCtx } from '../src/engines/types';
import { RoomStore, type Room } from '../src/rooms/store';
export const games = loadGames();
export function getGame<E extends Game['engine']>(id: string, engine: E): Extract<Game, { engine: E }> {
const game = games.get(id);
if (!game || game.engine !== engine) throw new Error(`no ${engine} game "${id}"`);
return game as Extract<Game, { engine: E }>;
}
export const storyGames = [...games.values()].filter((g): g is StoryGame => g.engine === 'story');
export const defuse = () => getGame('tick-tock-together', 'defuse') as DefuseGame;
export const sync = () => getGame('in-sync', 'sync') as SyncGame;
export const labyrinth = () => getGame('labyrinth-of-lanterns', 'labyrinth') as LabyrinthGame;
/** A room that is already in the `playing` phase for the given game. */
export function playingRoom(game: Game, startedAt = 1_000_000): Room {
const { room } = new RoomStore(null).create(game.id, 'duo', startedAt);
room.players[0].seat = 'A';
room.players.push({ token: 'b', seat: 'B', ready: true, viewing: null });
room.phase = 'playing';
room.startedAt = startedAt;
room.engine = initEngine(game);
return room;
}
/** A clock for tests: every call to `ctx()` is 3 seconds later, clear of the rate limit. */
export function clock(room: Room, start = 1_000_000) {
let now = start;
return {
ctx: (advanceMs = 3000) => createCtx(room, (now += advanceMs)),
get now() {
return now;
},
};
}