"""v1.1 WP-E: the contrast audit is a gate, not a report. Before this package `tools/contrast_audit.py` measured control boundaries, printed that two of them were below 3:1, and exited 0 anyway — on the argument that a control is identified by its label rather than its edge. A check that cannot fail is not a check, and these tests are what make it one: the threshold is exercised from both sides, on a real tokens file, so a future palette change that dims a control's edge stops the run instead of adding a line to it. python -m pytest tests/test_v11_e_contrast.py -v """ import sys from pathlib import Path import pytest sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "tools")) import contrast_audit as audit # noqa: E402 # --------------------------------------------------------------- the maths def test_the_ratio_is_the_wcag_ratio(): """Anchored on values with known answers, so a broken formula is visible.""" assert audit.ratio("#ffffff", "#000000") == pytest.approx(21.0, abs=0.01) assert audit.ratio("#ffffff", "#ffffff") == pytest.approx(1.0, abs=0.001) # Order does not matter: contrast is symmetric. assert audit.ratio("#131320", "#676792") == pytest.approx( audit.ratio("#676792", "#131320"), abs=1e-9) # ------------------------------------------------------- the gate itself def tokens_file(tmp_path: Path, **overrides: str) -> Path: """A real tokens file with named colours replaced.""" source = audit.TOKENS.read_text() for name, value in overrides.items(): token = "--" + name.replace("_", "-") start = source.index(f"{token}: ") end = source.index(";", start) source = source[:start] + f"{token}: {value}" + source[end:] written = tmp_path / "tokens.css" written.write_text(source) return written def run_against(path: Path, monkeypatch) -> int: monkeypatch.setattr(audit, "TOKENS", path) return audit.main() def test_a_boundary_below_three_to_one_fails_the_run(tmp_path, monkeypatch, capsys): """2.99:1 against --bg-input — the wrong side of the line by one hundredth. This value clears 3:1 against --bg-panel (3.21:1), so it would have passed the audit as M11 wrote it. It fails now because the floor is taken against the background the control is actually drawn on. """ below = tokens_file(tmp_path, border="#58639a") assert run_against(below, monkeypatch) == 1 printed = capsys.readouterr().out assert "2.99:1" in printed assert "FAIL" in printed assert "below 3:1 (WCAG 1.4.11)" in printed def test_a_boundary_at_three_to_one_passes(tmp_path, monkeypatch, capsys): """3.00:1 — the right side of the same line, one hundredth from the value above, and not failed for arithmetic the reader cannot see.""" at = tokens_file(tmp_path, border="#58639b") assert run_against(at, monkeypatch) == 0 printed = capsys.readouterr().out assert "3.00:1" in printed assert "every control boundary clears 3:1" in printed def test_the_v1_0_0_boundary_would_now_fail(tmp_path, monkeypatch, capsys): """The value v1.0.0 shipped. This is the defect WP-E closes, and the gate has to be the thing that would have caught it.""" shipped = tokens_file(tmp_path, border="#2b2b3d") assert run_against(shipped, monkeypatch) == 1 assert "1.24:1" in capsys.readouterr().out # against --bg-input, the worst case def test_a_text_pair_below_four_point_five_still_fails(tmp_path, monkeypatch, capsys): """WP-E raised the boundary floor and must not have lowered the text one.""" dimmed = tokens_file(tmp_path, text_dim="#5a5750") assert run_against(dimmed, monkeypatch) == 1 assert "below WCAG AA (1.4.3)" in capsys.readouterr().out def test_a_missing_token_is_a_failure_not_a_skip(tmp_path, monkeypatch, capsys): source = audit.TOKENS.read_text().replace("--border-bright:", "--border-was-renamed:") written = tmp_path / "tokens.css" written.write_text(source) assert run_against(written, monkeypatch) == 1 assert "MISSING TOKEN" in capsys.readouterr().out # ------------------------------------------------- the shipped palette def test_the_real_tokens_pass_both_criteria(capsys): """The palette as it stands, through the same gate CI would run.""" assert audit.main() == 0 printed = capsys.readouterr().out assert "every text pair clears WCAG AA (1.4.3)" in printed assert "every control boundary clears 3:1 (1.4.11)" in printed assert "FAIL" not in printed def test_every_boundary_pair_is_measured_against_the_background_it_is_drawn_on(): """The audit used to check borders only against --bg-panel, which is not where the bordered controls are: inputs and buttons sit on --bg-input (styles/forms.css), which is lighter and therefore harder. Checking only the easier background would let a token pass while the real control failed.""" boundary = [(fg, bg) for kind, fg, bg, _, _ in audit.PAIRS if kind == "boundary"] for background in ("--bg-input", "--bg-panel", "--bg"): assert ("--border", background) in boundary, background assert ("--border-bright", "--bg-input") in boundary def test_the_text_baselines_are_unchanged_by_wp_e(): """WP-E changed only boundary tokens. These are the M11 text measurements, and they have to still be exactly what the earlier reports recorded.""" tokens = audit.read_tokens(audit.TOKENS) measured = { "body text on the page": audit.ratio(tokens["--text"], tokens["--bg"]), "body text in a panel": audit.ratio(tokens["--text"], tokens["--bg-panel"]), "secondary text in a panel": audit.ratio(tokens["--text-dim"], tokens["--bg-panel"]), "secondary text on the page": audit.ratio(tokens["--text-dim"], tokens["--bg"]), } assert measured["body text on the page"] == pytest.approx(14.57, abs=0.01) assert measured["body text in a panel"] == pytest.approx(13.57, abs=0.01) assert measured["secondary text in a panel"] == pytest.approx(5.48, abs=0.01) assert measured["secondary text on the page"] == pytest.approx(5.88, abs=0.01) def test_the_hover_edge_stays_brighter_than_the_resting_edge(): """Rest and hover have to remain distinguishable from each other, not merely each clear the floor against the background.""" tokens = audit.read_tokens(audit.TOKENS) panel = tokens["--bg-panel"] assert audit.ratio(tokens["--border-bright"], panel) > audit.ratio(tokens["--border"], panel) def test_a_boundary_never_becomes_as_loud_as_body_text(): """A control's edge that outshines the words inside it is its own defect.""" tokens = audit.read_tokens(audit.TOKENS) panel = tokens["--bg-panel"] assert audit.ratio(tokens["--border-bright"], panel) < audit.ratio(tokens["--text"], panel)