From 766f13d37ad3b161dad256e45e0f7c8f6f2a4e65 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 14 Mar 2026 00:22:38 +0000 Subject: [PATCH] test: expand browser existing-session coverage --- src/browser/chrome-mcp.test.ts | 18 ++++++ .../routes/agent.existing-session.test.ts | 58 +++++++++++++++++++ src/browser/url-pattern.test.ts | 26 +++++++++ 3 files changed, 102 insertions(+) create mode 100644 src/browser/url-pattern.test.ts diff --git a/src/browser/chrome-mcp.test.ts b/src/browser/chrome-mcp.test.ts index a9571f31205..b6fe0a22f12 100644 --- a/src/browser/chrome-mcp.test.ts +++ b/src/browser/chrome-mcp.test.ts @@ -189,4 +189,22 @@ describe("chrome MCP page parsing", () => { expect(tabs).toHaveLength(2); expect(result).toBe(123); }); + + it("clears failed pending sessions so the next call can retry", async () => { + let factoryCalls = 0; + const factory: ChromeMcpSessionFactory = async () => { + factoryCalls += 1; + if (factoryCalls === 1) { + throw new Error("attach failed"); + } + return createFakeSession(); + }; + setChromeMcpSessionFactoryForTest(factory); + + await expect(listChromeMcpTabs("chrome-live")).rejects.toThrow(/attach failed/); + + const tabs = await listChromeMcpTabs("chrome-live"); + expect(factoryCalls).toBe(2); + expect(tabs).toHaveLength(2); + }); }); diff --git a/src/browser/routes/agent.existing-session.test.ts b/src/browser/routes/agent.existing-session.test.ts index 89b234cdc5c..0ab434cb38e 100644 --- a/src/browser/routes/agent.existing-session.test.ts +++ b/src/browser/routes/agent.existing-session.test.ts @@ -173,6 +173,64 @@ describe("existing-session browser routes", () => { expect(chromeMcpMocks.takeChromeMcpScreenshot).toHaveBeenCalled(); }); + it("allows ref screenshots for existing-session profiles", async () => { + const { app, postHandlers } = createApp(); + registerBrowserAgentSnapshotRoutes(app, { + state: () => ({ resolved: { ssrfPolicy: undefined } }), + } as never); + const handler = postHandlers.get("/screenshot"); + expect(handler).toBeTypeOf("function"); + + const response = createResponse(); + await handler?.( + { + params: {}, + query: {}, + body: { ref: "btn-1", type: "jpeg" }, + }, + response.res, + ); + + expect(response.statusCode).toBe(200); + expect(response.body).toMatchObject({ + ok: true, + path: "/tmp/fake.png", + targetId: "7", + }); + expect(chromeMcpMocks.takeChromeMcpScreenshot).toHaveBeenCalledWith({ + profileName: "chrome-live", + targetId: "7", + uid: "btn-1", + fullPage: false, + format: "jpeg", + }); + }); + + it("rejects selector-based element screenshots for existing-session profiles", async () => { + const { app, postHandlers } = createApp(); + registerBrowserAgentSnapshotRoutes(app, { + state: () => ({ resolved: { ssrfPolicy: undefined } }), + } as never); + const handler = postHandlers.get("/screenshot"); + expect(handler).toBeTypeOf("function"); + + const response = createResponse(); + await handler?.( + { + params: {}, + query: {}, + body: { element: "#submit" }, + }, + response.res, + ); + + expect(response.statusCode).toBe(400); + expect(response.body).toMatchObject({ + error: expect.stringContaining("element screenshots are not supported"), + }); + expect(chromeMcpMocks.takeChromeMcpScreenshot).not.toHaveBeenCalled(); + }); + it("fails closed for existing-session networkidle waits", async () => { const { app, postHandlers } = createApp(); registerBrowserAgentActRoutes(app, { diff --git a/src/browser/url-pattern.test.ts b/src/browser/url-pattern.test.ts new file mode 100644 index 00000000000..1cfdc06c36f --- /dev/null +++ b/src/browser/url-pattern.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from "vitest"; +import { matchBrowserUrlPattern } from "./url-pattern.js"; + +describe("browser url pattern matching", () => { + it("matches exact URLs", () => { + expect(matchBrowserUrlPattern("https://example.com/a", "https://example.com/a")).toBe(true); + expect(matchBrowserUrlPattern("https://example.com/a", "https://example.com/b")).toBe(false); + }); + + it("matches substring patterns without wildcards", () => { + expect(matchBrowserUrlPattern("example.com", "https://example.com/a")).toBe(true); + expect(matchBrowserUrlPattern("/dash", "https://example.com/app/dash")).toBe(true); + expect(matchBrowserUrlPattern("nope", "https://example.com/a")).toBe(false); + }); + + it("matches glob patterns", () => { + expect(matchBrowserUrlPattern("**/dash", "https://example.com/app/dash")).toBe(true); + expect(matchBrowserUrlPattern("https://example.com/*", "https://example.com/a")).toBe(true); + expect(matchBrowserUrlPattern("https://example.com/*", "https://other.com/a")).toBe(false); + }); + + it("rejects empty patterns", () => { + expect(matchBrowserUrlPattern("", "https://example.com")).toBe(false); + expect(matchBrowserUrlPattern(" ", "https://example.com")).toBe(false); + }); +});