Skip to content

g1t/apps/web/app/lib/usage.test.ts

101 lines5,067 bytesCodeBlame
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { axisMoney, byProject, columns, defaultGrain, isStaff, money, quantity, receipt, resolveRange, ticks, usageCsv } from "./usage.ts";
5
6const NOW = new Date("2026-10-08T15:00:00Z");
7
8test("periods resolve to whole UTC days, both ends included", () => {
9 assert.deepEqual(resolveRange(null, {}, NOW), { period: "cycle", from: "2026-10-01", until: "2026-10-08" });
10 assert.deepEqual(resolveRange("last_cycle", {}, NOW), { period: "last_cycle", from: "2026-09-01", until: "2026-09-30" });
11 assert.deepEqual(resolveRange("7d", {}, NOW), { period: "7d", from: "2026-10-02", until: "2026-10-08" });
12 assert.deepEqual(resolveRange("custom", { from: "2026-10-05", until: "2026-09-20" }, NOW), { period: "custom", from: "2026-09-20", until: "2026-10-05" });
13 // A custom range that is not days falls back to the cycle.
14 assert.equal(resolveRange("custom", { from: "yesterday", until: "2026-10-01" }, NOW).period, "cycle");
15 assert.equal(resolveRange("nonsense", {}, NOW).period, "cycle");
16});
17
18test("columns cover every day, stack products, and add up when cumulative", () => {
19 const days = [
20 { day: "2026-10-01", product: "agent", micros: 2_000_000 },
21 { day: "2026-10-01", product: "sandboxes", micros: 500_000 },
22 { day: "2026-10-03", product: "agent", micros: 1_000_000 },
23 ];
24 const daily = columns(days, "2026-10-01", "2026-10-03");
25 assert.deepEqual(daily.map((c) => c.total), [2_500_000, 0, 1_000_000]);
26 assert.equal(daily[0]!.parts.sandboxes, 500_000);
27 const running = columns(days, "2026-10-01", "2026-10-03", "day", true);
28 assert.deepEqual(running.map((c) => c.total), [2_500_000, 2_500_000, 3_500_000]);
29 assert.equal(running[2]!.parts.agent, 3_000_000);
30 // Weeks start on Monday: Oct 1 2026 is a Thursday.
31 const weekly = columns(days, "2026-10-01", "2026-10-08", "week");
32 assert.deepEqual(weekly.map((c) => c.key), ["2026-09-28", "2026-10-05"]);
33 assert.equal(weekly[0]!.total, 3_500_000);
34 assert.equal(columns(days, "2026-09-15", "2026-10-03", "month").length, 2);
35 assert.equal(defaultGrain("2026-10-01", "2026-10-31"), "day");
36 assert.equal(defaultGrain("2026-07-01", "2026-10-01"), "week");
37});
38
39test("the money axis has clean ticks, never the same label twice", () => {
40 assert.deepEqual(ticks(0), [0]);
41 const t = ticks(3_320_000);
42 assert.equal(t[0], 0);
43 assert.ok(t[t.length - 1]! >= 3_320_000);
44 const labels = t.map(axisMoney);
45 assert.equal(new Set(labels).size, labels.length, labels.join(" "));
46 const small = ticks(4_000).map(axisMoney);
47 assert.equal(new Set(small).size, small.length, small.join(" "));
48 assert.equal(axisMoney(2_000_000), "$2");
49 assert.equal(axisMoney(1_500_000_000), "$1.5K");
50});
51
52test("money and quantities read in their units", () => {
53 assert.equal(money(2_760_000), "$2.76");
54 assert.equal(money(4_000), "$0.004");
55 assert.equal(money(0), "$0.00");
56 assert.equal(quantity(1_234_567, "tokens"), "1.2M tokens");
57 assert.equal(quantity(3_725, "seconds"), "1h 2m");
58 assert.equal(quantity(504_000_000, "bytes"), "504 MB");
59 assert.equal(quantity(1, "entries"), "1 entry");
60});
61
62test("the receipt shows usage at price, then what paid, then what is charged", () => {
63 const lines = receipt(
64 { priceMicros: 3_320_000, discountMicros: 3_320_000, includedMicros: 0, creditsMicros: 0, chargedMicros: 0, pendingMicros: 0, costMicros: 0 },
65 100,
66 );
67 assert.deepEqual(lines.map((l) => l.label), ["Usage at price", "Discount (100%)", "Charged"]);
68});
69
70test("grouping by project adds a project's meters together", () => {
71 const meter = (label: string, parts: [string, number][]) => ({
72 key: label, label, product: "agent", unit: "entries", quantity: 0, micros: 0, daily: [],
73 byProject: parts.map(([project, micros]) => ({ project, micros, quantity: 0 })),
74 });
75 const rows = byProject({
76 products: [{ key: "agent", label: "Agent", micros: 0, meters: [meter("Model tokens", [["acme/web", 300], ["acme/api", 500]]), meter("Agent rate", [["acme/web", 400]])] }],
77 });
78 assert.deepEqual(rows.map((r) => [r.project, r.micros]), [["acme/web", 700], ["acme/api", 500]]);
79});
80
81test("the CSV has a row per day and meter with anything on it", () => {
82 const csv = usageCsv({
83 from: "2026-10-01",
84 until: "2026-10-02",
85 products: [{ key: "agent", label: "Agent", micros: 0, meters: [{ key: "agent_models", label: "Model tokens", product: "agent", unit: "tokens", quantity: 0, micros: 0, daily: [0, 1_500_000], byProject: [] }] }],
86 });
87 assert.equal(csv, "day,product,meter,usd\n2026-10-02,Agent,Model tokens,1.500000\n");
88});
89
90test("test-mode hints are for g1t's own people", () => {
91 assert.ok(isStaff({ workspaces: [{ slug: "flagon-io" }] }));
92 assert.ok(!isStaff({ workspaces: [{ slug: "acme" }] }));
93 assert.ok(!isStaff(null));
94});
95
96test("money under a hundredth of a cent reads $0.00, never $0.0000", () => {
97 assert.equal(money(3), "$0.00");
98 assert.equal(money(0), "$0.00");
99 assert.equal(money(4_000), "$0.004");
100 assert.equal(money(250), "$0.0003");
101});