import { describe, expect, it } from "vitest"; import { runtimeStages } from "./manastorm"; import { DEFAULT_MANASTORM_ADMIN_CONFIG, UNIFIED_MANASTORM_BOSS_CATALOG, authoredStageConfigForBoss, bossAdminRecordForStatus, derivePartySpawnSlots, effectiveManastormCatalog, isGameMasterSession, resolveBossAdminEntry, resolvedBossAdminCatalog, type ManastormAdminConfig, } from "./manastormAdminConfig"; function configWithBoss(key: string, record: ManastormAdminConfig["bosses"][string]): ManastormAdminConfig { return { ...DEFAULT_MANASTORM_ADMIN_CONFIG, bosses: { [key]: record }, }; } describe("Manastorm GM catalog", () => { it("deduplicates map/name records and defaults every boss to Needs tested", () => { const identities = UNIFIED_MANASTORM_BOSS_CATALOG.map((entry) => `${entry.mapId}:${entry.name.toLowerCase()}`); expect(new Set(identities).size).toBe(identities.length); expect(UNIFIED_MANASTORM_BOSS_CATALOG.length).toBeGreaterThan(0); expect(resolvedBossAdminCatalog(DEFAULT_MANASTORM_ADMIN_CONFIG).every((entry) => ( entry.status === "needs-tested" && !entry.inPublicPool ))).toBe(true); const crossMode = UNIFIED_MANASTORM_BOSS_CATALOG.find((entry) => entry.name === "Burning Felguard"); expect(crossMode?.baseStage?.modeIds).toEqual(expect.arrayContaining([0, 2])); }); it("publishes only runnable Ready bosses and never restores the legacy pool", () => { const candidate = UNIFIED_MANASTORM_BOSS_CATALOG.find((entry) => ( resolveBossAdminEntry(entry, configWithBoss(entry.key, { status: "ready" })).runnable )); expect(candidate).toBeTruthy(); const config = configWithBoss(candidate!.key, { status: "ready" }); const effective = effectiveManastormCatalog(config); expect(effective.fallbackPolicy).toBe("none"); expect(runtimeStages(effective)).toHaveLength(1); expect(runtimeStages(effective)[0].bossName).toBe(candidate!.name); const empty = effectiveManastormCatalog(DEFAULT_MANASTORM_ADMIN_CONFIG); expect(empty.fallbackPolicy).toBe("none"); expect(runtimeStages(empty)).toEqual([]); }); it("materializes an inherited imported stage when a runnable boss becomes Ready", () => { const candidate = UNIFIED_MANASTORM_BOSS_CATALOG.find((entry) => entry.baseStage); expect(candidate).toBeTruthy(); const record = bossAdminRecordForStatus(candidate!, DEFAULT_MANASTORM_ADMIN_CONFIG, "ready"); expect(record.status).toBe("ready"); expect(record.stage).toMatchObject({ dungeonId: candidate!.baseStage!.dungeonId, bossRuntimeId: candidate!.baseStage!.bossRuntimeId, bossPosition: candidate!.baseStage!.bossPosition, }); }); it("rejects stale exact-mob IDs and bounds required kills", () => { const candidate = UNIFIED_MANASTORM_BOSS_CATALOG.find((entry) => authoredStageConfigForBoss(entry, DEFAULT_MANASTORM_ADMIN_CONFIG)); expect(candidate).toBeTruthy(); const stage = authoredStageConfigForBoss(candidate!, DEFAULT_MANASTORM_ADMIN_CONFIG)!; const stale = configWithBoss(candidate!.key, { status: "ready", stage: { ...stage, linkedMobRuntimeIds: ["missing:runtime-id"], requiredKillCount: 1, }, }); const resolved = resolveBossAdminEntry(candidate!, stale); expect(resolved.runnable).toBe(false); expect(resolved.validationIssues.join(" ")).toContain("missing:runtime-id"); }); it("derives a stable five-person formation from one anchor and yaw", () => { const slots = derivePartySpawnSlots({ footPosition: [10, 2, 20], yaw: Math.PI / 2 }, 5); expect(slots).toHaveLength(5); expect(slots[0]).toEqual({ footPosition: [10, 2, 20], yaw: Math.PI / 2 }); expect(new Set(slots.map((slot) => slot.footPosition.join(","))).size).toBe(5); expect(slots.every((slot) => slot.yaw === Math.PI / 2)).toBe(true); }); it("never grants GM UI authority to offline or local-only sessions", () => { expect(isGameMasterSession({ kind: "offline", roles: ["gm"] })).toBe(false); expect(isGameMasterSession({ kind: "account", roles: ["gm"] })).toBe(false); expect(isGameMasterSession({ kind: "account", accessToken: "server-token", roles: ["gm"] })).toBe(true); }); });