import { content } from "@deadhead/content"; import { createGuestResponseSchema, errorResponseSchema, playerStateSchema, } from "@deadhead/schema"; import { beforeEach, describe, expect, it } from "vitest"; import { buildApp } from "../src/app"; import { createRecordingQueue } from "../src/jobs/queue"; import { useTestDatabase } from "./db"; import { testConfig } from "./helpers"; const database = useTestDatabase(); /** Turns Set-Cookie headers into a Cookie request header. */ function cookieFrom(setCookie: string | string[] | undefined): string { const values = Array.isArray(setCookie) ? setCookie : setCookie ? [setCookie] : []; return values.map((c) => c.split(";")[0]).join("; "); } describe("guest accounts", () => { let app: ReturnType; beforeEach(() => { app = buildApp(testConfig(), { database: database(), jobs: createRecordingQueue() }); return () => app.close(); }); it("creates a guest with a session cookie and a new tutorial player", async () => { const response = await app.inject({ method: "POST", url: "/api/guest" }); expect(response.statusCode).toBe(200); expect(cookieFrom(response.headers["set-cookie"])).toMatch(/session_token=/); const body = createGuestResponseSchema.parse(response.json()); expect(body.state.company.credits).toBe(content.config.startingCredits); expect(body.state.tutorial).toMatchObject({ loanerLocationId: "earth", runInFlight: false }); }); it("returns the new player's state for that session", async () => { const guest = await app.inject({ method: "POST", url: "/api/guest" }); const cookie = cookieFrom(guest.headers["set-cookie"]); const response = await app.inject({ method: "GET", url: "/api/state", headers: { cookie } }); expect(response.statusCode).toBe(200); const state = playerStateSchema.parse(response.json()); expect(state.company.credits).toBe(content.config.startingCredits); expect( state.locations .filter((l) => l.discovered) .map((l) => l.id) .sort(), ).toEqual(["earth", "moon"]); expect(state.pilots).toHaveLength(1); expect(state.pilots[0]).toMatchObject({ isAvatar: true, level: 0, xp: 0, locationId: "earth", status: "idle", }); expect(state.ships).toHaveLength(0); expect(state.tutorial).not.toBeNull(); }); it("gives each guest their own player", async () => { const a = createGuestResponseSchema.parse( (await app.inject({ method: "POST", url: "/api/guest" })).json(), ); const b = createGuestResponseSchema.parse( (await app.inject({ method: "POST", url: "/api/guest" })).json(), ); expect(a.playerId).not.toBe(b.playerId); }); it("rejects a state request with no session", async () => { const response = await app.inject({ method: "GET", url: "/api/state" }); expect(response.statusCode).toBe(401); expect(errorResponseSchema.parse(response.json()).error.code).toBe("unauthorized"); }); it("rejects a state request with a forged session cookie", async () => { const response = await app.inject({ method: "GET", url: "/api/state", headers: { cookie: "better-auth.session_token=forged.value" }, }); expect(response.statusCode).toBe(401); }); });