Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/scripts/billing-catalog/catalog.test.ts
T

125 lines
4.4 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { assessLagoCatalog, buildDesiredLagoCatalog, toLagoPlanPayload, toLagoTaxPayload, type LagoCatalogSnapshot } from "./catalog";
const desired = buildDesiredLagoCatalog();
function matchingSnapshot(): LagoCatalogSnapshot {
return {
organization: { name: "HiveGrid Test", idSha256: "a".repeat(64) },
tax: {
code: desired.tax.code,
name: desired.tax.name,
description: desired.tax.description,
rate: desired.tax.rate,
applied_to_organization: desired.tax.appliedToOrganization,
},
plans: desired.plans.map((plan) => ({
code: plan.code,
name: plan.name,
invoice_display_name: plan.invoiceDisplayName,
description: plan.description,
interval: plan.interval,
amount_cents: plan.amountCents,
amount_currency: plan.amountCurrency,
pay_in_advance: plan.payInAdvance,
taxes: plan.taxCodes.map((code) => ({ code })),
metadata: { ...plan.metadata },
})),
};
}
describe("HiveGrid Lago billing catalog", () => {
it("builds base plans, recurring storage products, and five email-marketing tiers", () => {
expect(desired.plans.map((plan) => plan.code)).toEqual([
"business",
"business_annual_sepa",
"email_marketing_l",
"email_marketing_m",
"email_marketing_s",
"email_marketing_xl",
"email_marketing_xxl",
"pro",
"pro_annual_sepa",
"starter",
"starter_annual_sepa",
"storage_100gb",
"storage_1tb",
"storage_500gb",
"storage_5tb",
]);
expect(desired.plans.every((plan) => plan.interval === "monthly")).toBe(true);
expect(desired.plans.every((plan) => plan.taxCodes.includes("de-vat-19"))).toBe(true);
expect(desired.plans.find((plan) => plan.code === "email_marketing_m")).toMatchObject({
amountCents: 14_900,
metadata: {
hivegrid_resource_kind: "email_marketing_add_on",
hivegrid_monthly_email_limit: "50000",
},
});
expect(desired.plans.find((plan) => plan.code === "pro")).toMatchObject({
metadata: {
hivegrid_included_storage_gb: "500",
hivegrid_storage_per_additional_seat_gb: "20",
},
});
expect(desired.plans.find((plan) => plan.code === "storage_1tb")).toMatchObject({
amountCents: 1_299,
metadata: {
hivegrid_resource_kind: "storage_add_on",
hivegrid_included_storage_gb: "1000",
hivegrid_purchasable: "true",
},
});
expect(desired.plans.find((plan) => plan.code === "storage_100gb")).toMatchObject({
amountCents: 125,
metadata: {
hivegrid_resource_kind: "storage_add_on",
hivegrid_included_storage_gb: "100",
hivegrid_purchasable: "false",
},
});
});
it("produces a deterministic machine-readable contract digest", () => {
expect(buildDesiredLagoCatalog()).toEqual(desired);
expect(desired.digestSha256).toMatch(/^[a-f0-9]{64}$/u);
});
it("reports a complete idempotent catalog as noops", () => {
const assessment = assessLagoCatalog(matchingSnapshot());
expect(assessment.complete).toBe(true);
expect(assessment.actions.every((action) => action.action === "noop")).toBe(true);
});
it("detects price, tax, and catalog-version drift", () => {
const snapshot = matchingSnapshot();
snapshot.tax!.rate = 7;
snapshot.plans[0]!.amount_cents += 1;
snapshot.plans[1]!.metadata = {
...snapshot.plans[1]!.metadata,
hivegrid_catalog_version: "old",
};
const assessment = assessLagoCatalog(snapshot);
expect(assessment.complete).toBe(false);
expect(assessment.actions.find((action) => action.resource === "tax")?.driftFields).toContain("rate");
expect(assessment.actions.find((action) => action.code === snapshot.plans[0]!.code)?.driftFields).toContain("amountCents");
expect(assessment.actions.find((action) => action.code === snapshot.plans[1]!.code)?.driftFields).toContain("metadata");
});
it("creates explicit Lago tax and non-cascading plan update payloads", () => {
expect(toLagoTaxPayload(desired.tax)).toMatchObject({
tax: { code: "de-vat-19", rate: 19, applied_to_organization: false },
});
expect(toLagoPlanPayload(desired.plans[0]!, true)).toMatchObject({
plan: {
interval: "monthly",
amount_currency: "EUR",
tax_codes: ["de-vat-19"],
cascade_updates: false,
},
});
});
});