mirror of
https://github.com/Routstr/routstrd.git
synced 2026-10-05 20:38:22 +00:00
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.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user