/* eslint-disable max-lines-per-function -- Test suites naturally have many cases */ /* eslint-disable max-lines -- Test suites naturally have many cases */ /* eslint-disable @typescript-eslint/consistent-type-assertions -- Tests build minimal state objects */ import { beforeEach, describe, expect, it, vi } from "vitest"; import { Hono } from "hono"; import type { GameState } from "@elysium/types"; vi.mock("../../src/db/client.js", () => ({ prisma: { gameState: { findUnique: vi.fn(), update: vi.fn() }, }, })); vi.mock("../../src/middleware/auth.js", () => ({ authMiddleware: vi.fn(async (c: { set: (key: string, value: string) => void }, next: () => Promise) => { c.set("discordId", "test_discord_id"); await next(); }), })); vi.mock("../../src/services/logger.js", () => ({ logger: { error: vi.fn().mockResolvedValue(undefined), metric: vi.fn().mockResolvedValue(undefined), }, })); const DISCORD_ID = "test_discord_id"; const makeSiring = (overrides: Record = {}) => ({ count: 0, ichor: 0, productionMultiplier: 1, purchasedUpgradeIds: [] as Array, ichorCombatMultiplier: 1, ...overrides, }); const makeAwakening = (overrides: Record = {}) => ({ count: 0, purchasedUpgradeIds: [] as Array, soulShards: 0, soulShardsBloodMultiplier: 1, soulShardsCombatMultiplier: 1, soulShardsMetaMultiplier: 1, soulShardsSiringIchorMultiplier: 1, soulShardsSiringThresholdMultiplier: 1, ...overrides, }); const makeVampireState = (overrides: Record = {}) => ({ achievements: [] as Array<{ id: string; unlockedAt: number | null; reward: unknown }>, awakening: makeAwakening(), baseClickPower: 1, bosses: [] as Array<{ id: string; status: string; zoneId: string; maxHp: number; currentHp: number; damagePerSecond: number; siringRequirement: number; bloodReward: number; ichorReward: number; soulShardsReward: number; upgradeRewards: Array; equipmentRewards: Array; bountyIchorClaimed: boolean; }>, equipment: [] as Array<{ id: string; owned: boolean; equipped: boolean; type: string; bonus: Record }>, eternalSovereignty: { count: 0 }, exploration: { areas: [] as Array<{ id: string; status: string; startedAt?: number; endsAt?: number; completedOnce?: boolean }>, craftedBloodMultiplier: 1, craftedCombatMultiplier: 1, craftedIchorMultiplier: 1, craftedRecipeIds: [] as Array, materials: [] as Array<{ materialId: string; quantity: number }>, }, lastTickAt: 0, lifetimeBloodEarned: 0, lifetimeBossesDefeated: 0, lifetimeQuestsCompleted: 0, quests: [] as Array<{ id: string; status: string; zoneId?: string; unlockQuestId?: string | null }>, siring: makeSiring(), thralls: [] as Array<{ id: string; count: number; combatPower: number; level: number; unlocked: boolean; bloodPerSecond: number; ichorPerSecond: number; baseCost: number; class: string; name: string; }>, totalBloodEarned: 0, upgrades: [] as Array<{ id: string; purchased: boolean; target: string; multiplier: number; thrallId?: string; unlocked?: boolean }>, zones: [] as Array<{ id: string; status: string; unlockBossId?: string; unlockQuestId?: string | null }>, ...overrides, }); const makeState = (overrides: Partial = {}): GameState => ({ player: { discordId: DISCORD_ID, username: "u", discriminator: "0", avatar: null, totalGoldEarned: 0, totalClicks: 0, characterName: "T" }, resources: { gold: 0, essence: 0, crystals: 0, runestones: 0 }, adventurers: [], upgrades: [], quests: [], bosses: [], equipment: [], achievements: [], zones: [], exploration: { areas: [], materials: [], craftedRecipeIds: [], craftedGoldMultiplier: 1, craftedEssenceMultiplier: 1, craftedClickMultiplier: 1, craftedCombatMultiplier: 1 }, companions: { unlockedCompanionIds: [], activeCompanionId: null }, prestige: { count: 0, runestones: 0, productionMultiplier: 1, purchasedUpgradeIds: [] }, baseClickPower: 1, lastTickAt: 0, schemaVersion: 1, ...overrides, } as GameState); const makeBoss = (overrides: Record = {}) => ({ id: "test_boss", status: "available", zoneId: "test_zone", maxHp: 100, currentHp: 100, damagePerSecond: 1, siringRequirement: 0, bloodReward: 100, ichorReward: 0, soulShardsReward: 0, upgradeRewards: [] as Array, equipmentRewards: [] as Array, bountyIchorClaimed: false, ...overrides, }); const makeStrongThrall = (overrides: Record = {}) => ({ id: "test_thrall", count: 10000, combatPower: 1000, level: 1, unlocked: true, bloodPerSecond: 0, ichorPerSecond: 0, baseCost: 0, class: "fighter", name: "Fighter", ...overrides, }); describe("vampireBoss route", () => { let app: Hono; let prisma: { gameState: { findUnique: ReturnType; update: ReturnType }; }; beforeEach(async () => { vi.clearAllMocks(); const { vampireBossRouter } = await import("../../src/routes/vampireBoss.js"); const { prisma: p } = await import("../../src/db/client.js"); prisma = p as typeof prisma; app = new Hono(); app.route("/vampire-boss", vampireBossRouter); }); const post = (path: string, body?: Record) => app.fetch(new Request(`http://localhost/vampire-boss${path}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body ?? {}), })); describe("POST /challenge", () => { it("returns 400 when bossId is missing from body", async () => { const res = await post("/challenge", {}); expect(res.status).toBe(400); const body = await res.json() as { error: string }; expect(body.error).toContain("Invalid request body"); }); it("returns 404 when no save is found", async () => { vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce(null); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(404); const body = await res.json() as { error: string }; expect(body.error).toContain("No save found"); }); it("returns 400 when vampire realm is not unlocked", async () => { const state = makeState(); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(400); const body = await res.json() as { error: string }; expect(body.error).toContain("Vampire realm"); }); it("returns 404 when boss is not found in state", async () => { const vampire = makeVampireState({ bosses: [] }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); const res = await post("/challenge", { bossId: "missing_boss" }); expect(res.status).toBe(404); const body = await res.json() as { error: string }; expect(body.error).toContain("Boss not found"); }); it("returns 400 when boss status is defeated", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ status: "defeated" }) ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(400); const body = await res.json() as { error: string }; expect(body.error).toContain("not currently available"); }); it("returns 400 when boss status is locked", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ status: "locked" }) ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(400); const body = await res.json() as { error: string }; expect(body.error).toContain("not currently available"); }); it("allows challenge when boss status is in_progress", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, maxHp: 1, status: "in_progress" }) ], thralls: [ makeStrongThrall() ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); }); it("returns 403 when siring requirement is not met", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ siringRequirement: 10 }) ], siring: makeSiring({ count: 0 }), }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(403); const body = await res.json() as { error: string }; expect(body.error).toContain("Siring requirement"); }); it("returns 400 when thralls have no combat power (empty thralls array)", async () => { const vampire = makeVampireState({ bosses: [ makeBoss() ], thralls: [], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(400); const body = await res.json() as { error: string }; expect(body.error).toContain("no combat power"); }); it("returns 400 when thrall count is zero", async () => { const vampire = makeVampireState({ bosses: [ makeBoss() ], thralls: [ makeStrongThrall({ count: 0 }) ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(400); const body = await res.json() as { error: string }; expect(body.error).toContain("no combat power"); }); it("returns won: true with rewards on a successful boss kill", async () => { // Boss with 1 HP, party kills it before it kills party const vampire = makeVampireState({ bosses: [ makeBoss({ bloodReward: 100, currentHp: 1, damagePerSecond: 1, maxHp: 1 }) ], thralls: [ makeStrongThrall() ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); const body = await res.json() as { won: boolean; rewards: { blood: number } }; expect(body.won).toBe(true); expect(body.rewards).toBeDefined(); expect(body.rewards.blood).toBe(100); }); it("sets boss status to defeated on win", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, maxHp: 1 }) ], thralls: [ makeStrongThrall() ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); await post("/challenge", { bossId: "test_boss" }); const updateCall = vi.mocked(prisma.gameState.update).mock.calls[0]; const savedState = (updateCall?.[0] as { data: { state: GameState } }).data.state; const savedBoss = savedState.vampire?.bosses.find((b) => b.id === "test_boss"); expect(savedBoss?.status).toBe("defeated"); }); it("unlocks next boss in same zone after win when siring requirement met", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, id: "boss_1", maxHp: 1, zoneId: "zone_a" }), makeBoss({ id: "boss_2", siringRequirement: 0, status: "locked", zoneId: "zone_a" }), ], thralls: [ makeStrongThrall() ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); await post("/challenge", { bossId: "boss_1" }); const updateCall = vi.mocked(prisma.gameState.update).mock.calls[0]; const savedState = (updateCall?.[0] as { data: { state: GameState } }).data.state; const nextBoss = savedState.vampire?.bosses.find((b) => b.id === "boss_2"); expect(nextBoss?.status).toBe("available"); }); it("returns won: false with casualties on loss", async () => { // Boss with very high HP/DPS, weak thrall const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 999_999, damagePerSecond: 999_999, maxHp: 999_999 }) ], thralls: [ makeStrongThrall({ combatPower: 1, count: 100, level: 1 }) ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); const body = await res.json() as { won: boolean; casualties: Array }; expect(body.won).toBe(false); expect(body.casualties).toBeDefined(); }); it("resets boss HP to maxHp on loss", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 999_999, damagePerSecond: 999_999, maxHp: 999_999 }) ], thralls: [ makeStrongThrall({ combatPower: 1, count: 100 }) ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); await post("/challenge", { bossId: "test_boss" }); const updateCall = vi.mocked(prisma.gameState.update).mock.calls[0]; const savedState = (updateCall?.[0] as { data: { state: GameState } }).data.state; const savedBoss = savedState.vampire?.bosses.find((b) => b.id === "test_boss"); expect(savedBoss?.currentHp).toBe(999_999); expect(savedBoss?.status).toBe("available"); }); it("returns 500 on DB Error throw", async () => { vi.mocked(prisma.gameState.findUnique).mockRejectedValueOnce(new Error("DB failure")); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(500); const body = await res.json() as { error: string }; expect(body.error).toContain("Internal server error"); }); it("returns 500 on non-Error throw", async () => { vi.mocked(prisma.gameState.findUnique).mockRejectedValueOnce("string error"); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(500); const body = await res.json() as { error: string }; expect(body.error).toContain("Internal server error"); }); it("grants ichor reward on win", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, ichorReward: 5, maxHp: 1 }) ], siring: makeSiring({ ichor: 0 }), thralls: [ makeStrongThrall() ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); const body = await res.json() as { rewards: { ichor: number } }; expect(body.rewards.ichor).toBe(5); }); it("grants soulShards reward on win", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, maxHp: 1, soulShardsReward: 3 }) ], thralls: [ makeStrongThrall() ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); const body = await res.json() as { rewards: { soulShards: number } }; expect(body.rewards.soulShards).toBe(3); }); it("increments lifetimeBossesDefeated on win", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, maxHp: 1 }) ], lifetimeBossesDefeated: 2, thralls: [ makeStrongThrall() ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); await post("/challenge", { bossId: "test_boss" }); const updateCall = vi.mocked(prisma.gameState.update).mock.calls[0]; const savedState = (updateCall?.[0] as { data: { state: GameState } }).data.state; expect(savedState.vampire?.lifetimeBossesDefeated).toBe(3); }); it("unlocks upgrade rewards on win", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, maxHp: 1, upgradeRewards: [ "upgrade_1" ] }) ], thralls: [ makeStrongThrall() ], upgrades: [ { id: "upgrade_1", multiplier: 2, purchased: false, target: "global", unlocked: false } ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); await post("/challenge", { bossId: "test_boss" }); const updateCall = vi.mocked(prisma.gameState.update).mock.calls[0]; const savedState = (updateCall?.[0] as { data: { state: GameState } }).data.state; const upgrade = savedState.vampire?.upgrades.find((u) => u.id === "upgrade_1"); expect(upgrade?.unlocked).toBe(true); }); it("response includes combat stats", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, maxHp: 1 }) ], thralls: [ makeStrongThrall() ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); const body = await res.json() as { partyDPS: number; partyMaxHp: number; bossDPS: number }; expect(body.partyDPS).toBeGreaterThan(0); expect(body.partyMaxHp).toBeGreaterThan(0); expect(body.bossDPS).toBe(1); }); it("unlocks a zone when its unlock boss is defeated and quest condition is met", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, id: "boss_for_zone", maxHp: 1, zoneId: "zone_a" }), makeBoss({ id: "new_zone_first_boss", siringRequirement: 0, status: "locked", zoneId: "new_zone" }), ], thralls: [ makeStrongThrall() ], zones: [ { id: "already_unlocked", status: "unlocked", unlockBossId: "boss_for_zone", unlockQuestId: null }, { id: "wrong_boss_zone", status: "locked", unlockBossId: "different_boss", unlockQuestId: null }, { id: "new_zone", status: "locked", unlockBossId: "boss_for_zone", unlockQuestId: null }, ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); await post("/challenge", { bossId: "boss_for_zone" }); const updateCall = vi.mocked(prisma.gameState.update).mock.calls[0]; const savedState = (updateCall?.[0] as { data: { state: GameState } }).data.state; const zone = savedState.vampire?.zones.find((z) => z.id === "new_zone"); expect(zone?.status).toBe("unlocked"); }); it("skips zone unlock when quest condition is not satisfied (quest exists but not completed)", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, id: "boss_for_quest_zone", maxHp: 1, zoneId: "zone_a" }) ], quests: [ { id: "required_quest", status: "in_progress" } ], thralls: [ makeStrongThrall() ], zones: [ { id: "quest_locked_zone", status: "locked", unlockBossId: "boss_for_quest_zone", unlockQuestId: "required_quest" } ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); await post("/challenge", { bossId: "boss_for_quest_zone" }); const updateCall = vi.mocked(prisma.gameState.update).mock.calls[0]; const savedState = (updateCall?.[0] as { data: { state: GameState } }).data.state; const zone = savedState.vampire?.zones.find((z) => z.id === "quest_locked_zone"); expect(zone?.status).toBe("locked"); }); it("unlocks a zone when both boss and required quest conditions are satisfied", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, id: "quest_boss", maxHp: 1, zoneId: "zone_a" }) ], quests: [ { id: "required_quest", status: "completed" } ], thralls: [ makeStrongThrall() ], zones: [ { id: "quest_zone", status: "locked", unlockBossId: "quest_boss", unlockQuestId: "required_quest" } ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); await post("/challenge", { bossId: "quest_boss" }); const updateCall = vi.mocked(prisma.gameState.update).mock.calls[0]; const savedState = (updateCall?.[0] as { data: { state: GameState } }).data.state; const zone = savedState.vampire?.zones.find((z) => z.id === "quest_zone"); expect(zone?.status).toBe("unlocked"); }); it("skips thralls with count=0 when computing casualties on loss", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 999_999, damagePerSecond: 999_999, maxHp: 999_999 }) ], thralls: [ makeStrongThrall({ combatPower: 1, count: 0, id: "dead_thrall" }), makeStrongThrall({ combatPower: 1, count: 100, id: "alive_thrall" }), ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); const body = await res.json() as { won: boolean; casualties: Array }; expect(body.won).toBe(false); expect(body.casualties).toBeDefined(); }); it("includes HMAC signature in response when ANTI_CHEAT_SECRET is set", async () => { process.env.ANTI_CHEAT_SECRET = "test_secret"; const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, maxHp: 1 }) ], thralls: [ makeStrongThrall() ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); const body = await res.json() as { signature: string }; expect(body.signature).toBeDefined(); delete process.env.ANTI_CHEAT_SECRET; }); it("applies purchased global upgrade multiplier to party DPS", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, maxHp: 1 }) ], thralls: [ makeStrongThrall({ combatPower: 100 }) ], upgrades: [ { id: "global_upgrade_1", multiplier: 2, purchased: true, target: "global", unlocked: true } ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); const body = await res.json() as { won: boolean }; expect(body.won).toBe(true); }); it("applies purchased thrall-specific upgrade multiplier to party DPS", async () => { const vampire = makeVampireState({ bosses: [ makeBoss({ currentHp: 1, maxHp: 1 }) ], thralls: [ makeStrongThrall({ combatPower: 100, id: "test_thrall" }) ], upgrades: [ { id: "thrall_upgrade_1", multiplier: 2, purchased: true, target: "thrall", thrallId: "test_thrall", unlocked: true } ], }); const state = makeState({ vampire: vampire as GameState["vampire"] }); vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never); vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never); const res = await post("/challenge", { bossId: "test_boss" }); expect(res.status).toBe(200); const body = await res.json() as { won: boolean }; expect(body.won).toBe(true); }); }); });