From d35743870dae7ba92395c67c1da5c0b816a46abf Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 10 Oct 2026 17:52:53 +0900 Subject: [PATCH] =?UTF-8?q?fix(B06):=20=EB=AA=A9=EB=A1=9D=20=EA=B3=A0?= =?UTF-8?q?=EB=A6=84=EB=8F=84=20=EB=8A=98=20=EA=B3=A0=EB=A6=84=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=E2=80=94=20=EA=B0=99=EC=9D=80=20=EC=B9=B4=EB=93=9C?= =?UTF-8?q?=20=EC=95=88=20=EA=B5=AC=EC=A1=B0=EB=AC=BC=EB=8F=84=20=EC=98=A4?= =?UTF-8?q?=EA=B0=90=20=C2=B7=20=EC=83=88=EB=A1=9C=20=EA=B3=A0=EC=B9=A8=20?= =?UTF-8?q?=EB=92=A4=20=EA=B7=B8=20=ED=8F=BC(231-2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 목록 · 알약 · 형상 고름은 노면공이 아니어도 그 구조물 id 를 고름 한 칸에 적음 · 측점 고름이 연 것은 측점만(189-1) - 새 시험 test_231_2 · test_231_1 · test_177_4 기대값 맞춤 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz --- .../B06_Section_UI_Page_Structures_Panel.ts | 5 +- resources/tester/helper_231_1_pave_reload.cjs | 48 +++++++++- .../tester/test_177_4_pavement_span_box.py | 3 +- resources/tester/test_231_1_pave_reload.py | 4 +- .../tester/test_231_2_list_pick_record.py | 88 +++++++++++++++++++ 5 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 resources/tester/test_231_2_list_pick_record.py diff --git a/B06_Section/B06_Section_UI_Page_Structures_Panel.ts b/B06_Section/B06_Section_UI_Page_Structures_Panel.ts index 6fdb971ce..fc0d5a3ae 100644 --- a/B06_Section/B06_Section_UI_Page_Structures_Panel.ts +++ b/B06_Section/B06_Section_UI_Page_Structures_Panel.ts @@ -227,9 +227,10 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc preferredId = null; // 알약은 카드 뒤에 — 카드 측점이 알약을 갈아 끼우거나 끄지 않게(53-2) deps.markStructure?.(id, !openingAtStation); // 측점 고름이 연 것 = 카드 하나 · 범위 테두리 없음(231-1) - // 카드 고름 리스너를 안 거치니 세션 고름은 여기서(B05 로 가도 그 노면공) + // 목록 · 알약 · 형상 고름은 늘 고름 한 칸에 그 구조물 — 같은 카드라 카드 리스너가 안 돌아도 + // 오감 · 새로 고침 뒤 그 폼(188-1 · 231-2) · 측점 고름이 연 것은 측점만(카드 리스너 몫 · 189-1) const at = { chainageM: focusOf(structure), structureId: id }; - if (pave) selectDesign(deps.projectId, at, { from: "b06" }); + if (!openingAtStation) selectDesign(deps.projectId, at, { from: "b06" }); }, getInterval: deps.stationInterval, // 관 추가 — 정본은 [저장]·[확정]에서 나간다. 화면 목록·알약은 바로 세운다. diff --git a/resources/tester/helper_231_1_pave_reload.cjs b/resources/tester/helper_231_1_pave_reload.cjs index 3319d3183..24d17d3e8 100644 --- a/resources/tester/helper_231_1_pave_reload.cjs +++ b/resources/tester/helper_231_1_pave_reload.cjs @@ -249,9 +249,10 @@ view.listener = (stationId) => { view.selectMark(mark, false); }; -async function build(list) { +/** 새로 세움 — keep = 새로 고침(F5 · 세션은 남고 화면 · 폼은 처음부터). */ +async function build(list, keep = false) { current.structures = list; - store.clear(); + if (!keep) store.clear(); form.id = null; form.pipe = null; view.selected = null; @@ -305,6 +306,12 @@ async function roundTrip() { restore(); } +/** 새로 고침(F5) — 첫 마운트 `load().then(restoreStructurePick)` 차례(231-2). */ +async function refresh() { + await build(current.structures, true); + restore(); +} + function snap() { const mark = marks.find((entry) => entry.structure_id === view.spanMarkId); const pave = mark && isPavement(mark.structure_id); @@ -320,6 +327,11 @@ function snap() { const cardPick = (at) => view.selectStation(cardAt(at).station_id); const listPick = (id) => loadForm(structures.find((entry) => entry.structure_id === id)); +/** 좌측 목록 관 줄 — B05 패널 `onSelectPipe`(loadPipeForm → onPipeSelect). */ +const listPipe = (at) => { + loadPipeForm(at); + binding.onPipeSelect(at); +}; /** B05 3D 부재 고름 — 진짜 `wireStructurePick` 에 B05 와 같은 거름(design_view_profile). */ function pick3d(chainageM) { @@ -378,6 +390,38 @@ function pick3d(chainageM) { out.pick3dBare = { sid: snap().sid, form: snap().form }; await roundTrip(); out.pick3dAfter = snap(); + + // 231-2 목록 고름도 늘 고름 기록 — 카드 120 → 목록 관 · 표지 · 옹벽 → 오감 · 새로 고침 + await build([PAVE, WALL, SIGN]); + cardPick(120); + listPipe(80.17); + out.listPipe = snap(); + await roundTrip(); + out.listPipeTrip = snap(); + await refresh(); + out.listPipeF5 = snap(); + + await build([PAVE, SIGN]); + cardPick(120); + listPick("sign"); // 같은 카드 120 — 카드 리스너 안 돎 + out.listSign = snap(); + await roundTrip(); + out.listSignTrip = snap(); + await refresh(); + out.listSignF5 = snap(); + + await build([PAVE, WALL]); + cardPick(120); + listPick("wall"); + out.listWall = snap(); + await roundTrip(); + out.listWallTrip = snap(); + + await build([PAVE, SIGN]); + cardPick(120); + listPick("pave"); + await refresh(); + out.listPaveF5 = snap(); process.stdout.write(JSON.stringify(out)); })().catch((error) => { process.stderr.write(String(error?.stack ?? error)); diff --git a/resources/tester/test_177_4_pavement_span_box.py b/resources/tester/test_177_4_pavement_span_box.py index b604678ee..324224a05 100644 --- a/resources/tester/test_177_4_pavement_span_box.py +++ b/resources/tester/test_177_4_pavement_span_box.py @@ -71,4 +71,5 @@ def test_스크롤만_길은_리스너를_안_거침(): assert "if (revealOnly) sectionView.revealStation(nearest.station_id);" in cross panel = _read("B06_Section", "B06_Section_UI_Page_Structures_Panel.ts") assert "const pave = !coverable(structure);" in panel - assert 'if (pave) selectDesign(deps.projectId, at, { from: "b06" });' in panel + # 목록 고름은 노면공뿐 아니라 늘 고름 기록(231-2) + assert 'if (!openingAtStation) selectDesign(deps.projectId, at, { from: "b06" });' in panel diff --git a/resources/tester/test_231_1_pave_reload.py b/resources/tester/test_231_1_pave_reload.py index 7363f9b3e..898c92503 100644 --- a/resources/tester/test_231_1_pave_reload.py +++ b/resources/tester/test_231_1_pave_reload.py @@ -57,9 +57,9 @@ def test_범위_안_카드_고름_오감해도_노면공_안_켬_폼_그대로(o def test_같은_카드_목록_고름_뒤_오감도_노면공_안_켬(out) -> None: assert out["signPick"]["form"] == "sign" after = out["signAfter"] - assert after["form"] != "pave" + assert after["form"] == "sign" # 목록 고름도 기록 — 오감 뒤 그 폼(231-2) assert after["paveLayer"] is None - assert after["span"] is None + assert after["span"] != "pave" assert after["card"] == 120 diff --git a/resources/tester/test_231_2_list_pick_record.py b/resources/tester/test_231_2_list_pick_record.py new file mode 100644 index 000000000..a1a41b153 --- /dev/null +++ b/resources/tester/test_231_2_list_pick_record.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +"""231-2 목록 고름도 늘 고름 기록 — 조사 AD 2안. + +까닭: B06 목록 고름은 노면공일 때만 고름 한 칸에 적고 그 밖은 카드 리스너에 맡겼음 → 같은 카드 안 구조물을 +목록으로 고르면 리스너가 안 돌아 기록이 「측점만」 그대로 → 오감 · 새로 고침 뒤 그 폼이 사라짐. +고침: 목록 · 알약 · 형상 고름은 늘 그 구조물 id 를 적음 · 측점 고름(카드 · 다시 세움)이 연 것은 측점만(189-1). +B05 목록은 원래 늘 적음(`rememberPick(…, structure_id)`). 헬퍼 = `helper_231_1_pave_reload.cjs`. +""" + +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="프론트엔드 의존성 미설치", +) + + +def _read(*parts: str) -> str: + with open(os.path.join(ROOT, *parts), encoding="utf-8") as handle: + return handle.read() + + +@pytest.fixture(scope="module") +def out() -> dict: + proc = subprocess.run( # noqa: S603 — 고정 실행 파일 + ["node", os.path.join(HERE, "helper_231_1_pave_reload.cjs")], + capture_output=True, + text=True, + encoding="utf-8", + timeout=60, + ) + assert proc.returncode == 0, proc.stderr + return json.loads(proc.stdout) + + +def test_카드_120_뒤_목록_관_오감_새로고침_관_폼(out) -> None: + for key in ("listPipe", "listPipeTrip", "listPipeF5"): + got = out[key] + assert got["form"] == "pipe-80.17", key + assert got["card"] == 80.17, key + assert got["paveLayer"] is None, key + + +def test_같은_카드_목록_표지는_기록되고_오감_새로고침_뒤_그대로(out) -> None: + sign = {"form": "sign", "paveLayer": None, "span": "sign", "card": 120, "sid": "sign"} + assert out["listSign"] == sign + assert out["listSignTrip"] == sign + assert out["listSignF5"] == sign + + +def test_목록_옹벽은_기준_카드_오감_뒤_그대로(out) -> None: + wall = {"form": "wall", "paveLayer": None, "span": "wall", "card": 100, "sid": "wall"} + assert out["listWall"] == wall + assert out["listWallTrip"] == wall + + +def test_목록_노면공은_새로고침_뒤도_범위_그대로(out) -> None: + assert out["listPaveF5"] == { + "form": "pave", + "paveLayer": "pave", + "span": "pave", + "card": None, + "sid": "pave", + } + + +def test_측점_고름이_연_것은_측점만(out) -> None: + assert out["wallCard"]["sid"] is None # 카드 하나(189-1) + assert out["wallAfter"]["sid"] is None # 다시 세움도 + assert out["cardAfter"]["sid"] is None + + +def test_배선() -> None: + panel = _read("B06_Section", "B06_Section_UI_Page_Structures_Panel.ts") + assert 'if (!openingAtStation) selectDesign(deps.projectId, at, { from: "b06" });' in panel + assert "if (pave) selectDesign(" not in panel + profile = _read("A00_Common", "design", "design_view_profile.ts") + # B05 목록은 원래 늘 그 구조물 id 를 적음 + assert "rememberPick(structureAnchorM(structure), structure.structure_id ?? null)" in profile