import { beforeEach, describe, expect, mock, test } from "bun:test"; import { scopedTestState } from "./sites/scoped.test-helper"; const kv = new Map(); mock.module("cloudflare:workers", () => ({ env: { KV: { get: async (key: string) => kv.get(key) ?? null, put: async (key: string, value: string) => void kv.set(key, value), }, }, waitUntil: () => undefined, })); const ACCOUNTS = ["o1", "o2", "o3", "u1"]; mock.module("./db", () => ({ all: async (sql: string, cursor?: string) => sql.includes("kind = 'org'") ? ["o1", "o2", "o3"].map((id) => ({ id })) : ACCOUNTS.filter((id) => id > (cursor ?? "")).map((id) => ({ id })), })); const scoped = scopedTestState(); scoped.install(); const { backfillInviters, invitationOrgs, registerInviter } = await import("./invitation-index"); function invite(orgId: string, id: string, userId: string, invitedBy: string): void { for (const scope of [orgId, userId]) { scoped .account(scope) .query( "INSERT INTO org_invitations (id, org_id, user_id, role, invited_by, created_at, expires_at) VALUES (?, ?, ?, 'member', ?, 0, 1)", ) .run(id, orgId, userId, invitedBy); } } beforeEach(() => { kv.clear(); scoped.reset(); }); describe("invitation orgs", () => { test("every org until the inviter index is backfilled, then only the orgs that matter", async () => { invite("o1", "i1", "u1", "x"); invite("o2", "i2", "x", "u1"); expect((await invitationOrgs("u1", [])).sort()).toEqual(["o1", "o2", "o3"]); expect(await backfillInviters()).toBe(true); expect((await invitationOrgs("u1", ["o3"])).sort()).toEqual(["o1", "o2", "o3"]); expect((await invitationOrgs("u1", [])).sort()).toEqual(["o1", "o2"]); await registerInviter("u1", "i3", "o3"); expect((await invitationOrgs("u1", [])).sort()).toEqual(["o1", "o2", "o3"]); }); });