"""PLAN 173-3 · 173-4 — B06 횡단 카드 면적표 열 연동 · [상세] 그림 테마 색 · 칸 가득. 짝: `B06_Section/B06_Section_UI_Style_Cross_Areas.css`(글자 = 그림 칸 폭 · 379-2 카드 면적표 걷음) · `_UI_Section_View.ts`(그리드 data-columns · `detailChart`) · `_UI_Cross_Detail.ts`(칸 크기로 새로 그림) · `_UI_Style_Cross_Detail.css`(테마 토큰) · `_UI_Cross_View_Metrics.ts` `fitPlotBase`(Node 헬퍼 `helper_173_detail_fit.cjs` 가 실제 TS 를 돌림). """ from __future__ import annotations import json import os import subprocess import pytest HERE = os.path.dirname(__file__) ROOT = os.path.join(HERE, "..", "..") B06 = os.path.join(ROOT, "B06_Section") def _read(name: str) -> str: with open(os.path.join(B06, name), encoding="utf-8") as f: return f.read().replace(chr(13), "") @pytest.fixture(scope="module") def fit() -> dict: if not os.path.isdir(os.path.join(ROOT, "config", "node_modules")): pytest.skip("프론트엔드 의존성 미설치") proc = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", os.path.join(HERE, "helper_173_detail_fit.cjs")], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) # ── 173-3 그림 칸 글자 · 379-2 카드 좌상 면적표 걷음 ───────────────── def test_그림_칸_글자_폭_비례_남김(): css = _read("B06_Section_UI_Style_Cross_Areas.css") wrap = css.split(".b06-cross-card__chart-wrap {", 1)[1].split("}", 1)[0] assert "--b06-areas-font: clamp(0.6rem, 0.55rem + 0.7cqw, 0.9rem);" in wrap assert "font-size: var(--b06-areas-font);" in css # 남은 쓰는 곳 assert "font-size: 0.72rem" not in css # 3열 그림 칸 ≈ 400 px → 지금 글자(0.72rem)와 거의 같음 · 1열 · 6열은 끝값 def rem(width_px: float) -> float: # 1cqw = 칸 폭 1% · 1rem = 16 px return min(max(0.6, 0.55 + 0.7 * width_px / 100 / 16), 0.9) assert rem(400) == pytest.approx(0.725) assert rem(1232) == 0.9 and rem(192) == pytest.approx(0.634) def test_카드_좌상_면적표_걷음_조정창은_위에서(): """379-2 — 카드 좌상 면적표 지움 · 조정창 top = spacing-8 · 모달 표는 그대로.""" css = _read("B06_Section_UI_Style_Cross_Areas.css") assert "b06-cross-card__areas" not in css and "--b06-areas-height" not in css assert "buildAreaReadout" not in _read("B06_Section_UI_Cross_Areas.ts") view = _read("B06_Section_UI_Cross_View.ts") assert "buildAreaReadout" not in view and "setChipActive" not in view controls = _read("B06_Section_UI_Style_Cross_Controls.css") panel = controls.split(".b06-structure-panel {", 1)[1].split("}", 1)[0] assert "top: var(--spacing-8);" in panel and "--b06-areas-height" not in controls table = os.path.join(ROOT, "B07_DesignDetail", "B07_DesignDetail_Engine_Cad_Table.py") assert os.path.isfile(table) # 모달 표 그대로 # ── 173-4 [상세] 그림 ──────────────────────────────────────── def test_상세_테마_토큰_어두운_고정색_없음(): css = _read("B06_Section_UI_Style_Cross_Detail.css") cad = css.split(".b06-detail__cad {", 1)[1].split("}", 1)[0] assert "background: var(--color-surface-raised);" in cad assert "color: var(--color-text);" in cad assert "--color-" not in cad.replace("var(--color-", "") # 토큰 덮어쓰기 없음 assert "#111111" not in css and "#f2f2f2" not in css and "#1a1a1a" not in css def test_상세_칸_크기로_새로_그림_배선(): src = _read("B06_Section_UI_Cross_Detail.ts") assert "const { clientWidth: width, clientHeight: height } = cad;" in src assert "const drawn = drawChart(state.section, width, height);" in src assert "host?.chart(section.station_id, widthPx, heightPx)" in src assert "new ResizeObserver(() => state.paint())" in src and "resize.disconnect()" in src # 카드 clip id 와 가름 · 그리는 동안 refresh 되먹임 막음 assert "clip.id = `b06-detail-${id}`;" in src assert "if (drawing || !open || open.stationId !== section.station_id) return;" in src assert "getElementById(`cross-" not in src # 카드 DOM 복제 지움 view = _read("B06_Section_UI_Section_View.ts") assert "detailChart(stationId, widthPx, heightPx) {" in view assert "base && fitPlotBase(base, heightPx)" in view assert "cardZoomStates.delete(stationId);" in view types = _read("B06_Section_UI_Section_View_Types.ts") # 179-3 — svg + 축 옵션 assert ( " ) => { svg: SVGSVGElement; axes: CrossAxesOptions | null; homeScale: number } | null;" in types ) assert ( " detailChart: (\n stationId: string,\n widthPx: number,\n heightPx: number," in types ) sync = _read("B06_Section_UI_Page_Design_Sync.ts") assert "ctx.view().detailChart(stationId, widthPx, heightPx)" in sync def test_칸_가득_넓은_칸은_가로_범위_넓힘(fit): assert fit["natural"] > 400 assert fit["fitHeight"] == pytest.approx(400) assert fit["plotHeight"] == pytest.approx(400) assert fit["innerAfter"] == pytest.approx(fit["innerBefore"]) # 도면 폭 그대로 assert fit["wider"] is True assert fit["midAfter"] == pytest.approx(fit["midBefore"]) # 좌우 같이 def test_칸_가득_높은_칸은_그대로(fit): assert fit["tallSame"] is True # crossPlotFromBase 가 세로 범위를 늘려 채움 def test_뷰_파일_700줄_안(): for name in ("B06_Section_UI_Section_View.ts", "B06_Section_UI_Cross_Detail.ts"): assert len(_read(name).splitlines()) <= 700, name