import { describe, it, expect } from "vitest"; import type { MediaItem } from "$lib/api/types"; import { buildHeroMix, shuffle } from "./heroMix"; /** Minimal MediaItem for hero tests; `art: false` strips the image tags. */ function item(id: string, art = true): MediaItem { return { id, name: `Item ${id}`, type: "Movie", primaryImageTag: art ? `tag-${id}` : undefined, } as MediaItem; } const hasArt = (i: MediaItem) => !!i.primaryImageTag; describe("shuffle", () => { it("returns a permutation without mutating the input", () => { const input = [1, 2, 3, 4, 5]; const copy = [...input]; const result = shuffle(input); expect(input).toEqual(copy); expect([...result].sort()).toEqual([...input].sort()); }); }); describe("buildHeroMix", () => { it("returns empty for empty pools", () => { expect(buildHeroMix([[], []], hasArt)).toEqual([]); }); it("caps the rotation at count", () => { const pool = Array.from({ length: 20 }, (_, i) => item(`a${i}`)); expect(buildHeroMix([pool], hasArt, 6)).toHaveLength(6); }); it("filters items without artwork", () => { const result = buildHeroMix([[item("a", false), item("b")]], hasArt); expect(result.map(i => i.id)).toEqual(["b"]); }); it("de-duplicates across pools", () => { const a = item("a"); const result = buildHeroMix([[a], [a, item("b")]], hasArt); const ids = result.map(i => i.id); expect(ids).toHaveLength(new Set(ids).size); expect(ids).toContain("a"); expect(ids).toContain("b"); }); it("leads with an item from the first non-empty pool", () => { const personal = [item("p1"), item("p2"), item("p3")]; const rest = [item("r1"), item("r2"), item("r3")]; for (let run = 0; run < 20; run++) { const result = buildHeroMix([personal, rest], hasArt); expect(["p1", "p2", "p3"]).toContain(result[0].id); } }); it("takes at most perPool items per pool before backfilling", () => { const a = [item("a1"), item("a2"), item("a3"), item("a4")]; const b = [item("b1"), item("b2"), item("b3"), item("b4")]; // count 4 with perPool 2: exactly 2 from each pool, no backfill needed. for (let run = 0; run < 20; run++) { const result = buildHeroMix([a, b], hasArt, 4, 2); const fromA = result.filter(i => i.id.startsWith("a")).length; const fromB = result.filter(i => i.id.startsWith("b")).length; expect(fromA).toBe(2); expect(fromB).toBe(2); } }); it("backfills from leftovers when samples fall short of count", () => { const a = [item("a1"), item("a2"), item("a3"), item("a4"), item("a5"), item("a6")]; const result = buildHeroMix([a], hasArt, 6, 2); expect(result).toHaveLength(6); }); });