"""183-3 자재단가대비표 적용 단가 — 칸 누름 고르기 메뉴 · 고른 출처 칸 강조 · 기본 최저. - 공용 표 `cellClass` 옵션(칸 class · 안 주면 같은 글) — Node 로 `renderDataTableHtml` - 고르기 항목 `appliedChoices`(값 있는 출처 · 견적 · 최저(자동) · ✓ 표시) — Node 로 함수만 떼어 돌림 - 배선: 수기 적용 칸 · 출처 칸 돌림 없앰 · Shell 이 cellClass · choices 를 넘김 · B09 메뉴 한 벌 셈 · 저장(pick › applied › 최저)은 그대로(test_144 · test_166_4). """ import json import subprocess from pathlib import Path ROOT = Path(__file__).resolve().parents[2] TS = ROOT / "config" / "node_modules" / "typescript" def _src(rel: str) -> str: return (ROOT / rel).read_text(encoding="utf-8") def _node(script: str): out = subprocess.run( ["node", "-e", script], capture_output=True, text=True, encoding="utf-8", timeout=60 ) assert out.returncode == 0, out.stderr return json.loads(out.stdout) PRELUDE = f""" const fs = require("fs"); const ts = require({json.dumps(str(TS))}); const js = (code) => ts.transpileModule(code, {{ compilerOptions: {{ module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }}, }}).outputText; """ def test_공용_표_cellClass_칸_class_안_주면_같은_글(): table = json.dumps(str(ROOT / "ui_template" / "ui_template_data_table.ts")) got = _node( PRELUDE + f""" const box = {{ exports: {{}} }}; new Function("exports", "module", "require", js(fs.readFileSync({table}, "utf8")))( box.exports, box, (p) => (p.endsWith(".css") ? {{}} : require(p))); const m = box.exports; const o = {{ columns: [{{ key: "a", label: "A" }}, {{ key: "b", label: "B" }}], rows: [{{ a: 1, b: 2 }}, {{ a: 3, b: 4 }}] }}; const marked = m.renderDataTableHtml({{ ...o, cellClass: (i, k) => (i === 0 && k === "b" ? "is-picked" : null) }}); console.log(JSON.stringify({{ plain: m.renderDataTableHtml(o), none: m.renderDataTableHtml({{ ...o, cellClass: () => null }}), count: marked.split("is-picked").length - 1, row0: marked.split("")[1].split("")[0], }})); """ ) assert got["plain"] == got["none"] assert got["count"] == 1 and '2' in got["row0"] def test_고르기_항목_값_있는_출처_견적_최저_자동(): base = _src("B09_Estimation/B09_Estimation_UI_Tabs_Base.ts") start = base.index("function appliedChoices") body = base[start : base.index("\n}\n", start) + 3] sources = _src("B09_Estimation/B09_Estimation_Calc_Base.ts") at = sources.index("export const SOURCES") line = sources[at : sources.index(";", at) + 1] + "\n" got = _node( PRELUDE + f""" const appliedChoices = new Function(js({json.dumps(line.replace("export ", "") + body)}) + "; return appliedChoices;")(); const r = {{ prices: {{ 관급: null, 물가정보: 1200, 물가자료: 0, 유통물가: 1000, 견적: 1500 }}, lowest_from: "유통물가", applied_from: "유통물가", pick: null }}; const seen = []; const items = appliedChoices(r, (s) => seen.push(s)); items.forEach((x) => Array.isArray(x) && x[1]()); const pick = {{ ...r, applied_from: "견적", pick: "견적" }}; console.log(JSON.stringify({{ labels: items.map((x) => (Array.isArray(x) ? x[0] : x)), seen, picked: appliedChoices(pick, () => 0).map((x) => (Array.isArray(x) ? x[0] : x)), }})); """ ) assert got["labels"] == [ "물가정보 1,200", "✓ 유통물가 1,000 · 최저", "견적 1,500", "-", "✓ 최저(자동)", ] assert got["seen"] == ["물가정보", "유통물가", "견적", None] assert got["picked"][2] == "✓ 견적 1,500" and got["picked"][-1] == "최저(자동)" def test_배선_수기_적용_칸_출처_돌림_없앰(): base = _src("B09_Estimation/B09_Estimation_UI_Tabs_Base.ts") compare = base[base.index("export const buildCompare") : base.index("function usesOf")] assert 'editable: (_i, key) => key === "p:견적",' in compare assert "nextPick" not in base and 'key === "applied_from"' not in compare assert 'key === `p:${rows[i]?.applied_from}` ? "is-picked"' in compare assert ( 'key === "applied" && rows[i] ? chooseApplied(rows[i]) : null' in compare ) # 257-3 메뉴 둘 공용 assert "delete cell.applied" in compare shell = _src("B09_Estimation/B09_Estimation_UI_Shell.ts") builders = _src("B09_Estimation/B09_Estimation_UI_Builders.ts") # 303-2 옵션 짜기 assert "cellClass: spec.cellClass," in builders and "...tableOptionsOf(spec, tab)," in shell assert "openMenuAt(box.left, box.bottom, items)" in shell edit = _src("B09_Estimation/B09_Estimation_UI_Tabs_Bill_Edit.ts") assert "export function openMenuAt(" in edit and "const ctxMenu = sharedMenu();" in edit css = _src("B09_Estimation/B09_Estimation_UI_Page.css") assert "td.is-picked" in css and "var(--color-success)" in css # 257-3 초록 테두리