import { describe, expect, mock, test } from "bun:test"; import { Database } from "bun:sqlite"; import { applyCombinedSchema } from "./test-schema.test-helper"; import type { Viewer } from "~/lib/types"; mock.module("cloudflare:workers", () => ({ env: { PUBLIC_URL: "https://forge.example.com" }, waitUntil: () => undefined, WorkflowEntrypoint: class {}, DurableObject: class {}, WorkerEntrypoint: class {}, })); mock.module("@tanstack/react-start/server", () => ({ getRequestHeader: () => undefined, getRequest: () => undefined, deleteCookie: () => undefined, getCookie: () => undefined, setCookie: () => undefined, setResponseHeader: () => undefined, setResponseStatus: () => undefined, })); const db = new Database(":memory:"); applyCombinedSchema(db); type Statement = { sql: string; params: unknown[] }; const exec = (sql: string, params: unknown[]) => db.query(sql).run(...(params as never[])); mock.module("./db", () => ({ first: async (sql: string, ...params: unknown[]) => db.query(sql).get(...(params as never[])) ?? null, all: async (sql: string, ...params: unknown[]) => db.query(sql).all(...(params as never[])), run: async (sql: string, ...params: unknown[]) => ({ meta: { changes: exec(sql, params).changes } }), batch: async (statements: Statement[]) => statements.map((statement) => exec(statement.sql, statement.params)), stmt: (sql: string, ...params: unknown[]): Statement => ({ sql, params }), placeholders: (count: number) => Array(count).fill("?").join(", "), chunks: (items: T[]) => [items], MAX_IN_LIST: 90, })); const { sharedScopes } = await import("./test-shared-scopes"); mock.module("./scoped-db", () => sharedScopes(db)); const actualBridge = await import("./git/pull-bridge"); mock.module("./git/pull-bridge", () => ({ ...actualBridge, dropPullRefsForIssue: async () => undefined })); const actualEmit = await import("./events/emit"); mock.module("./events/emit", () => ({ ...actualEmit, emitWebhook: async () => undefined, publicUrl: (path: string) => `https://forge.example.com${path}`, })); const { loadIssue, setIssueState } = await import("./issues"); const { requirePull, requirePullMutation } = await import("./pull-access"); db.exec(` INSERT INTO accounts (id, name, kind, created_at) VALUES ('owner', 'owner', 'user', 0), ('admin', 'admin', 'user', 0); INSERT INTO users (account_id, email, is_admin) VALUES ('owner', 'o@x', 0), ('admin', 'a@x', 1); INSERT INTO repos (id, owner_id, name, visibility, status, default_branch, artifacts_name, artifacts_remote, created_at, updated_at, open_issues_count, open_pulls_count) VALUES ('r1', 'owner', 'blog', 'public', 'ready', 'main', 'a1', 'x', 0, 0, 0, 0); INSERT INTO issues (id, repo_id, number, author_id, title, state, is_pull, created_at, updated_at, hidden_at) VALUES ('i1', 'r1', 1, 'owner', 'spam', 'open', 0, 0, 0, 1), ('p1', 'r1', 2, 'owner', 'spam pr', 'open', 1, 0, 0, 1); INSERT INTO pull_requests (issue_id, repo_id, head_repo_id, head_ref, head_sha, base_ref, base_sha) VALUES ('p1', 'r1', 'r1', 'feat', 'h', 'main', 'b'); `); const owner: Viewer = { id: "owner", name: "owner", displayName: null, email: "o@x", isAdmin: false, emailVerified: true, }; const admin: Viewer = { id: "admin", name: "admin", displayName: null, email: "a@x", isAdmin: true, emailVerified: true, }; describe("hidden issues and pull requests", () => { test("loadIssue leaves them out unless a site-admin read asks", async () => { expect(await loadIssue("r1", 1)).toBeNull(); expect((await loadIssue("r1", 1, { includeHidden: true }))?.id).toBe("i1"); }); test("site admins can read a hidden pull request; everyone else gets 404, and no one can mutate it", async () => { expect((await requirePull("owner", "blog", 2, admin, "read")).pull.issue_id).toBe("p1"); await expect(requirePull("owner", "blog", 2, owner, "read")).rejects.toThrow("Pull request not found"); await expect(requirePull("owner", "blog", 2, null, "read")).rejects.toThrow("Pull request not found"); await expect(requirePull("owner", "blog", 2, admin, "write")).rejects.toThrow("Pull request not found"); await expect(requirePullMutation("owner", "blog", 2, admin, "read")).rejects.toThrow("Pull request not found"); }); test("state changes on a hidden issue leave the open counter alone", async () => { const issue = await loadIssue("r1", 1, { includeHidden: true }); if (!issue) throw new Error("missing issue"); await setIssueState(issue, "closed", "admin"); expect(db.query("SELECT open_issues_count AS n FROM repos").get()).toEqual({ n: 0 }); expect(db.query("SELECT state FROM issues WHERE id = 'i1'").get()).toEqual({ state: "closed" }); }); });