"""관리 화면 「구조물 조합」(PLAN 26-7a~d) — 이름 · 숨김(비고 · 전구간 · 합계) · 참조표 잠금 · 나무 자리. ① `comboView` · `comboMerge`(Node) — 보일 문서에서 비고 열 · 줄 · 합계 줄을 빼고, [저장] 때 저장본 것을 다시 끼움(열 차례 = 저장본 · 보인 고침은 받음). ② 표 부품 `lockHead` — 열 더하기 · 지우기 · 머리 · 층 이름 고치기 없음(단위 · 조회 후 선택은 그대로). ③ 좌측 패널에 나무 없음 · 페이지가 나무를 편집 칸 왼쪽(`aside`)에 · 「구조물 조합」일 때만 보임. """ from __future__ import annotations import json import re import shutil import subprocess from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] M02 = ROOT / "M02_MasterTemplete" SHEET = ROOT / "ui_template" / "sheet" def _text(path: Path) -> str: return path.read_text(encoding="utf-8") @pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음") def test_숨긴_것은_저장_때_저장본에서_다시_끼움(): src = _text(M02 / "M02_MasterTemplete_Structure.ts") part = re.search( r"^const HIDDEN_COLUMNS[\s\S]*?^export function comboMerge[\s\S]*?^}", src, re.M ) assert part, "comboView · comboMerge 를 못 찾음" script = ( "interface StructureColumn { id: string; 머리: (string | null)[]; 꼴?: string | null;" " 단위?: string }\n" + part.group(0).replace("export ", "") + """ const stored = { 열: [{ id: "no", 머리: ["NO"] }, { id: "a", 머리: ["가"], 꼴: "수" }, { id: "b", 머리: ["나"], 꼴: "수" }, { id: "memo", 머리: ["비고"] }], 줄: [{ id: "all", 값: { memo: "x" } }], 합계줄: [{ id: "sum" }], 변수: { k: 1 }, }; const view = comboView(stored); const edited = structuredClone(view); edited.열[2].단위 = "m"; const saved = comboMerge(stored, edited); console.log(JSON.stringify([ view.열.map((c) => c.id), view.줄, view.합계줄, stored.열.length, saved.열.map((c) => c.id), saved.열[2].단위, saved.줄, saved.합계줄, saved.변수, ])); """ ) result = subprocess.run( ["node", "--experimental-strip-types", "--no-warnings", "--input-type=module-typescript", "-e", script], capture_output=True, text=True, encoding="utf-8", timeout=60, ) # fmt: skip assert result.returncode == 0, result.stderr assert json.loads(result.stdout) == [ ["no", "a", "b"], [], [], 4, # 저장본은 안 바뀜 ["no", "a", "b", "memo"], "m", [{"id": "all", "값": {"memo": "x"}}], [{"id": "sum"}], {"k": 1}, ] def test_참조표는_열_머리를_못_고침(): sheet = _text(SHEET / "ui_template_sheet.ts") assert 'const editCols = opts.mode === "master" && !ro && !opts.lockHead;' in sheet assert "if (editCols) toolbar.append(colDelete);" in sheet assert "if (editCols) syncLevels(!!col);" in sheet assert "if (th && editCols) editHead(th);" in sheet assert "else if (layer && editCols) editLayer(layer);" in sheet assert 'ro || opts.lockHead ? { hidden: "" }' in sheet render = _text(SHEET / "ui_template_sheet_render.ts") assert 'const heads = mode === "master" && !state.headLocked;' in render main = _text(M02 / "M02_MasterTemplete_UI_Main.ts") assert "struct ? comboView(doc) : doc" in main assert "getDoc: () => comboMerge(loaded, shown.getDoc())" in main def test_나무는_편집_칸_왼쪽_좌측_패널엔_없음(): side = _text(M02 / "M02_MasterTemplete_UI_Side.ts") assert "createTreePanel" not in side and "M02_TreeTitle" not in side assert 'info.이름 === STRUCTURE_TABLE ? L("M02_KindTable")' in side # 좌측 줄 이름 page = _text(M02 / "M02_MasterTemplete_UI_Page.ts") assert "createTreePanel({" in page and "aside," in page and "tree.select(column)" in page main = _text(M02 / "M02_MasterTemplete_UI_Main.ts") assert 'at.kind === "table" && at.name === STRUCTURE_TABLE && at.layer !== "project"' in main assert 'isCombo(next) ? L("M02_KindTable")' in main # 상세 제목 assert main.count("showAside();") == 3 # 열 때 · 양식 밖 화면 · 처음 locale = _text(ROOT / "ui_template" / "ui_template_locale_m2.ts") assert 'M02_KindTable: ["구조물 조합"' in locale assert ".m02-shell__tree[hidden]" in _text(M02 / "M02_MasterTemplete_UI_Style.css") tree = _text(M02 / "M02_MasterTemplete_TreePanel.ts") assert ( 'error instanceof StaleError && error.message === "HTTP 409"' in tree ) # 같은 이름 = 까닭 글