176 lines
5.8 KiB
TypeScript
176 lines
5.8 KiB
TypeScript
import { describe, expect, it, beforeEach } from "vitest"
|
|
import { RoomManager } from "../src/rooms/room-manager"
|
|
import type { Act } from "@celebrate-esc/shared"
|
|
|
|
describe("RoomManager", () => {
|
|
let manager: RoomManager
|
|
|
|
beforeEach(() => {
|
|
manager = new RoomManager()
|
|
})
|
|
|
|
describe("createRoom", () => {
|
|
it("returns a 4-character room code and session ID", () => {
|
|
const result = manager.createRoom("Host")
|
|
expect(result.code).toMatch(/^[A-Z0-9]{4}$/)
|
|
expect(result.sessionId).toBeDefined()
|
|
expect(result.sessionId.length).toBe(36) // UUID
|
|
})
|
|
|
|
it("creates the host as a player in the room", () => {
|
|
const { code, sessionId } = manager.createRoom("Host")
|
|
const room = manager.getRoom(code)
|
|
expect(room).toBeDefined()
|
|
expect(room!.players).toHaveLength(1)
|
|
expect(room!.players[0]!.displayName).toBe("Host")
|
|
expect(room!.players[0]!.isHost).toBe(true)
|
|
expect(room!.players[0]!.sessionId).toBe(sessionId)
|
|
})
|
|
|
|
it("starts in lobby state", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
const room = manager.getRoom(code)
|
|
expect(room!.currentAct).toBe("lobby")
|
|
})
|
|
|
|
it("generates unique room codes", () => {
|
|
const codes = new Set<string>()
|
|
for (let i = 0; i < 50; i++) {
|
|
const { code } = manager.createRoom(`Host ${i}`)
|
|
codes.add(code)
|
|
}
|
|
expect(codes.size).toBe(50)
|
|
})
|
|
})
|
|
|
|
describe("joinRoom", () => {
|
|
it("adds a player to an existing room", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
const result = manager.joinRoom(code, "Player 1")
|
|
|
|
expect("sessionId" in result).toBe(true)
|
|
if ("sessionId" in result) {
|
|
const room = manager.getRoom(code)
|
|
expect(room!.players).toHaveLength(2)
|
|
expect(room!.players[1]!.displayName).toBe("Player 1")
|
|
expect(room!.players[1]!.isHost).toBe(false)
|
|
}
|
|
})
|
|
|
|
it("rejects join if room not found", () => {
|
|
const result = manager.joinRoom("ZZZZ", "Player")
|
|
expect(result).toEqual({ error: "Room not found" })
|
|
})
|
|
|
|
it("rejects join if room has ended", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
// Force room to ended state
|
|
manager.advanceAct(code, manager.getRoom(code)!.hostSessionId)
|
|
manager.advanceAct(code, manager.getRoom(code)!.hostSessionId)
|
|
manager.advanceAct(code, manager.getRoom(code)!.hostSessionId)
|
|
manager.advanceAct(code, manager.getRoom(code)!.hostSessionId)
|
|
const result = manager.joinRoom(code, "Late Player")
|
|
expect(result).toEqual({ error: "Room has ended" })
|
|
})
|
|
|
|
it("rejects join if display name is taken", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
manager.joinRoom(code, "Player 1")
|
|
const result = manager.joinRoom(code, "Player 1")
|
|
expect(result).toEqual({ error: "Name already taken" })
|
|
})
|
|
|
|
it("rejects join if room is full (10 players)", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
for (let i = 1; i <= 9; i++) {
|
|
manager.joinRoom(code, `Player ${i}`)
|
|
}
|
|
const result = manager.joinRoom(code, "Player 10")
|
|
expect(result).toEqual({ error: "Room is full" })
|
|
})
|
|
})
|
|
|
|
describe("advanceAct", () => {
|
|
it("advances through acts in order", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
const room = manager.getRoom(code)!
|
|
const hostSession = room.hostSessionId
|
|
|
|
const expectedSequence: Act[] = ["pre-show", "live-event", "scoring", "ended"]
|
|
for (const expected of expectedSequence) {
|
|
const result = manager.advanceAct(code, hostSession)
|
|
expect(result).toEqual({ newAct: expected })
|
|
expect(manager.getRoom(code)!.currentAct).toBe(expected)
|
|
}
|
|
})
|
|
|
|
it("cannot advance past ended", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
const room = manager.getRoom(code)!
|
|
// Advance to ended
|
|
for (let i = 0; i < 4; i++) {
|
|
manager.advanceAct(code, room.hostSessionId)
|
|
}
|
|
const result = manager.advanceAct(code, room.hostSessionId)
|
|
expect(result).toEqual({ error: "Room has already ended" })
|
|
})
|
|
|
|
it("rejects advance from non-host", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
const joinResult = manager.joinRoom(code, "Player")
|
|
if ("sessionId" in joinResult) {
|
|
const result = manager.advanceAct(code, joinResult.sessionId)
|
|
expect(result).toEqual({ error: "Only the host can advance acts" })
|
|
}
|
|
})
|
|
})
|
|
|
|
describe("endRoom", () => {
|
|
it("sets room to ended state", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
const room = manager.getRoom(code)!
|
|
const result = manager.endRoom(code, room.hostSessionId)
|
|
expect(result).toEqual({ success: true })
|
|
expect(manager.getRoom(code)!.currentAct).toBe("ended")
|
|
})
|
|
|
|
it("rejects end from non-host", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
const joinResult = manager.joinRoom(code, "Player")
|
|
if ("sessionId" in joinResult) {
|
|
const result = manager.endRoom(code, joinResult.sessionId)
|
|
expect(result).toEqual({ error: "Only the host can end the room" })
|
|
}
|
|
})
|
|
})
|
|
|
|
describe("getRoom", () => {
|
|
it("returns null for non-existent room", () => {
|
|
expect(manager.getRoom("ZZZZ")).toBeNull()
|
|
})
|
|
|
|
it("returns serialized room state", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
const room = manager.getRoom(code)
|
|
expect(room).toBeDefined()
|
|
expect(room!.code).toBe(code)
|
|
expect(room!.currentAct).toBe("lobby")
|
|
expect(Array.isArray(room!.players)).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe("reconnect", () => {
|
|
it("re-identifies an existing player by session ID", () => {
|
|
const { code, sessionId } = manager.createRoom("Host")
|
|
const result = manager.reconnectPlayer(code, sessionId)
|
|
expect(result).toEqual({ success: true, playerId: expect.any(String) })
|
|
})
|
|
|
|
it("rejects reconnect with unknown session ID", () => {
|
|
const { code } = manager.createRoom("Host")
|
|
const result = manager.reconnectPlayer(code, "00000000-0000-0000-0000-000000000000")
|
|
expect(result).toEqual({ error: "Session not found in this room" })
|
|
})
|
|
})
|
|
})
|