"""272 · 468 (C1) 되돌리기 빈 칸 — 「{}」 · 「null」 · 「""」 = 칸 없음 · 세션 맵 빈 쓰기 = 칸 지움. R4 — 교점 ↓ → ↶ → B06(누름 뒤 첫 마운트가 빈 맵 여섯 「{}」를 씀) → ↶ 켜짐 · ↷ 사라짐 → 이제 ↶ 꺼짐 · ↷ 남음. 「[]」 는 목록 초안(관 · 구조물 모두 지움 = 저장분과 다름)이라 걸음 그대로. 짝: `helper_272_value_hold.mjs`(vite ssr 로 묶은 진짜 모듈 · `helper_272_entry.ts`). ./venv/Scripts/python.exe -m pytest resources/tester/test_272_history_empty_cells.py -q """ from __future__ import annotations import json import shutil import subprocess from pathlib import Path import pytest HERE = Path(__file__).resolve().parent ROOT = HERE.parents[1] pytestmark = pytest.mark.skipif( not (ROOT / "config" / "node_modules" / "vite").is_dir(), reason="프론트엔드 의존성 미설치", ) def run_helper(tmp_path_factory: pytest.TempPathFactory) -> dict: work = tmp_path_factory.mktemp("b272") build = subprocess.run( [ "node", str(ROOT / "config" / "node_modules" / "vite" / "bin" / "vite.js"), "build", "--configLoader", "runner", "--ssr", "../resources/tester/helper_272_entry.ts", "--outDir", str(work), "--logLevel", "error", ], cwd=ROOT, capture_output=True, text=True, encoding="utf-8", timeout=300, ) assert build.returncode == 0, build.stderr bundle = work / "bundle.mjs" shutil.copy(work / "helper_272_entry.js", bundle) proc = subprocess.run( ["node", str(HERE / "helper_272_value_hold.mjs"), str(bundle)], cwd=ROOT, capture_output=True, text=True, encoding="utf-8", timeout=120, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) @pytest.fixture(scope="module") def out(tmp_path_factory): return run_helper(tmp_path_factory) def test_되돌린_뒤_빈_칸이_생겨도_다시하기_남음(out): h1 = out["h1"] assert h1["edited"] is True assert h1["undone"] == {"undo": False, "redo": True, "grade": None} # 빈 맵 여섯 「{}」 · 「null」 · 「""」 = 걸음 아님 assert h1["after"] == {"undo": False, "redo": True} def test_사용자_조작은_한_걸음_그대로(out): h1 = out["h1"] assert h1["redone"] is True assert h1["redoGrade"] == json.dumps({"station_offsets": {"100": 1}}, separators=(",", ":")) assert h1["final"] == {"undo": True, "redo": False} def test_빈_목록_초안은_걸음(out): # 관 모두 지움(「[]」) ≠ 칸 없음(저장분 관) — 되돌리기 · 다시하기 그대로 assert out["h2"] == {"step": True, "undonePipes": None, "redonePipes": "[]"} def test_빈_칸_걸음으로_되돌리면_빈_칸(out): h3 = out["h3"] assert h3["step"] is True assert h3["crossw"] in (None, "{}") # 빈 칸 = 칸 없음(읽는 쪽은 빈 맵) assert h3["revetx"] == json.dumps({"100.00:inlet": {"x": 1}}, separators=(",", ":")) def test_세션_맵_빈_쓰기는_칸_지움(out): h4 = out["h4"] assert h4["emptyWrite"] is None assert h4["filledWrite"] == '{"100.00":6}' assert h4["clearedWrite"] is None # 472-5 5-D — 메모리 맵 · 맵 이동(moveSessionMaps)을 걷음 · 측점 이동은 세션 칸을 바로(`Station_Keys`) · # 연동 두 겹은 둘 다 빌 때 칸 지움 assert h4["linkBoth"] == '{"detached":{"100.00":true},"grade":{"100.00":false}}' assert h4["linkGrade"] == '{"detached":{},"grade":{"100.00":false}}' assert h4["linkCleared"] is None