generated from nhcarrigan/template
test: add coverage for sync-new-content and explore claimable endpoints
This commit is contained in:
@@ -557,6 +557,192 @@ describe("debug route", () => {
|
||||
});
|
||||
});
|
||||
|
||||
const syncNewContent = () =>
|
||||
app.fetch(new Request("http://localhost/debug/sync-new-content", { method: "POST" }));
|
||||
|
||||
describe("POST /sync-new-content", () => {
|
||||
it("returns 404 when no game state found", async () => {
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce(null);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(404);
|
||||
});
|
||||
|
||||
it("returns 200 with zero counts when state already has all content", async () => {
|
||||
const state = makeState();
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it("injects missing entries when arrays are empty", async () => {
|
||||
const state = makeState({ adventurers: [], bosses: [], quests: [], upgrades: [], achievements: [], equipment: [], zones: [] });
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { adventurersAdded: number; bossesAdded: number };
|
||||
expect(body.adventurersAdded).toBeGreaterThan(0);
|
||||
expect(body.bossesAdded).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("injects missing exploration areas when exploration has no areas", async () => {
|
||||
const state = makeState({ exploration: makeExploration([]) });
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { explorationAreasAdded: number };
|
||||
expect(body.explorationAreasAdded).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("skips existing exploration areas when building the id set", async () => {
|
||||
const state = makeState({ exploration: makeExploration([
|
||||
{ id: "verdant_meadow", status: "available", completedOnce: false } as GameState["exploration"]["areas"][0],
|
||||
]) });
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { explorationAreasAdded: number };
|
||||
// One area already existed so total injected is one less than full count
|
||||
expect(body.explorationAreasAdded).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("returns explorationAreasAdded=0 when exploration state is undefined", async () => {
|
||||
const state = makeState({ exploration: undefined as unknown as GameState["exploration"] });
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { explorationAreasAdded: number };
|
||||
expect(body.explorationAreasAdded).toBe(0);
|
||||
});
|
||||
|
||||
it("patches quest rewards when saved quest has fewer rewards than default", async () => {
|
||||
const state = makeState({
|
||||
quests: [{ id: "first_steps", status: "available", rewards: [] }] as GameState["quests"],
|
||||
});
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { state: GameState };
|
||||
const quest = body.state.quests.find((q) => q.id === "first_steps");
|
||||
expect(quest?.rewards.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("skips quest reward patching for quests not in defaults", async () => {
|
||||
const state = makeState({
|
||||
quests: [{ id: "nonexistent_quest", status: "available", rewards: [] }] as GameState["quests"],
|
||||
});
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { state: GameState };
|
||||
const quest = body.state.quests.find((q) => q.id === "nonexistent_quest");
|
||||
expect(quest?.rewards).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it("does not re-add rewards that are already present in the saved quest", async () => {
|
||||
const state = makeState({
|
||||
quests: [{ id: "first_steps", status: "available", rewards: [{ type: "adventurer", targetId: "militia" }] }] as GameState["quests"],
|
||||
});
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { state: GameState };
|
||||
const quest = body.state.quests.find((q) => q.id === "first_steps");
|
||||
// Reward already present so count stays the same
|
||||
expect(quest?.rewards.filter((r) => r.targetId === "militia").length).toBe(1);
|
||||
});
|
||||
|
||||
it("patches boss upgrade rewards when saved boss has fewer rewards than default", async () => {
|
||||
const state = makeState({
|
||||
bosses: [{ id: "troll_king", status: "available", upgradeRewards: [] }] as GameState["bosses"],
|
||||
});
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { state: GameState };
|
||||
const boss = body.state.bosses.find((b) => b.id === "troll_king");
|
||||
expect(boss?.upgradeRewards.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("skips boss reward patching for bosses not in defaults", async () => {
|
||||
const state = makeState({
|
||||
bosses: [{ id: "nonexistent_boss", status: "available", upgradeRewards: [] }] as GameState["bosses"],
|
||||
});
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { state: GameState };
|
||||
const boss = body.state.bosses.find((b) => b.id === "nonexistent_boss");
|
||||
expect(boss?.upgradeRewards).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it("sorts multiple legacy items to the end when their ids are not in the defaults", async () => {
|
||||
const state = makeState({
|
||||
achievements: [
|
||||
{ id: "legacy_achievement_a", status: "locked" },
|
||||
{ id: "legacy_achievement_b", status: "locked" },
|
||||
] as GameState["achievements"],
|
||||
});
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it("uses amount field when building the reward key for quests with amount-based rewards", async () => {
|
||||
const state = makeState({
|
||||
quests: [{ id: "dragon_lair", status: "available", rewards: [{ type: "gold", amount: 500 }] }] as GameState["quests"],
|
||||
});
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it("falls back to empty string when reward has neither targetId nor amount", async () => {
|
||||
const state = makeState({
|
||||
quests: [{ id: "first_steps", status: "available", rewards: [{ type: "unknown" }] }] as GameState["quests"],
|
||||
});
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it("computes HMAC signature when ANTI_CHEAT_SECRET is set", async () => {
|
||||
process.env.ANTI_CHEAT_SECRET = "test_secret";
|
||||
const state = makeState();
|
||||
vi.mocked(prisma.gameState.findUnique).mockResolvedValueOnce({ state } as never);
|
||||
vi.mocked(prisma.gameState.update).mockResolvedValueOnce({} as never);
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { signature: string | undefined };
|
||||
expect(body.signature).toBeDefined();
|
||||
delete process.env.ANTI_CHEAT_SECRET;
|
||||
});
|
||||
|
||||
it("returns 500 when DB throws an Error", async () => {
|
||||
vi.mocked(prisma.gameState.findUnique).mockRejectedValueOnce(new Error("DB error"));
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(500);
|
||||
});
|
||||
|
||||
it("returns 500 when DB throws a non-Error value", async () => {
|
||||
vi.mocked(prisma.gameState.findUnique).mockRejectedValueOnce("raw error");
|
||||
const res = await syncNewContent();
|
||||
expect(res.status).toBe(500);
|
||||
});
|
||||
});
|
||||
|
||||
describe("POST /hard-reset", () => {
|
||||
it("returns 404 when no player found", async () => {
|
||||
vi.mocked(prisma.player.findUnique).mockResolvedValueOnce(null);
|
||||
|
||||
Reference in New Issue
Block a user