Files
Aislo/resources/tester/test_183_3_b09_applied_pick.py
T
eomsangdonandClaude Opus 5.5 9d5694371f feat(b09): 자재단가대비표 적용 단가 = 칸 누름 고르기 메뉴 · 고른 출처 칸 강조 · 기본 최저 (183-3)
- 공용 표 cellClass 옵션 하나(칸 class · 안 주면 같은 글)
- B09: TabTable cellClass · choices → Shell 이 넘김 · 누른 칸 아래 B09 메뉴 한 벌(openMenuAt · 우클릭 메뉴와 공유)
- 대비표: 적용 단가 칸 누름 = 값 있는 출처 · 견적 · 최저(자동) → pick(옛 수기 applied 지움) · 수기 적용 칸 · 출처 칸 돌림 없앰 · 적용 출처 단가 칸 is-picked 강조(테마 토큰)
- 셈 · 저장 그대로(pick › applied › 최저 짝)
- 시험: test_183_3_b09_applied_pick

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SE9MxeXTu2uaDZ55BJowAY
2026-10-10 12:02:06 +09:00

114 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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("<tbody>")[1].split("</tr>")[0],
}}));
"""
)
assert got["plain"] == got["none"]
assert got["count"] == 1 and '<td class="is-picked">2</td>' 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 'if (key !== "applied" || !r) return null;' in compare
assert "delete cell.applied" in compare
shell = _src("B09_Estimation/B09_Estimation_UI_Shell.ts")
assert (
"cellClass: spec.cellClass," in shell and "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-accent)" in css