Review caught two soft spots in the loosened regex: the broadened pattern also matched the update-card wrapper, so a broken account block could hide behind the lookalike, and the \S wildcard could in principle walk across the closing quote into other markup. The match is now anchored to the displayTitle span that only the account block contains (bounded, stopping at any closing div), and every wildcard is restricted to non-quote characters so it can never leave the className attribute. Verified exactly one match at the account block on current sources; all three tests pass.
62 lines
2.7 KiB
Python
62 lines
2.7 KiB
Python
"""Regression guard: Studio text spans must not pair `leading-none` with
|
|
`truncate`, which clips glyph descenders (g, p, q, y, j) in visible labels.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
WORKDIR = Path(__file__).resolve().parents[2]
|
|
MODEL_SELECTOR = (
|
|
WORKDIR / "studio" / "frontend" / "src" / "components" / "assistant-ui" / "model-selector.tsx"
|
|
)
|
|
APP_SIDEBAR = WORKDIR / "studio" / "frontend" / "src" / "components" / "app-sidebar.tsx"
|
|
|
|
|
|
def _read(path: Path) -> str:
|
|
assert path.exists(), f"missing source file: {path}"
|
|
return path.read_text()
|
|
|
|
|
|
def test_model_selector_trigger_label_uses_leading_tight():
|
|
src = _read(MODEL_SELECTOR)
|
|
pattern = re.compile(
|
|
r'<span\s+className="[^"]*\bmin-w-0\b[^"]*\bflex-1\b[^"]*\btruncate\b[^"]*\bfont-heading\b[^"]*\btext-\[16px\][^"]*"',
|
|
)
|
|
matches = pattern.findall(src)
|
|
assert matches, "could not find ModelSelectorTrigger model-name span"
|
|
for cls in matches:
|
|
assert "leading-tight" in cls, f"expected leading-tight, got: {cls}"
|
|
assert "leading-none" not in cls, f"leading-none must not coexist with truncate here: {cls}"
|
|
|
|
|
|
def test_sidebar_account_block_uses_leading_tight():
|
|
src = _read(APP_SIDEBAR)
|
|
# Match the account-block parent div regardless of its gap utility or any
|
|
# sizing classes between flex and flex-col (min-w-0 flex-1 arrived with the
|
|
# long-name truncation work); this guard is about the leading-* class only.
|
|
# [^"\s] keeps the wildcard inside the className attribute, and the trailing
|
|
# displayTitle anchor pins the match to the account block itself so a
|
|
# lookalike wrapper (the update card) can never satisfy the guard.
|
|
pattern = re.compile(
|
|
r'<div\s+className="flex\s+(?:[^"\s]+\s+)*?flex-col\s+gap-[^"\s]+\s+([^"\s]+)\s+'
|
|
r'group-data-\[collapsible=icon\]:hidden">(?:(?!</div>)[\s\S]){0,400}?\{displayTitle\}',
|
|
)
|
|
matches = pattern.findall(src)
|
|
assert matches, "could not find sidebar account-block parent div"
|
|
leading_classes = [m for m in matches if m.startswith("leading-")]
|
|
assert leading_classes, f"no leading-* class on sidebar account-block parent: {matches}"
|
|
for cls in leading_classes:
|
|
assert cls == "leading-tight", f"sidebar account-block must use leading-tight, got: {cls}"
|
|
|
|
|
|
def test_no_truncate_plus_leading_none_in_changed_files():
|
|
for path in (MODEL_SELECTOR, APP_SIDEBAR):
|
|
src = _read(path)
|
|
for line in src.splitlines():
|
|
if "truncate" in line and "leading-none" in line:
|
|
raise AssertionError(
|
|
f"{path.name}: same line uses truncate + leading-none, descenders will clip: {line.strip()}"
|
|
)
|