Files
Aislo/resources/tester/test_401_project_isolation.py
T
eomsangdonandClaude Opus 5.5 2da632dc45 refactor(B05·B06): 부름 0 옛 줄 · 늘 건너뛰는 시험 지움 (PLAN 472-8 ② ③ · 요구 409)
지움
- flushDesignStore(design_store · 부름 0) — 시험 344-4 의 flush 대조 한 줄도
- b_page_state 옛 세션 열쇠 옮김(legacy · migrate) · b_project_switch 옛 키 머리
  — 옛 열쇠는 세션 저장소(탭 닫으면 사라짐) · 지금 코드가 안 씀 · storage · DB 에 없음
  · 시험 290-1 · 401 · 384-1 의 옛 키 줄 뺌
- 시험만 부르던 TS — planFootprint(346-2 거울은 footprintRecord + slopePieces 로 그대로)
  · shiftSegment · shiftMovingPoints(쉬프트 단추는 09-02 지움 · min_cover_guard 쉬프트 시험 뺌)
  · dropStationsNear(test_b05_station_merge.mjs 지움) · createIrregularStationsSection(부름 0)
  · generalStations(234-1 은 기본 맞춤 값으로 같은 것 잼) · sameSummaryItem
- test_b05_b06_save_roundtrip + helper_b05_save_payload 둘 — 프로젝트 936be972 storage 없어 늘 skip
  · 같은 저장 왕복은 test_472_6_design_save(창구 원자성) · test_449_save_pipes(관 PUT)
    · test_238_1_save_keeps_structure_stations(구조물 측점)가 잼

남김
- migrateLegacyStations — 부르는 곳 있음(design_view_profile_sections) · storage 에 비정규 측점 남음
- common_util_excavation 셋 — 지금은 운영이 부름(design_calc_node)

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

109 lines
5.0 KiB
Python

"""401 프로젝트마다 따로 동작(요구 400~403 · PLAN 572).
- 지금 프로젝트 = 탭마다(탭 세션 칸 먼저 · 새 탭 = 마지막 값) · 다른 프로젝트 화면을 그리려 하면 새로 엶
- 떠남 = 그 프로젝트 세션 칸 · 준비 표식 · 3D 보관함 몫만 지움 · 밖 칸 · 취향 · CAD 복구본 · 다른 탭은 그대로
- 떠남 물음 = 화면에 붙은 가드 {dirty, save} 를 모아 [취소 · 폐기 · 저장] 한 번
`helper_401_project_isolation.cjs` 가 진짜 TS 를 가짜 저장소 · 가짜 IndexedDB 위에서 돌림.
"""
import json
import os
import re
import subprocess
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
HERE = os.path.dirname(os.path.abspath(__file__))
X = "11111111-aaaa-4aaa-8aaa-000000000001"
Y = "22222222-bbbb-4bbb-8bbb-000000000002"
#: 아직 직접 읽는 B · D · E 페이지(572-2 · 572-3 창 몫) — 고치면 여기서 뺌.
PENDING: set[str] = set()
@pytest.fixture(scope="module")
def out():
proc = subprocess.run(
["node", os.path.join(HERE, "helper_401_project_isolation.cjs")],
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
def test_탭마다_지금_프로젝트(out):
assert out["newTabStartsWithLast"] == X
assert out["tabs"] == {"a": X, "b": Y, "fresh": Y, "last": Y}
def test_다른_프로젝트_화면은_새로_엶(out):
assert out["reload"] == {"first": False, "same": False, "other": True, "count": 1}
def test_떠남은_그_프로젝트_몫만_지움(out):
leave = out["leave"]
assert leave["keys"] == leave["expected"] # B · D · E · 준비 표식 0 · 밖 칸 그대로
assert leave["entered"] == X # 탭 프로젝트 표식은 남김
assert leave["local"] == ["1", "1"] # 취향 · CAD 복구본
assert leave["idb"] == [f"{Y}|u1"] # 보관함 = X 줄만 지움
assert leave["otherTabKept"] == "1" # 다른 탭 세션은 안 건드림
assert leave["notified"] == 6 # 지운 칸마다 지움 알림 — 설계 가게가 미룬 쓰기(1 s)를 거둠
def test_떠남_물음_한_번(out):
g = out["guard"]
assert g["armed"] and g["cleanLeave"] and not g["cleanUnload"] and g["asked0"] == 0
assert g["dirtyUnload"] and g["cancel"] is False and g["save"] is True
assert g["messages"] == ["둘째 글", "둘째 글"] # 고친 가드 하나 = 그 글
assert g["saveFail"] is False and g["discard"] is True
assert g["saves"] == [2, 1] and g["discards"] == 1 # 고친 가드만 저장
assert g["samePage"] and g["reArmed"] and g["samePageAsked"] == 0
def test_지금_프로젝트_직접_읽기는_한_곳():
hits = set()
tracked = subprocess.run(
["git", "ls-files", "*.ts"], cwd=ROOT, capture_output=True, text=True, check=True
).stdout.split() # storage · node_modules 는 훑지 않음
for rel in tracked:
text = (ROOT / rel).read_text(encoding="utf-8", errors="ignore")
if re.search(r"localStorage\.getItem\(\s*CURRENT_PROJECT_ID_KEY", text):
hits.add(rel)
assert hits - PENDING == {"A00_Common/b_project_switch.ts"} - PENDING
assert "A00_Common/b_project_switch.ts" in hits
def test_공용이_도우미를_씀():
router = (ROOT / "A00_Common/router.ts").read_text(encoding="utf-8")
assert "export const isProjectRoute" in router and "reloadIfOtherProject()" in router
group = (ROOT / "A00_Common/group_workflow.ts").read_text(encoding="utf-8")
assert "guardProjectLeave(root, { dirty, save, discard, message })" in group
leave = (ROOT / "A00_Common/design/design_leave.ts").read_text(encoding="utf-8")
assert "guardProjectLeave(root, {" in leave
state = (ROOT / "A00_Common/b_page_state.ts").read_text(encoding="utf-8")
for name in ("d02-points", "e02-ground", "e03-prob", "e04-settings", "e05-report"):
assert f'"{name}": {{ bucket: "draft", scope: "project"' in state
assert '"e06-rock"' in state and '"e07-settings"' in state
def test_떠남_취소_뒤_단계_단추_다시_맞춤():
# [취소] = 주소만 되돌림(hashchange 없음) → 「되돌림」 알림으로 [<] [>] 다시 맞춤
main = (ROOT / "A00_Common/main.ts").read_text(encoding="utf-8")
assert "window.dispatchEvent(new Event(ROUTE_RESTORED_EVENT))" in main
help_ts = (ROOT / "ui_template/ui_template_help.ts").read_text(encoding="utf-8")
assert "window.addEventListener(ROUTE_RESTORED_EVENT, onHash);" in help_ts
def test_떠남은_물음_뒤_한_자리에서_비움():
# 572-4 — hashchange 가드(물음)를 지난 renderAll 첫머리 · 프로젝트 화면 → 밖 일 때만
main = (ROOT / "A00_Common/main.ts").read_text(encoding="utf-8")
render = main[main.index("const renderAll") : main.index("const within")]
assert "isProjectRoute(shown) && !isProjectRoute(currentRoute())" in render
assert "leaveProject(currentProjectId())" in render
assert main.index("takeLeaveGuard()") > main.index("const renderAll") # 물음은 renderAll 앞에서