┌─ TS ───────────────────────────────────────────────────────────────────────┐
│ import { describe, expect, it } from "vitest"; │
│ import { layoutTimeline } from "./Timeline"; │
│ import { G, len } from "../../lib/ascii"; │
│ │
│ const E = (date: string, title: string, desc?: string) => ({ date, title, desc }); │
│ │
│ describe("layoutTimeline", () => { │
│ it("opens the spine with ┬ and continues with ┼", () => { │
│ const rows = layoutTimeline([E("2026-01-01", "A"), E("2026-01-02", "B"), E("20 │
│ 26-01-03", "C")], 48); │
│ const junctions = rows.filter((r) => !r.soft).map((r) => [...r.prefix][12]); │
│ expect(junctions).toEqual([G.TJ, G.X, G.X]); │
│ }); │
│ │
│ it("renders a lone entry without a spine", () => { │
│ const rows = layoutTimeline([E("2026-01-01", "ONLY")], 48); │
│ expect(rows).toHaveLength(1); │
│ expect(rows[0].prefix).toContain(`${G.H}${G.H}${G.H}`); │
│ }); │
│ │
│ it("aligns the rail under the junction", () => { │
│ const rows = layoutTimeline([E("2026-01-01", "A", "some detail"), E("2026-01-0 │
│ 2", "B")], 48); │
│ const jCol = [...rows[0].prefix].indexOf(G.TJ); │
│ expect([...rows[1].prefix].indexOf(G.V)).toBe(jCol); │
│ }); │
│ │
│ it("wraps descriptions inside the frame", () => { │
│ const rows = layoutTimeline([E("2026-01-01", "A", "word ".repeat(30).trim()), │
│ E("2026-01-02", "B")], 48); │
│ for (const r of rows) expect(len(r.prefix + r.text)).toBeLessThanOrEqual(48); │
│ expect(rows.filter((r) => r.soft && r.text).length).toBeGreaterThan(1); │
│ }); │
│ │
│ it("truncates overlong titles with an ellipsis", () => { │
│ const rows = layoutTimeline([E("2026-01-01", "x".repeat(80)), E("2026-01-02", │
│ "B")], 48); │
│ expect(rows[0].text.endsWith("...")).toBe(true); │
│ expect(len(rows[0].prefix + rows[0].text)).toBeLessThanOrEqual(48); │
│ }); │
│ }); │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ TS ─────────────────────────────────┐
│ import { describe, expect, it } from "vitest │
│ "; │
│ import { layoutTimeline } from "./Timeline"; │
│ import { G, len } from "../../lib/ascii"; │
│ │
│ const E = (date: string, title: string, desc │
│ ?: string) => ({ date, title, desc }); │
│ │
│ describe("layoutTimeline", () => { │
│ it("opens the spine with ┬ and continues w │
│ ith ┼", () => { │
│ const rows = layoutTimeline([E("2026-01- │
│ 01", "A"), E("2026-01-02", "B"), E("2026-01- │
│ 03", "C")], 48); │
│ const junctions = rows.filter((r) => !r. │
│ soft).map((r) => [...r.prefix][12]); │
│ expect(junctions).toEqual([G.TJ, G.X, G. │
│ X]); │
│ }); │
│ │
│ it("renders a lone entry without a spine", │
│ () => { │
│ const rows = layoutTimeline([E("2026-01- │
│ 01", "ONLY")], 48); │
│ expect(rows).toHaveLength(1); │
│ expect(rows[0].prefix).toContain(`${G.H} │
│ ${G.H}${G.H}`); │
│ }); │
│ │
│ it("aligns the rail under the junction", ( │
│ ) => { │
│ const rows = layoutTimeline([E("2026-01- │
│ 01", "A", "some detail"), E("2026-01-02", "B │
│ ")], 48); │
│ const jCol = [...rows[0].prefix].indexOf │
│ (G.TJ); │
│ expect([...rows[1].prefix].indexOf(G.V)) │
│ .toBe(jCol); │
│ }); │
│ │
│ it("wraps descriptions inside the frame", │
│ () => { │
│ const rows = layoutTimeline([E("2026-01- │
│ 01", "A", "word ".repeat(30).trim()), E("202 │
│ 6-01-02", "B")], 48); │
│ for (const r of rows) expect(len(r.prefi │
│ x + r.text)).toBeLessThanOrEqual(48); │
│ expect(rows.filter((r) => r.soft && r.te │
│ xt).length).toBeGreaterThan(1); │
│ }); │
│ │
│ it("truncates overlong titles with an elli │
│ psis", () => { │
│ const rows = layoutTimeline([E("2026-01- │
│ 01", "x".repeat(80)), E("2026-01-02", "B")], │
│ 48); │
│ expect(rows[0].text.endsWith("...")).toB │
│ e(true); │
│ expect(len(rows[0].prefix + rows[0].text │
│ )).toBeLessThanOrEqual(48); │
│ }); │
│ }); │
└──────────────────────────────────────────────┘