Skip to content

g1t/apps/sudo/app/lib/forms.test.ts

213 lines10,837 bytesCodeBlame
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import {
5 parseAllowances,
6 parseCredit,
7 parseDecision,
8 parseEmail,
9 parseGoodwill,
10 parsePayment,
11 parseSales,
12 parseSalesNote,
13 parseSlugList,
14 parseTerms,
15} from "./forms.ts";
16
17const NOW = new Date("2026-10-04T12:00:00Z");
18
19function form(entries: Record<string, string>): FormData {
20 const data = new FormData();
21 for (const [name, value] of Object.entries(entries)) data.set(name, value);
22 return data;
23}
24
25test("a 100% discount keeps its budget and an end date, and names who set it", () => {
26 const result = parseTerms(form({ preset: "100", note: "g1t's own", ceiling: "500", until: "2026-12-31", discount: "40" }), "owner@g1t.sh", NOW);
27 assert.deepEqual(result, {
28 ok: true,
29 value: {
30 kind: "custom",
31 discountPercent: 100,
32 ceilingMicros: 500_000_000,
33 note: "g1t's own",
34 until: "2026-12-31T23:59:59Z",
35 setBy: "owner@g1t.sh",
36 setAt: NOW.toISOString(),
37 },
38 });
39 // A form from before discounts, saying comped, is a 100% discount.
40 const old = parseTerms(form({ kind: "comped", note: "g1t's own" }), "a", NOW);
41 assert.ok(old.ok && old.value.kind === "custom" && old.value.discountPercent === 100);
42});
43
44test("a discount is a preset or a custom whole percent", () => {
45 const custom = parseTerms(form({ preset: "custom", discount: "30", note: "Design partner" }), "a", NOW);
46 assert.ok(custom.ok && custom.value.discountPercent === 30 && custom.value.kind === "custom");
47 const half = parseTerms(form({ preset: "50", discount: "30", note: "x" }), "a", NOW);
48 assert.ok(half.ok && half.value.discountPercent === 50);
49 // A limit alone is custom terms too.
50 const limit = parseTerms(form({ preset: "0", ceiling: "250", note: "x" }), "a", NOW);
51 assert.ok(limit.ok && limit.value.kind === "custom" && limit.value.discountPercent === 0);
52});
53
54test("no discount and no limit is standard, which clears the end date", () => {
55 const result = parseTerms(form({ preset: "0", note: "back to normal", until: "2027-01-01" }), "a@g1t.sh", NOW);
56 assert.ok(result.ok);
57 assert.equal(result.value.kind, "standard");
58 assert.equal(result.value.ceilingMicros, null);
59 assert.equal(result.value.until, null);
60});
61
62test("terms are refused without a note, with a bad discount, or ending in the past", () => {
63 assert.equal(parseTerms(form({ preset: "100", note: "" }), "a", NOW).ok, false);
64 assert.equal(parseTerms(form({ preset: "custom", note: "x", discount: "101" }), "a", NOW).ok, false);
65 assert.equal(parseTerms(form({ preset: "custom", note: "x" }), "a", NOW).ok, false);
66 assert.equal(parseTerms(form({ preset: "custom", note: "x", discount: "20", until: "2026-10-01" }), "a", NOW).ok, false);
67 assert.equal(parseTerms(form({ preset: "custom", note: "x", discount: "20", until: "2026-02-30" }), "a", NOW).ok, false);
68 assert.equal(parseTerms(form({ preset: "75", note: "x" }), "a", NOW).ok, true);
69 assert.equal(parseTerms(form({ preset: "free", note: "x" }), "a", NOW).ok, false);
70});
71
72test("workspace lists take commas, spaces and lines, once each", () => {
73 assert.deepEqual(parseSlugList("acme, Acme-labs\nbeta beta"), { ok: true, value: ["acme", "acme-labs", "beta"] });
74 assert.equal(parseSlugList("acme, bad--slug").ok, false);
75 assert.equal(parseSlugList("../etc").ok, false);
76});
77
78test("invoice emails are one address", () => {
79 assert.deepEqual(parseEmail(" Billing@Acme.com "), { ok: true, value: "billing@acme.com" });
80 assert.equal(parseEmail("a@b").ok, false);
81 assert.equal(parseEmail("a@b.com, c@d.com").ok, false);
82 assert.equal(parseEmail("a@@b.com").ok, false);
83 assert.equal(parseEmail("").ok, false);
84});
85
86test("credits are positive and capped", () => {
87 assert.deepEqual(parseCredit("25.50"), { ok: true, value: 25_500_000 });
88 assert.equal(parseCredit("0").ok, false);
89 assert.equal(parseCredit("10000.01").ok, false);
90});
91
92test("a sales record: a stage, an owner's email or nobody, a next step and its day", () => {
93 assert.deepEqual(parseSales(form({ stage: "contacted", owner: " Me@G1t.sh ", nextStep: "Call about\n terms", nextAt: "2026-10-09" })), {
94 ok: true,
95 value: { stage: "contacted", owner: "me@g1t.sh", nextStep: "Call about terms", nextAt: "2026-10-09" },
96 });
97 assert.deepEqual(parseSales(form({ stage: "none", owner: "", nextStep: "", nextAt: "" })), {
98 ok: true,
99 value: { stage: "none", owner: null, nextStep: null, nextAt: null },
100 });
101 assert.equal(parseSales(form({ stage: "closed" })).ok, false);
102 assert.equal(parseSales(form({ stage: "lead", owner: "not an email" })).ok, false);
103 assert.equal(parseSales(form({ stage: "lead", nextStep: "x".repeat(201) })).ok, false);
104 assert.equal(parseSales(form({ stage: "lead", nextStep: "Call", nextAt: "2026-02-30" })).ok, false);
105 assert.equal(parseSales(form({ stage: "lead", nextStep: "Call", nextAt: "next week" })).ok, false);
106 // A date needs a step to go with it.
107 assert.equal(parseSales(form({ stage: "lead", nextAt: "2026-10-09" })).ok, false);
108});
109
110test("a sales note is required, and not endless", () => {
111 assert.deepEqual(parseSalesNote("Spoke to Ana; wants an enterprise quote."), { ok: true, value: "Spoke to Ana; wants an enterprise quote." });
112 assert.equal(parseSalesNote("").ok, false);
113 assert.equal(parseSalesNote("x".repeat(2001)).ok, false);
114});
115
116
117test("allowances: the plan without its price, pool shares, and staff's overrides", () => {
118 assert.deepEqual(parseAllowances(form({})), {
119 ok: true,
120 value: {
121 plan: false,
122 ossRepoMicros: null,
123 trialMicros: null,
124 maxConcurrentAgents: null,
125 runCapMicros: null,
126 issueCapMicros: null,
127 auditRetentionDays: null,
128 hold: null,
129 },
130 });
131 assert.deepEqual(
132 parseAllowances(form({ plan: "on", oss: "5", trial: "2.50", agents: "20", runCap: "25", issueCap: "500", auditDays: "365", hold: " Card disputed;\nwaiting on the bank " })),
133 {
134 ok: true,
135 value: {
136 plan: true,
137 ossRepoMicros: 5_000_000,
138 trialMicros: 2_500_000,
139 maxConcurrentAgents: 20,
140 runCapMicros: 25_000_000,
141 issueCapMicros: 500_000_000,
142 auditRetentionDays: 365,
143 hold: "Card disputed; waiting on the bank",
144 },
145 },
146 );
147 assert.equal(parseAllowances(form({ oss: "lots" })).ok, false);
148 assert.equal(parseAllowances(form({ trial: "5000" })).ok, false);
149 assert.equal(parseAllowances(form({ agents: "0" })).ok, false);
150 assert.equal(parseAllowances(form({ agents: "101" })).ok, false);
151 assert.equal(parseAllowances(form({ agents: "2.5" })).ok, false);
152 assert.equal(parseAllowances(form({ runCap: "0.05" })).ok, false);
153 assert.equal(parseAllowances(form({ runCap: "1000.01" })).ok, false);
154 assert.equal(parseAllowances(form({ issueCap: "10000.01" })).ok, false);
155 // Audit log days: shorter or longer than the plan's, up to 400.
156 assert.equal((parseAllowances(form({ auditDays: "3" })) as { value: { auditRetentionDays: number } }).value.auditRetentionDays, 3);
157 assert.equal((parseAllowances(form({ auditDays: "400" })) as { value: { auditRetentionDays: number } }).value.auditRetentionDays, 400);
158 assert.equal(parseAllowances(form({ auditDays: "0" })).ok, false);
159 assert.equal(parseAllowances(form({ auditDays: "401" })).ok, false);
160 assert.equal(parseAllowances(form({ auditDays: "30.5" })).ok, false);
161 assert.equal(parseAllowances(form({ auditDays: "a year" })).ok, false);
162 assert.equal(parseAllowances(form({ hold: "x".repeat(201) })).ok, false);
163});
164
165test("a bank transfer: an amount, its reference, a note, and the slug typed out", () => {
166 const ok = { amount: "1,500", reference: " TRX 0042 ", note: "Invoice INV-7, by wire", confirmation: "acme" };
167 assert.deepEqual(parsePayment(form(ok), "acme"), { ok: true, value: { amountMicros: 1_500_000_000, reference: "TRX 0042", note: "Invoice INV-7, by wire" } });
168 assert.equal(parsePayment(form({ ...ok, amount: "0" }), "acme").ok, false);
169 assert.equal(parsePayment(form({ ...ok, amount: "100000.01" }), "acme").ok, false);
170 assert.equal(parsePayment(form({ ...ok, reference: "" }), "acme").ok, false);
171 assert.equal(parsePayment(form({ ...ok, note: "" }), "acme").ok, false);
172 assert.equal(parsePayment(form({ ...ok, confirmation: "Acme" }), "acme").ok, false);
173});
174
175test("a decision: approve as asked or at another amount; decline needs a note", () => {
176 assert.deepEqual(parseDecision(form({ id: "lr_1", decision: "approve" })), {
177 ok: true,
178 value: { id: "lr_1", decision: "approve", amountMicros: null, note: "" },
179 });
180 assert.deepEqual(parseDecision(form({ id: "lr_1", decision: "approve", amount: "750", note: "Half now." })), {
181 ok: true,
182 value: { id: "lr_1", decision: "approve", amountMicros: 750_000_000, note: "Half now." },
183 });
184 assert.equal(parseDecision(form({ id: "lr_1", decision: "approve", amount: "0.50" })).ok, false);
185 assert.equal(parseDecision(form({ id: "lr_1", decision: "approve", amount: "1000000.01" })).ok, false);
186 assert.equal(parseDecision(form({ id: "lr_1", decision: "decline" })).ok, false);
187 assert.deepEqual(parseDecision(form({ id: "lr_1", decision: "decline", note: "After a month of payments.", amount: "5" })), {
188 ok: true,
189 value: { id: "lr_1", decision: "decline", amountMicros: null, note: "After a month of payments." },
190 });
191 assert.equal(parseDecision(form({ id: "../x", decision: "approve" })).ok, false);
192 assert.equal(parseDecision(form({ id: "lr_1", decision: "maybe" })).ok, false);
193});
194
195test("goodwill: no amount is the one-click credit; a reason when one is needed; a day not in the future", () => {
196 const never = () => false;
197 const always = () => true;
198 assert.deepEqual(parseGoodwill(form({}), never, NOW), { ok: true, value: { amountMicros: null, reason: "", day: null } });
199 assert.deepEqual(parseGoodwill(form({ amount: "60", reason: "Looping agent on #12, owner caught it late.", day: "2026-10-03" }), always, NOW), {
200 ok: true,
201 value: { amountMicros: 60_000_000, reason: "Looping agent on #12, owner caught it late.", day: "2026-10-03" },
202 });
203 assert.equal(parseGoodwill(form({ amount: "60", reason: "oops" }), always, NOW).ok, false);
204 assert.equal(parseGoodwill(form({ amount: "0" }), never, NOW).ok, false);
205 assert.equal(parseGoodwill(form({ amount: "10000.01" }), never, NOW).ok, false);
206 assert.equal(parseGoodwill(form({ day: "2026-10-05" }), never, NOW).ok, false);
207 assert.equal(parseGoodwill(form({ day: "2026-02-30" }), never, NOW).ok, false);
208 // The check is given the amount typed, or null for the one-click credit.
209 const seen: (number | null)[] = [];
210 parseGoodwill(form({ amount: "12.50" }), (amount) => (seen.push(amount), false), NOW);
211 parseGoodwill(form({}), (amount) => (seen.push(amount), false), NOW);
212 assert.deepEqual(seen, [12_500_000, null]);
213});