Files
Aislo/resources/tester/test_202_1_table_hint_bottom.py
T

177 lines
8.4 KiB
Python

"""202-1 B08 · B09 표 칸 — 안내 · 경고 줄 = 맨 아래 · 박스보기 · 가로 열 수 = 보조 탭 줄 오른쪽.
- B09 안내 줄 = 표 · 카드 판 아래(마지막 자식) · 묶음 탭 도구(보기 단추 · 열 수) = 아래 탭 줄 오른쪽 · 단독 탭 빈 줄에서도
- B08 안내 · 경고 줄 = 표 · 아래 줄 뒤 맨 아래(토공 · 운반 시트 · 자재 · 구조물 집계)
- 창 끝까지 셈(199-1) = 아래로 간 안내 줄 몫 포함
"""
import json
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from resources.tester.helper_b09_group_cards import COMMON, GROUPS, RAW, TABS, run # noqa: E402
B09 = "B09_Estimation/B09_Estimation_UI_"
BAR = f"{B09}TabBar.ts"
DG = {"id": "DG1", "no": 1, "name": "찰쌓기", "unit": "m2", "lines": [], "sum": 0}
def _block(css: str, selector: str) -> str:
m = re.search(re.escape(selector) + r"\s*\{([^}]*)\}", css)
assert m, selector
return m.group(1)
# ── B09 보조 탭 줄 오른쪽 도구 ──────────────────────────────────────────────
def test_도구_자리_보조_줄_오른쪽_빈_줄에서도_보임():
out = run(
[TABS, BAR],
"""
const bars = createTabBars(() => {});
const mk = (n) => { const b = document.createElement('button'); b.textContent = n; return b; };
const snap = () => ({
kids: bars.sub.children.map((c) => (c.classList.contains('b09-estimation__tools') ? 'TOOLS' : c.textContent)),
last: bars.sub.children[bars.sub.children.length - 1].children.map((x) => x.textContent),
});
bars.draw('dg');
bars.setTools([mk('가'), mk('나')]);
const a = snap();
bars.draw('compare'); // 다른 묶음으로 옮겨도 도구 자리는 그대로 마지막
const b = snap();
bars.draw('cost'); // 단독 탭 = 빈 보조 줄
const c = snap();
const ghost = bars.sub.children[0];
bars.setTools([]);
const d = snap();
console.log(JSON.stringify({
a: a.kids, aLast: a.last,
b: b.kids.slice(-1), bLast: b.last,
c: c.kids, cLast: c.last,
blank: bars.sub.classList.contains('b09-estimation__tabs--blank'),
subHidden: bars.sub.attrs['aria-hidden'] ?? null, ghostHidden: ghost.attrs['aria-hidden'],
dLast: d.last.length,
}));
""",
)
tools = "TOOLS"
assert out["a"] == ["일위대가목록표", "일위대가표", tools] # 아래 탭 뒤 오른쪽 자리
assert out["aLast"] == ["가", "나"]
assert out["b"] == [tools] and out["bLast"] == ["가", "나"] # 탭을 옮겨도 도구는 그대로
assert out["blank"] and len(out["c"]) == 2 and out["c"][1] == tools # 숨은 단추 + 도구
assert out["cLast"] == ["가", "나"]
assert out["subHidden"] is None and out["ghostHidden"] == "true" # 줄 전체가 아니라 숨은 단추만
assert out["dLast"] == 0 # 비움
def test_묶음_탭_단추가_보조_줄에_안내는_아래에():
"""쉘이 하는 대로 — 줄 그림 → 묶음 판 그림(`setTools` = 보조 줄 도구) → 단추는 줄에, 판에는 없음."""
out = run(
[COMMON, TABS, f"{B09}Tabs_Labor.ts", GROUPS, BAR],
f"\nconst spec = buildDaegaBlocks({{ sheets: {{ daega_blocks: [{json.dumps(DG, ensure_ascii=False)}] }} }});"
"\nconst bars = createTabBars(() => {});"
"\nconst hint = document.createElement('p');"
"\nconst res = {};"
"\nfor (const view of ['cards', 'table']) {"
"\n chooseGroupView(view);"
"\n bars.draw('dg'); bars.setTools([]);"
"\n const panel = renderGroupPanel({ tab: 'dg', spec, hint, goto: () => {}, redraw: () => {},"
" makeTable: () => ({ root: document.createElement('table'), focusRow: () => {} }),"
" setTools: bars.setTools });"
"\n const tools = bars.sub.children[bars.sub.children.length - 1];"
"\n res[view] = { inRow: tools.all('[data-b09-group-view]').map((b) => b.textContent),"
" cols: tools.all('[data-group-cols]').length,"
" inPanel: panel.flatMap((e) => [e, ...e.all('[data-b09-group-view]'), ...e.all('[data-group-cols]')])"
".filter((e) => e.dataset.b09GroupView || e.dataset.groupCols).length,"
" hintLast: panel[panel.length - 1] === hint, n: panel.length };"
"\n}"
"\nconsole.log(JSON.stringify(res));",
RAW,
)
# 304-1 보기 고름 = 좌측 하단 스위치(보조 줄에 없음) · 가로 열 수 = 보조 줄 그대로
assert out["cards"]["inRow"] == [] and out["cards"]["cols"] == 4
assert out["table"]["inRow"] == [] and out["table"]["cols"] == 0
for view in ("cards", "table"):
assert out[view]["inPanel"] == 0 # 판 안에는 단추 없음
assert out[view]["hintLast"] and out[view]["n"] == 2 # 판 + 안내 줄(맨 아래)
def test_잇기_쉘_안내_줄_아래_도구_비움():
shell = (ROOT / "B09_Estimation" / "B09_Estimation_UI_Shell.ts").read_text("utf-8")
assert (
"panel.replaceChildren(table.root, ...(level ? [level.guide] : []), ...(hint ? [hint] : []))"
in shell
) # 229-1 레벨 단추 = 보조 탭 줄 · 안내 글 = 표 아래 · 안내 줄 = 맨 아래
assert "...(hint ? [hint] : []), table.root" not in shell # 위 자리 없음
assert re.search(r"bars\.draw\(tab\);\s*bars\.setTools\(\[\]\);", shell)
assert "setTools: bars.setTools" in shell
def test_CSS_도구_오른쪽_맞춤_빈_줄_숨김_규칙에_안_걸림():
css = (ROOT / "B09_Estimation" / "B09_Estimation_UI_Page.css").read_text("utf-8")
tools = _block(css, ".b09-estimation__tools")
assert "margin-left: auto" in tools and "flex-wrap: nowrap" in tools
hidden = _block(css, ".b09-estimation__tabs--blank > .ui-btn")
assert "visibility: hidden" in hidden # 직계 단추만 — 도구 묶음은 안 숨김
assert ".b09-estimation__bar" not in css # 옛 머리 줄(안내 + 단추) 풂
# ── B08 안내 · 경고 줄 맨 아래 ──────────────────────────────────────────────
def test_B08_표_카드_차례_표_아래줄_안내():
src = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Earthwork.ts").read_text("utf-8")
fn = re.search(r"export function tableCard\(.*?\n}\n", src, re.S)
assert fn
code = fn.group(0).replace("export ", "")
js = (
"const createCard = ({ body }) => body;\n"
+ code
+ "\nconsole.log(JSON.stringify(tableCard(['i1', 'i2'], 'T', ['a1', 'a2'])));"
)
result = subprocess.run(
["node", "--experimental-strip-types", "--no-warnings", "--input-type=module-typescript"],
input=js,
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
)
assert result.returncode == 0, result.stderr
assert json.loads(result.stdout) == ["T", "a1", "a2", "i1", "i2"] # 표 · 아래 줄 · 안내 줄
def test_B08_자재_구조물_안내_줄_표_아래():
material = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Material.ts").read_text("utf-8")
assert "createCard({ body: [toolbar, table.root, excel, notes] })" in material
assert "toolbar.append(save);" in material # 저장 단추만 위 줄(안내는 아래)
summary = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Summary.ts").read_text("utf-8")
assert "createCard({ body: [table, ...parts] })" in summary
css = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Page.css").read_text("utf-8")
assert "justify-content: flex-end" in _block(css, ".b08-material__toolbar")
# ── 창 끝까지 셈(199-1)에 아래 줄 몫 ────────────────────────────────────────
def test_창_끝까지_셈에_아래_안내_줄_포함():
proc = subprocess.run(
["node", str(ROOT / "resources" / "tester" / "helper_202_1_fill_below.cjs")],
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
)
assert proc.returncode == 0, proc.stderr
r = json.loads(proc.stdout)
assert r["below"] == r["belowExpected"] == 134 # 아래 줄 · 안내 줄 둘 + 여백
assert r["bottom"] == r["viewport"] # 문서 맨 아래 = 창 끝 → 페이지 스크롤 0
assert r["afterHintGrow"] == r["firstMinusGrow"] # 안내 줄이 늘면 표 칸이 그만큼 줄어듦