import { describe, expect, it, vi } from "vitest"; import { extractPalette } from "../../src/palette/extract"; import { extractPaletteSafely } from "../../src/palette/worker-client"; const makePixels = ( colours: readonly (readonly [number, number, number, number])[], ) => ({ width: colours.length, height: 1, data: new Uint8ClampedArray(colours.flat()), }); describe("deterministic Oklab palette extraction", () => { it("returns dominant colours in coverage order", () => { const input = makePixels([ [255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255], [0, 0, 255, 255], ]); const palette = extractPalette(input, { count: 2 }); expect(palette.map((colour) => colour.hex)).toEqual(["#FF0000", "#0000FF"]); expect(palette[0]?.coverage).toBeCloseTo(0.75, 8); expect(palette[1]?.coverage).toBeCloseTo(0.25, 8); }); it("produces byte-for-byte stable results for repeated runs", () => { const input = makePixels([ [248, 245, 238, 255], [20, 80, 180, 255], [245, 140, 20, 255], [248, 245, 238, 255], [25, 85, 175, 220], [240, 145, 25, 255], ]); const first = extractPalette(input, { count: 3 }); const second = extractPalette(input, { count: 3 }); expect(second).toEqual(first); }); it("ignores fully transparent pixels and respects the alpha threshold", () => { const input = makePixels([ [255, 0, 255, 0], [255, 0, 0, 15], [0, 255, 0, 255], [0, 0, 255, 255], ]); const palette = extractPalette(input, { count: 3, minimumAlpha: 16 }); expect(palette.map((colour) => colour.hex)).toEqual(["#0000FF", "#00FF00"]); expect( palette.reduce((sum, colour) => sum + colour.coverage, 0), ).toBeCloseTo(1, 8); }); it("handles a fully transparent image without inventing colours", () => { expect(extractPalette(makePixels([[10, 20, 30, 0]]), { count: 6 })).toEqual( [], ); }); it("rejects malformed pixel buffers", () => { expect(() => extractPalette( { width: 2, height: 2, data: new Uint8ClampedArray(4) }, { count: 2 }, ), ).toThrow("Invalid pixel buffer"); }); it("falls back safely when Web Workers are unavailable", async () => { const input = makePixels([ [255, 0, 0, 255], [0, 0, 255, 255], ]); vi.stubGlobal("Worker", undefined); try { await expect( extractPaletteSafely(input, { count: 2 }), ).resolves.toHaveLength(2); } finally { vi.unstubAllGlobals(); } }); });