# -*- coding: utf-8 -*- """한 페이지 뼈대(계획서 24-3a) · 겹친 알약(24-6b) 회귀검증. 주소 둘(`#/b05-profile` · `#/b06-section`)이 같은 페이지(`A00_Common/design/design_page.ts`)를 열고, 같은 페이지 안 이동은 다시 만들지 않고 보기만 바꾸는지, 떠날 때 3D(WebGL 문맥) · 종단도 · 횡단을 정리하는지, 숨긴 3D 는 그리기 루프를 멈추는지, 창에 건 키 듣기를 떼는지 본다. 화면 수치(문맥 수 · 루프 · 같은 노드 · 전환 시간)는 ORCA 로 잰다 — 여기서는 길이 끊기지 않게 잠근다. """ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent.parent def _read(relative: str) -> str: return (ROOT / relative).read_text(encoding="utf-8") def test_주소_둘이_같은_페이지(): router = _read("A00_Common/router.ts") assert router.count('(await import("./design/design_page")).renderDesignPage') == 2 assert "export function showWithinPage(" in router # 다른 페이지로 떠나면 정리 · 늦게 끝난 옛 렌더는 버림 assert "mounted?.dispose();" in router assert "if (page && seq !== renderSeq) page.dispose();" in router def test_같은_페이지면_셸도_다시_안_그림(): main = _read("A00_Common/main.ts") within = main.index("showWithinPage(currentRoute())") assert within < main.index("renderShell(appRoot") assert "if (within) return;" in main def test_보기_약속_가운데만(): """끝 모습(24-3b) — 보기는 가운데 위 칸만 채우고 좌측 패널 · 단추 · 종단도는 한 벌을 쓴다.""" page = _read("A00_Common/design/design_page.ts") assert "export interface DesignPageView" in page assert "mount?: (root" not in page # 보기가 틀을 통째로 그리던 중간 길은 걷음 assert "mountCenter: (" in page and "shared: DesignPageShared" in page assert 'import("./design_view_profile")).mountProfileView' in page assert 'import("./design_view_cross")).mountCrossView' in page for hook in ("onShow:", "onHide:", "onDispose:"): assert hook in page # 보기는 처음 보일 때 한 번만 만든다 — 있으면 보이기만. assert "if (slot) {\n slot.show();" in page def test_페이지가_숨김_떠남을_건다(): life = _read("B05_Profile/B05_Profile_UI_Page_Life.ts") assert "deps.viewer.setActive(false)" in life and "deps.viewer.dispose()" in life assert "bindProfileViewLife(host," in _read("A00_Common/design/design_view_profile.ts") cross = _read("A00_Common/design/design_view_cross.ts") assert "sectionView.dispose();" in cross[cross.index("host.onDispose(") :] # 종단도는 한 벌 — 보기가 숨어도 그대로 두고, 페이지를 떠날 때 한 번 정리한다. assert "shared.profile?.dispose();" in _read("A00_Common/design/design_page.ts") def test_3D_멈춤과_문맥_놓기(): viewer = _read("B05_Profile/B05_Profile_UI_Viewer.ts") assert "setActive(active)" in viewer assert "renderer.forceContextLoss();" in viewer # 보관 지형은 다음 뷰어가 쓴다 — 떠날 때 버리지 않는다. assert "if (terrain !== cachedTerrain.object) disposeObject(terrain);" in viewer assert len(viewer.splitlines()) <= 700 def test_창_키_듣기를_뗌(): tools = _read("B05_Profile/B05_Profile_UI_Profile_Panel_Tools.ts") assert 'window.removeEventListener("keydown", onKeyDown);' in tools assert 'window.addEventListener("keydown", (event)' not in tools profile = _read("A00_Common/design/design_profile.ts") assert "setListening(false);" in profile # dispose pick = _read("B05_Profile/B05_Profile_UI_Viewer_Structure_Pick.ts") assert "setListening(on)" in pick def test_겹친_알약은_누른_것을_그대로(): profile = _read("A00_Common/design/design_profile.ts") assert "stationIdAtStructure(selectedStructureId) === stationId" in profile def test_진행_단계_두_칸이_보기를_따라감(): """종단설계 · 횡단설계 두 칸은 같은 페이지 — 누르면 주소만 바꿔 보기만 바뀐다(계획서 24-3b).""" page = _read("A00_Common/design/design_page.ts") assert "const VIEW_STEP: Record = { profile: 2, cross: 3 };" in page assert "layout?.setActiveStep(VIEW_STEP[view]);" in page assert "layout?.setTitle(" in page click = page[page.index("onStepClick: (stepIndex) => {") :][:260] assert "if (designViewOf(route)) navigateTo(route);" in click layout = _read("ui_template/ui_template_workflow_layout.ts") assert "setActiveStep: (stepIndex) =>" in layout and "setTitle: (title) =>" in layout def test_초기화_계획노선_편집은_다시_세움(): """같은 페이지 안 이동은 보기만 바꾸므로 [초기화] · 계획노선 편집은 페이지를 다시 세운다.""" router = _read("A00_Common/router.ts") assert "export function remountRoute(" in router assert "remountRoute(ROUTES.B05_PROFILE)" in _read("A00_Common/design/design_reset.ts") assert "remountRoute(ROUTES.B05_PROFILE)" in _read("A00_Common/design/design_view_profile.ts") def test_종단_보기_확정은_횡단_보기를_숨긴_채_세움(): page = _read("A00_Common/design/design_page.ts") assert "ensureView: (view) => (slots.get(view) ?? mountView(view, false)).ready," in page cross = _read("A00_Common/design/design_view_cross.ts") # 숨긴 채 섰으면 한 벌 폼은 종단 보기 몫 — 보일 때 싣는다. assert "if (host.visible()) void structuresPanel.load()" in cross