from __future__ import annotations import re import unittest from collections import defaultdict from pathlib import Path from tests.frontend_test_helpers import assembled_frontend_document ROOT = Path(__file__).resolve().parents[1] STATIC = ROOT / "frontend" TOKENS = STATIC / "shared" / "tokens.css" MODULE_STYLESHEETS = ( "shared/base.css", "shared/shell.css", "shared/auth.css", "shared/components/controls.css", "shared/components/navigation.css", "shared/components/cards.css", "shared/components/tables.css", "shared/components/dialogs.css", "shared/components/feedback.css", "pages/market/foundation.css", "pages/sentiment/foundation.css", "pages/pools/foundation.css", "pages/ladder/foundation.css", "pages/rotation/foundation.css", "pages/auction/foundation.css", "pages/themes/foundation.css", "pages/popularity/foundation.css", "pages/dragon-tiger/foundation.css", "pages/screener/foundation.css", "pages/mentor/foundation.css", "pages/heaven/foundation.css", "pages/review/foundation.css", ) RETIRED_STYLESHEETS = ( "styles/styles.css", "styles/renovation.css", "styles/redesign-v2.css", "styles/design-system.css", "styles/theme.css", "pages/heaven/page.css", ) PAGE_OWNERS = { "sentimentCycleView": "pages/sentiment/foundation.css", "limitPool": "pages/pools/foundation.css", "brokenView": "pages/pools/foundation.css", "downView": "pages/pools/foundation.css", "yesterdayView": "pages/pools/foundation.css", "performanceView": "pages/pools/foundation.css", "ladderView": "pages/ladder/foundation.css", "rotationView": "pages/rotation/foundation.css", "auctionView": "pages/auction/foundation.css", "themeLibraryView": "pages/themes/foundation.css", "popularityView": "pages/popularity/foundation.css", "dragonView": "pages/dragon-tiger/foundation.css", "screenerView": "pages/screener/foundation.css", "screenerTrackingView": "pages/screener/foundation.css", "mentorView": "pages/mentor/foundation.css", "heavenView": "pages/heaven/foundation.css", "reviewWorkspaceView": "pages/review/foundation.css", } SHARED_ROOT_OWNERS = { ".app-header": "shared/shell.css", ".app-main": "shared/shell.css", ".module-nav": "shared/shell.css", ".overview-strip": "shared/shell.css", ".sidebar": "shared/shell.css", ".status-bar": "shared/shell.css", ".workspace-view": "shared/shell.css", ".button": "shared/components/controls.css", ".icon-button": "shared/components/controls.css", ".segment": "shared/components/navigation.css", ".data-table": "shared/components/tables.css", ".card": "shared/components/cards.css", ".dialog": "shared/components/dialogs.css", ".toast": "shared/components/feedback.css", } HISTORICAL_RUNTIME_CSS_BYTES = 861_341 HISTORICAL_SELECTOR_CONTEXT_RULES = 8_569 def normalize(value: str) -> str: return re.sub(r"\s+", " ", re.sub(r"/\*.*?\*/", "", value, flags=re.DOTALL)).strip() def normalize_context(value: str) -> str: """Normalize equivalent at-rule spellings before ownership checks.""" return re.sub(r"\s*([():,])\s*", r"\1", normalize(value)) def skip_space_and_comments(text: str, position: int) -> int: while position < len(text): if text[position].isspace(): position += 1 elif text.startswith("/*", position): closing = text.find("*/", position + 2) position = len(text) if closing < 0 else closing + 2 else: break return position def find_delimiter(text: str, position: int) -> tuple[int, str]: quote = "" escaped = False depth = 0 in_comment = False while position < len(text): char = text[position] pair = text[position : position + 2] if in_comment: if pair == "*/": in_comment = False position += 2 continue position += 1 continue if quote: if escaped: escaped = False elif char == "\\": escaped = True elif char == quote: quote = "" position += 1 continue if pair == "/*": in_comment = True position += 2 continue if char in "\"'": quote = char elif char in "([": depth += 1 elif char in ")]": depth = max(0, depth - 1) elif depth == 0 and char in "{;": return position, char position += 1 return len(text), "" def find_closing_brace(text: str, opening: int) -> int: depth = 1 position = opening + 1 quote = "" escaped = False in_comment = False while position < len(text): char = text[position] pair = text[position : position + 2] if in_comment: if pair == "*/": in_comment = False position += 2 continue position += 1 continue if quote: if escaped: escaped = False elif char == "\\": escaped = True elif char == quote: quote = "" position += 1 continue if pair == "/*": in_comment = True position += 2 continue if char in "\"'": quote = char elif char == "{": depth += 1 elif char == "}": depth -= 1 if depth == 0: return position position += 1 raise AssertionError(f"unclosed CSS block at offset {opening}") def split_selectors(prelude: str) -> list[str]: selectors: list[str] = [] start = 0 quote = "" escaped = False depth = 0 for index, char in enumerate(prelude): if quote: if escaped: escaped = False elif char == "\\": escaped = True elif char == quote: quote = "" continue if char in "\"'": quote = char elif char in "([": depth += 1 elif char in ")]": depth = max(0, depth - 1) elif char == "," and depth == 0: selectors.append(normalize(prelude[start:index])) start = index + 1 selectors.append(normalize(prelude[start:])) return [selector for selector in selectors if selector] def stylesheet_rule_keys(text: str, contexts: tuple[str, ...] = ()) -> list[tuple[tuple[str, ...], str]]: keys: list[tuple[tuple[str, ...], str]] = [] position = 0 while True: position = skip_space_and_comments(text, position) if position >= len(text): return keys delimiter, kind = find_delimiter(text, position) prelude = normalize(text[position:delimiter]) if not kind: raise AssertionError(f"unparsed CSS tail: {prelude[:80]}") if kind == ";": position = delimiter + 1 continue closing = find_closing_brace(text, delimiter) body = text[delimiter + 1 : closing] lowered = prelude.lower() if lowered.startswith(("@media", "@supports", "@container", "@layer", "@starting-style", "@scope")): keys.extend(stylesheet_rule_keys(body, contexts + (normalize_context(prelude),))) elif lowered.startswith(("@keyframes", "@-webkit-keyframes")): keys.append((contexts, prelude)) elif not prelude.startswith("@"): keys.extend((contexts, selector) for selector in split_selectors(prelude)) position = closing + 1 def declaration_properties(body: str) -> frozenset[str]: properties: set[str] = set() start = 0 position = 0 quote = "" escaped = False depth = 0 in_comment = False while position <= len(body): char = body[position] if position < len(body) else ";" pair = body[position : position + 2] if in_comment: if pair == "*/": in_comment = False position += 2 continue position += 1 continue if quote: if escaped: escaped = False elif char == "\\": escaped = True elif char == quote: quote = "" position += 1 continue if pair == "/*": in_comment = True position += 2 continue if char in "\"'": quote = char elif char in "([": depth += 1 elif char in ")]": depth = max(0, depth - 1) elif char == ";" and depth == 0: declaration = normalize(body[start:position]) match = re.match(r"^(--[-a-zA-Z0-9_]+|[-a-zA-Z][-_a-zA-Z0-9]*)\s*:", declaration) if match: properties.add(match.group(1).lower()) start = position + 1 position += 1 return frozenset(properties) def stylesheet_rules( text: str, contexts: tuple[str, ...] = (), ) -> list[tuple[tuple[str, ...], str, frozenset[str]]]: rules: list[tuple[tuple[str, ...], str, frozenset[str]]] = [] position = 0 while True: position = skip_space_and_comments(text, position) if position >= len(text): return rules delimiter, kind = find_delimiter(text, position) prelude = normalize(text[position:delimiter]) if not kind: raise AssertionError(f"unparsed CSS tail: {prelude[:80]}") if kind == ";": position = delimiter + 1 continue closing = find_closing_brace(text, delimiter) body = text[delimiter + 1 : closing] lowered = prelude.lower() if lowered.startswith(("@media", "@supports", "@container", "@layer", "@starting-style", "@scope")): rules.extend(stylesheet_rules(body, contexts + (normalize_context(prelude),))) elif not prelude.startswith("@"): properties = declaration_properties(body) rules.extend((contexts, selector, properties) for selector in split_selectors(prelude)) position = closing + 1 def remove_page_scope(selector: str, view_id: str) -> str: prefixes = ( rf":where\(#{re.escape(view_id)}\)\s+", rf"#{re.escape(view_id)}\s+", rf"body\[data-active-view=[\"']{re.escape(view_id)}[\"']\]\s+", ) semantic = selector for prefix in prefixes: semantic = re.sub(rf"^(?P:root(?:\[[^\]]+\])?\s+)?{prefix}", r"\g", semantic) return normalize(semantic) def find_matching_parenthesis(value: str, opening: int) -> int: depth = 1 quote = "" escaped = False for position in range(opening + 1, len(value)): char = value[position] if quote: if escaped: escaped = False elif char == "\\": escaped = True elif char == quote: quote = "" continue if char in "\"'": quote = char elif char == "(": depth += 1 elif char == ")": depth -= 1 if depth == 0: return position raise AssertionError(f"unclosed selector function: {value}") def prune_selector_consumers( selector: str, source: str, dynamic_prefixes: set[str], ) -> tuple[str, bool, bool]: output: list[str] = [] cursor = 0 changed = False function_pattern = re.compile(r":(is|where|has|not)\(", re.IGNORECASE) while match := function_pattern.search(selector, cursor): opening = match.end() - 1 closing = find_matching_parenthesis(selector, opening) output.append(selector[cursor : match.start()]) name = match.group(1).lower() content = selector[opening + 1 : closing] arguments = split_selectors(content) retained: list[str] = [] nested_changed = False for argument in arguments: pruned, reachable, argument_changed = prune_selector_consumers(argument, source, dynamic_prefixes) nested_changed |= argument_changed if reachable: retained.append(pruned) else: nested_changed = True if name != "not" and not retained: return selector, False, True if name == "not" and not retained: changed = True elif nested_changed or len(retained) != len(arguments): output.append(f":{name}({', '.join(retained)})") changed = True else: output.append(selector[match.start() : closing + 1]) cursor = closing + 1 output.append(selector[cursor:]) pruned_selector = "".join(output) tokens = { match.group(2) for match in re.finditer(r"([.#])([_a-zA-Z][-_a-zA-Z0-9]*)", pruned_selector) } reachable = all( token in source or any(token.startswith(prefix) for prefix in dynamic_prefixes) for token in tokens ) return pruned_selector, reachable, changed or not reachable class CssGovernanceTests(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.html = assembled_frontend_document() cls.tokens = TOKENS.read_text(encoding="utf-8") cls.modules = { relative: (STATIC / relative).read_text(encoding="utf-8") for relative in MODULE_STYLESHEETS } cls.rule_keys = { relative: stylesheet_rule_keys(stylesheet) for relative, stylesheet in cls.modules.items() } cls.rules = { relative: stylesheet_rules(stylesheet) for relative, stylesheet in cls.modules.items() } cls.runtime_source = "\n".join( path.read_text(encoding="utf-8") for path in STATIC.rglob("*") if path.is_file() and path.suffix in {".html", ".js", ".mjs"} and "_css_core_before" not in path.parts and path.name != "css-core-before.html" ) cls.dynamic_class_prefixes = { *re.findall(r"([_a-zA-Z][-_a-zA-Z0-9]*)\$\{", cls.runtime_source), *re.findall(r'["\']([_a-zA-Z][-_a-zA-Z0-9]*)["\']\s*\+', cls.runtime_source), } def test_runtime_loads_only_the_canonical_stylesheet_stack(self) -> None: expected = ("shared/tokens.css", *MODULE_STYLESHEETS) positions = [self.html.index(f'/{path}') for path in expected] self.assertEqual(positions, sorted(positions)) self.assertEqual(self.html.count(' None: for relative in RETIRED_STYLESHEETS: self.assertFalse((STATIC / relative).exists(), relative) self.assertNotIn(f'/{relative}', self.html) for name in ("legacy.css", "override.css", "fix.css"): self.assertFalse(any(STATIC.rglob(name)), name) def test_every_module_declares_its_owner_and_is_nonempty(self) -> None: for relative, stylesheet in self.modules.items(): owner = Path(relative).parent.name if "/pages/" in f"/{relative}" else Path(relative).stem if relative.startswith("shared/components/"): owner = Path(relative).stem self.assertTrue( stylesheet.startswith( f"/* Canonical CSS owner: {owner}. Historical layers consolidated 2026-08-02. */" ), relative, ) self.assertIn("{", stylesheet, relative) def test_modules_do_not_contain_empty_declarations(self) -> None: for relative, stylesheet in self.modules.items(): self.assertNotRegex(stylesheet, r"(?m)^\s*[-_a-zA-Z0-9]+:\s*;\s*$", relative) def test_selector_and_context_have_exactly_one_owner(self) -> None: owners: dict[tuple[tuple[str, ...], str], list[str]] = defaultdict(list) for relative, keys in self.rule_keys.items(): for key in keys: owners[key].append(relative) duplicates = { f"{' > '.join(contexts) or ''} :: {selector}": paths for (contexts, selector), paths in owners.items() if len(paths) != 1 } self.assertEqual(duplicates, {}) def test_page_ids_only_appear_in_their_owner_stylesheet(self) -> None: for relative, stylesheet in self.modules.items(): for view_id, owner in PAGE_OWNERS.items(): if re.search(rf"(?:#{re.escape(view_id)}|data-active-view=[\"']{re.escape(view_id)})", stylesheet): self.assertIn(relative, (owner, "shared/shell.css"), f"{view_id} leaked into {relative}") def test_unscoped_shared_roots_stay_in_their_shared_owner(self) -> None: for relative, keys in self.rule_keys.items(): for contexts, selector in keys: owner = SHARED_ROOT_OWNERS.get(selector) page_scoped = any(any(f"#{view_id}" in context for view_id in PAGE_OWNERS) for context in contexts) if owner and not page_scoped: self.assertEqual(relative, owner, f"{selector} leaked into {relative}") def test_historical_shell_aliases_cannot_return(self) -> None: class_tokens = { token for value in re.findall(r'class=["\']([^"\']*)["\']', self.html) for token in value.split() } self.assertTrue({"app-header", "module-nav", "overview-strip", "status-bar"} <= class_tokens) self.assertTrue({"topbar", "statusbar", "mktstrip", "brand", "logo"}.isdisjoint(class_tokens)) selector_text = "\n".join( selector for keys in self.rule_keys.values() for _contexts, selector in keys ) for alias in ("topbar", "statusbar", "mktstrip"): self.assertNotRegex(selector_text, rf"(? None: exact_owners = { ".lucide": "shared/components/controls.css", ".visually-hidden": "shared/base.css", } for selector, expected_owner in exact_owners.items(): owners = [ relative for relative, keys in self.rule_keys.items() if any(candidate == selector for _contexts, candidate in keys) ] self.assertEqual(owners, [expected_owner], selector) for relative, keys in self.rule_keys.items(): for _contexts, selector in keys: if ".wentian-v2-dialog" in selector: self.assertEqual(relative, "pages/heaven/foundation.css", selector) if re.search(r"\.admin-dialog\s+\.model-", selector): self.assertEqual(relative, "shared/components/dialogs.css", selector) def test_page_scope_variants_never_override_the_same_property(self) -> None: conflicts: dict[str, list[str]] = defaultdict(list) for view_id, owner in PAGE_OWNERS.items(): variants: dict[tuple[tuple[str, ...], str], list[tuple[str, frozenset[str]]]] = defaultdict(list) for contexts, selector, properties in self.rules[owner]: semantic = remove_page_scope(selector, view_id) if semantic != selector: variants[(contexts, semantic)].append((selector, properties)) for (contexts, semantic), rows in variants.items(): unique_selectors = {selector for selector, _properties in rows} if len(unique_selectors) < 2: continue for index, (left_selector, left_properties) in enumerate(rows): for right_selector, right_properties in rows[index + 1 :]: if left_selector == right_selector: continue overlap = sorted(left_properties & right_properties) if overlap: context = " > ".join(contexts) or "" conflicts[owner].append( f"{context} :: {semantic} :: {left_selector} <> {right_selector}: {overlap}" ) details = "\n".join( f"{owner}: {detail}" for owner, owner_conflicts in conflicts.items() for detail in owner_conflicts ) self.assertFalse(conflicts, details) def test_every_selector_has_a_runtime_consumer(self) -> None: stale: list[str] = [] for relative, keys in self.rule_keys.items(): for contexts, selector in keys: if selector.lower().startswith(("@keyframes", "@-webkit-keyframes")): continue _pruned, reachable, changed = prune_selector_consumers( selector, self.runtime_source, self.dynamic_class_prefixes, ) if not reachable or changed: context = " > ".join(contexts) or "" stale.append(f"{relative}: {context} :: {selector}") self.assertEqual(stale, []) def test_runtime_css_is_smaller_and_has_fewer_rules(self) -> None: total_bytes = sum((STATIC / path).stat().st_size for path in MODULE_STYLESHEETS) total_rules = sum(len(keys) for keys in self.rule_keys.values()) self.assertLess(total_bytes, HISTORICAL_RUNTIME_CSS_BYTES) self.assertLess(total_rules, HISTORICAL_SELECTOR_CONTEXT_RULES) def test_token_file_has_three_layer_contract(self) -> None: for heading in ( "/* Primitive tokens */", "/* Semantic tokens */", "/* Component tokens */", "/* Compatibility aliases.", ): self.assertIn(heading, self.tokens) for variable in ( "--color-action:", "--surface-canvas:", "--text-primary:", "--card-bg:", "--control-height:", "--sidebar-width:", ): self.assertIn(variable, self.tokens) def test_light_and_dark_semantics_share_one_owner(self) -> None: self.assertIn(':root[data-theme="dark"] {', self.tokens) global_root = re.compile(r'(?m)^:root(?:\[data-theme="dark"\])?\s*\{') for filename, stylesheet in self.modules.items(): self.assertIsNone(global_root.search(stylesheet), filename) def test_wentian_tokens_remain_isolated(self) -> None: self.assertNotRegex(self.tokens, r"--wt-[a-z0-9-]+\s*:") wentian = self.modules["pages/heaven/foundation.css"] self.assertRegex(wentian, r"--wt-[a-z0-9-]+\s*:") def test_compatibility_aliases_cover_historical_layers(self) -> None: for variable in ( "--blue:", "--up:", "--xb-blue-500:", "--r2-blue:", "--chart-background:", "--dragon-profile-list-width:", ): self.assertIn(variable, self.tokens) if __name__ == "__main__": unittest.main()