Adds tests, three test-kit builders and goldens only; no production file changes. TestBillingListsGolden compares each list's data, in the default and the all state, with a file under testdata/operator_billing for a fixture of two organizations and four billing accounts (live, unrecorded, unmapped, test), each with a subscription, an invoice and a payment. Each file was read against the fixture before it was committed: the test-mapped row is hidden by default with the line counting one, shown with the test badge in the all state, the unmapped row reads not_mapped, and every row names its own organization. TestBillingListsKeepTheirFallbacksWhenAReadFails pins, per list, that a failed organization read leaves the name empty and a failed mapping read shows not mapped. TestLookupInvoiceCandidatesNameTheirOrganizations pins the invoice candidates' organization names and the organization id as their fallback. The read-count table gains billing accounts, billing subscriptions, billing invoices, billing payments and lookup rows. Each grow adds its rows on a new organization named from a counter, and the lookup row is sent as an htmx request. Measured per row: 2 for each billing list, 1 for the lookup, as predicted. world gains MapAccount, MapSubscription and MapPayment, which record no environment, beside MapInvoice. Names and results of ./internal/server and ./internal/testkit/... match the parent apart from the new tests, which pass: TestBillingListsGolden and its twelve subtests, TestBillingListsKeepTheirFallbacksWhenAReadFails and its twelve, TestLookupInvoiceCandidatesNameTheirOrganizations and its two, and the read-count subtests billing_accounts, billing_subscriptions, billing_invoices, billing_payments and lookup. A second run without -update leaves the tree unchanged, and the tests pass three runs in a row after a reset. Thirty-two edits to the list code and the lookup, each breaking one fact, fail the test that names it. Unprobed: the goldens pin the loaders' other fields (dates, amounts, statuses, account names, payment method, invoice numbers, Overdue, the pager and the absence line) with no break, because no later section edits the code that fills them; the breaks probe the fields the mapping and naming changes move.
112 lines
2.8 KiB
JSON
112 lines
2.8 KiB
JSON
{
|
|
"Subscriptions": [
|
|
{
|
|
"SubscriptionID": "<subscription:Alder unmapped>",
|
|
"BillingAccountID": "<account:Alder unmapped>",
|
|
"BillingAccountName": "Alder unmapped",
|
|
"OrgID": "<org:Alder>",
|
|
"OrgName": "Alder",
|
|
"Status": "active",
|
|
"StatusState": "active",
|
|
"CurrentPeriodStart": "Jan 1, 2026",
|
|
"CurrentPeriodEnd": "Feb 1, 2026",
|
|
"CancelAtPeriodEnd": false,
|
|
"StripeSubscriptionID": "",
|
|
"StripeSyncStatus": "not_mapped",
|
|
"CreatedAt": "<today>",
|
|
"EnvState": ""
|
|
},
|
|
{
|
|
"SubscriptionID": "<subscription:Birch unrecorded>",
|
|
"BillingAccountID": "<account:Birch unrecorded>",
|
|
"BillingAccountName": "Birch unrecorded",
|
|
"OrgID": "<org:Birch>",
|
|
"OrgName": "Birch",
|
|
"Status": "active",
|
|
"StatusState": "active",
|
|
"CurrentPeriodStart": "Jan 1, 2026",
|
|
"CurrentPeriodEnd": "Feb 1, 2026",
|
|
"CancelAtPeriodEnd": false,
|
|
"StripeSubscriptionID": "sub_<subscription:Birch unrecorded>",
|
|
"StripeSyncStatus": "synced",
|
|
"CreatedAt": "<today>",
|
|
"EnvState": ""
|
|
},
|
|
{
|
|
"SubscriptionID": "<subscription:Alder live>",
|
|
"BillingAccountID": "<account:Alder live>",
|
|
"BillingAccountName": "Alder live",
|
|
"OrgID": "<org:Alder>",
|
|
"OrgName": "Alder",
|
|
"Status": "active",
|
|
"StatusState": "active",
|
|
"CurrentPeriodStart": "Jan 1, 2026",
|
|
"CurrentPeriodEnd": "Feb 1, 2026",
|
|
"CancelAtPeriodEnd": false,
|
|
"StripeSubscriptionID": "sub_<subscription:Alder live>",
|
|
"StripeSyncStatus": "synced",
|
|
"CreatedAt": "<today>",
|
|
"EnvState": ""
|
|
}
|
|
],
|
|
"Error": "",
|
|
"EnvNotice": {
|
|
"Text": "1 subscription from test mode is not shown.",
|
|
"LinkLabel": "Show all",
|
|
"LinkHref": "/operator/billing/subscriptions?env=all\u0026q=",
|
|
"Target": "",
|
|
"SyncSelect": ""
|
|
},
|
|
"StripeConfigured": true,
|
|
"Nav": {
|
|
"BasePath": "/operator/billing/subscriptions",
|
|
"SearchPlaceholder": "Organization or billing account",
|
|
"FacetParam": "status",
|
|
"FacetOptions": [
|
|
{
|
|
"Value": "incomplete",
|
|
"Label": "Incomplete"
|
|
},
|
|
{
|
|
"Value": "incomplete_expired",
|
|
"Label": "Incomplete expired"
|
|
},
|
|
{
|
|
"Value": "trialing",
|
|
"Label": "Trialing"
|
|
},
|
|
{
|
|
"Value": "active",
|
|
"Label": "Active"
|
|
},
|
|
{
|
|
"Value": "past_due",
|
|
"Label": "Past due"
|
|
},
|
|
{
|
|
"Value": "canceled",
|
|
"Label": "Canceled"
|
|
},
|
|
{
|
|
"Value": "unpaid",
|
|
"Label": "Unpaid"
|
|
},
|
|
{
|
|
"Value": "paused",
|
|
"Label": "Paused"
|
|
}
|
|
],
|
|
"Q": "",
|
|
"Facet": "",
|
|
"Page": 1,
|
|
"Total": 3,
|
|
"ParamPrefix": "",
|
|
"Extra": null,
|
|
"PerPage": 0,
|
|
"DefaultPerPage": 0,
|
|
"PerPageOptions": null,
|
|
"Target": "",
|
|
"SyncSelect": ""
|
|
}
|
|
}
|