Files
Aislo/resources/tester/test_552_2_button.py
T
eomsangdonandClaude Opus 5.5 877b89f37c fix(ui-kit): 부품 흠 다섯 — 보조 글 줄 안 inline · 단추 실측 = 단 · 숨김 단추 · 놓기 칸 전체 누름 · 격자표 (PLAN 552-5)
- 보조 글: span · small 에 붙은 .ui-text = inline(줄 안 끊김) · p · div 는 한 줄 상자 그대로
- 단추: 위아래 여백 = 1em 기준 + 줄 높이 1 · 왼쪽 패널 양식(.ui-panel-form) 옛 규칙(글 12 · 줄 높이 normal)이 단을 덮지 않음 — B07 도면 단추 35 → 32
- 숨김: .ui-btn · .ui-icon-btn [hidden] = display none(공용 기본 꼴이 안 실린 곳에서도)
- 파일 놓기 칸: 칸 어디든 누름 · 초점 Enter · Space = 파일 고르기(옛 B03 동작) · 단추 누름은 칸으로 올라가 한 번만
- 표: 격자 꼴(grid · 세로선 · 칸 테두리 · 몸 안 이름 칸 th) · 합친 칸(colSpan · rowSpan · head) · columns 비우면 머리 줄 없음 · 기본 꼴 그대로
- 부품 모음 견본: 글 줄 안 보조 글 · 격자표(수량 산출표 꼴)
- 시험: test_552_5_part_fixes 새 · test_552_2_button 높이 식 기대 고침(1em · 줄 높이 1)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 23:38:33 +09:00

105 lines
5.1 KiB
Python

"""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)
# 552-5 — 여백 = 1em 기준 · 줄 높이 1 (페이지 글 크기 · 줄 높이가 단을 안 바꿈)
assert "calc((var(--ui-size-h) - 2px - 1em) / 2) var(--ui-size-px)" in rule
assert "line-height: 1;" in rule
assert not re.search(r"(^|[^-])height:", rule) # 높이를 박지 않음(line-height 만)
# 아이콘은 글 높이 안 — 단 높이가 아이콘 때문에 늘지 않음
assert "margin-block: calc((1em - 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 # 한 벌