import { describe, expect, test } from 'vitest'; import { READER_THEMES } from './readerThemes.js'; // WCAG relative luminance and contrast ratio const luminance = (hex) => { const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255) .map((c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4)); return 0.2126 * r + 0.7152 * g + 0.0722 * b; }; const contrast = (a, b) => { const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x); return (hi + 0.05) / (lo + 0.05); }; // Small text needs 4.5:1. These are the pairings the app actually draws. describe.each(Object.entries(READER_THEMES))('%s theme contrast', (_id, { vars }) => { const v = (name) => vars[`--r-${name}`]; test.each([ ['text', 'bg'], ['text', 'bar'], ['text', 'hl'], ['sub', 'bg'], ['sub', 'bar'], ['sub', 'hl'], ['accent', 'bg'], ['accent', 'bar'], ['danger', 'bg'], ['danger', 'bar'], ['on', 'accent'], ])('%s on %s is at least 4.5:1', (fg, bg) => { expect(contrast(v(fg), v(bg))).toBeGreaterThanOrEqual(4.5); }); });