"""552-2 부품 「단추」 · 「아이콘 단추」 · 「아이콘」 · 크기 여덟 단 지킴 시험 — 화면 확인은 ORCA. · 크기 = data-size 여덟 단(18 ~ 42) · 단마다 높이 · 글자 · 여백 · 아이콘 · 둥글기 · 옛 sm = 18 · 단추 높이 = 글 한 줄 + 여백 + 테두리 = 단(높이를 박지 않음 — 페이지 여백 덮어쓰기 그대로) · 상태 = :hover · :active 를 data-state 로도 받음 · 아이콘 단추 = title + aria-label · 색 = 공통 값만(날 색 · --b01-* · --draw-* 없음) · 옛 클래스 이름 그대로 · 부르는 길(ui_template_elements) 그대로 """ from __future__ import annotations import re from pathlib import Path ROOT = Path(__file__).resolve().parents[2] UI = ROOT / "ui_template" SIZES = [18, 20, 22, 24, 28, 32, 36, 42] def _text(path: Path) -> str: return path.read_text(encoding="utf-8") def _rungs(css: str) -> dict[int, dict[str, str]]: out = {} for size, body in re.findall(r':where\(\[data-size="(\d+)"\]\) \{([^}]*)\}', css): out[int(size)] = dict(re.findall(r"--ui-size-([\w-]+):\s*([^;]+);", body)) return out def test_여덟_단(): src = _text(UI / "ui_template_button.ts") assert "UI_SIZES = [18, 20, 22, 24, 28, 32, 36, 42] as const" in src rungs = _rungs(_text(UI / "ui_template_button.css")) assert sorted(rungs) == SIZES for size, v in rungs.items(): assert v["h"] == f"{size}px" assert set(v) == {"h", "font", "px", "icon", "radius", "gap"} # 글자 짝 — 18 ~ 24 = 12 · 28 이상 = 14 assert v["font"] == ("var(--text-caption)" if size <= 24 else "var(--text-body-sm)") # 아이콘 크기 — TS 짝과 같음 px = dict(re.findall(r"(\d+): (\d+)", re.search(r"ICON_PX[^{]*\{([^}]*)\}", src).group(1))) assert {int(k): f"{v}px" for k, v in px.items()} == {s: rungs[s]["icon"] for s in SIZES} def test_단추_높이_식(): css = _text(UI / "ui_template_button.css") rule = re.search(r"\.ui-btn\[data-size\] \{([^}]*)\}", css).group(1) assert "calc((var(--ui-size-h) - 2px - var(--ui-size-font)) / 2) var(--ui-size-px)" in rule assert "height" not in rule # 높이를 박지 않음 # 아이콘은 글 높이 안 — 단 높이가 아이콘 때문에 늘지 않음 assert "margin-block: calc((var(--ui-size-font) - var(--ui-size-icon)) / 2)" in css # 32 단 = 옛 기본(여백 8 · 글 14) · 18 단 = 옛 sm(여백 2 · 글 12) rungs = _rungs(css) assert (32 - 2 - 14) / 2 == 8 and rungs[32]["px"] == "16px" assert (18 - 2 - 12) / 2 == 2 and rungs[18]["px"] == "8px" and rungs[18]["radius"] == "4px" def test_옛_이름_부르는_길(): src = _text(UI / "ui_template_button.ts") assert 'opts.size === "sm" ? 18' in src assert 'opts.size === "sm" ? " ui-btn--sm" : ""' in src # 옛 클래스 그대로 for cls in ("ui-btn ui-btn--", "ui-btn__icon", "ui-btn__label", "ui-icon-btn ui-icon-btn--"): assert cls in src, cls elements = _text(UI / "ui_template_elements.ts") assert 'export * from "./ui_template_button";' in elements assert "export function createButton" not in elements # 한 벌 def test_상태(): styles = _text(UI / "ui_template_elements_styles.ts") for variant in ("filled", "ghost", "pill", "danger", "danger-ghost", "glass"): assert f'.ui-btn--{variant}:is(:hover, [data-state="hover"]):not(:disabled)' in styles assert '.ui-btn:is(:active, [data-state="active"]):not(:disabled)' in styles assert "--color-primary-hover" in styles css = _text(UI / "ui_template_button.css") assert '.ui-icon-btn:is(:hover, [data-state="hover"]):not(:disabled)' in css assert '.ui-icon-btn:is(:active, [data-state="active"]):not(:disabled)' in css assert '.ui-icon-btn[aria-pressed="true"]' in css and ".ui-icon-btn:disabled" in css src = _text(UI / "ui_template_button.ts") assert 'title: opts.title, "aria-label": opts.title' in src def test_날_색_없음(): for name in ("ui_template_button.css", "ui_template_icons.css"): css = _text(UI / name) assert not re.search(r"#[0-9a-fA-F]{3,8}\b|rgba?\(", css), name assert "--b01-" not in css and "--draw-" not in css and "font-family" not in css for name in ("ui_template_button.ts", "ui_template_button.css", "ui_template_icons.ts"): assert len(_text(UI / name).splitlines()) <= 700 def test_아이콘(): src = _text(UI / "ui_template_icons.ts") names = re.findall(r"^ (\w+):", src[src.index("const PATHS") : src.index("} as const")], re.M) assert len(names) == len(set(names)) >= 60 for n in ("settings", "x", "menu", "undo", "redo", "mapPin", "dots", "plus", "inbox"): assert n in names, n assert not re.search( r"[\U0001F300-\U0001FAFF☀-➿]", src[src.index("const PATHS") :] ) # 그림 이모지 없음 kit = _text(ROOT / "B01_Dashboard" / "B01_Dashboard_UI_PageKit.ts") assert "KIT_PATHS" not in kit and "return icon(name, size);" in kit # 한 벌