import { describe, it, expect, vi, beforeEach } from "vitest"; import { createRequest, createRouteContext } from "@/__tests__/helpers/api-test-utils"; import { TEST_ROOM_DATA } from "@/__tests__/helpers/fixtures"; vi.mock("@/lib/prisma", () => ({ prisma: {} })); vi.mock("@/lib/roomRepository", () => ({ atomicUpdateRoom: vi.fn(), })); vi.mock("@/lib/roomEvents", () => ({ notify: vi.fn(), })); import { POST } from "./route"; import { atomicUpdateRoom } from "@/lib/roomRepository"; const mockAtomicUpdate = vi.mocked(atomicUpdateRoom); beforeEach(() => { vi.clearAllMocks(); }); describe("POST /api/room/[id]/manage", () => { it("locks the room", async () => { mockAtomicUpdate.mockImplementation(async (_id, updater) => { const data = structuredClone(TEST_ROOM_DATA); const result = updater(data); expect(result.locked).toBe(true); return result; }); const req = createRequest("/api/room/ROOM01/manage", { method: "POST", body: { userId: "user-1", action: "lock" }, }); const ctx = createRouteContext({ id: "ROOM01" }); const res = await POST(req, ctx); expect(res.status).toBe(200); }); it("unlocks the room", async () => { mockAtomicUpdate.mockImplementation(async (_id, updater) => { const data = structuredClone(TEST_ROOM_DATA); data.locked = true; const result = updater(data); expect(result.locked).toBe(false); return result; }); const req = createRequest("/api/room/ROOM01/manage", { method: "POST", body: { userId: "user-1", action: "unlock" }, }); const ctx = createRouteContext({ id: "ROOM01" }); const res = await POST(req, ctx); expect(res.status).toBe(200); }); it("kicks a user", async () => { mockAtomicUpdate.mockImplementation(async (_id, updater) => { const data = structuredClone(TEST_ROOM_DATA); const result = updater(data); expect(result.users).not.toContain("user-2"); expect(result.kickedUsers).toContain("user-2"); return result; }); const req = createRequest("/api/room/ROOM01/manage", { method: "POST", body: { userId: "user-1", action: "kick", targetUserId: "user-2" }, }); const ctx = createRouteContext({ id: "ROOM01" }); const res = await POST(req, ctx); expect(res.status).toBe(200); }); it("prevents kicking yourself", async () => { mockAtomicUpdate.mockImplementation(async (_id, updater) => { const data = structuredClone(TEST_ROOM_DATA); return updater(data); }); const req = createRequest("/api/room/ROOM01/manage", { method: "POST", body: { userId: "user-1", action: "kick", targetUserId: "user-1" }, }); const ctx = createRouteContext({ id: "ROOM01" }); const res = await POST(req, ctx); expect(res.status).toBe(400); }); it("ends voting by setting all swipeCounts to total", async () => { mockAtomicUpdate.mockImplementation(async (_id, updater) => { const data = structuredClone(TEST_ROOM_DATA); const result = updater(data); expect(result.swipeCounts["user-1"]).toBe(3); expect(result.swipeCounts["user-2"]).toBe(3); return result; }); const req = createRequest("/api/room/ROOM01/manage", { method: "POST", body: { userId: "user-1", action: "end_voting" }, }); const ctx = createRouteContext({ id: "ROOM01" }); const res = await POST(req, ctx); expect(res.status).toBe(200); }); it("returns 403 when not the creator", async () => { mockAtomicUpdate.mockImplementation(async (_id, updater) => { const data = structuredClone(TEST_ROOM_DATA); data.creatorId = "other-user"; return updater(data); }); const req = createRequest("/api/room/ROOM01/manage", { method: "POST", body: { userId: "user-1", action: "lock" }, }); const ctx = createRouteContext({ id: "ROOM01" }); const res = await POST(req, ctx); expect(res.status).toBe(403); }); it("returns 400 for unknown action", async () => { mockAtomicUpdate.mockImplementation(async (_id, updater) => { const data = structuredClone(TEST_ROOM_DATA); return updater(data); }); const req = createRequest("/api/room/ROOM01/manage", { method: "POST", body: { userId: "user-1", action: "unknown" }, }); const ctx = createRouteContext({ id: "ROOM01" }); const res = await POST(req, ctx); expect(res.status).toBe(400); }); });