feat(D · E): 떠남 = 공용 물음 [취소 · 폐기 · 저장] · 캐시 = 등록표 · 프로젝트 = 탭 currentProjectId (PLAN 572-3 · 요구 400~403)

- D02 · D03 · E02 말없이 저장 → mountGroupStep {dirty, save, discard} 공용 물음
- D04 · E05 · E06 가드 새로 · E03 = 대표 단면 별 저장 진행 중일 때만 물음
- D02 · E02~E07 세션 직접 읽기 · 쓰기 → 등록표 d02-points · e02-ground · e03-prob · e04-settings · e05-report · e06-rock · e07-settings
- 아홉 페이지 localStorage 지금 프로젝트 직접 읽기 → currentProjectId() (다른 탭이 바꿔도 이 탭 그대로)
- test_560_4 D · E 줄 넓힘(옛 beforeLeave 단언 → dirty · save) · test_401 PENDING 에서 D · E 뺌

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-28 18:09:08 +09:00
co-authored by Claude Opus 5.5
parent a98533cf39
commit c3fbcb13f1
12 changed files with 220 additions and 112 deletions
@@ -33,15 +33,6 @@ PENDING = {
"B09_Estimation/B09_Estimation_UI_Tabs_Bill_Link.ts",
"B09_Estimation/draft/B09_Draft_Print_Page.ts",
"B11_Status/B11_Status_UI_Loading.ts",
"D02_PlanBase/D02_PlanBase_UI_Page.ts",
"D03_PlanAnalysis/D03_PlanAnalysis_UI_Page.ts",
"D04_PlanConfirm/D04_PlanConfirm_UI_Page.ts",
"E02_StabGround/E02_StabGround_UI_Page.ts",
"E03_StabSection/E03_StabSection_UI_Page.ts",
"E04_Stab3D/E04_Stab3D_UI_Page.ts",
"E05_StabReport/E05_StabReport_UI_Page.ts",
"E06_StabRock/E06_StabRock_UI_Page.ts",
"E07_StabArea/E07_StabArea_UI_Page.ts",
}
+57 -2
View File
@@ -1,5 +1,6 @@
"""560-4 D 단계 이동 = 저장 뒤 이동 지킴 시험 — 서버 · 화면 없이 소스만 본다.
단계 아이콘 · [<] [>] · 머리 메뉴 · 뒤로가 한 함수(beforeLeave)를 거치고 · D02 첫 불러오기 실패에도 지도를 세움."""
단계 아이콘 · [<] [>] · 머리 메뉴 · 뒤로가 한 함수(beforeLeave)를 거치고 · D02 첫 불러오기 실패에도 지도를 세움.
572-3 — D · E 페이지는 공용 가드에 {dirty, save} 를 둠(말없이 저장 없음) · 캐시 = 등록표 · 프로젝트 = currentProjectId."""
import re
from pathlib import Path
@@ -20,8 +21,62 @@ def test_group_step_waits_before_leave():
def test_d02_leave_saves_and_builds_map_on_fail():
ts = _src("D02_PlanBase/D02_PlanBase_UI_Page.ts")
assert "beforeLeave:" in ts and "ui-step-nav" not in ts # 따로 듣개 없음
assert "dirty:" in ts and "save:" in ts and "ui-step-nav" not in ts # 따로 듣개 없음
tail = ts[ts.rindex(" try {") :]
# 불러오기 catch 뒤에 paint() — 실패해도 지도 · 표를 세움
assert re.search(r"\} catch \(error\) \{[^}]*\}\s*active = firstEmpty\(\);\s*paint\(\);", tail)
assert "sameBase" in ts # 옛 캐시는 그때 서버 값이 지금과 같을 때만
# 572-3 D · E — 고침 판별 · 저장 · [폐기] 때 지울 등록표 칸(E03 = 별 저장 진행 중만 · 지울 칸 없음)
DE_GUARDED = {
"D02_PlanBase/D02_PlanBase_UI_Page.ts": "d02-points",
"D03_PlanAnalysis/D03_PlanAnalysis_UI_Page.ts": "d03-plan",
"D04_PlanConfirm/D04_PlanConfirm_UI_Page.ts": "d04-assignees",
"E02_StabGround/E02_StabGround_UI_Page.ts": "e02-ground",
"E03_StabSection/E03_StabSection_UI_Page.ts": None,
"E05_StabReport/E05_StabReport_UI_Page.ts": "e05-report",
"E06_StabRock/E06_StabRock_UI_Page.ts": "e06-rock",
}
DE_PAGES = [
*DE_GUARDED,
"E03_StabSection/E03_StabSection_UI_Prob.ts",
"E04_Stab3D/E04_Stab3D_UI_Page.ts",
"E07_StabArea/E07_StabArea_UI_Page.ts",
]
DE_STATES = [
"d02-points",
"e02-ground",
"e03-prob",
"e04-settings",
"e05-report",
"e06-rock",
"e07-settings",
]
def test_de_pages_guard_leave():
for path, name in DE_GUARDED.items():
ts = _src(path)
call = ts[ts.index("mountGroupStep(root") :]
call = call[: call.index("});")]
assert "dirty: () =>" in call and "save" in call, path
assert "beforeLeave" not in ts, path # 말없이 저장 없음 — 공용 셋 물음
if name:
assert f'discard: () => clearState("{name}", projectId)' in call, path
e03 = _src("E03_StabSection/E03_StabSection_UI_Page.ts")
assert "dirty: () => repPending > 0" in e03 and "repPending -= 1" in e03
def test_de_pages_shared_project_and_registry():
for path in DE_PAGES:
ts = _src(path)
assert "CURRENT_PROJECT_ID_KEY" not in ts and "localStorage" not in ts, path
assert "sessionStorage" not in ts, path
if path.endswith("_UI_Page.ts"):
assert "const projectId = currentProjectId();" in ts, path
registry = _src("A00_Common/b_page_state.ts")
for name in DE_STATES:
assert re.search(rf'"{name}": \{{[^}}]*bucket: "draft",[^}}]*scope: "project"', registry), (
name
)