"""409 B05 평면 구조물 마커 맨 위 · 다른 곳 누르면 고름 풀림(요구 252-4). 그림 = 맨 마지막(교각점 · 손잡이 · 맴돔 위) · 누름 · 맴돔 · 커서 = 재기 다음 마커 먼저 · 마커 누르면 고른 교각점 풂 · 마커 아닌 곳 누름 · Esc = 공용 고름을 `b05-plan` 으로 비움(오른쪽 횡단 판 그대로). TS 셈은 `helper_399_plan_structure_marks.cjs`(⑥ 고름 풀기). ./venv/Scripts/python.exe -m pytest resources/tester/test_409_mark_top_deselect.py -q """ import json import subprocess from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] HELPER = Path(__file__).with_name("helper_399_plan_structure_marks.cjs") def _read(*parts: str) -> str: return (ROOT.joinpath(*parts)).read_text(encoding="utf-8") @pytest.fixture(scope="module") def got() -> dict: run = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", str(HELPER)], capture_output=True, text=True, encoding="utf-8", timeout=120, ) assert run.returncode == 0, run.stderr return json.loads(run.stdout) def test_풀기_고른_것_없으면_아무_일_없음(got) -> None: assert got["deselectNone"] == [False, 0] def test_풀기_공용_고름을_b05_plan_으로_비움(got) -> None: assert got["deselectPicked"] == [True, [None, "b05-plan"], None] def test_Esc_마커_고름만_풂(got) -> None: assert got["escapePicked"] == [[None, "b05-plan"], None, 1] # 관 고름도 · 공용 Esc 막음 assert got["escapeNone"] == [0, 1] # 고른 것 없음 = 공용 Esc 몫 def test_마커_누름은_그대로_고름(got) -> None: assert got["pressAfterRelease"] == "A" def test_누름_마커_먼저_교각점_풂() -> None: pointer = _read("B05_Profile", "B05_Profile_UI_RouteEdit_Pointer.ts") down = pointer[pointer.index("if (marks.press(px, py)) {") :] branch = down[: down.index("marks.deselect();")] assert "params.setPicked(-1);" in branch and "params.syncCurveBar();" in branch assert "canvas.setPointerCapture(event.pointerId);\n return;" in branch assert "else if (marks.press(" not in pointer # 옛 차례(교각점 · 손잡이 다음) 걷힘 def test_맴돔_커서_마커_먼저() -> None: pointer = _read("B05_Profile", "B05_Profile_UI_RouteEdit_Pointer.ts") over = pointer.index("const onMark = !measuring && marks.over(px, py);") pick = pointer.index("const over = measuring || onMark ? null : pickAt(px, py);") cursor = pointer.index("canvas.style.cursor = onMark") assert over < pick < cursor def test_오른쪽_판은_제_이름_알림을_거름() -> None: cross = _read("B05_Profile", "B05_Profile_UI_RouteEdit_Cross.ts") assert "if (from !== PLAN_PICK_FROM) follow(selection);" in cross marks = _read("B05_Profile", "B05_Profile_UI_RouteEdit_StructureMarks.ts") assert "selectDesign(projectId, NO_SELECTION, { from: PLAN_PICK_FROM });" in marks # ── 409-2 마커 고름 풂 = 좌측 목록 강조 · 폼도 풂 · 패널 접힘 · 펼침 그대로 · 오른쪽 판 그대로 ── HELPER_2 = Path(__file__).with_name("helper_409_2_plan_release_form.cjs") @pytest.fixture(scope="module") def got2() -> dict: run = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", str(HELPER_2)], capture_output=True, text=True, encoding="utf-8", timeout=120, ) assert run.returncode == 0, run.stderr return json.loads(run.stdout) def test_풂_관_폼_닫힘_오른쪽_판은_제_알림만(got2) -> None: release = got2["pipeRelease"] assert release["form"] == {"open": None, "resets": 1} assert release["crossSaw"] == [[None, "b05-plan"]] # 폼이 낸 b05 풂은 알림 안 감(되울림 막이) assert release["session"] is None def test_풂_구조물_폼_닫힘(got2) -> None: assert got2["structureRelease"] == {"form": {"open": None, "resets": 2}, "pill": None} def test_눈금_클릭은_폼_그대로(got2) -> None: assert got2["tickKeepsForm"] == "A" assert got2["noFormNoReset"] == 0 assert got2["planName"] == "b05-plan" def test_폼_닫기는_패널_안_폄() -> None: panel = _read("B05_Profile", "B05_Profile_UI_Structures_Panel.ts") head = panel[panel.index(" selectById(structureId) {") :] assert head.index("if (structureId !== null) callbacks.onReveal?.();") < head.index( "resetForm();" ) assert "is-collapsed" not in head[: head.index(" addAt(")] # 접힘 · 펼침 안 건드림 pick = _read("A00_Common", "design", "design_pick_profile.ts") assert "from === PLAN_PICK_FROM && selection.chainageM === null" in pick