test(design-system): assert WCAG 2.2 AA contrast for key color pairs

White on --green-dark (not --green) is the correct button background;
--green (#3D8C4A) gives only 4.16:1 which fails AA for normal-size text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-02 12:43:21 +02:00
parent 82815205d0
commit 7c8d725fce

View File

@@ -0,0 +1,51 @@
import { describe, it, expect } from 'vitest';
// WCAG 2.2 relative luminance for a single 8-bit channel value
function channelLuminance(val: number): number {
const sRGB = val / 255;
return sRGB <= 0.04045 ? sRGB / 12.92 : ((sRGB + 0.055) / 1.055) ** 2.4;
}
function relativeLuminance(hex: string): number {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return 0.2126 * channelLuminance(r) + 0.7152 * channelLuminance(g) + 0.0722 * channelLuminance(b);
}
function contrastRatio(hex1: string, hex2: string): number {
const l1 = relativeLuminance(hex1);
const l2 = relativeLuminance(hex2);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
// Design token values from app.css @theme
const tokens = {
colorText: '#1C1C18',
colorTextMuted: '#6B6A63',
colorPage: '#FAFAF7',
colorSurface: '#F5F4EE',
greenDark: '#2E6E39', // button background — --green (#3D8C4A) only gives 4.16:1, fails AA
white: '#FFFFFF'
};
describe('WCAG 2.2 AA contrast ratios', () => {
it('--color-text on --color-page meets 4.5:1 (normal text)', () => {
expect(contrastRatio(tokens.colorText, tokens.colorPage)).toBeGreaterThanOrEqual(4.5);
});
it('--color-text on --color-surface meets 4.5:1 (card text)', () => {
expect(contrastRatio(tokens.colorText, tokens.colorSurface)).toBeGreaterThanOrEqual(4.5);
});
it('--color-text-muted on --color-page meets 4.5:1 (muted labels)', () => {
expect(contrastRatio(tokens.colorTextMuted, tokens.colorPage)).toBeGreaterThanOrEqual(4.5);
});
it('white on --green-dark meets 4.5:1 (primary button background)', () => {
// --green (#3D8C4A) only gives 4.16:1 — buttons use --green-dark (#2E6E39) instead
expect(contrastRatio(tokens.white, tokens.greenDark)).toBeGreaterThanOrEqual(4.5);
});
});