// The grid's plan: the decisions `gridTable` used to make while creating // elements, where a wrong answer showed up as a wrong pixel. import { test } from "node:test"; import assert from "node:assert/strict"; import { gridPlan } from "../shell.js"; const cell = (text, extra = {}) => ({ text, numeric: true, error: false, selected: false, editable: true, ...extra, }); /// A grid with a group header between its data rows — the shape the row /// index has to survive. Two column levels under one group run. function grouped() { return { row_levels: 2, col_levels: [["Q1", ""], ["Revenue", "Cost"]], col_groups: [{ span: 2, label: "2026", collapsed: false }], totals: [], editing: null, rows: [ { kind: "group", label: "Hot", collapsed: false }, { kind: "data", labels: ["Hot", "Espresso"], cells: [cell("1"), cell("2")] }, { kind: "data", labels: ["", "Latte"], cells: [cell("3"), cell("4")] }, { kind: "group", label: "Cold", collapsed: true }, { kind: "data", labels: ["Cold", "Cold Brew"], cells: [cell("5"), cell("6")] }, ], }; } test("a group header consumes no data row index", () => { const plan = gridPlan(grouped()); const data = plan.body.filter((r) => r.kind === "data"); assert.deepEqual(data.map((r) => r.row), [0, 1, 2]); // And every cell in a row carries that row's index, not its position in // `rows` — the coordinate a click sends. assert.deepEqual( data.at(-1).cells.map((c) => [c.row, c.col]), [[2, 0], [2, 1]], ); }); test("a group header spans the labels and the cells together", () => { const plan = gridPlan(grouped()); const groups = plan.body.filter((r) => r.kind === "group"); assert.deepEqual(groups.map((r) => r.colSpan), [4, 4]); assert.deepEqual(groups.map((r) => r.text), ["▼ Hot", "▶ Cold"]); assert.equal(plan.cornerSpan, 2); }); test("a column run in no group is blank, and an empty name is a name", () => { const model = grouped(); model.col_groups = [ { span: 1, label: null, collapsed: false }, { span: 1, label: "", collapsed: true }, ]; const plan = gridPlan(model); assert.deepEqual(plan.groups, [ { span: 1, text: "" }, { span: 1, text: "▶ " }, ]); }); test("the typed text replaces only the selected cell, and carries a caret", () => { const model = grouped(); model.editing = "12"; model.rows[1].cells[1].selected = true; const plan = gridPlan(model); const row = plan.body[1]; assert.equal(row.cells[0].text, "1"); assert.equal(row.cells[1].text, "12▏"); assert.equal(row.cells[1].classes.typing, true); // A cell being typed into is not drawn as a number: the buffer is text. assert.equal(row.cells[1].classes.numeric, false); assert.equal(row.cells[0].classes.numeric, true); }); test("a selected cell with no editor open is not typing", () => { const model = grouped(); model.editing = null; model.rows[1].cells[0].selected = true; const plan = gridPlan(model); const first = plan.body[1].cells[0]; assert.equal(first.classes.typing, false); assert.equal(first.classes.selected, true); assert.equal(first.text, "1"); }); test("an empty edit buffer still means an editor is open", () => { const model = grouped(); model.editing = ""; model.rows[1].cells[0].selected = true; const plan = gridPlan(model); assert.equal(plan.body[1].cells[0].classes.typing, true); assert.equal(plan.body[1].cells[0].text, "▏"); }); test("an empty totals strip is no strip at all, not a row of blanks", () => { // Gotcha 33: an EMPTY strip means this grid has no totals — records mode, // or an empty grid — so there is nothing to draw and nothing to pad. assert.equal(gridPlan(grouped()).totals, null); }); test("the totals strip is relayed, and its label spans the row headers", () => { const model = grouped(); model.totals = [ { text: "9,001", numeric: true, error: false }, { text: "err", numeric: false, error: true }, ]; const plan = gridPlan(model); assert.equal(plan.totals.span, 2, "the label spans every row-header level"); assert.equal(plan.totals.label, "Total"); assert.deepEqual( plan.totals.cells.map((c) => [c.text, c.classes.numeric, c.classes.error]), [ ["9,001", true, false], ["err", false, true], ], ); // And it carries no coordinates: a total is not a cell a click can name. assert.ok(!("row" in plan.totals.cells[0])); });