From 319585e67b5619919475b0ae536735ec4ba48d2d Mon Sep 17 00:00:00 2001 From: redshift <213178690+1ftredsh@users.noreply.github.com> Date: Mon, 14 Sep 2026 12:48:28 +0200 Subject: [PATCH] test(tui): cover renderBox borders, padding and side-by-side composition Rescued from the deleted root-level scratch scripts test_box.ts, test_split_box.ts and test_split_box2.ts, which were never run by bun test and were never typechecked (tsconfig only includes src/**/*). Adds onto the existing src/tui/usage/render.test.ts instead of replacing it, so the npub/client-label/stacked-bar coverage stays intact. --- src/tui/usage/render.test.ts | 79 +++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/tui/usage/render.test.ts b/src/tui/usage/render.test.ts index 1a1a864..239a837 100644 --- a/src/tui/usage/render.test.ts +++ b/src/tui/usage/render.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { renderNpubs, renderRecent, renderStackedBar, tokenSegments } from "./render.ts"; +import { renderBox, renderNpubs, renderRecent, renderStackedBar, tokenSegments } from "./render.ts"; import { stripAnsi } from "./terminal.ts"; import { COLORS } from "./constants.ts"; import { buildClientNaming, resolveClientLabel, type ClientInfo, type NpubEntry } from "./data.ts"; @@ -254,3 +254,80 @@ describe("renderRecent token bars", () => { } }); }); + +/** Visible column count of a rendered line, ignoring ANSI colour codes. */ +function visibleWidths(box: string): number[] { + return box.split("\n").map((line) => stripAnsi(line).length); +} + +describe("renderBox", () => { + test("renders every line at the requested width when given a title", () => { + const box = renderBox(["Hello World", "Line 2"], 40, "Title"); + + expect(box.split("\n")).toHaveLength(4); // top, 2 content rows, bottom + for (const width of visibleWidths(box)) { + expect(width).toBe(40); + } + }); + + test("renders every line at the requested width without a title", () => { + const box = renderBox(["Hello World", "Line 2"], 40); + + for (const width of visibleWidths(box)) { + expect(width).toBe(40); + } + }); + + test("puts the title in the top border", () => { + const [topBorder] = renderBox(["body"], 40, "Stats of Sats").split("\n"); + + expect(topBorder).toContain("Stats of Sats"); + }); + + test("pads content rows so ANSI-coloured lines still align", () => { + const colored = "\x1b[32mgreen\x1b[0m"; + const box = renderBox([colored, "plain"], 30); + + for (const width of visibleWidths(box)) { + expect(width).toBe(30); + } + }); + + test("composes two half-width boxes into rows of the full width", () => { + const width = 80; + const halfWidth1 = Math.floor(width / 2); + const halfWidth2 = width - halfWidth1; + + const left = renderBox( + ["Total Spent: 12.78k sats", "Total Requests: 1.0k"], + halfWidth1, + "Stats of Sats", + ).split("\n"); + const right = renderBox( + ["Total Tokens: 25.8M", "Avg Tokens/Req: 25.8K"], + halfWidth2, + "Token Stats", + ).split("\n"); + + expect(left).toHaveLength(right.length); + for (let i = 0; i < left.length; i++) { + expect(stripAnsi(left[i]! + right[i]!).length).toBe(width); + } + }); + + test("pads the shorter side when the two boxes have unequal heights", () => { + const width = 80; + const halfWidth1 = Math.floor(width / 2); + const halfWidth2 = width - halfWidth1; + + const left = renderBox(["a", "b", "c"], halfWidth1, "Left").split("\n"); + const right = renderBox(["x"], halfWidth2, "Right").split("\n"); + + const rows = Math.max(left.length, right.length); + for (let i = 0; i < rows; i++) { + const l = left[i] ?? " ".repeat(halfWidth1); + const r = right[i] ?? " ".repeat(halfWidth2); + expect(stripAnsi(l + r).length).toBe(width); + } + }); +});