import { content } from "@deadhead/content"; import { errorResponseSchema, pilotResponseSchema } from "@deadhead/schema"; import { eq } from "drizzle-orm"; import { describe, expect, it } from "vitest"; import { pilots } from "../src/db/schema"; import { makeOwner, useTestDatabase } from "./db"; import { call, signUp, useTestApp, type Guest } from "./game"; const database = useTestDatabase(); const testApp = useTestApp(database); /** An owner whose avatar has `xp` XP and the given skills and points spent. */ async function pilotWith(xp: number, skills: Record = {}, spent = 0) { const guest = await signUp(testApp().app); await makeOwner(database().db, guest.playerId, guest.avatarId); await database() .db.update(pilots) .set({ xp, skills, skillPointsSpent: spent }) .where(eq(pilots.id, guest.avatarId)); return guest; } function spend(guest: Guest, skillId: string) { return call(testApp().app, guest, "POST", `/api/pilots/${guest.avatarId}/skills`, { skillId }); } const errorCode = (response: { json(): unknown }) => errorResponseSchema.parse(response.json()).error.code; // Level 1 gives `skillPointsPerLevel` points. const level1Xp = content.config.pilotLevelXpThresholds[0]!; describe("spending skill points", () => { it("raises the skill by one and uses one point", async () => { const guest = await pilotWith(level1Xp); const response = await spend(guest, "heavy-cargo"); expect(response.statusCode).toBe(200); const { pilot } = pilotResponseSchema.parse(response.json()); expect(pilot.skills).toEqual({ "heavy-cargo": 1 }); expect(pilot.skillPointsAvailable).toBe(content.config.skillPointsPerLevel - 1); }); it("refuses with no points available", async () => { const guest = await pilotWith(0); const response = await spend(guest, "heavy-cargo"); expect(response.statusCode).toBe(409); expect(errorCode(response)).toBe("no-skill-points"); }); it("refuses a skill already at max level", async () => { const guest = await pilotWith(level1Xp, { "long-haul": 5 }); expect(errorCode(await spend(guest, "long-haul"))).toBe("skill-maxed"); }); it("refuses an unknown skill", async () => { const guest = await pilotWith(level1Xp); const response = await spend(guest, "juggling"); expect(response.statusCode).toBe(404); expect(errorCode(response)).toBe("unknown-skill"); }); });