"""The CI-side token check (#2277).
The checker is stdlib-only and lives in scripts/ so CI can run it without an
install, so these tests import it by path rather than as a package.
Two properties matter more than the parsing: it must not fire on a COMMENT that
discusses a rule, and it must not fire on a longer literal that merely contains a
shorter one. Both would make the report untrustworthy, and an untrustworthy
report is worse than none — people stop reading it and the check stops working
while still passing.
"""
import importlib.util
import pathlib
import pytest
_PATH = pathlib.Path(__file__).resolve().parents[1] / "scripts" / "check_design_tokens.py"
_spec = importlib.util.spec_from_file_location("check_design_tokens", _PATH)
check = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(check)
SHEET = """
:root {
/* surface */
--fs-surface-page: #14171A; /* page bg */
--fs-text-primary: #E8E4D8;
}
/* SUPERSEDES — write the token, not the literal.
* #fff -> --fs-text-primary
* #ffffff -> --fs-text-primary
* bold -> --fs-weight-medium
*/
"""
# --- reading the sheet ------------------------------------------------------
def test_declarations_after_a_comment_are_not_lost():
"""Anchored on the colon alone. Anchoring on `{` or `;` silently drops every
declaration that follows a comment — a mistake made once already in this
codebase, which lost three tokens without erroring."""
assert check.declared_tokens(SHEET) == {"--fs-surface-page", "--fs-text-primary"}
def test_the_supersedes_block_is_read_from_the_sheet_not_hardcoded():
"""Rule #115: the checker must know nothing about any install's palette.
Everything it enforces comes out of the stylesheet it is pointed at."""
assert check.superseded_literals(SHEET) == {
"#fff": "--fs-text-primary",
"#ffffff": "--fs-text-primary",
"bold": "--fs-weight-medium",
}
def test_a_sheet_with_no_supersedes_block_yields_nothing():
assert check.superseded_literals(":root { --a: 1px; }") == {}
# --- the literal matcher ----------------------------------------------------
def test_a_short_hex_does_not_match_inside_a_longer_one():
"""`#fff` firing on `#ffffff` would send someone to change correct code."""
assert check._literal_pattern("#fff").search("color: #ffffff;") is None
assert check._literal_pattern("#fff").search("color: #fff;") is not None
def test_the_match_is_case_insensitive():
assert check._literal_pattern("#ffffff").search("color: #FFFFFF;") is not None
def test_a_keyword_does_not_match_inside_a_longer_word():
"""`bold` must not fire on `font-weight: bolder` or a class named
`.bold-label` — the boundary is what keeps the report readable."""
assert check._literal_pattern("bold").search("font-weight: bolder;") is None
assert check._literal_pattern("bold").search(".bold-label { }") is None
assert check._literal_pattern("bold").search("font-weight: bold;") is not None
# --- reading a component ----------------------------------------------------
def test_only_the_style_block_of_an_sfc_is_read(tmp_path):
"""A hex in a template attribute or a script string is not a stylesheet
violation, and reporting it would bury the ones that are."""
sfc = tmp_path / "X.vue"
sfc.write_text(
'white
\n'
'\n'
'\n'
)
css = check.style_source(sfc)
assert "--fs-text-primary" in css
assert "#fff" not in css
def test_a_comment_explaining_a_rule_is_not_a_violation(tmp_path):
"""LOAD-BEARING, and it fired on the first real run. A comment documenting
why a literal is avoided necessarily contains that literal — this codebase's
own stylesheet says so about `#fff`. A checker that flags the documentation
of a rule teaches people to stop documenting rules."""
sfc = tmp_path / "Y.vue"
sfc.write_text(
"\n"
)
css = check.style_source(sfc)
assert check._literal_pattern("#fff").search(css) is None
def test_a_plain_css_file_is_read_whole(tmp_path):
css_file = tmp_path / "shared.css"
css_file.write_text(".a { color: #fff; }")
assert "#fff" in check.style_source(css_file)
# --- the gate ---------------------------------------------------------------
def _run(tmp_path, sheet: str, component: str, monkeypatch, capsys):
(tmp_path / "assets").mkdir(parents=True, exist_ok=True)
sheet_path = tmp_path / "assets" / "theme.css"
sheet_path.write_text(sheet)
(tmp_path / "C.vue").write_text(f"")
monkeypatch.setattr(
"sys.argv",
["check", "--sheet", str(sheet_path), "--root", str(tmp_path)],
)
code = check.main()
return code, capsys.readouterr().out
def test_an_unresolvable_reference_fails_the_build(tmp_path, monkeypatch, capsys):
"""The one hard gate. It is safe to gate on because the count is zero today —
a ratchet holding a line already reached, not a backlog that keeps CI red."""
code, out = _run(tmp_path, SHEET, ".a { color: var(--nope); }", monkeypatch, capsys)
assert code == 1
assert "--nope" in out
def test_a_resolvable_reference_passes(tmp_path, monkeypatch, capsys):
code, out = _run(
tmp_path, SHEET, ".a { color: var(--fs-text-primary); }", monkeypatch, capsys
)
assert code == 0
assert "every var() reference resolves" in out
def test_a_locally_declared_property_is_not_unresolved(tmp_path, monkeypatch, capsys):
"""A component may legitimately define its own custom property for local use —
a keyframe variable, a per-instance override. Only a reference to a name that
exists NOWHERE is broken."""
code, _ = _run(
tmp_path, SHEET, ".a { --local: 4px; padding: var(--local); }", monkeypatch, capsys
)
assert code == 0
def test_a_superseded_literal_reports_but_does_not_fail(tmp_path, monkeypatch, capsys):
"""Hundreds exist. Gating would make a permanently-red job, which is a check
nobody reads — worse than no check at all."""
code, out = _run(tmp_path, SHEET, ".a { color: #fff; }", monkeypatch, capsys)
assert code == 0
assert "#fff -> --fs-text-primary" in out
def test_a_missing_stylesheet_is_an_error_not_a_pass(tmp_path, monkeypatch, capsys):
"""If the sheet moves, the check must fail loudly rather than silently
passing with zero tokens to compare against — which would look identical to
a clean run."""
monkeypatch.setattr(
"sys.argv", ["check", "--sheet", str(tmp_path / "gone.css"), "--root", str(tmp_path)]
)
assert check.main() == 2