Files
Aislo/resources/tester/test_design_view_parity.py
T
eomsangdonandClaude Opus 5.5 99ec4b8efe feat(B05 평면 지도): 공용 도구줄 표 · 겹 줄 · 범례 · 지형 칩 붙임 · 노선추천 = 도구줄 미리보기(넷 · 하나만 · 끔) · [적용] · 추천 모달 · 좌측 칸 걷음 · 지형 바꿈 = 지형 칩 (PLAN 624-3 · 626-1 · 요구 530 · 531)
- 624-3 도구줄 = 공용 표 「b05」 · 아래 줄 = 공용 겹 줄(띠 · 올린 임도망도 숨김 · 처음 = 등고선 · 하천) · 범례 = 공용 legendRows(상태 글판 위)
- 노선 띠 300 m 자르기 = B05 자기 칸(등고선 · 하천 · 1 m)만 · 그 밖 겹 = 안 자르는 둘째 GL 칸(맨 밑 · 켠 겹 있을 때만 · GL 만) · 등고선 끔 = 등고 글도 숨김
- 626-1 추천 보기 = 도구줄 아이콘 + 아래 판(영선 · 토공 최소 · 기울기 최소 · 비중 계산 · 끔) — route_recommend 저장본(지금 설계 지형) 선만 · 다시 셈 · 쓰기 없음
- 지형 칩 → 확인창 → 새 POST /route/design-terrain(설계 지형만 바꿈 · 노선 저장 체인 다시 · 노선 · 초기값 · 추천 저장본 그대로 · 잠금 · 실패 되돌림)
- 걷음 — 추천 모달(_Recommend · _Help · _Map · CSS) · 좌측 「노선 추천」 칸 · saveRecommendedRoute · UI_RouteReset(서버 as_initial 길 · 시험은 남김)
- 부품 상자 — createPickMenu(아이콘 고르기 메뉴 · 판 = body fixed · ✓)
- 낡은 시험 고침 · 지움 — 모달 · 좌측 칸 · [적용] 화면 배선을 보던 시험(283 · 346_3 · 349 · 364_4 · 383_1 · 390_5 · 418 · 421 · 421_2 · 476_2 · 509_2 · 509_5 · 551_2 · 600_3 · b05_routeedit_initial · design_view_parity · modal_top · 133_1 · 133_2) · test_508_2 · helper_283 지움(모달 전용)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 21:30:49 +09:00

153 lines
6.6 KiB
Python

# -*- coding: utf-8 -*-
"""B05 · B06 한 페이지 두 보기 — **좌측 패널 한 벌 지킴**(계획서 24-2f · 24-3b).
① 좌측 패널을 **하나** 세우고 보기를 오가도 뿌리 · 구조물 배치 · 아래 고정 영역 · 단추 셋이 같은 노드인지,
보기마다 제 칸만 보이는지 본다(Node 헬퍼 `helper_design_view_parity.cjs`
가 등록부를 트랜스파일해 가짜 DOM 위에서 돌린다).
② 보기 파일(`design_view_profile.ts` · `design_view_cross.ts`)이 좌측 칸 · 아래 단추 · 저장 단추를
직접 만들면 빨강 — 칸 · 단추 · 저장은 한 벌(`design_shared`)만 만든다.
"""
import json
import os
import re
import subprocess
from pathlib import Path
import pytest
HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = Path(HERE).parents[1]
PAGE_FILES = (
ROOT / "A00_Common" / "design" / "design_view_profile.ts",
ROOT / "A00_Common" / "design" / "design_view_cross.ts",
)
# 페이지 파일에 나오면 안 되는 것 — 좌측 칸 · 아래 단추 · 저장 단추를 직접 만든다는 표시.
FORBIDDEN_IN_PAGES = (
"createButton(",
"attachCollapsible(",
"buildGroup(",
"createSectionFrame(",
"registerPanelSection(",
"createDesignDock(",
"ui-sidebar-actions",
"b05-route__dock",
"b05-route__actions",
"b06-profile__actions",
"b06-profile__form",
"b05-route__panel",
"b06-profile__group",
"saveButton",
"confirmButton",
"actionDock",
)
@pytest.fixture(scope="module")
def results():
proc = subprocess.run(
["node", os.path.join(HERE, "helper_design_view_parity.cjs")],
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
def test_보기를_오가도_좌측_패널_단추_구조물_배치는_같은_노드(results):
assert results["sameNodes"] == {"cross": True, "back": True}
# 보기마다 새로 만들지 않는다 — 칸은 처음 보일 때 한 번만 서고 뒤로는 숨김 · 보임만.
# 아래 고정 영역 + 종단 칸 둘 + 횡단 칸 둘(345-2 선택 포인트 · 345-3 계획노선 지움 · 626-1 노선 추천 걷음)
assert results["childCount"] == 1 + 2 + 2
def test_구조물_배치는_두_보기_모두_맨_위_같은_DOM(results):
views = results["views"]
assert views["profile"]["structuresHtml"] == views["cross"]["structuresHtml"]
assert all(views[name]["structuresFirst"] for name in ("profile", "cross", "back"))
def test_구조물_목록은_두_보기_모두_아래_고정_영역_맨_위(results):
views = results["views"]
assert views["profile"]["dockFirstChild"] == views["cross"]["dockFirstChild"]
assert all(views[name]["dockIsLast"] for name in ("profile", "cross", "back"))
def test_보기마다_제_칸만_보인다(results):
views = results["views"]
assert views["profile"]["shownTitles"] == [
"구조물 배치",
"페이지 설정",
]
assert views["cross"]["shownTitles"] == ["구조물 배치", "횡단 보기 설정", "표준 횡단면 설정"]
assert views["back"]["shownTitles"] == views["profile"]["shownTitles"]
assert results["sectionIds"]["cross"] == ["structures", "cross-view", "standard-cross"]
def test_아래_단추는_둘_보기_전환_없음(results):
"""[노선 보기] · [횡단 보기] 지움 — 보기 오가기는 공용 [<] [>](요구 280-2) · [확정] 지움 = B06 [>](496-1)"""
views = results["views"]
for name in ("profile", "cross", "back"):
assert views[name]["dockActions"] == ["save", "reset"]
assert views[name]["dockLabels"] == ["저장", "초기화"]
assert views[name]["dockDisabled"] == [False, False]
# [초기화] = 테두리 · 글만 빨강(danger-ghost) · [저장] = ghost
assert views[name]["dockClasses"] == ["ui-btn ui-btn--ghost", "ui-btn ui-btn--danger-ghost"]
def test_단추는_한_벌_동작을_부름(results):
names = ["save", "reset"]
assert results["calls"] == [
*(f"profile:{n}" for n in names),
*(f"cross:{n}" for n in names),
*(f"profile:{n}" for n in names),
]
def test_횡단_보기_칸_정의와_차례():
"""B06 칸 정의는 소스로도 본다 — 차례가 바뀌면 빨강."""
source = (ROOT / "B06_Section" / "B06_Section_UI_Page_Panel.ts").read_text(encoding="utf-8")
found = re.findall(
r'id: "([\w-]+)",\s*title:[^\n]*\n\s*views: \["cross"\],\s*order: (\d+)', source
)
ordered = [name for name, _ in sorted(found, key=lambda item: int(item[1]))]
assert ordered == ["cross-view", "standard-cross"]
shared = (ROOT / "A00_Common" / "design" / "design_sections.ts").read_text(encoding="utf-8")
assert 'views: ["profile", "cross"]' in shared # 구조물 배치는 한 정의로 두 보기
@pytest.mark.parametrize("page", PAGE_FILES, ids=lambda path: path.name)
def test_보기_파일이_좌측_칸_단추_저장을_직접_만들지_않는다(page):
text = page.read_text(encoding="utf-8")
found = [marker for marker in FORBIDDEN_IN_PAGES if marker in text]
assert not found, f"{page.name} 이(가) 좌측 칸 · 단추를 직접 만든다: {found}"
assert "createDesignPanel(" not in text and "saveDesign(" not in text
# 좌측 패널은 한 벌을 쓴다 — 종단 보기는 칸 재료 모듈(`createRoutePanel`)이 대신 부른다.
assert "sharedPanel(shared)" in text or "createRoutePanel(" in text
route_panel = (ROOT / "B05_Profile" / "B05_Profile_UI_Panel.ts").read_text(encoding="utf-8")
assert "sharedPanel(shared)" in route_panel
def test_한_벌이_패널_종단도_폼을_한_번만_만든다():
shared = (ROOT / "A00_Common" / "design" / "design_shared.ts").read_text(encoding="utf-8")
for maker in ("createDesignPanel(", "createDesignProfile(", "createStructuresSection("):
assert shared.count(maker) == 1, maker
for guard in (
"if (shared.panel) return shared.panel;",
"if (shared.profile) return shared.profile;",
"if (shared.structures) return shared.structures;",
):
assert guard in shared
# 보기 쪽은 만들지 않고 한 벌을 쓴다.
for relative in (
"B05_Profile/B05_Profile_UI_Panel.ts",
"B05_Profile/B05_Profile_UI_Profile_Panel.ts",
"B06_Section/B06_Section_UI_Section_View_Profile.ts",
"B06_Section/B06_Section_UI_Page_Structures_Panel.ts",
):
text = (ROOT / relative).read_text(encoding="utf-8")
for maker in ("createDesignPanel(", "createDesignProfile(", "createStructuresSection("):
assert maker not in text, f"{relative} 가 {maker} 를 따로 부름"