Skip to content

Commit 56dd6eb

Browse files
committed
fix(web): retain prepared browser popup handle
1 parent 45ac47e commit 56dd6eb

4 files changed

Lines changed: 51 additions & 4 deletions

File tree

packages/app/src/web/open-url.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const prepareOpenUrl = (): PreparedOpenUrl => {
2020
if (typeof globalThis.open !== "function") {
2121
return blockedPreparedOpenUrl()
2222
}
23-
const openedWindow = globalThis.open("about:blank", "_blank", "noopener")
23+
const openedWindow = globalThis.open("about:blank", "_blank")
2424
if (openedWindow === null) {
2525
return blockedPreparedOpenUrl()
2626
}

packages/app/tests/docker-git/actions-browser.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ describe("web browser actions", () => {
6767
expect(setProjectBrowser).toHaveBeenCalledWith(runningBrowser)
6868
}))
6969

70-
expect(openMock).toHaveBeenCalledWith("about:blank", "_blank", "noopener")
70+
expect(openMock).toHaveBeenCalledWith("about:blank", "_blank")
7171
expect(openedWindow.location.href).toBe("/api/projects/project-1/browser/novnc")
7272
expect(setMessage).toHaveBeenLastCalledWith("Browser opened. CDP endpoint: /api/projects/project-1/browser/cdp.")
7373
}))
@@ -89,7 +89,7 @@ describe("web browser actions", () => {
8989
}))
9090

9191
expect(startProjectBrowserMock).toHaveBeenCalledWith("project-1")
92-
expect(openMock).toHaveBeenCalledWith("about:blank", "_blank", "noopener")
92+
expect(openMock).toHaveBeenCalledWith("about:blank", "_blank")
9393
expect(openedWindow.close).toHaveBeenCalledOnce()
9494
expect(setMessage).toHaveBeenLastCalledWith(
9595
"Browser runtime is missing. Enable Playwright MCP and start the project first."

packages/app/tests/docker-git/actions-skiller.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ describe("web Skiller actions", () => {
8787

8888
openSkillerApp(context)
8989

90-
expect(browserOpenMock).toHaveBeenCalledWith("about:blank", "_blank", "noopener")
90+
expect(browserOpenMock).toHaveBeenCalledWith("about:blank", "_blank")
9191
expect(setMessage).toHaveBeenCalledWith("Opening Skiller...")
9292
yield* _(waitForAssertion(() => {
9393
expect(openSkillerMock).toHaveBeenCalledWith(undefined, undefined)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { describe, expect, it } from "@effect/vitest"
2+
import { afterEach, vi } from "vitest"
3+
4+
import { openUrl, prepareOpenUrl } from "../../src/web/open-url.js"
5+
import { makeBrowserOpenMockWindow, stubBrowserOpen } from "./browser-open-fixture.js"
6+
7+
describe("open-url helpers", () => {
8+
afterEach(() => {
9+
vi.unstubAllGlobals()
10+
})
11+
12+
it("opens prepared async popups without noopener so the caller keeps the window handle", () => {
13+
const openedWindow = makeBrowserOpenMockWindow()
14+
const openMock = stubBrowserOpen(openedWindow)
15+
16+
const prepared = prepareOpenUrl()
17+
18+
expect(openMock).toHaveBeenCalledWith("about:blank", "_blank")
19+
expect(openedWindow.opener).toBeNull()
20+
expect(prepared.navigate("/api/projects/project-1/browser/novnc")).toBe(true)
21+
expect(openedWindow.location.href).toBe("/api/projects/project-1/browser/novnc")
22+
expect(openedWindow.focus).toHaveBeenCalledOnce()
23+
24+
prepared.close()
25+
26+
expect(openedWindow.close).toHaveBeenCalledOnce()
27+
})
28+
29+
it("falls back to direct noopener open when the prepared popup is blocked", () => {
30+
const openedWindow = makeBrowserOpenMockWindow()
31+
const openMock = vi.fn((url: string) => url === "about:blank" ? null : openedWindow)
32+
vi.stubGlobal("open", openMock)
33+
34+
const prepared = prepareOpenUrl()
35+
36+
expect(prepared.navigate("/api/projects/project-1/browser/novnc")).toBe(true)
37+
expect(openMock).toHaveBeenNthCalledWith(1, "about:blank", "_blank")
38+
expect(openMock).toHaveBeenNthCalledWith(2, "/api/projects/project-1/browser/novnc", "_blank", "noopener")
39+
})
40+
41+
it("reports direct opens as blocked when no browser open function exists", () => {
42+
vi.stubGlobal("open", null)
43+
44+
expect(openUrl("/api/projects/project-1/browser/novnc")).toBe(false)
45+
expect(prepareOpenUrl().navigate("/api/projects/project-1/browser/novnc")).toBe(false)
46+
})
47+
})

0 commit comments

Comments
 (0)