"""755 B05 평면 예정노선 수정 흐름(요구 589-1 · 3 · 5 · 6 · 7 · 8). - 755-1 켠 동안 = 판만 고침 · 끊김 허용(가운데 묶음 지움) · 이 판 사진첩(Ctrl+Z · 도구줄 단추) · 끌 때 한 번 = 끊겼으면 알림하고 안 끔 · 바뀌었으면 `/route/follow` 한 걸음 · [잇기] = B05 사용. - 755-2 켠 동안 재기 = D03 재기 겹 · 받은 노선 = 분홍 점선 + 검은 테 · 켬 설명 걷음 · 위치 칸 걷음. - 755-3 켠 채 판 고침 = [저장] · [확정] 막고 알림 · 떠남 = 공용 떠남 물음(탭 닫기 = 브라우저 물음). ./venv/Scripts/python.exe -m pytest resources/tester/test_755_expected_flow.py -q """ from __future__ import annotations import re from pathlib import Path ROOT = Path(__file__).resolve().parents[2] B05 = ROOT / "B05_Profile" D03 = ROOT / "D03_PlanAnalysis" def _body() -> str: return (B05 / "B05_Profile_UI_ExpectedDraw.ts").read_text("utf-8").split("*/", 1)[1] def _fn(body: str, head: str) -> str: start = body.index(head) end = body.index("\n }\n", start) return body[start:end] def test_켠_동안_판만_한_걸음_사진첩(): body = _body().replace("\r\n", "\n") commit = _fn(body, "function commit(") assert "undoStack.push(network);" in commit and "redoStack = [];" in commit assert "follow(" not in commit and "apply(" not in commit # 켠 동안 평면선 안 바꿈 assert "function apply(" not in body and "strokeBase" not in body assert "onMode: () => params.redraw()," in body # 긋기 끝 = 다시 추적 아님 assert 'keyIs(event, "plan.undo")\n ? (step("undo"), true)' in body assert "history: () =>\n open" in body # 끔 = 페이지 사진첩 history = (B05 / "B05_Profile_UI_RouteEdit_History.ts").read_text("utf-8") assert "const local = params.local?.();" in history assert "params.local?.() ?? getHistory()" in history main = (B05 / "B05_Profile_UI_RouteEdit.ts").read_text("utf-8") assert "local: () => expectedDraw.history()," in main assert "onHistory: () => historyControls.sync()," in main def test_끌_때_끊김_알림_안_끔_한_번_추적(): body = _body().replace("\r\n", "\n") open_ = _fn(body, "async function setOpen(") assert "if (!next && open && !(await finish())) return toggle.set(true);" in open_ finish = _fn(body, "async function finish(") assert "drawn.length > 1" in finish and "return false;" in finish and "showToast(" in finish assert "return sameLine(points, base) || (await follow(points, points));" in finish follow = _fn(body, "async function follow(") assert ( "/route/follow" in follow and "return true;" in follow and "if (!ok) return false;" in follow ) assert "revert" not in body # 실패 · 취소 = 판 그대로(켠 채) table = (D03 / "D03_PlanAnalysis_UI_Features.ts").read_text("utf-8") assert re.search(r'key: "join",[^}]*b05: "use"', table, re.S) assert re.search(r'key: "branch",[^}]*b05: "hide"', table, re.S) # 갈래 · 둘째 선 그대로 막음 def test_재기_D03_겹_켠_동안(): body = _body() assert "createPlanMeasure(" in body and "params.measuring()" in body assert "kit.layers([], [measure.layer])" in body and "layers: liveLayers," in body assert "idle: () => open && !measuring()," in body # 재는 동안 고르기 · 끌기 쉼 main = (B05 / "B05_Profile_UI_RouteEdit.ts").read_text("utf-8") assert "measuring: () => measureControls.mode()," in main def test_받은_노선_색_설명_위치_걷음(): body = _body() assert 'strokeCased(context, themeColor("--draw-map-route-3", "#ff8cbc"), 2.5, [8, 5]);' in body assert "--draw-text-secondary" not in body assert "HINT =" not in body.replace("OFF_HINT =", "") and "hint.hidden = open;" in body table = (D03 / "D03_PlanAnalysis_UI_Features.ts").read_text("utf-8") assert re.search(r'key: "site",[^}]*b05: "hide"', table, re.S) assert re.search(r'key: "site",[^}]*d03: "use"', table, re.S) # D03 그대로 theme = (ROOT / "ui_template" / "ui_template_theme.css").read_text("utf-8") assert "--draw-map-route-3:" in theme def test_켠_채_저장_떠남_알림(): body = _body().replace("\r\n", "\n") assert "const pending = (): boolean => open && undoStack.length > 0;" in body assert "holdDesignSave(canvas, () => (pending() ? HELD : null));" in body assert "guardProjectLeave(canvas, {\n dirty: pending," in body save = (ROOT / "A00_Common" / "design" / "design_save.ts").read_text("utf-8") save = save.replace("\r\n", "\n") head = save[save.index("export async function saveDesign(") :] held = head.index("const held = heldSave();") assert held < head.index("saving.add(ctx.projectId);") # 막음 = 저장 줄 앞 · 가림막 없음 assert held < head.index("showLoadingOverlay")