From 1287abe0b5a1ecd7b4fd363cb1a90bc7a29a82b0 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 15 Feb 2026 23:33:29 +0000 Subject: [PATCH] perf(test): consolidate browser utility tests --- src/browser/browser-utils.test.ts | 178 ++++++++++++++++++ src/browser/cdp.helpers.test.ts | 26 --- .../client-fetch.bridge-auth-registry.test.ts | 19 -- src/browser/csrf.test.ts | 80 -------- src/browser/routes/utils.test.ts | 21 --- src/browser/target-id.test.ts | 36 ---- 6 files changed, 178 insertions(+), 182 deletions(-) create mode 100644 src/browser/browser-utils.test.ts delete mode 100644 src/browser/cdp.helpers.test.ts delete mode 100644 src/browser/client-fetch.bridge-auth-registry.test.ts delete mode 100644 src/browser/csrf.test.ts delete mode 100644 src/browser/routes/utils.test.ts delete mode 100644 src/browser/target-id.test.ts diff --git a/src/browser/browser-utils.test.ts b/src/browser/browser-utils.test.ts new file mode 100644 index 00000000000..4ff4a2f0610 --- /dev/null +++ b/src/browser/browser-utils.test.ts @@ -0,0 +1,178 @@ +import { describe, expect, it, vi } from "vitest"; +import { appendCdpPath, getHeadersWithAuth } from "./cdp.helpers.js"; +import { __test } from "./client-fetch.js"; +import { shouldRejectBrowserMutation } from "./csrf.js"; +import { toBoolean } from "./routes/utils.js"; +import { resolveTargetIdFromTabs } from "./target-id.js"; + +describe("toBoolean", () => { + it("parses yes/no and 1/0", () => { + expect(toBoolean("yes")).toBe(true); + expect(toBoolean("1")).toBe(true); + expect(toBoolean("no")).toBe(false); + expect(toBoolean("0")).toBe(false); + }); + + it("returns undefined for on/off strings", () => { + expect(toBoolean("on")).toBeUndefined(); + expect(toBoolean("off")).toBeUndefined(); + }); + + it("passes through boolean values", () => { + expect(toBoolean(true)).toBe(true); + expect(toBoolean(false)).toBe(false); + }); +}); + +describe("browser target id resolution", () => { + it("resolves exact ids", () => { + const res = resolveTargetIdFromTabs("FULL", [{ targetId: "AAA" }, { targetId: "FULL" }]); + expect(res).toEqual({ ok: true, targetId: "FULL" }); + }); + + it("resolves unique prefixes (case-insensitive)", () => { + const res = resolveTargetIdFromTabs("57a01309", [ + { targetId: "57A01309E14B5DEE0FB41F908515A2FC" }, + ]); + expect(res).toEqual({ + ok: true, + targetId: "57A01309E14B5DEE0FB41F908515A2FC", + }); + }); + + it("fails on ambiguous prefixes", () => { + const res = resolveTargetIdFromTabs("57A0", [ + { targetId: "57A01309E14B5DEE0FB41F908515A2FC" }, + { targetId: "57A0BEEF000000000000000000000000" }, + ]); + expect(res.ok).toBe(false); + if (!res.ok) { + expect(res.reason).toBe("ambiguous"); + expect(res.matches?.length).toBe(2); + } + }); + + it("fails when no tab matches", () => { + const res = resolveTargetIdFromTabs("NOPE", [{ targetId: "AAA" }]); + expect(res).toEqual({ ok: false, reason: "not_found" }); + }); +}); + +describe("browser CSRF loopback mutation guard", () => { + it("rejects mutating methods from non-loopback origin", () => { + expect( + shouldRejectBrowserMutation({ + method: "POST", + origin: "https://evil.example", + }), + ).toBe(true); + }); + + it("allows mutating methods from loopback origin", () => { + expect( + shouldRejectBrowserMutation({ + method: "POST", + origin: "http://127.0.0.1:18789", + }), + ).toBe(false); + + expect( + shouldRejectBrowserMutation({ + method: "POST", + origin: "http://localhost:18789", + }), + ).toBe(false); + }); + + it("allows mutating methods without origin/referer (non-browser clients)", () => { + expect( + shouldRejectBrowserMutation({ + method: "POST", + }), + ).toBe(false); + }); + + it("rejects mutating methods with origin=null", () => { + expect( + shouldRejectBrowserMutation({ + method: "POST", + origin: "null", + }), + ).toBe(true); + }); + + it("rejects mutating methods from non-loopback referer", () => { + expect( + shouldRejectBrowserMutation({ + method: "POST", + referer: "https://evil.example/attack", + }), + ).toBe(true); + }); + + it("rejects cross-site mutations via Sec-Fetch-Site when present", () => { + expect( + shouldRejectBrowserMutation({ + method: "POST", + secFetchSite: "cross-site", + }), + ).toBe(true); + }); + + it("does not reject non-mutating methods", () => { + expect( + shouldRejectBrowserMutation({ + method: "GET", + origin: "https://evil.example", + }), + ).toBe(false); + + expect( + shouldRejectBrowserMutation({ + method: "OPTIONS", + origin: "https://evil.example", + }), + ).toBe(false); + }); +}); + +describe("cdp.helpers", () => { + it("preserves query params when appending CDP paths", () => { + const url = appendCdpPath("https://example.com?token=abc", "/json/version"); + expect(url).toBe("https://example.com/json/version?token=abc"); + }); + + it("appends paths under a base prefix", () => { + const url = appendCdpPath("https://example.com/chrome/?token=abc", "json/list"); + expect(url).toBe("https://example.com/chrome/json/list?token=abc"); + }); + + it("adds basic auth headers when credentials are present", () => { + const headers = getHeadersWithAuth("https://user:pass@example.com"); + expect(headers.Authorization).toBe(`Basic ${Buffer.from("user:pass").toString("base64")}`); + }); + + it("keeps preexisting authorization headers", () => { + const headers = getHeadersWithAuth("https://user:pass@example.com", { + Authorization: "Bearer token", + }); + expect(headers.Authorization).toBe("Bearer token"); + }); +}); + +describe("fetchBrowserJson loopback auth (bridge auth registry)", () => { + it("falls back to per-port bridge auth when config auth is not available", async () => { + const port = 18765; + const getBridgeAuthForPort = vi.fn((candidate: number) => + candidate === port ? { token: "registry-token" } : undefined, + ); + const init = __test.withLoopbackBrowserAuth(`http://127.0.0.1:${port}/`, undefined, { + loadConfig: () => ({}), + resolveBrowserControlAuth: () => ({}), + getBridgeAuthForPort, + }); + const headers = new Headers(init.headers ?? {}); + expect(headers.get("authorization")).toBe("Bearer registry-token"); + expect(getBridgeAuthForPort).toHaveBeenCalledWith(port); + }); +}); diff --git a/src/browser/cdp.helpers.test.ts b/src/browser/cdp.helpers.test.ts deleted file mode 100644 index b41864ee431..00000000000 --- a/src/browser/cdp.helpers.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { appendCdpPath, getHeadersWithAuth } from "./cdp.helpers.js"; - -describe("cdp.helpers", () => { - it("preserves query params when appending CDP paths", () => { - const url = appendCdpPath("https://example.com?token=abc", "/json/version"); - expect(url).toBe("https://example.com/json/version?token=abc"); - }); - - it("appends paths under a base prefix", () => { - const url = appendCdpPath("https://example.com/chrome/?token=abc", "json/list"); - expect(url).toBe("https://example.com/chrome/json/list?token=abc"); - }); - - it("adds basic auth headers when credentials are present", () => { - const headers = getHeadersWithAuth("https://user:pass@example.com"); - expect(headers.Authorization).toBe(`Basic ${Buffer.from("user:pass").toString("base64")}`); - }); - - it("keeps preexisting authorization headers", () => { - const headers = getHeadersWithAuth("https://user:pass@example.com", { - Authorization: "Bearer token", - }); - expect(headers.Authorization).toBe("Bearer token"); - }); -}); diff --git a/src/browser/client-fetch.bridge-auth-registry.test.ts b/src/browser/client-fetch.bridge-auth-registry.test.ts deleted file mode 100644 index 8e8ef5848b6..00000000000 --- a/src/browser/client-fetch.bridge-auth-registry.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; -import { __test } from "./client-fetch.js"; - -describe("fetchBrowserJson loopback auth (bridge auth registry)", () => { - it("falls back to per-port bridge auth when config auth is not available", async () => { - const port = 18765; - const getBridgeAuthForPort = vi.fn((candidate: number) => - candidate === port ? { token: "registry-token" } : undefined, - ); - const init = __test.withLoopbackBrowserAuth(`http://127.0.0.1:${port}/`, undefined, { - loadConfig: () => ({}), - resolveBrowserControlAuth: () => ({}), - getBridgeAuthForPort, - }); - const headers = new Headers(init.headers ?? {}); - expect(headers.get("authorization")).toBe("Bearer registry-token"); - expect(getBridgeAuthForPort).toHaveBeenCalledWith(port); - }); -}); diff --git a/src/browser/csrf.test.ts b/src/browser/csrf.test.ts deleted file mode 100644 index 6f4bedd692f..00000000000 --- a/src/browser/csrf.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { shouldRejectBrowserMutation } from "./csrf.js"; - -describe("browser CSRF loopback mutation guard", () => { - it("rejects mutating methods from non-loopback origin", () => { - expect( - shouldRejectBrowserMutation({ - method: "POST", - origin: "https://evil.example", - }), - ).toBe(true); - }); - - it("allows mutating methods from loopback origin", () => { - expect( - shouldRejectBrowserMutation({ - method: "POST", - origin: "http://127.0.0.1:18789", - }), - ).toBe(false); - - expect( - shouldRejectBrowserMutation({ - method: "POST", - origin: "http://localhost:18789", - }), - ).toBe(false); - }); - - it("allows mutating methods without origin/referer (non-browser clients)", () => { - expect( - shouldRejectBrowserMutation({ - method: "POST", - }), - ).toBe(false); - }); - - it("rejects mutating methods with origin=null", () => { - expect( - shouldRejectBrowserMutation({ - method: "POST", - origin: "null", - }), - ).toBe(true); - }); - - it("rejects mutating methods from non-loopback referer", () => { - expect( - shouldRejectBrowserMutation({ - method: "POST", - referer: "https://evil.example/attack", - }), - ).toBe(true); - }); - - it("rejects cross-site mutations via Sec-Fetch-Site when present", () => { - expect( - shouldRejectBrowserMutation({ - method: "POST", - secFetchSite: "cross-site", - }), - ).toBe(true); - }); - - it("does not reject non-mutating methods", () => { - expect( - shouldRejectBrowserMutation({ - method: "GET", - origin: "https://evil.example", - }), - ).toBe(false); - - expect( - shouldRejectBrowserMutation({ - method: "OPTIONS", - origin: "https://evil.example", - }), - ).toBe(false); - }); -}); diff --git a/src/browser/routes/utils.test.ts b/src/browser/routes/utils.test.ts deleted file mode 100644 index 4f7762a944e..00000000000 --- a/src/browser/routes/utils.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { toBoolean } from "./utils.js"; - -describe("toBoolean", () => { - it("parses yes/no and 1/0", () => { - expect(toBoolean("yes")).toBe(true); - expect(toBoolean("1")).toBe(true); - expect(toBoolean("no")).toBe(false); - expect(toBoolean("0")).toBe(false); - }); - - it("returns undefined for on/off strings", () => { - expect(toBoolean("on")).toBeUndefined(); - expect(toBoolean("off")).toBeUndefined(); - }); - - it("passes through boolean values", () => { - expect(toBoolean(true)).toBe(true); - expect(toBoolean(false)).toBe(false); - }); -}); diff --git a/src/browser/target-id.test.ts b/src/browser/target-id.test.ts deleted file mode 100644 index a63b6aedbf3..00000000000 --- a/src/browser/target-id.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { resolveTargetIdFromTabs } from "./target-id.js"; - -describe("browser target id resolution", () => { - it("resolves exact ids", () => { - const res = resolveTargetIdFromTabs("FULL", [{ targetId: "AAA" }, { targetId: "FULL" }]); - expect(res).toEqual({ ok: true, targetId: "FULL" }); - }); - - it("resolves unique prefixes (case-insensitive)", () => { - const res = resolveTargetIdFromTabs("57a01309", [ - { targetId: "57A01309E14B5DEE0FB41F908515A2FC" }, - ]); - expect(res).toEqual({ - ok: true, - targetId: "57A01309E14B5DEE0FB41F908515A2FC", - }); - }); - - it("fails on ambiguous prefixes", () => { - const res = resolveTargetIdFromTabs("57A0", [ - { targetId: "57A01309E14B5DEE0FB41F908515A2FC" }, - { targetId: "57A0BEEF000000000000000000000000" }, - ]); - expect(res.ok).toBe(false); - if (!res.ok) { - expect(res.reason).toBe("ambiguous"); - expect(res.matches?.length).toBe(2); - } - }); - - it("fails when no tab matches", () => { - const res = resolveTargetIdFromTabs("NOPE", [{ targetId: "AAA" }]); - expect(res).toEqual({ ok: false, reason: "not_found" }); - }); -});