65 lines
2.3 KiB
Python
65 lines
2.3 KiB
Python
"""Design-token checks for src/javis/gui/theme.py (WCAG 2.2 AA contrast)."""
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
import pytest
|
|
|
|
from javis.gui import theme
|
|
|
|
# (foreground, background) pairs rendered as text: need 4.5:1 (SC 1.4.3).
|
|
TEXT_PAIRS = [
|
|
("text", "bg"), ("text", "surface"), ("text", "surface2"), ("text", "input"),
|
|
("muted", "bg"), ("muted", "surface"), ("muted", "surface2"),
|
|
("accent", "bg"), ("accent", "surface"),
|
|
("on_accent", "primary"), ("on_accent", "primary_hover"),
|
|
("success", "bg"), ("error", "bg"), ("error", "error_bg"), ("warn_fg", "bg"),
|
|
("tool_fg", "tool_bg"), ("tool_muted", "tool_bg"), ("code_fg", "code_bg"),
|
|
("link", "bg"),
|
|
]
|
|
# Control boundaries and focus indicators: need 3:1 (SC 1.4.11).
|
|
UI_PAIRS = [
|
|
("stroke_strong", "bg"), ("stroke_strong", "surface"),
|
|
("focus", "bg"), ("focus", "surface"), ("primary", "bg"), ("on_accent", "primary"),
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize("name", sorted(theme.THEMES))
|
|
@pytest.mark.parametrize("fg,bg", TEXT_PAIRS)
|
|
def test_text_contrast(name, fg, bg):
|
|
t = theme.THEMES[name]
|
|
assert theme.contrast_ratio(t[fg], t[bg]) >= 4.5, f"{name}: {fg} on {bg}"
|
|
|
|
|
|
@pytest.mark.parametrize("name", sorted(theme.THEMES))
|
|
@pytest.mark.parametrize("fg,bg", UI_PAIRS)
|
|
def test_ui_contrast(name, fg, bg):
|
|
t = theme.THEMES[name]
|
|
assert theme.contrast_ratio(t[fg], t[bg]) >= 3.0, f"{name}: {fg} vs {bg}"
|
|
|
|
|
|
def test_palettes_share_keys():
|
|
assert set(theme.PAL_DARK) == set(theme.PAL_LIGHT)
|
|
|
|
|
|
def test_accent_hue_kept():
|
|
# The redesign must keep the brand colours of the dark theme.
|
|
assert theme.PAL_DARK["accent"].lower() == "#da7756"
|
|
assert theme.PAL_DARK["bg"] == "#1e1e1e"
|
|
|
|
|
|
def test_contrast_math():
|
|
assert theme.contrast_ratio("#000000", "#ffffff") == pytest.approx(21.0)
|
|
assert theme.readable_on("#DA7756") == "#1e1e1e"
|
|
assert theme.readable_on("#3c3c3c") == "#ffffff"
|
|
|
|
|
|
@pytest.mark.parametrize("name", sorted(theme.THEMES))
|
|
def test_qss_is_well_formed(name):
|
|
qss = theme.build_qss(theme.THEMES[name], "Segoe UI")
|
|
assert qss.count("{") == qss.count("}")
|
|
# every palette value used in the sheet is a full hex colour
|
|
for hex_color in re.findall(r"#[0-9a-fA-F]+\b", qss):
|
|
assert len(hex_color) in (4, 7), hex_color
|
|
assert "variant=\"primary\"" in qss
|