Files
healer-man/src/game/combatMediaPack.test.ts
T
2026-09-11 14:26:15 -04:00

106 lines
3.8 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const content = vi.hoisted(() => ({
usable: false,
install: vi.fn(async (): Promise<void> => undefined),
remove: vi.fn(async () => undefined),
listener: null as (() => void) | null,
snapshot: {
downloadedBytes: 4,
totalBytes: 8,
manifest: {
packs: [{ id: "core:combat-media", fileCount: 12 }],
},
},
}));
vi.mock("../content/contentManager", () => ({
contentPackIsUsable: () => content.usable,
getContentManagerSnapshot: () => content.snapshot,
installContentPack: content.install,
removeContentPack: content.remove,
resolveContentUrl: (url: string) => `resolved:${url}`,
subscribeContentManager: (listener: () => void) => {
content.listener = listener;
return () => { content.listener = null; };
},
}));
import {
combatMediaPackReady,
downloadCombatMediaPack,
ensureCombatMediaPack,
fetchCombatMediaAsset,
removeCombatMediaPack,
} from "./combatMediaPack";
beforeEach(() => {
content.usable = false;
content.install.mockReset();
content.remove.mockClear();
vi.unstubAllGlobals();
});
describe("original combat media pack", () => {
it("uses the shared verified content-pack installer", async () => {
const progress = vi.fn();
await expect(downloadCombatMediaPack(progress)).resolves.toEqual({ fileCount: 12 });
expect(content.install).toHaveBeenCalledWith("core:combat-media");
expect(progress).toHaveBeenLastCalledWith({ completed: 4, total: 8 });
});
it("automatically installs missing default media and reuses installed media", async () => {
content.install.mockImplementationOnce(async () => { content.usable = true; });
await expect(ensureCombatMediaPack()).resolves.toBe(true);
await expect(ensureCombatMediaPack()).resolves.toBe(true);
expect(content.install).toHaveBeenCalledTimes(1);
});
it("allows visual fallback after a failed download and retries on the next preparation", async () => {
content.install.mockRejectedValueOnce(new Error("Offline"));
await expect(ensureCombatMediaPack()).resolves.toBe(false);
content.install.mockImplementationOnce(async () => { content.usable = true; });
await expect(ensureCombatMediaPack()).resolves.toBe(true);
expect(content.install).toHaveBeenCalledTimes(2);
});
it("shares an in-flight installation between automatic preparation and a download request", async () => {
let finish!: () => void;
content.install.mockImplementationOnce(() => new Promise<void>((resolve) => { finish = resolve; }));
const preparation = ensureCombatMediaPack();
const download = downloadCombatMediaPack();
expect(content.install).toHaveBeenCalledTimes(1);
content.usable = true;
finish();
await expect(preparation).resolves.toBe(true);
await expect(download).resolves.toEqual({ fileCount: 12 });
});
it("does not fetch source media while its pack is offloaded", async () => {
const fetch = vi.fn();
vi.stubGlobal("fetch", fetch);
expect(combatMediaPackReady()).toBe(false);
await expect(fetchCombatMediaAsset("/assets/game/combat-effects/audio/shield.wav"))
.rejects.toThrow("not installed");
expect(fetch).not.toHaveBeenCalled();
});
it("resolves installed media through the shared content router and removes the same pack", async () => {
content.usable = true;
const response = new Response(new Uint8Array([1, 2, 3]));
const fetch = vi.fn(async () => response);
vi.stubGlobal("fetch", fetch);
await expect(fetchCombatMediaAsset("/assets/game/combat-effects/audio/shield.wav"))
.resolves.toBe(response);
expect(fetch).toHaveBeenCalledWith(
"resolved:/assets/game/combat-effects/audio/shield.wav",
{ cache: "no-store" },
);
await removeCombatMediaPack();
expect(content.remove).toHaveBeenCalledWith("core:combat-media");
});
});