summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_css_variables.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/tests/test_css_variables.py')
-rw-r--r--packages/meshbay-hub/tests/test_css_variables.py78
1 files changed, 78 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_css_variables.py b/packages/meshbay-hub/tests/test_css_variables.py
new file mode 100644
index 0000000..ec576d6
--- /dev/null
+++ b/packages/meshbay-hub/tests/test_css_variables.py
@@ -0,0 +1,78 @@
+"""
+Every `var(--x)` names a variable this stylesheet defines.
+
+CSS fails silently and generously: an unknown custom property makes the whole
+declaration invalid, and the rule around it still applies. So a panel written
+`background: var(--bg-panel)` when the palette calls it `--bg-surface` does not
+error, does not warn, and does not look obviously wrong in a diff — it just has
+no background, and the page shows straight through the modal.
+
+That is not hypothetical. It shipped in the folder picker, and the same file
+already carried one from before: `.notif-badge` asked for `--danger` where the
+palette says `--error`, so the unread count was white text on nothing. Found by
+a person looking at a screenshot, which is the only thing that was going to
+find it.
+
+A fallback (`var(--x, #ef4444)`) is a lesser version of the same mistake: the
+declaration is valid and renders, but the name is still fiction, and the next
+reader is told a variable exists that does not. Those are reported separately.
+
+There was a third check here, comparing the dark palette against the light one
+for anything a theme must not inherit. It fired on `--border-focus`, which is
+a focus ring deliberately shared by both themes — correct code. A heuristic
+that has to be explained away on its first run is worse than no test, so it is
+gone rather than exempted.
+"""
+
+import re
+from pathlib import Path
+
+import pytest
+
+STYLE = (Path(__file__).resolve().parents[1] / "src" / "meshbay_hub"
+ / "static" / "style.css")
+
+pytestmark = pytest.mark.skipif(not STYLE.exists(),
+ reason="the stylesheet is not in this checkout")
+
+# Where a custom property is defined. Two forms, and both had to be learned
+# the hard way while writing this: a scoped one written inline
+# (`.video-overview-wrap { --ov-lh: 1.5em; --ov-lines: 3; }`), which an
+# anchored pattern misses, and one preceded by an explanatory comment, which a
+# `[{;]`-prefixed pattern misses because the character before it is `/`. Either
+# mistake reports correct code as broken, which is the fastest way to have a
+# test like this ignored.
+DEFINE = re.compile(r"(?:^|[{;])\s*(--[A-Za-z0-9_-]+)\s*:", re.M)
+# `var(--name` and `var(--name, fallback`.
+USE = re.compile(r"var\(\s*(--[A-Za-z0-9_-]+)\s*(,)?")
+
+
+def _text() -> str:
+ return STYLE.read_text(encoding="utf-8")
+
+
+def test_every_variable_used_without_a_fallback_is_defined():
+ source = _text()
+ defined = set(DEFINE.findall(source))
+ assert defined, "no custom properties found — did the palette move?"
+
+ missing = sorted({name for name, fallback in USE.findall(source)
+ if not fallback and name not in defined})
+ assert not missing, (
+ "used but never defined, so every declaration naming one of these is "
+ "invalid and silently does nothing:\n " + "\n ".join(missing))
+
+
+def test_a_fallback_does_not_excuse_an_unknown_name():
+ """
+ `var(--danger, #ef4444)` renders, so it is not the same bug — but it is the
+ same mistake, and it will read as intentional to the next person. Reported
+ so the name gets corrected rather than the fallback relied on.
+ """
+ source = _text()
+ defined = set(DEFINE.findall(source))
+ guessed = sorted({name for name, fallback in USE.findall(source)
+ if fallback and name not in defined})
+ assert not guessed, (
+ "used with a fallback but not defined anywhere — rename to the real "
+ "variable:\n " + "\n ".join(guessed))