/* 202-1 — 표 칸 아래로 간 안내 줄 몫이 창 끝까지 셈(`ui_template_data_table.ts` fillViewport)에 들어가는지 단위검증 헬퍼. * 카드 본문 = [표 칸][아래 줄][안내 줄 · 안내 줄 …](B08 `tableCard` 꼴) 가짜 DOM 에서 돌리고 JSON 으로 냄. */ const fs = require("fs"); const path = require("path"); const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript")); const file = path.join(__dirname, "..", "..", "ui_template", "ui_template_data_table.ts"); const js = ts.transpileModule(fs.readFileSync(file, "utf8"), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText; const win = { innerHeight: 900, scrollY: 0, addEventListener() {}, removeEventListener() {} }; const observers = []; class RO { constructor(fn) { this.fn = fn; observers.push(this); } observe() {} disconnect() {} } const el = (name, css = {}, height = 0) => ({ name, css, height, top: 0, parentElement: null, nextElementSibling: null, isConnected: true, style: {}, getBoundingClientRect() { return { top: this.top, height: this.height }; }, }); function link(parent, ...kids) { kids.forEach((k, i) => { k.parentElement = parent; k.nextElementSibling = kids[i + 1] ?? null; }); return parent; } const sty = (n) => ({ rowGap: n.css.rowGap ?? "normal", paddingBottom: n.css.paddingBottom ?? "0px", borderBottomWidth: n.css.borderBottomWidth ?? "0px", marginBottom: n.css.marginBottom ?? "0px", }); const box = { exports: {} }; new Function("exports", "module", "require", "window", "document", "getComputedStyle", "ResizeObserver", js)( box.exports, box, (p) => (p.endsWith(".css") ? {} : require(p)), win, { body: null }, sty, RO, ); const m = box.exports; // 문서: body(padding-bottom 8) > card(padding-bottom 12 · gap 8) > [root][avg 20][info 30][hint 40] const body = el("body", { paddingBottom: "8px" }); const card = el("card", { paddingBottom: "12px", rowGap: "8px" }); const root = el("root"); const avg = el("avg", {}, 20); const info = el("info", {}, 30); const hint = el("hint", {}, 40); link(body, card); link(card, root, avg, info, hint); root.top = 200; m.fillViewport(root); observers.forEach((o) => o.fn()); const out = { first: parseFloat(root.style.maxHeight) }; out.below = m.spaceBelow(root); out.belowExpected = 3 * 8 + 20 + 30 + 40 + 12 + 8; // 줄 사이 8 셋 · 아래 줄 · 안내 둘 · 카드 · 본문 여백 out.bottom = root.top + out.first + out.below; // 문서 맨 아래 = 창 아래 끝(페이지 스크롤 0) out.viewport = win.innerHeight; // 안내 줄이 두 줄로 늘어남 → 표 칸이 그만큼 줄어듦 hint.height = 60; observers.forEach((o) => o.fn()); out.afterHintGrow = parseFloat(root.style.maxHeight); out.firstMinusGrow = out.first - 20; console.log(JSON.stringify(out));