Files
healer-man/src/game/manastormClientCues.test.ts
T
2026-09-05 11:40:50 -04:00

110 lines
4.2 KiB
TypeScript

import { readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
MANASTORM_DEFAULT_PORTAL_READY_CUE_ID,
MANASTORM_PORTAL_AUDIO_ROOT,
MANASTORM_PORTAL_AUDIO_CUES,
manastormCueForStatusTransition,
manastormPortalAudioCue,
playManastormClientCue,
stopManastormClientCue,
type ManastormAudioHandle,
} from "./manastormClientCues";
import { useManastormStore } from "./manastormStore";
const projectDirectory = fileURLToPath(new URL("../..", import.meta.url));
describe("Manastorm imported client cues", () => {
afterEach(() => {
stopManastormClientCue();
useManastormStore.getState().resetRun();
});
it("catalogs every locally verified portal cue without inventing timing", () => {
expect(MANASTORM_PORTAL_AUDIO_CUES).toHaveLength(5);
expect(new Set(MANASTORM_PORTAL_AUDIO_CUES.map((cue) => cue.id)).size).toBe(5);
expect(MANASTORM_PORTAL_AUDIO_CUES.filter((cue) => cue.signal === "portal-ready"))
.toHaveLength(2);
expect(MANASTORM_PORTAL_AUDIO_CUES.filter((cue) => cue.signal === "portal-coming-up"))
.toHaveLength(3);
for (const cue of MANASTORM_PORTAL_AUDIO_CUES) {
expect(cue.fileName).toMatch(/^Manastorm_BossKill_.+\.wav$/);
expect(cue.url).toBe(`${MANASTORM_PORTAL_AUDIO_ROOT}/${cue.fileName}`);
const audio = readFileSync(path.join(projectDirectory, "public", cue.url.slice(1)));
expect(audio.subarray(0, 4).toString("ascii")).toBe("RIFF");
expect(audio.subarray(8, 12).toString("ascii")).toBe("WAVE");
}
});
it("keeps optional portal audio out of Vite source imports", () => {
const source = readFileSync(
new URL("./manastormClientCues.ts", import.meta.url),
"utf8",
);
expect(source).not.toContain("LadiksMPQEditor");
expect(source).not.toMatch(/new URL\s*\(/);
});
it("maps only an actual portal-ready state edge to the automatic cue", () => {
expect(manastormCueForStatusTransition("awaiting-loot", "portal-ready"))
.toBe(MANASTORM_DEFAULT_PORTAL_READY_CUE_ID);
expect(manastormCueForStatusTransition("portal-ready", "portal-ready")).toBeNull();
expect(manastormCueForStatusTransition("fighting", "awaiting-loot")).toBeNull();
expect(manastormCueForStatusTransition("transitioning", "entering")).toBeNull();
});
it("configures and plays a requested local cue through an injectable audio boundary", async () => {
const play = vi.fn(async () => undefined);
const pause = vi.fn();
const audio: ManastormAudioHandle = {
currentTime: 12,
preload: "",
volume: 1,
pause,
play,
};
const factory = vi.fn(() => audio);
await expect(playManastormClientCue("generic-portals-ready", factory))
.resolves.toBe(true);
expect(factory).toHaveBeenCalledWith(
manastormPortalAudioCue("generic-portals-ready").url,
);
expect(audio).toMatchObject({ currentTime: 0, preload: "auto", volume: 0.72 });
expect(play).toHaveBeenCalledOnce();
});
it("queues explicit cues with monotonic revisions for external server data", () => {
const state = useManastormStore.getState();
expect(state.requestClientCue("single-portal-coming-up")).toBe(true);
const first = useManastormStore.getState().clientCue;
expect(first).toMatchObject({ cueId: "single-portal-coming-up" });
expect(useManastormStore.getState().requestClientCue("generic-portals-ready-alt"))
.toBe(true);
const second = useManastormStore.getState().clientCue;
expect(second?.revision).toBe((first?.revision ?? 0) + 1);
useManastormStore.getState().clearClientCue();
expect(useManastormStore.getState().clientCue).toBeNull();
});
it("queues the verified ready cue when the existing run state opens its portal", () => {
const state = useManastormStore.getState();
state.startRun(() => 0);
expect(useManastormStore.getState().enterStage()).toBe(true);
useManastormStore.getState().observeTrash(true);
useManastormStore.getState().observeBoss(true, true);
expect(useManastormStore.getState()).toMatchObject({
status: "portal-ready",
clientCue: {
cueId: MANASTORM_DEFAULT_PORTAL_READY_CUE_ID,
},
});
});
});