Files
healer-man/src/game/gmContentReview.test.ts
T
2026-09-01 14:35:56 -04:00

137 lines
6.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { DUNGEON_CATALOG } from "./dungeonCatalog";
import {
configWithGmReviewNote,
configWithGmReviewStatus,
describeGmReviewTarget,
drawRandomGmReviewTarget,
gmReviewQueue,
type GmReviewTarget,
} from "./gmContentReview";
import {
DEFAULT_MANASTORM_ADMIN_CONFIG,
resolvedBossAdminCatalog,
type GmReadinessStatus,
type ManastormAdminConfig,
} from "./manastormAdminConfig";
function configWithBossStatuses(statuses: Readonly<Record<string, GmReadinessStatus>>): ManastormAdminConfig {
return {
...DEFAULT_MANASTORM_ADMIN_CONFIG,
bosses: Object.fromEntries(Object.entries(statuses).map(([key, status]) => [key, { status }])),
};
}
describe("random GM content review", () => {
it("draws Needs tested dungeons before Not ready and never draws Ready", () => {
const available = DUNGEON_CATALOG.filter((dungeon) => dungeon.available);
expect(available.length).toBeGreaterThan(2);
const config: ManastormAdminConfig = {
...DEFAULT_MANASTORM_ADMIN_CONFIG,
dungeons: Object.fromEntries(available.map((dungeon, index) => [
dungeon.id,
{ status: index === 0 ? "needs-tested" : index === 1 ? "not-ready" : "ready" },
])),
};
expect(drawRandomGmReviewTarget("dungeon", config, null, () => 0.99)).toEqual({
kind: "dungeon",
dungeonId: available[0].id,
});
const withoutNeedsTested = configWithGmReviewStatus(
config,
{ kind: "dungeon", dungeonId: available[0].id },
"ready",
)!;
expect(drawRandomGmReviewTarget("dungeon", withoutNeedsTested, null, () => 0)).toEqual({
kind: "dungeon",
dungeonId: available[1].id,
});
});
it("uses separate dungeon-boss and imported-Manastorm source queues", () => {
const catalog = resolvedBossAdminCatalog(DEFAULT_MANASTORM_ADMIN_CONFIG);
const dungeonBosses = catalog.filter((entry) => entry.runnable && entry.source.includes("dungeon"));
const manastorms = catalog.filter((entry) => entry.runnable && entry.source.includes("installed-manastorm"));
expect(dungeonBosses.length).toBeGreaterThan(0);
expect(manastorms.length).toBeGreaterThan(0);
const bossQueue = gmReviewQueue("boss", DEFAULT_MANASTORM_ADMIN_CONFIG);
const manastormQueue = gmReviewQueue("manastorm", DEFAULT_MANASTORM_ADMIN_CONFIG);
expect(bossQueue.every((target) => target.kind === "boss"
&& dungeonBosses.some((entry) => entry.key === target.bossKey))).toBe(true);
expect(manastormQueue.every((target) => target.kind === "manastorm"
&& manastorms.some((entry) => entry.key === target.bossKey))).toBe(true);
const overlap = catalog.find((entry) => entry.runnable
&& entry.source.includes("dungeon")
&& entry.source.includes("installed-manastorm"));
expect(overlap).toBeTruthy();
expect(bossQueue).toContainEqual({ kind: "boss", bossKey: overlap!.key });
expect(manastormQueue).toContainEqual({ kind: "manastorm", bossKey: overlap!.key });
});
it("avoids an immediate repeat when another prioritized target exists", () => {
const targets = gmReviewQueue("manastorm", DEFAULT_MANASTORM_ADMIN_CONFIG);
expect(targets.length).toBeGreaterThan(1);
const previous = targets[0] as GmReviewTarget;
const next = drawRandomGmReviewTarget("manastorm", DEFAULT_MANASTORM_ADMIN_CONFIG, previous, () => 0);
expect(next).not.toEqual(previous);
});
it("returns no target when every runnable record is Ready", () => {
const catalog = resolvedBossAdminCatalog(DEFAULT_MANASTORM_ADMIN_CONFIG);
const config = configWithBossStatuses(Object.fromEntries(catalog.map((entry) => [entry.key, "ready"])));
expect(drawRandomGmReviewTarget("boss", config, null, () => 0)).toBeNull();
expect(drawRandomGmReviewTarget("manastorm", config, null, () => 0)).toBeNull();
});
it("updates the shared boss record and resolves exact review details", () => {
const target = gmReviewQueue("manastorm", DEFAULT_MANASTORM_ADMIN_CONFIG)[0];
expect(target?.kind).toBe("manastorm");
const updated = configWithGmReviewStatus(DEFAULT_MANASTORM_ADMIN_CONFIG, target!, "not-ready");
expect(updated).toBeTruthy();
const descriptor = describeGmReviewTarget(target!, updated!);
expect(descriptor).toMatchObject({ status: "not-ready", runnable: true });
if (target?.kind !== "dungeon") expect(updated!.bosses[target!.bossKey]?.status).toBe("not-ready");
});
it("keeps one shared review note across overlapping Boss and Manastorm targets", () => {
const overlap = resolvedBossAdminCatalog(DEFAULT_MANASTORM_ADMIN_CONFIG).find((entry) => (
entry.runnable
&& entry.source.includes("dungeon")
&& entry.source.includes("installed-manastorm")
));
expect(overlap).toBeTruthy();
const bossTarget = { kind: "boss", bossKey: overlap!.key } as const;
const manastormTarget = { kind: "manastorm", bossKey: overlap!.key } as const;
const noted = configWithGmReviewNote(
DEFAULT_MANASTORM_ADMIN_CONFIG,
bossTarget,
"Portal clips the west wall.",
)!;
const changedStatus = configWithGmReviewStatus(noted, manastormTarget, "not-ready")!;
expect(describeGmReviewTarget(manastormTarget, changedStatus)).toMatchObject({
status: "not-ready",
note: "Portal clips the west wall.",
});
expect(changedStatus.bosses[overlap!.key]).toMatchObject({
status: "not-ready",
note: "Portal clips the west wall.",
});
});
it("adds and clears advisory dungeon notes without changing availability", () => {
const dungeon = DUNGEON_CATALOG.find((entry) => entry.available)!;
const target = { kind: "dungeon", dungeonId: dungeon.id } as const;
const noted = configWithGmReviewNote(DEFAULT_MANASTORM_ADMIN_CONFIG, target, "Verify the final door.")!;
const cleared = configWithGmReviewNote(noted, target, "")!;
expect(describeGmReviewTarget(target, noted)).toMatchObject({ note: "Verify the final door.", runnable: true });
expect(cleared.dungeons[dungeon.id]?.note).toBeUndefined();
expect(dungeon.available).toBe(true);
});
});