import { describe, it, expect, vi, beforeEach } from "vitest"; import type { RouterContextProvider } from "react-router"; import { action } from "~/routes/api/draft.start"; const ctx = {} as unknown as RouterContextProvider; vi.mock("~/database/context"); vi.mock("~/server/socket", () => ({ getSocketIO: vi.fn(), })); vi.mock("@clerk/react-router/server", () => ({ getAuth: vi.fn(), })); vi.mock("~/models/commissioner", () => ({ isCommissioner: vi.fn(), })); vi.mock("~/models/draft-timer", () => ({ deleteSeasonTimers: vi.fn(), initializeDraftTimers: vi.fn(), })); // ── Fixtures ───────────────────────────────────────────────────────────────── const SEASON_ID = "season-1"; const COMMISSIONER_ID = "commissioner-user-1"; const mockDraftSlots = [ { id: "slot-1", seasonId: SEASON_ID, teamId: "team-1", draftOrder: 1 }, { id: "slot-2", seasonId: SEASON_ID, teamId: "team-2", draftOrder: 2 }, ]; function makeSeason(overrides: Record = {}) { return { id: SEASON_ID, leagueId: "league-1", status: "pre_draft", draftInitialTime: 120, draftIncrementTime: 30, draftTimerMode: "chess_clock", ...overrides, }; } function makeRequest() { const formData = new FormData(); formData.append("seasonId", SEASON_ID); return new Request("http://localhost/api/draft/start", { method: "POST", body: formData, }); } // ── Tests ───────────────────────────────────────────────────────────────────── describe("draft.start action — timer initialization", () => { let mockDb: any; let mockSocketIO: any; beforeEach(async () => { vi.clearAllMocks(); const { getAuth } = await import("@clerk/react-router/server"); vi.mocked(getAuth).mockResolvedValue({ userId: COMMISSIONER_ID } as any); const { isCommissioner } = await import("~/models/commissioner"); vi.mocked(isCommissioner).mockResolvedValue(true); mockSocketIO = { to: vi.fn().mockReturnThis(), emit: vi.fn() }; const socketModule = await import("~/server/socket"); vi.mocked(socketModule.getSocketIO).mockReturnValue(mockSocketIO); mockDb = { query: { seasons: { findFirst: vi.fn() }, draftSlots: { findMany: vi.fn() }, }, update: vi.fn().mockReturnThis(), set: vi.fn().mockReturnThis(), where: vi.fn().mockReturnThis(), }; mockDb.query.draftSlots.findMany.mockResolvedValue(mockDraftSlots); const { database } = await import("~/database/context"); vi.mocked(database).mockReturnValue(mockDb); }); describe("chess_clock mode", () => { it("initializes each team's timer to draftInitialTime", async () => { mockDb.query.seasons.findFirst.mockResolvedValue( makeSeason({ draftTimerMode: "chess_clock", draftInitialTime: 120, draftIncrementTime: 30 }) ); await action({ request: makeRequest(), params: {}, context: ctx }); const { initializeDraftTimers } = await import("~/models/draft-timer"); expect(vi.mocked(initializeDraftTimers)).toHaveBeenCalledWith( SEASON_ID, expect.any(Array), 120 // draftInitialTime, not draftIncrementTime ); }); it("uses the configured draftInitialTime (not the increment)", async () => { mockDb.query.seasons.findFirst.mockResolvedValue( makeSeason({ draftTimerMode: "chess_clock", draftInitialTime: 28800, draftIncrementTime: 3600 }) ); await action({ request: makeRequest(), params: {}, context: ctx }); const { initializeDraftTimers } = await import("~/models/draft-timer"); expect(vi.mocked(initializeDraftTimers)).toHaveBeenCalledWith( SEASON_ID, expect.any(Array), 28800 // 8 hours initial bank ); }); }); describe("standard mode", () => { it("initializes each team's timer to draftIncrementTime (the per-pick time)", async () => { mockDb.query.seasons.findFirst.mockResolvedValue( makeSeason({ draftTimerMode: "standard", draftInitialTime: 120, draftIncrementTime: 30 }) ); await action({ request: makeRequest(), params: {}, context: ctx }); const { initializeDraftTimers } = await import("~/models/draft-timer"); expect(vi.mocked(initializeDraftTimers)).toHaveBeenCalledWith( SEASON_ID, expect.any(Array), 30 // draftIncrementTime, not draftInitialTime ); }); it("ignores draftInitialTime — uses only increment for the starting clock", async () => { // Even though initialTime=600, standard mode should use increment=45 mockDb.query.seasons.findFirst.mockResolvedValue( makeSeason({ draftTimerMode: "standard", draftInitialTime: 600, draftIncrementTime: 45 }) ); await action({ request: makeRequest(), params: {}, context: ctx }); const { initializeDraftTimers } = await import("~/models/draft-timer"); expect(vi.mocked(initializeDraftTimers)).toHaveBeenCalledWith( SEASON_ID, expect.any(Array), 45 // increment only — initial time is irrelevant in standard mode ); }); }); });