Files
Aislo/resources/tester/test_346_3_route_save_screen.py
T
eomsangdonandClaude Opus 5.5 4eec3a4b37 feat(509-5 · 509-2 B05 추천 지형): 분석 지형 고르기 = 추천 노선 창 안 · 지형마다 추천 미리 셈 · [적용] = 창 지형이 설계 지형 · 평면은 지형 이름만 · 설계 지형 격자 하나(수치지형도 적용이면 그 격자)
- 전처리 미리 셈이 고를 수 있는 지형마다(설계 지형 먼저 · 수치지형도는 DB 모델 있을 때만) 다섯 갈래 + 초기 종단
- 창 지형 바꿈 = 그 지형 저장본만 · 없으면 409 안내(+[재계산]) · 기본값 판정에서 지형 뺌
- POST /route/initial terrain = 창 지형 · [적용] draft.terrain = 창 지형 · 손 [저장]은 지형 안 바꿈(서버도 as_initial 일 때만)
- 평면 분석 지형 고르기 · 화면 취향(routeedit-terrain) 걷음 · 지반고 · 묶음 초안 = 설계 지형(null) · 적용 뒤 받아 둔 격자 버림
- 시험 test_509_5 · test_509_2 · 걷은 고르기를 보던 옛 시험 새 동작으로(352_3 건너뜀)

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

155 lines
6.9 KiB
Python

"""346-3 화면 — [노선 반영] 없앰 · [저장]이 노선부터 · 추천 [적용] = as_initial 저장 · 저장 뒤 초안 넘김.
노선 이음(`B05_Profile_UI_RouteEdit_Apply`)은 Node 헬퍼 `helper_346_3_route_save.cjs` 가 서버 · 화면
창구만 가짜로 두고 돌림 · 서버 길 시험은 `test_346_3_route_save.py` · 저장 차례(노선 먼저 · 안 바뀌면
안 보냄 · 실패 때 초안 남음)는 `test_design_store_save.py`.
"""
from __future__ import annotations
import json
import subprocess
from pathlib import Path
import pytest
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[1]
def _read(rel: str) -> str:
return (ROOT / rel).read_text(encoding="utf-8")
@pytest.fixture(scope="module")
def out() -> dict:
run = subprocess.run(
["node", str(HERE / "helper_346_3_route_save.cjs")],
capture_output=True,
text=True,
encoding="utf-8",
check=True,
)
return json.loads(run.stdout)
def test_노선_안_바뀜_안_보냄(out):
assert out["noneAtAll"] is None
assert out["unchanged"] is None # 편집기가 정함 — 가게에 초안이 남아 있어도
assert out["storeOnly"]["draft"]["rev"] == 3 # 편집기 없으면 가게 routeDraft
def test_초안은_계약_RouteDraft_꼴(out):
draft = out["body"]["draft"]
assert set(draft) == {
"rev",
"nodes",
"curveOn",
"curveRadius",
"curveLock",
"curveArc",
"stationSnap",
"stationSnapStep",
"terrain",
}
n = len(draft["nodes"])
assert all(
len(draft[name]) == n for name in ("curveOn", "curveRadius", "curveLock", "curveArc")
)
assert draft["curveOn"] == [True, False, True] and draft["curveRadius"] == [None, 25, None]
assert draft["stationSnap"] is True and draft["terrain"] is None # 손 저장 = 설계 지형(509-5)
assert draft["stationSnapStep"] == 20 # 390-5 간격도 함께 실림
assert out["body"]["initial"] == {"mode": "follow"}
assert "balanced_profile" not in out["body"] # 손으로 고친 노선 = 계획고 옮김만(349-0v)
assert "as_initial" not in out["body"] # 손으로 고친 노선 = 초기값 그대로
def test_저장_뒤_가게_초안_비움_결과_한_줄(out):
assert out["savedRouteId"] == 9
assert out["storeAfterSave"] is None
assert out["keptAfterSave"] == 1
assert out["summary"] == "undefined" # 498-3 — 결과 한 줄(관 지킴 · 노선 밖 고침 …) 걷음
def test_초안_넘김_차례(out):
"""472-6 6-B — 넘김(측점 열쇠 · 누가거리 칸 · 얹기 · patch)은 서버가 같은 TS 로(Node `stations.carry` ·
`test_472_6_route_save`) · 브라우저는 옛 노선 세션 칸 원본 + 횡단 본문만 · 저장 뒤 상단측 · 종류 바꿈 비움."""
assert out["carryCalls"][0] == "carryInputs:7"
assert out["carry"] == {"from_keys": [], "from": 7}
assert out["crossBody"] == {
"standard": {"std": 1},
"massHaul": {"balloon_offsets": {"b": [1, 2]}},
}
assert out["uphillBeforeAfter"] == {"40.00": "right"} # 다 저장하기 전엔 그대로
assert out["uphillAfter"] is None and out["kindresetAfter"] is None
assert any("상단측 손 고침 1곳" in c for c in out["carryCalls"]) # 요구 274 — 새 지형이 정함
def test_추천_적용은_as_initial_저장_뒤_다시_세움(out):
assert out["recommendOk"] is True
body = out["recommendBody"]
assert body["as_initial"] is True and body["initial"] == {"mode": "earthwork"}
assert body["draft"]["nodes"] == [[1, 1], [9, 9]]
assert body["draft"]["terrain"] == "sheet" # 창 지형 = 설계 지형(509-5)
# 잠금 막 하나(472-6 6-B — 저장 직전 저장 관 떠 두기는 서버 한 본문 몫 · 추천은 초안을 비우니 안 받음)
assert out["recommendCalls"] == [
"overlay:on",
"replan",
"commit",
"grid:forget", # 새 설계 지형 격자로(509-2)
"overlay:off",
] # 초안 전 시설 버림
assert out["recommendDraftsLeft"] == {"route": None, "pipes": None} # 새 초기값에서 다시
assert out["rebuilt"] == 1
def test_추천_저장_실패는_한_줄_다시_안_세움(out):
assert out["recommendFail"] is False
errors = [c for c in out["recommendFailCalls"] if c.startswith("toast:error:")]
assert len(errors) == 1 and "체인 실패" in errors[0]
assert out["rebuiltAfterFail"] == 1
def test_노선_반영_단추_없앰_배선():
chrome = _read("B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts")
assert 'data-act="apply"' not in chrome and "노선 반영</button>" not in chrome
apply = _read("B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts")
assert "addEventListener" not in apply # 단추 듣기 없음 — [저장]이 부름
save = _read("A00_Common/design/design_save.ts")
assert "await pendingRouteSave(ctx.projectId)" in save
# 6-B — 노선 초안 = 한 본문 `route` 칸 · 서버가 맨 앞에서 노선 저장(옛 차례 길 걷음)
assert "route ? { route, carry: carried?.carry } : {}" in save
assert "carryAfterRouteSave" not in save and "saveRouteDraft" not in save
server = _read("B06_Section/B06_Section_Router_DesignSave.py")
assert server.index('step("route"') < server.index('step("settings"')
initial = _read("B05_Profile/B05_Profile_UI_RouteEdit_Initial.ts")
at = initial.index("onApply: (picked) => {")
assert "saveRecommendedRoute(" in initial[at : at + 900]
replan = _read("B05_Profile/B05_Profile_Api_Replan.ts")
assert "body: JSON.stringify(body)" in replan and "as_initial?: boolean;" in replan
def test_넘김_알림은_결과_한_줄에_합침():
"""346-3 덧 — [저장] 뒤 「노선 밖 고침」 두 줄 → 한 줄 · 넘김은 조용히 수만 · 기본은 알림 그대로."""
keys = _read("B06_Section/B06_Section_Station_Keys.ts")
assert "{ quiet = false }: { quiet?: boolean } = {}," in keys
assert "if (outside.size && !quiet)" in keys
patch = _read("B06_Section/B06_Section_Route_Carry_Patch.ts")
assert "outside: keyed.outside.size + chain.outside.size" in patch
# 498-3 — 결과 한 줄 걷음 · 남김 = 따라감 실패 · 새 교차 관
save = _read("A00_Common/design/design_save.ts")
assert "routeSaveSummary" not in save and "새 교차 관 ${crossing}개" in save
def test_노선_반영_글자_없음():
recommend = _read("B05_Profile/B05_Profile_UI_Panel_Recommend.ts")
assert "노선 반영" not in recommend # 칸 [초기화](「다시 계산은 [저장]에서」 글) 지움(418)
for rel in (
"B05_Profile/B05_Profile_UI_RouteEdit.ts",
"B05_Profile/B05_Profile_UI_RouteEdit_History.ts",
"B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts",
"A00_Common/design/design_view_profile.ts",
):
text = _read(rel)
assert "[노선 반영]" not in text and "[반영 전으로]" not in text, rel