"""552-4 틀 부품 아홉 지킴 시험 — 화면 확인은 부품 모음(`#/b01-account?view=ui-kit`) · ORCA. 부품마다(이름 · data-size · 상태 규칙 · 날 색 없음): · 작업 화면 틀(overlay) · 일반 화면 틀(general_layout) · 공개 화면 틀(public_layout) · 떠 있는 판 · 오른쪽 서랍(side_panels) · 도구줄 · 단계 줄(workflow_layout) · 패널 머리 · 목록 줄 · 부품 모음 목록 = 아홉 모두 `frame` 묶음 · 견본(demo) 있음 · 파일 이름 = 552-1 목록 그대로 · 옛 공용 이름(`ui-sidebar-actions` · `ui-sidebar-row` · `ui-workflow-layout__step` …)은 그대로 냄 """ from __future__ import annotations import re from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] UI = ROOT / "ui_template" # 부품 열쇠 → (ts 파일, css 파일, 만들기 함수, 낼 클래스, 높이 단) PARTS = { "work-frame": ("ui_template_overlay", "createWorkflowOverlays", "ui-workflow-overlay", ()), "page-frame": ("ui_template_general_layout", "createPageFrame", "ui-page-frame", ()), "public-frame": ("ui_template_public_layout", "createPublicFrame", "ui-public-frame", ()), "float-panel": ("ui_template_float_panel", "createFloatPanel", "ui-float-panel", (32,)), "drawer": ("ui_template_side_panels", "createSidePanels", "ui-side-panels", ()), "toolbar": ("ui_template_toolbar", "createToolbar", "ui-toolbar", (24, 28, 32)), "map-tools": ("ui_template_map_tools", "createMapTools", "ui-map-tools", ()), "steps": ("ui_template_workflow_layout", "createStepBar", "ui-workflow-layout__step", (28, 40)), "panel-head": ("ui_template_panel_head", "createPanelHead", "ui-panel-head", (32,)), "list-row": ("ui_template_list_row", "createListRow", "ui-list-row", (28, 32, 36)), } RAW_COLOR = re.compile(r"#[0-9a-fA-F]{3,8}\b|rgba?\(|hsla?\(|var\(--(?:b01|draw)-") def _text(path: Path) -> str: return path.read_text(encoding="utf-8") def _strip_comments(css: str) -> str: return re.sub(r"/\*[\s\S]*?\*/", "", css) @pytest.mark.parametrize("key", PARTS) def test_머리_이름_크기(key): stem, maker, cls, sizes = PARTS[key] ts = _text(UI / f"{stem}.ts") head = ts.split("*/", 1)[0] # 규칙 8 — 머리에 무엇 · 꼴 · 크기 · 상태 · 쓰는 법 · 대신하는 옛 변종 for word in ("꼴", "크기", "상태", "쓰는 법", "대신하는 옛 변종"): assert word in head, f"{stem} 머리에 {word} 없음" assert re.search(rf"export function {maker}\b", ts), maker assert cls in ts css = _strip_comments(_text(UI / f"{stem}.css")) for size in sizes: assert f'[data-size="{size}"]' in css or f"min-height: {size}px" in css, (stem, size) assert len(ts.splitlines()) <= 700 and len(css.splitlines()) <= 700 @pytest.mark.parametrize("key", PARTS) def test_날_색_없음(key): stem = PARTS[key][0] css = _strip_comments(_text(UI / f"{stem}.css")) assert not RAW_COLOR.search(css), (stem, RAW_COLOR.search(css)) assert "font-family" not in css # 글꼴 = --font-ui 상속 def test_상태_규칙(): # 마우스 · 눌림을 data-state 로 굳혀 보일 수 있음 for stem in ("ui_template_list_row", "ui_template_workflow_layout", "ui_template_overlay"): css = _text(UI / f"{stem}.css") assert ':is(:hover, [data-state="hover"])' in css, stem row = _text(UI / "ui_template_list_row.css") assert ".ui-sidebar-row.is-active" in row and '[aria-disabled="true"]' in row def test_작업_화면_틀_겉(): css = _strip_comments(_text(UI / "ui_template_overlay.css")) title = re.search(r"\.ui-workflow-overlay__panel--title \{([^}]*)\}", css).group(1) # 흰 판 + 1 px 선 · 그림자 없음(요구 375 정함 7) assert "box-shadow: none" in title and "border-right-color: var(--color-border)" in title # 손잡이는 강조색 그대로(2026-08-04 사용자 지시) assert "border: 1px solid var(--panel-handle-border" in css assert "background: var(--color-scrim)" in css # 옛 이름 그대로 — 아래 단추 줄 · [?][<][>] for name in (".ui-sidebar-actions", ".ui-workflow-overlay__handle--side"): assert name in css # 아래 단추 줄 — 다 안 들면 두 줄로 감음 · 글자 단추는 글보다 안 좁아짐(552-7 E03 「해석」 잘림) row = re.search(r"\.ui-sidebar-actions \[data-help-row\] \{([^}]*)\}", css).group(1) assert "flex-wrap: wrap" in row btn = re.search(r"\[data-help-row\] > \.ui-btn:not\([^)]*\) \{([^}]*)\}", css).group(1) assert "min-width: max-content" in btn ts = _text(UI / "ui_template_overlay.ts") assert 'import "./ui_template_list_row.css"' in ts # 옛 목록 줄 겉도 함께 def test_부품_모음_목록(): src = _text(UI / "ui_template_ui_kit_parts.ts") rows = dict(re.findall(r'\{ key: "([^"]+)", name: "[^"]+", group: "(\w+)"', src)) lines = src.splitlines() for key, (stem, *_rest) in PARTS.items(): assert rows.get(key) == "frame", key i = next(i for i, x in enumerate(lines) if f'key: "{key}"' in x) assert f'file: "{stem}.ts"' in lines[i], key assert "demo:" in lines[i] + lines[i + 1], key