import type { ColorBlindnessType } from "@snapotter/image-engine"; import { COLOR_BLINDNESS_MATRICES, colorBlindness } from "@snapotter/image-engine"; import sharp from "sharp"; import { describe, expect, it } from "vitest"; const ALL_TYPES: ColorBlindnessType[] = [ "protanopia", "deuteranopia", "tritanopia", "protanomaly", "deuteranomaly", "tritanomaly", "achromatopsia", "blueConeMonochromacy", ]; function makeColorImage(r: number, g: number, b: number): sharp.Sharp { return sharp({ create: { width: 10, height: 10, channels: 3, background: { r, g, b } }, }).png(); } describe("Color blindness matrices", () => { it("all 8 types have a valid 3x3 matrix", () => { for (const type of ALL_TYPES) { const matrix = COLOR_BLINDNESS_MATRICES[type]; expect(matrix).toBeDefined(); expect(matrix).toHaveLength(3); for (const row of matrix) { expect(row).toHaveLength(3); for (const val of row) { expect(Number.isFinite(val)).toBe(true); } } } }); it("matrix row sums are in a reasonable range (0 to 1.5)", () => { for (const type of ALL_TYPES) { const matrix = COLOR_BLINDNESS_MATRICES[type]; for (const row of matrix) { const sum = row[0] + row[1] + row[2]; expect(sum).toBeGreaterThanOrEqual(0); expect(sum).toBeLessThanOrEqual(1.5); } } }); }); describe("colorBlindness operation", () => { it("returns a Sharp instance for each type", async () => { for (const type of ALL_TYPES) { const result = await colorBlindness(makeColorImage(255, 0, 0), { type }); const buf = await result.toBuffer(); expect(buf.length).toBeGreaterThan(0); } }); it("different types produce different outputs on a red image", async () => { const outputs = new Map(); for (const type of ALL_TYPES) { const result = await colorBlindness(makeColorImage(255, 0, 0), { type }); const { data } = await result.removeAlpha().raw().toBuffer({ resolveWithObject: true }); outputs.set(type, Buffer.from(data)); } const uniqueOutputs = new Set([...outputs.values()].map((b) => `${b[0]},${b[1]},${b[2]}`)); expect(uniqueOutputs.size).toBeGreaterThan(1); }); it("achromatopsia produces grayscale output (R === G === B)", async () => { const result = await colorBlindness(makeColorImage(255, 0, 0), { type: "achromatopsia", }); const { data } = await result.removeAlpha().raw().toBuffer({ resolveWithObject: true }); expect(data[0]).toBe(data[1]); expect(data[1]).toBe(data[2]); }); it("preserves image dimensions", async () => { const result = await colorBlindness(makeColorImage(100, 150, 200), { type: "deuteranomaly", }); const meta = await result.metadata(); expect(meta.width).toBe(10); expect(meta.height).toBe(10); }); });