import { afterEach, describe, expect, mock, test } from "bun:test"; const fakeEnv: Record = {}; mock.module("cloudflare:workers", () => ({ env: fakeEnv, waitUntil: () => undefined })); mock.module("./db", () => ({ first: async () => ({ kind: "org" }) })); const { analyticsConfig, captureServerEvent } = await import("./analytics"); const { handleIngestProxy, ingestUpstream } = await import("./analytics-proxy"); const { scrubErrorMessage } = await import("~/lib/scrub-error"); const PROD = { POSTHOG_KEY: "phc_abc123", PUBLIC_URL: "https://gitfor.dev" }; afterEach(() => { for (const key of Object.keys(fakeEnv)) delete fakeEnv[key]; }); describe("analyticsConfig environments", () => { test("on in production", () => { Object.assign(fakeEnv, PROD); expect(analyticsConfig()).toEqual({ key: "phc_abc123", host: "https://us.i.posthog.com" }); }); test("off in local dev, on loopback and in named non-production environments", () => { Object.assign(fakeEnv, PROD, { GITFOR_LOCAL: "true" }); expect(analyticsConfig()).toBeNull(); Object.assign(fakeEnv, PROD, { GITFOR_LOCAL: undefined, PUBLIC_URL: "http://localhost:3000" }); expect(analyticsConfig()).toBeNull(); Object.assign(fakeEnv, PROD, { GITFOR_ENV: "staging" }); expect(analyticsConfig()).toBeNull(); fakeEnv.GITFOR_ENV = "production"; expect(analyticsConfig()).not.toBeNull(); }); }); describe("captureServerEvent", () => { test("org-owned events carry $groups", async () => { Object.assign(fakeEnv, PROD); const bodies: string[] = []; const original = globalThis.fetch; globalThis.fetch = (async (_url: string, init: RequestInit) => { bodies.push(String(init.body)); return new Response("ok"); }) as typeof fetch; try { captureServerEvent("pull_opened", "user1", { private_repo: true }, { ownerAccountId: "org1" }); await new Promise((resolve) => setTimeout(resolve, 10)); } finally { globalThis.fetch = original; } expect(JSON.parse(bodies[0] ?? "{}").properties.$groups).toEqual({ org: "org1" }); }); }); describe("ingest proxy", () => { test("404 when analytics is off, ignores other paths", async () => { expect(await handleIngestProxy(new Request("https://gitfor.dev/x"), new URL("https://gitfor.dev/x"))).toBeNull(); const off = await handleIngestProxy( new Request("https://gitfor.dev/ingest/e/"), new URL("https://gitfor.dev/ingest/e/"), ); expect(off?.status).toBe(404); }); test("forwards without cookies and drops upstream cookies", async () => { Object.assign(fakeEnv, PROD); let seen: Request | null = null; const original = globalThis.fetch; globalThis.fetch = (async (url: URL, init: RequestInit) => { seen = new Request(url, init); return new Response("ok", { headers: { "set-cookie": "a=b" } }); }) as typeof fetch; try { const url = "https://gitfor.dev/ingest/i/v0/e/?ver=1"; const request = new Request(url, { method: "POST", body: "{}", headers: { cookie: "session=s", "content-type": "application/json" }, }); const response = await handleIngestProxy(request, new URL(url)); expect(response?.headers.has("set-cookie")).toBe(false); } finally { globalThis.fetch = original; } const forwarded = seen as Request | null; expect(forwarded?.url).toBe("https://us.i.posthog.com/i/v0/e/?ver=1"); expect(forwarded?.headers.has("cookie")).toBe(false); }); test("static assets come from the assets host", () => { expect(ingestUpstream("https://eu.i.posthog.com", "/static/recorder.js")).toBe("https://eu-assets.i.posthog.com"); expect(ingestUpstream("https://eu.i.posthog.com", "/e/")).toBe("https://eu.i.posthog.com"); }); }); describe("scrubErrorMessage", () => { test("removes emails, urls, tokens, repo names and quoted values", () => { const out = scrubErrorMessage("bob@x.com https://a.b/c ghp_abc acme/secret 'branch' /a/b"); for (const leaked of ["bob", "a.b", "ghp_", "acme", "secret", "branch", "/a/b"]) expect(out).not.toContain(leaked); }); });