import { describe, expect, test } from "bun:test"; import { METERS } from "./meters"; import { DEFAULT_PLANS } from "./plans"; import { CONTAINER_SPECS, MARKUP, METER_PRICES, PACKS, PRO_PRICE_CENTS, containerCostPerHour, containerPricePerHour, creditPoolFor, meterPriceDollars, } from "./pricing"; describe("pricing", () => { test("every meter has exactly one price", () => { expect(Object.keys(METER_PRICES).toSorted()).toEqual(METERS.map((meter) => meter.id).toSorted()); for (const meter of METERS) expect(meter.microCentsPerUnit).toBe(METER_PRICES[meter.id]); }); test("runner tiers are priced by their resources at the target markup", () => { for (const spec of Object.values(CONTAINER_SPECS)) { expect(containerPricePerHour(spec) / containerCostPerHour(spec)).toBeCloseTo(MARKUP, 9); } expect(meterPriceDollars("compute.runner", 3600)).toBeCloseTo( containerPricePerHour(CONTAINER_SPECS["standard-1"]), 9, ); expect(meterPriceDollars("compute.runner_xlarge", 3600)).toBeCloseTo( containerPricePerHour(CONTAINER_SPECS["standard-4"]), 9, ); }); test("a Pro month that uses every allowance in full still keeps the margin", () => { let cost = 0; for (const [meter, quantity] of Object.entries(DEFAULT_PLANS.pro.included)) { cost += meterPriceDollars(meter as keyof typeof METER_PRICES, quantity ?? 0) / MARKUP; } expect(cost * MARKUP).toBeLessThanOrEqual(PRO_PRICE_CENTS / 100); }); test("packs cost exactly what the same usage costs as overage", () => { for (const pack of PACKS) { const meter = pack.pool === "compute" ? "compute.runner" : "ai.tokens"; expect(pack.cents).toBe(Math.round(meterPriceDollars(meter, pack.quantity) * 100)); } }); test("compute credit is spent at each meter's price relative to standard-1", () => { expect(creditPoolFor("compute.runner")).toEqual({ pool: "compute", factor: 1 }); expect(creditPoolFor("compute.editor")?.factor).toBeCloseTo(1, 9); expect(creditPoolFor("compute.runner_xlarge")?.factor).toBeCloseTo( containerCostPerHour(CONTAINER_SPECS["standard-4"]) / containerCostPerHour(CONTAINER_SPECS["standard-1"]), 9, ); expect(creditPoolFor("compute.runner_self_hosted")).toBeNull(); expect(creditPoolFor("ai.calls")).toBeNull(); }); });