259 lines · 11.2 KB
import { beforeEach, describe, expect, mock, test } from "bun:test";
import type { Viewer } from "~/lib/types";

class StubEntrypoint {}
mock.module("cloudflare:workers", () => ({
  env: { PUBLIC_URL: "https://forge.example.com" },
  waitUntil: () => undefined,
  WorkflowEntrypoint: StubEntrypoint,
  DurableObject: StubEntrypoint,
  WorkerEntrypoint: StubEntrypoint,
}));

type Member = { userId: string; role: "owner" | "member" };
const users: Record<string, string> = { alice: "u-alice", bob: "u-bob", carol: "u-carol" };
let members: Member[] = [];
let invitations: { userId: string; role: string; invitedBy?: string | null }[] = [];

const d1 = {
  first: async (sql: string, ...params: unknown[]) => {
    if (sql.includes("kind = 'org'")) return params[0] === "acme" ? { id: "org-acme" } : null;
    if (sql.includes("JOIN users u")) {
      const id = users[String(params[0])];
      return id ? { id } : null;
    }
    if (sql.includes("COUNT(*) AS count FROM org_invitations")) return { count: invitations.length };
    if (sql.includes("COUNT(*)")) {
      return { count: members.filter((item) => item.role === "owner" && item.userId !== params[1]).length };
    }
    if (sql.includes("FROM org_invitations WHERE org_id = ? AND user_id = ?")) {
      const row = invitations.find((item) => item.userId === params[1]);
      return row ? { role: row.role, invited_by: row.invitedBy ?? null, expires_at: Date.now() + 1000 } : null;
    }
    if (sql.includes("is_admin = 1")) {
      return members.some((item) => item.userId === params[1] && item.role === "owner") ? { ok: 1 } : null;
    }
    if (sql.includes("SELECT role FROM org_members")) {
      const userId = params.length > 1 ? params[1] : params[0];
      const row = members.find((item) => item.userId === userId);
      return row ? { role: row.role } : null;
    }