# -*- coding: utf-8 -*- """PLAN 216-1 — B05 종단 측점선 고름 → 좌측 구조물 폼이 B06 카드 고름과 같게. 까닭: `syncIrregularSelection` 이 일반 측점이면 폼을 안 건드리고 끝났고(옛 폼이 남음 · 덮는 옹벽도 안 열림), 비정규 측점도 관 전용 `selectPipeByChainage` 만 불러 A군 수동 구조물은 안 열렸음. B06 카드 고름은 `showAtChainage` = `resolveSelection`(관 → 덮는 구조물 · 노면공 뺌 → 없으면 비움). 고침: B05 측점 고름도 같은 `resolveSelection` + 같은 `coversAtStation` 으로 폼을 엶(`openAtStation`). 실제 TS 를 `helper_216_1_b05_station_panel.cjs` 가 Node 로 돌린다. """ from __future__ import annotations import json import os import subprocess import pytest HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.abspath(os.path.join(HERE, "..", "..")) pytestmark = pytest.mark.skipif( not os.path.isdir(os.path.join(ROOT, "config", "node_modules")), reason="프론트엔드 의존성 미설치", ) @pytest.fixture(scope="module") def out() -> dict: proc = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", os.path.join(HERE, "helper_216_1_b05_station_panel.cjs")], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def _read(*parts: str) -> str: with open(os.path.join(ROOT, *parts), encoding="utf-8") as handle: return handle.read() def _forms(steps: list) -> list: return [(step["b05"], step["b06"]) for step in steps] def test_관_지점_측점선은_그_관_폼(out) -> None: assert _forms(out["pipe"]) == [("pipe-33.40", "pipe-33.40")] def test_관_폼이_열린_채_빈_일반_측점이면_폼을_비움(out) -> None: assert _forms(out["pipeThenPlain"])[-1] == (None, None) def test_일반_측점은_그_측점을_덮는_구조물_폼(out) -> None: assert _forms(out["wallStation"]) == [(None, None), ("wall", "wall")] assert _forms(out["wallMiddle"]) == [("wall", "wall")] assert _forms(out["channel"]) == [("chan", "chan")] # A군 수동 구조물 측점 def test_노면공은_측점_고름으로_안_엶(out) -> None: assert _forms(out["pave"]) == [("wall", "wall"), (None, None)] assert out["covers"] == {"G": False, "C": True, "none": True} def test_다시_누름_풂과_모르는_측점(out) -> None: assert _forms(out["release"])[-1] == (None, None) assert out["release"][-1]["pick"] is None assert out["unknown"][-1]["b05"] == "wall" # 모르는 측점은 폼 그대로 assert out["unknown"][-1]["pick"] == {"chainageM": 60, "structureId": None} def test_고름_한_칸은_측점_구조물_id_없음(out) -> None: # 폼이 옹벽을 열어도(목록 고름 알림이 구조물을 적어도) 마지막은 그 측점(188-1 · B06 카드와 같음) for key in ("wallStation", "wallMiddle", "channel", "pave", "pipeThenPlain"): for step in out[key]: assert step["pick"]["structureId"] is None, key assert step["pick"]["chainageM"] in (20, 33.4, 60, 80, 100, 140, 160), key def test_배선() -> None: sync = _read("B05_Profile", "B05_Profile_UI_Selection.ts") assert "(ports.openAtStation ?? ports.selectSidebar)(at);" in sync assert "if (stationId !== null && !stationId.startsWith(prefix)) return;" not in sync # 고름 한 칸은 폼 동기화 뒤에 적음 assert sync.index("ports.remember?.(at);") > sync.index("ports.setSyncing(false);") view = _read("A00_Common", "design", "design_view_profile.ts") assert "openAtStation: (chainageM) =>" in view assert "panel.structures.selectAt({ chainageM, structureId: null }, (entry) =>" in view assert "coversAtStation(bridge.typeGroup(entry.type_id))" in view b06 = _read("B06_Section", "B06_Section_UI_Page_Structures_Panel.ts") assert "coversAtStation(markTypes.find((type) => type.type_id === entry.type_id)?.group)" in b06 assert "resolveSelection(selection, pipeFacilities, structures, coverable)" in b06 panel = _read("B05_Profile", "B05_Profile_UI_Structures_Panel.ts") assert "resolveSelection(selection, pipeFacilities, structures, coverable)" in panel