Skip to content
93 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Put the stylesheet at the top of the head, before React Router's preloads1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { axisDollars, barPath, change, marginOf, monthBars, monthLong, monthShort, niceCeiling, shares, ticks } from "./chart.ts";
5
6const M = 1_000_000;
7const month = (m: string, charged: number, cost: number) => ({ month: m, chargedMicros: charged, costMicros: cost, paidMicros: 0 });
8
9test("niceCeiling rounds up to 1, 2, 2.5 or 5 times a power of ten", () => {
10 assert.equal(niceCeiling(0), 1 * M);
11 assert.equal(niceCeiling(1 * M), 1 * M);
12 assert.equal(niceCeiling(1.2 * M), 2 * M);
13 assert.equal(niceCeiling(2.2 * M), 2.5 * M);
14 assert.equal(niceCeiling(3 * M), 5 * M);
15 assert.equal(niceCeiling(7 * M), 10 * M);
16 assert.equal(niceCeiling(420 * M), 500 * M);
17 assert.equal(niceCeiling(10_001 * M), 20_000 * M);
18});
19
20test("ticks run from zero to the top", () => {
21 assert.deepEqual(ticks(100, 4), [0, 25, 50, 75, 100]);
22});
23
24test("months are named", () => {
25 assert.equal(monthShort("2026-10"), "Oct");
26 assert.equal(monthShort("2026-01"), "Jan");
27 assert.equal(monthShort("soon"), "soon");
28 assert.equal(monthLong("2026-10"), "October 2026");
29 assert.equal(monthLong("2026-13"), "2026-13");
30});
31
32test("margin and change", () => {
33 assert.deepEqual(marginOf(100 * M, 80 * M), { micros: 20 * M, percent: 20 });
34 assert.deepEqual(marginOf(0, 5 * M), { micros: -5 * M, percent: null });
35 assert.equal(change(100, 150), 50);
36 assert.equal(change(0, 150), null);
37 assert.equal(change(200, 100), -50);
38});
39
40test("monthBars scales both series to one axis from zero", () => {
41 const chart = monthBars([month("2026-09", 400 * M, 300 * M), month("2026-10", 100 * M, 0)], { width: 300, height: 120, left: 40, right: 0, top: 0, bottom: 20 });
42 assert.equal(chart.top, 500 * M);
43 assert.deepEqual(chart.plot, { x: 40, y: 0, width: 260, height: 100 });
44 const [sep, oct] = chart.bars;
45 assert.equal(sep.label, "Sep");
46 // 400 of 500 is 80 of the plot's 100.
47 assert.equal(Math.round(sep.charged.height), 80);
48 assert.equal(Math.round(sep.charged.y), 20);
49 assert.equal(Math.round(sep.cost.height), 60);
50 // Bars stand on the baseline.
51 assert.equal(sep.charged.y + sep.charged.height, 100);
52 assert.equal(oct.cost.height, 0);
53 // Charged on the left, cost on the right, 2px apart, inside the slot.
54 assert.equal(Math.round((sep.cost.x - (sep.charged.x + sep.charged.width)) * 100) / 100, 2);
55 assert.ok(sep.charged.x >= sep.slot.x && sep.cost.x + sep.cost.width <= sep.slot.x + sep.slot.width);
56 assert.equal(chart.ticks[0].y, 100);
57 assert.equal(chart.ticks.at(-1)?.y, 0);
58});
59
60test("a tiny month still shows, and an empty chart has an axis", () => {
61 const chart = monthBars([month("2026-09", 1000 * M, 0), month("2026-10", 1, 0)]);
62 assert.ok(chart.bars[1].charged.height >= 1.5);
63 const empty = monthBars([month("2026-10", 0, 0)]);
64 assert.equal(empty.top, 1 * M);
65 assert.equal(empty.bars[0].charged.height, 0);
66 assert.equal(monthBars([]).bars.length, 0);
67});
68
69test("negative figures draw nothing below the baseline", () => {
70 const chart = monthBars([month("2026-10", -5 * M, 2 * M)]);
71 assert.equal(chart.bars[0].charged.height, 0);
72});
73
74test("barPath rounds the top and keeps the foot square", () => {
75 assert.equal(barPath({ x: 0, y: 0, width: 10, height: 20 }), "M0 20 V4 Q0 0 4 0 H6 Q10 0 10 4 V20 Z");
76 assert.equal(barPath({ x: 0, y: 0, width: 10, height: 0 }), "");
77 // Never rounder than the bar is tall.
78 assert.equal(barPath({ x: 0, y: 9, width: 10, height: 1 }), "M0 10 V10 Q0 9 1 9 H9 Q10 9 10 10 V10 Z");
79});
80
81test("axis labels are short", () => {
82 assert.equal(axisDollars(0), "$0");
83 assert.equal(axisDollars(250 * M), "$250");
84 assert.equal(axisDollars(1500 * M), "$1.5k");
85 assert.equal(axisDollars(20_000 * M), "$20k");
86 assert.equal(axisDollars(1_200_000 * M), "$1.2M");
87 assert.equal(axisDollars(0.25 * M), "$0.25");
88});
89
90test("shares are against the largest", () => {
91 assert.deepEqual(shares([50, 100, 0, -5]), [0.5, 1, 0, 0]);
92 assert.deepEqual(shares([0, 0]), [0, 0]);
93});

This file's history is long; its oldest lines are credited to the oldest commit read.