Files
Aislo/resources/tester/test_m02_detail_nav.py
T
eomsangdonandClaude Opus 5.5 16ac946212 feat(m02): 상세 이동 단추 · 도면 상세에서 면적산출로 보내기(105-2 · 105-4)
- 상세 머리 제목과 ? 사이 [도면][일위대가][면적산출] — 지금 것 눌림 · 문서 없는 열은 꺼짐 · 뒤로 단추와 같은 보임
- 구조물 도면 상세 머리 [면적산출로 보내기] · TOAREA 듣기 — 같은 열 면적 상세로 옮겨 가 넣을 자리 창
- 미저장 도면이면 물음 · 읽기 · 프로젝트 층 막음 · 저장은 사용자 [저장]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KYZ2HWWdUwZWYnn3tQz7X
2026-10-08 16:22:20 +09:00

143 lines
5.9 KiB
Python

"""상세 이동 단추 · 도면 상세 → 면적산출(PLAN 105-2 · 105-4) — Node 로 판정 · 화면은 ORCA.
못박는 것
- 머리 제목과 [?] 사이 [도면][일위대가][면적산출](`ui-btn-group`) · 지금 상세 = 눌림(aria-pressed) ·
그 열 문서(번호)가 없으면 그 단추 꺼짐 · 프로젝트 층 · 남의 층은 번호를 안 읽고 다 켬 · 상세 아니면 숨김.
- 보임 조건 = 뒤로 단추와 같음 · 누름 = confirmLeave → open({...sel, kind}) · 지금 것 누름 = 그대로.
- 도면 상세 머리 [면적산출로 보내기] = CAD 요청 · 받은 표(TOAREA 도 같은 길) → 같은 열 면적 상세로 옮겨 가
넣을 자리 창(`importDrawingTable`) · 읽기 · 프로젝트 층은 단추 없음 · 떠나면 듣기를 뗌.
"""
import json
import shutil
import subprocess
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
M02 = ROOT / "M02_MasterTemplete"
SCRIPT = r"""
const fs = require("fs");
const ts = require(process.argv[1] + "/config/node_modules/typescript");
const src = fs.readFileSync(process.argv[1] + "/M02_MasterTemplete/M02_MasterTemplete_DetailNav.ts", "utf8");
const js = ts.transpileModule(src, {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
let fetched = 0;
let numbers = {};
const button = (o) => {
const b = { label: o.label, size: o.size, dataset: {}, attrs: {}, disabled: false, title: "", onClick: o.onClick };
b.setAttribute = (k, v) => (b.attrs[k] = v);
return b;
};
const stubs = {
"@ui/ui_template_elements": {
createButton: button,
el: (tag, o) => ({ tag, className: o.className, attrs: o.attrs, children: o.children, hidden: false }),
},
"./M02_MasterTemplete_Api_Fetch": {
fetchStructureNumbers: async () => (fetched++, numbers),
getActiveLayer: () => "system",
},
};
const box = { exports: {} };
new Function("exports", "module", "require", js)(box.exports, box, (n) => stubs[n] ?? require(n));
const gone = [];
const nav = box.exports.createDetailNav((kind) => gone.push(kind));
const view = () => ({
hidden: nav.root.hidden,
pressed: nav.root.children.map((b) => b.attrs["aria-pressed"]),
disabled: nav.root.children.map((b) => b.disabled),
});
const tick = () => new Promise((r) => setTimeout(r, 0));
(async () => {
const out = { className: nav.root.className, labels: nav.root.children.map((b) => b.label) };
numbers = { c1: { 도번: "SD-000001", 일위대가번: "", 면적번: "SA-000001" } };
nav.update({ layer: "system", kind: "area", name: "c1" });
out.before = view();
await tick();
out.area = view();
nav.update({ layer: "project", kind: "structure", name: "c1" });
await tick();
out.project = view();
nav.update({ layer: "company", kind: "labor", name: "c1" }); // 남의 층(지금 층 아님)
await tick();
out.other = view();
out.fetched = fetched;
nav.update(null);
out.none = view();
nav.root.children[1].onClick();
out.gone = gone;
console.log(JSON.stringify(out));
})();
"""
@pytest.fixture(scope="module")
def run():
node = shutil.which("node")
if not node:
pytest.skip("node 없음")
done = subprocess.run(
[node, "-e", SCRIPT, str(ROOT)],
capture_output=True,
text=True,
encoding="utf-8",
check=True,
)
return json.loads(done.stdout)
def _text(name: str) -> str:
return (M02 / name).read_text(encoding="utf-8")
def test_단추_셋_묶음(run):
assert run["labels"] == ["도면", "일위대가", "면적산출"]
assert "ui-btn-group" in run["className"]
def test_지금_것_눌림_없는_문서_꺼짐(run):
assert run["before"]["pressed"] == ["false", "false", "true"]
assert run["before"]["disabled"] == [False, False, False] # 번호 받기 전엔 켬
assert run["area"]["disabled"] == [False, True, False] # 일위대가번 없음 = 꺼짐
assert run["area"]["hidden"] is False
def test_프로젝트_남의_층은_안_읽음(run):
assert run["project"]["pressed"] == ["true", "false", "false"]
assert run["project"]["disabled"] == [False, False, False]
assert run["other"]["disabled"] == [False, False, False]
assert run["fetched"] == 1
def test_상세_아니면_숨김_누름은_옮겨_감(run):
assert run["none"]["hidden"] is True
assert run["gone"] == ["labor"]
def test_머리_줄_자리와_보임_조건():
main = _text("M02_MasterTemplete_UI_Main.ts")
assert " title,\n nav.root,\n helpSlot," in main # 제목과 ? 사이
assert "nav.update(back.hidden ? null : sel); // 보임 조건 = 뒤로 단추와 같음" in main
assert "if (!at || at.kind === kind || !(await confirmLeave())) return;" in main
assert "void open({ ...at, kind });" in main
css = (M02 / "M02_MasterTemplete_UI_Style.css").read_text(encoding="utf-8")
assert '.m02-main__nav .ui-btn[aria-pressed="true"]' in css
def test_도면_상세에서_면적으로_보내기():
main = _text("M02_MasterTemplete_UI_Main.ts")
block = main.split("const off = attachDrawingToArea(")[1].split("return;\n }\n empty(")[0]
assert 'readOnly || at.layer === "project"' in block # 읽기 · 프로젝트 층 막음
assert "if (!(await confirmLeave())) return;" in block # 미저장 도면이면 물음
assert 'await open({ ...at, kind: "area" });' in block
assert "void importDrawingTable(sheetHandle, table);" in block # 넣을 자리 창 · 저장은 사용자
assert "editor = { ...made, destroy: () => (off(), made.destroy()) };" in block # 떠나면 뗌
to_area = _text("M02_MasterTemplete_DrawingToArea.ts")
assert "postMessage({ type: EXPORT_TABLE_REQUEST }, window.location.origin)" in to_area
assert "if (data?.type !== EXPORT_TABLE || !data.table) return;" in to_area
assert "if (onTable) slot.append(send);" in to_area
assert "event.source !== win" in to_area # 다른 iframe(면적 도면 패널) 메시지는 안 받음