import { describe, expect, it } from "vitest"; import { DUNGEON_CATALOG, DUNGEON_CATEGORIES, dungeonById, dungeonsByCategory, randomDungeonByCategory, randomRegularDungeon, randomizedBiteSizedDungeons, randomRandomizedBiteSizedDungeon, } from "./dungeonCatalog"; import { DUNGEON_MANIFEST } from "./dungeonManifest"; import { RUNEWAKER_DUNGEON_DEFINITIONS } from "./generated/runewakerDungeonDefinitions.generated"; import { compareDungeonReleaseOrder } from "./dungeonReleaseStage"; import availability from "./generated/dungeonAvailability.json"; import queuePolicyCatalog from "./generated/dungeonLeaderboardCatalog.generated.json"; describe("dungeon catalog", () => { it("lists the complete campaign and bite-sized variants", () => { expect(DUNGEON_CATALOG).toHaveLength(92); expect(DUNGEON_CATALOG.find((dungeon) => dungeon.id === "stormwind-stockade")).toMatchObject({ id: "stormwind-stockade", releaseStage: "beta", available: true, }); expect(dungeonById(DUNGEON_MANIFEST.id)).toMatchObject({ title: DUNGEON_MANIFEST.title, mapId: DUNGEON_MANIFEST.mapId, entranceName: DUNGEON_MANIFEST.entrance.name, releaseStage: "alpha", }); expect(DUNGEON_CATALOG.find((dungeon) => dungeon.id === "deadmines")).toMatchObject({ id: "deadmines", mapId: 36, available: true, }); expect(DUNGEON_CATALOG.find((dungeon) => dungeon.id === "forsaken-abbey")).toMatchObject({ id: "forsaken-abbey", category: "rom", mapId: 102, available: true, }); }); it("separates WoW, RoM, and bite-sized dungeons", () => { expect(DUNGEON_CATEGORIES.map((category) => category.id)).toEqual(["wow", "rom", "bite-sized"]); expect(dungeonsByCategory("rom").map((dungeon) => dungeon.id).sort()).toEqual([ "forsaken-abbey", ...RUNEWAKER_DUNGEON_DEFINITIONS.map((definition) => definition.id), ].sort()); expect(dungeonsByCategory("wow")).not.toContainEqual( expect.objectContaining({ id: "forsaken-abbey" }), ); expect(dungeonsByCategory("rom")).toHaveLength(30); expect(dungeonsByCategory("bite-sized").map((dungeon) => dungeon.id).sort()) .toEqual(["bite-sized-deadmines-ship", "bite-sized-forsaken-abbey-ancalon", "bite-sized-mystic-altar-golem", "bite-sized-paspers-shrine-hafiz", "bite-sized-stormwind-stockade", "bite-sized-utgarde-pinnacle-skadi", "bite-sized-wailing-caverns"]); }); it("selects another available category dungeon", () => { expect(randomDungeonByCategory("bite-sized", "bite-sized-stormwind-stockade", () => 0)?.id) .not.toBe("bite-sized-stormwind-stockade"); expect(randomDungeonByCategory("wow", "stormwind-stockade", () => 0)?.id) .not.toBe("stormwind-stockade"); }); it("selects regular full dungeons without entering either Bite-Sized pool", () => { const first = randomRegularDungeon(undefined, () => 0); const last = randomRegularDungeon(undefined, () => 0.999999); for (const dungeon of [first, last]) { expect(dungeon?.available).toBe(true); expect(["wow", "rom"]).toContain(dungeon?.category); } expect(randomRegularDungeon(first?.id, () => 0)?.id).not.toBe(first?.id); expect(randomRegularDungeon(undefined, () => 0, () => false)).toBeNull(); }); it("keeps randomized replay in the separate randomized Bite-Sized location pool", () => { expect(randomizedBiteSizedDungeons().map((dungeon) => dungeon.id)) .toEqual(["randomized-bite-sized-stormwind-stockade"]); expect(randomRandomizedBiteSizedDungeon("randomized-bite-sized-stormwind-stockade", () => 0)?.id) .toBe("randomized-bite-sized-stormwind-stockade"); }); it("keeps stable unique ids and resolves only catalogued dungeons", () => { const ids = DUNGEON_CATALOG.map((dungeon) => dungeon.id); expect(new Set(ids).size).toBe(ids.length); expect(dungeonById(DUNGEON_MANIFEST.id)).toBe(DUNGEON_CATALOG.find((dungeon) => dungeon.id === DUNGEON_MANIFEST.id)); expect(dungeonById("missing-dungeon")).toBeNull(); }); it("keeps every queue candidate in the server policy validation catalog", () => { const policyIds = new Set(queuePolicyCatalog.dungeons.map((dungeon) => dungeon.id)); expect(DUNGEON_CATALOG.every((dungeon) => policyIds.has(dungeon.id))).toBe(true); }); it("provides centralized display copy for every entry", () => { for (const dungeon of DUNGEON_CATALOG) { expect(dungeon.location.trim()).not.toBe(""); expect(dungeon.theme.trim()).not.toBe(""); expect(dungeon.summary.trim()).not.toBe(""); } }); it("keeps all Stockades experiences in Beta and alphabetizes each release group", () => { expect(DUNGEON_CATALOG.filter((dungeon) => dungeon.releaseStage === "beta").map((dungeon) => dungeon.id)) .toEqual([ "bite-sized-forsaken-abbey-ancalon", "bite-sized-mystic-altar-golem", "bite-sized-paspers-shrine-hafiz", "randomized-bite-sized-stormwind-stockade", "stormwind-stockade", "bite-sized-stormwind-stockade", "bite-sized-deadmines-ship", "bite-sized-utgarde-pinnacle-skadi", "bite-sized-wailing-caverns", ]); expect(DUNGEON_CATALOG.filter((dungeon) => !dungeon.id.includes("stormwind-stockade") && !dungeon.id.startsWith("bite-sized-")) .every((dungeon) => dungeon.releaseStage === "alpha")) .toBe(true); for (const category of DUNGEON_CATEGORIES) { const dungeons = dungeonsByCategory(category.id); expect(dungeons).toEqual([...dungeons].sort(compareDungeonReleaseOrder)); } const stages = [ { title: "Zeta", releaseStage: "alpha" as const }, { title: "Beta Z", releaseStage: "beta" as const }, { title: "Released Z", releaseStage: "full-release" as const }, { title: "Alpha", releaseStage: "alpha" as const }, { title: "Beta A", releaseStage: "beta" as const }, { title: "Released A", releaseStage: "full-release" as const }, ]; expect(stages.sort(compareDungeonReleaseOrder).map((entry) => entry.title)) .toEqual(["Released A", "Released Z", "Beta A", "Beta Z", "Alpha", "Zeta"]); }); it("shares the complete dungeon identity list used to validate reports on the server", () => { expect(DUNGEON_CATALOG.map((dungeon) => dungeon.id).sort()) .toEqual(["bite-sized-deadmines-ship", "bite-sized-forsaken-abbey-ancalon", "bite-sized-mystic-altar-golem", "bite-sized-paspers-shrine-hafiz", "bite-sized-stormwind-stockade", "bite-sized-utgarde-pinnacle-skadi", "bite-sized-wailing-caverns", "randomized-bite-sized-stormwind-stockade", "forsaken-abbey", ...Object.keys(availability.enabled)].sort()); }); });