import { describe, expect, it } from "vitest"; import { contrastRatio, readableColor } from "@/lib/theme-contrast"; import { PRESETS } from "@/lib/theme-presets"; describe("contrastRatio", () => { it("calculates the WCAG ratio for black on white", () => { expect(contrastRatio("#000000", "#ffffff")).toBe(21); }); it("returns null for unsupported color formats", () => { expect(contrastRatio("var(--color-text)", "#ffffff")).toBeNull(); }); }); describe("built-in theme presets", () => { it("derives WCAG-readable public foregrounds for every palette", () => { for (const preset of Object.values(PRESETS)) { const backgrounds = [preset.color_background, preset.color_surface]; const foregrounds = [ readableColor(preset.color_text, backgrounds), readableColor(preset.color_text_muted, backgrounds), readableColor(preset.color_primary, backgrounds), readableColor(preset.color_accent, backgrounds), ]; for (const foreground of foregrounds) { for (const background of backgrounds) { expect(contrastRatio(foreground, background)).toBeGreaterThanOrEqual(4.5); } } const buttonText = readableColor(preset.button_text_color, [preset.button_primary_color]); expect(contrastRatio(buttonText, preset.button_primary_color)).toBeGreaterThanOrEqual(4.5); const primaryForeground = readableColor(preset.button_text_color, [preset.color_primary]); expect(contrastRatio(primaryForeground, preset.color_primary)).toBeGreaterThanOrEqual(4.5); } }); it.each(["#22c55e", "#ef4444"])("derives readable text for default button %s", (background) => { const foreground = readableColor("#ffffff", [background]); expect(contrastRatio(foreground, background)).toBeGreaterThanOrEqual(4.5); }); }); describe("readableColor", () => { it("keeps the preferred color when it passes on every background", () => { expect(readableColor("#0f172a", ["#ffffff", "#f8fafc"], 4.5)).toBe("#0f172a"); }); it("replaces low-contrast golden text with a readable neutral", () => { const color = readableColor("#f59e0b", ["#ffffff", "#f8fafc"], 4.5); expect(color).toBe("#000000"); expect(contrastRatio(color, "#ffffff")).toBeGreaterThanOrEqual(4.5); expect(contrastRatio(color, "#f8fafc")).toBeGreaterThanOrEqual(4.5); }); it("chooses white text for a dark button when configured text fails", () => { expect(readableColor("#777777", ["#111827"], 4.5)).toBe("#ffffff"); }); it("preserves unsupported custom colors instead of corrupting CSS", () => { expect(readableColor("rgb(1, 2, 3)", ["#ffffff"], 4.5)).toBe("rgb(1, 2, 3)"); }); });