- UI_Main showView 에 tools(빈 slot · 다음 열기 때 drop 이 비움) · .m02-main__tools 오른쪽 끝 - 읽기 층은 단추 없음 · 목록 안 옛 단추 뺌 - 조합 목록 = ui-general-block__table(줄 선 · 머리 줄 고정) · 줄 누름 모양 - 시험 test_m02_labor_tree 한 건 더함 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BU9gbNE3aWFUvE61pS2WGt
125 lines
6.2 KiB
Python
125 lines
6.2 KiB
Python
"""일위대가 라이브러리 나무 자료(PLAN 27-2b · `Labor_Tree.ts`) — Node 로 TS 를 돌려 판정.
|
|
|
|
못박는 것
|
|
- 조합 → 나무 항목: 경로 = [구분, 상세구분, 이름](빈 칸 건너뜀) · 열 = 키.
|
|
- 나무 고침 알림: 새 · 바뀐 · 옮긴 폴더 경로 · 조합 고침은 그 조합(열)을 고른 채 ·
|
|
지우기는 고름 없음.
|
|
"""
|
|
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
SCRIPT = r"""
|
|
const fs = require("fs");
|
|
const ts = require(process.argv[1] + "/config/node_modules/typescript");
|
|
const file = "/M02_MasterTemplete/M02_MasterTemplete_Labor_Tree.ts";
|
|
const src = fs.readFileSync(process.argv[1] + file, "utf8");
|
|
const js = ts.transpileModule(src, {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
new Function("exports", "module", "require", js)(box.exports, box, require);
|
|
const m = box.exports;
|
|
const row = (키, 이름, 구분, 상세구분) => ({ 키, 이름, 구분, 상세구분, 단위: "m" });
|
|
const list = {
|
|
판: "v1",
|
|
폴더: [["석축"], ["석축", "찰쌓기"], ["빈"]],
|
|
줄: [row("UP1-000001", "가", "석축", "찰쌓기"), row("UP1-000002", "나", "석축", null),
|
|
row("UP1-000003", "다", null, "무시")],
|
|
};
|
|
const view = m.toView(list);
|
|
const notes = [
|
|
{ op: "add-folder", 경로: ["석축"], 이름: "메쌓기" },
|
|
{ op: "rename", 경로: ["석축", "찰쌓기"], 이름: "찰" },
|
|
{ op: "move", 경로: ["석축", "찰쌓기"], 새경로: [] },
|
|
{ op: "move", 경로: ["석축"], 키: "UP1-000002", 새경로: ["빈"] },
|
|
{ op: "rename", 경로: ["석축"], 키: "UP1-000002", 이름: "나나" },
|
|
{ op: "delete", 경로: ["석축"], 키: "UP1-000002" },
|
|
{ op: "delete", 경로: ["빈"] },
|
|
].map((e) => m.noteOf(e, e.op === "delete" ? ["UP1-000002"] : []));
|
|
console.log(JSON.stringify({ view, notes }));
|
|
"""
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def got():
|
|
if shutil.which("node") is None:
|
|
pytest.skip("node 가 없음")
|
|
proc = subprocess.run(
|
|
["node", "-e", SCRIPT, str(ROOT)], capture_output=True, text=True, encoding="utf-8"
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def test_조합이_나무_항목으로(got):
|
|
items = got["view"]["items"]
|
|
assert [i["경로"] for i in items] == [["석축", "찰쌓기", "가"], ["석축", "나"], ["다"]]
|
|
assert [i["열"] for i in items] == ["UP1-000001", "UP1-000002", "UP1-000003"]
|
|
assert got["view"]["폴더"] == [["석축"], ["석축", "찰쌓기"], ["빈"]]
|
|
assert "알림" not in got["view"]
|
|
|
|
|
|
def test_나무_고침_알림(got):
|
|
add, rename, move, move_item, rename_item, delete_item, delete_folder = got["notes"]
|
|
assert add["경로"] == ["석축", "메쌓기"] and "열" not in add
|
|
assert rename["경로"] == ["석축", "찰"]
|
|
assert move["경로"] == ["찰쌓기"]
|
|
assert move_item["열"] == "UP1-000002" and move_item["경로"][:-1] == ["빈"]
|
|
assert rename_item["경로"] == ["석축", "나나"]
|
|
assert "열" not in delete_item and delete_item["지운항목"] == ["UP1-000002"]
|
|
assert "경로" not in delete_folder
|
|
|
|
|
|
def test_뿌리를_바꿔도_일위대가_화면_유지_해시도_맞춤():
|
|
"""브레인 검증 흠(27-2b) · 29-2 — 층 단추 두 벌(일위대가 라이브러리 · 구조물 조합 줄 아래) ·
|
|
일위대가 단추로 층을 바꾸면 일위대가 화면 그대로 · 좌측 「일위대가 라이브러리」를 열면 해시
|
|
`open=일위대가`(다시 그리지 않고 주소만)."""
|
|
page = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_UI_Page.ts").read_text("utf-8")
|
|
assert "go: (next, nextOwner) => void go(next, nextOwner, open)," in page # 두 벌 같은 길
|
|
assert (
|
|
'bar: (add, back) => layerBar("일위대가", add, back),' in page
|
|
and 'layerBar("구조물조합", tree.add, () => void main.openTable(layer)),' in page
|
|
)
|
|
labor = page.split("buildLaborSection({")[1].split("make:")[0]
|
|
assert 'mark("일위대가")' in labor # 여는 순간 해시 open
|
|
assert "history.replaceState" in page # hashchange 없이(화면 다시 안 그림)
|
|
assert 'if (main.current() && view === "일위대가") mark("구조물조합")' in page
|
|
|
|
|
|
def test_일위대가_나무에_여러_개_복사_붙여넣기_연결():
|
|
"""PLAN 30-3 — 공용 나무 부품(30-2) 콜백을 일위대가 서버 길에 이음 ·
|
|
붙임 종류는 따로(구조물과 안 섞임)."""
|
|
labor = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_Labor.ts").read_text("utf-8")
|
|
assert 'clipKind: "일위대가"' in labor and "copyTo: opt.copyTo" in labor
|
|
assert "editComboTreeMany(ops, 판, scope)" in labor # 여러 개 옮기기 · 지우기
|
|
assert "pasteCombos(clip.from as LaborScope, pick, dest, list.판, to)" in labor # 대상 층
|
|
page = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_UI_Page.ts").read_text("utf-8")
|
|
assert "canEdit: isAdmin, reveal, copyTo })" in page # 구조물 나무와 같은 「〇〇로 복사」 목록
|
|
|
|
|
|
def test_새_조합_단추는_제목_줄_오른쪽_목록은_공용_표():
|
|
"""PLAN 30-5 — 「새 조합」 = 제목 줄 오른쪽 끝(읽기 층 없음) · 목록 = 공용 표(줄 선).
|
|
머리 줄도 공용 표 모양."""
|
|
edit = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_Labor_Edit.ts").read_text("utf-8")
|
|
assert (
|
|
"newButton: edit" in edit and 'className: "ui-general-block__table m02-labor__list"' in edit
|
|
)
|
|
assert (
|
|
'tc("New"), variant: "filled", onClick: () => startNew([]) })]' not in edit
|
|
) # 목록 안 옛 자리
|
|
labor = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_Labor.ts").read_text("utf-8")
|
|
assert 'library.bind(opt.show(tc("Library"), library.root, library.tools))' in labor
|
|
main = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_UI_Main.ts").read_text("utf-8")
|
|
assert (
|
|
'slot.replaceChildren(el("span", { className: "m02-main__tools", children: [tools] }))'
|
|
in main
|
|
)
|
|
css = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_UI_Style.css").read_text("utf-8")
|
|
assert ".m02-main__tools {\n display: inline-flex;\n margin-left: auto;" in css
|