"""PLAN 445-2 — 교점 끈 뒤 [저장] · [확정]마다 노선 저장이 다시 돌던 것. 까닭(화면 실측 378 → 414 → 416 → 417) — 노선 저장 뒤 페이지가 다시 서며 평면 판이 접혀 편집기가 떠나는데, 노선 저장 등록부(`bindRouteApply`)에 옛 편집기가 남아 「고친 것 있음」(창을 연 때 대비)을 계속 냄 → [저장] · [확정]마다 같은 초안으로 노선 저장 체인. 덧 — 고정(잠금)만 바꿔도 노선 저장. 못박는 것 - 편집기가 떠나면 등록부에서 풀림 → 노선 초안 = 가게 칸(저장 뒤 비움). - 늦게 풀리는 옛 편집기가 새 편집기 등록을 안 지움. - 고정만 바꾼 걸음 = 노선 안 바뀜(`lineChanged`) · [초기화] 판정(`isDirty`)은 그대로. - 편집기 배선(떠날 때 풂 · 판정 셋 자리). 짝: `helper_445_2_route_pending.cjs`. """ from __future__ import annotations import json import subprocess from pathlib import Path import pytest HERE = Path(__file__).resolve().parent ROOT = HERE.parents[1] pytestmark = pytest.mark.skipif( not (ROOT / "config" / "node_modules" / "typescript").is_dir(), reason="프론트엔드 의존성 미설치", ) @pytest.fixture(scope="module") def r() -> dict: proc = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", str(HERE / "helper_445_2_route_pending.cjs")], cwd=ROOT, capture_output=True, text=True, encoding="utf-8", timeout=120, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def test_편집기가_떠나면_노선_저장_안_돎(r): assert r["boundPending"] is True # 끈 채 등록된 편집기 assert r["afterUnbind"] is False # 떠난 뒤 = 가게 칸(비었음) — 예전엔 옛 편집기가 계속 true def test_늦게_풀리는_옛_편집기가_새_등록을_안_지움(r): assert r["newKept"] is None # 새 편집기(안 바뀜)가 판정 def test_고정만_바꾸면_노선_안_바뀜(r): assert r["lockOnly"] == {"isDirty": True, "lineChanged": False} assert r["moved"] == {"lineChanged": True} def test_편집기_배선(): edit = (ROOT / "B05_Profile" / "B05_Profile_UI_RouteEdit.ts").read_text(encoding="utf-8") dispose = edit[edit.index("const dispose = (): void => {") :] assert "unbindApply();" in dispose[:80] assert "const unbindApply = bindRouteApply({" in edit assert "history.isDirty() ||" not in edit and "history?.isDirty()" not in edit assert edit.count("lineChanged(history)") == 2 and len(edit.splitlines()) <= 695 draft = (ROOT / "B05_Profile" / "B05_Profile_UI_RouteEdit_Draft.ts").read_text(encoding="utf-8") assert "bridge.edited(lineChanged(history)" in draft