Files
Aislo/resources/tester/test_m02_detail_nav.py
T
eomsangdonandClaude Opus 5.5 a6ddc84f1b feat(m02): 상세 머리 이동 단추 — 지금 페이지 숨김 · 이동 단추 · 머리 [?] 보통 크기(113-2)
- DetailNav 지금 상세 단추 hidden · size sm 지움 · 눌림 CSS 지움
- 머리 [?] 만 ui-btn--sm 뺌 · 카드 [?] 는 작게 그대로
- test_m02_detail_nav 기대 고침 · test_m02_layer_screen 머리 줄 정규식에 nav.root

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

152 lines
6.4 KiB
Python

"""상세 이동 단추 · 도면 상세 → 면적산출(PLAN 105-2 · 105-4) — Node 로 판정 · 화면은 ORCA.
못박는 것
- 머리 제목과 [?] 사이 [도면][일위대가][면적산출](`ui-btn-group` · 보통 크기) · 지금 상세 단추 = 숨김(113-2) ·
그 열 문서(번호)가 없으면 그 단추 꺼짐 · 프로젝트 층 · 남의 층은 번호를 안 읽고 다 켬 · 상세 아니면 숨김.
- 보임 조건 = 뒤로 단추와 같음 · 누름 = 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, hidden: 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,
shown: nav.root.children.map((b) => !b.hidden),
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),
sizes: nav.root.children.map((b) => b.size ?? null),
};
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"]
assert run["sizes"] == [None, None, None] # 113-2 — [다시 열기]와 같은 보통 크기
def test_지금_것_숨김_없는_문서_꺼짐(run):
assert run["before"]["shown"] == [True, True, False] # 113-2 — 지금 상세 단추 숨김
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"]["shown"] == [False, True, True]
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 "aria-pressed" not in css # 113-2 — 눌림 대신 숨김
# 머리 [?] 만 보통 크기 · 카드 [?] 는 작게 그대로(`helpParts` sm)
assert 'help?.button.classList.remove("ui-btn--sm");' in main
shell = _text("M02_MasterTemplete_CardShell.ts")
assert 'createButton({ label: CARD_TEXT.help, variant: "ghost", size: "sm" })' in shell
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(면적 도면 패널) 메시지는 안 받음