import { beforeEach, describe, expect, it, vi } from "vitest"; const content = vi.hoisted(() => ({ usable: false, install: vi.fn(async (): Promise => 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((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"); }); });