import { beforeEach, describe, expect, mock, test } from "bun:test";
import { fakeD1 } from "./fake-d1.test-helper";
import { memoryScopes } from "../scoped-db/testing";
let d1 = fakeD1();
const fakeEnv: Record<string, unknown> = {
get DB() {
return d1.binding;
},
KV: { get: async () => null, put: async () => undefined, delete: async () => undefined },
METERING_PLANS: JSON.stringify({ free: { hardCaps: { "ai.calls": 0 } } }),
PUBLIC_URL: "https://forge.test",
};
mock.module("cloudflare:workers", () => ({ env: fakeEnv, waitUntil: () => undefined }));
let scopes = memoryScopes();
mock.module("../scoped-db", () => ({
repoDb: (id: string) => scopes.repoDb(id),
accountDb: (id: string) => scopes.accountDb(id),
stmt: scopes.module.stmt,
}));
const accountSql = (id: string) => scopes.raw("account", id);
const { assertWithinQuota, planBlockReason, QuotaExceededError, setPlan, setSpendingLimit } = await import("./quota");
const { withBillingContext } = await import("./access");
const { HttpError } = await import("../errors");
beforeEach(() => {
d1 = fakeD1();
scopes = memoryScopes();
d1.db
.exec(`INSERT INTO accounts (id, name, kind) VALUES ('u1', 'alice', 'user'), ('u2', 'bob', 'user'), ('o1', 'acme', 'org');
INSERT INTO org_members VALUES ('o1', 'u1', 'owner', 0), ('o1', 'u2', 'member', 0);`);
});
describe("out-of-budget errors", () => {
test("a hard cap is a 402 naming the meter, reason and account", async () => {
const error = await assertWithinQuota("o1", "ai.calls", 1).catch((caught: unknown) => caught);
expect(error).toBeInstanceOf(QuotaExceededError);
expect(error).not.toBeInstanceOf(HttpError);
const http = (error as InstanceType<typeof QuotaExceededError>).toHttpError();