Files
moltbot/src/browser/pw-tools-core.snapshot.navigate-guard.test.ts
SidQin-cyber 7c9d2c1d48 fix(browser): retry relay navigation after frame detach
Retry browser navigate once after transient frame-detached/target-closed errors by forcing a clean Playwright reconnect, so extension-relay sessions stay controllable across navigation swaps.

Closes #29431
2026-03-02 06:14:52 +00:00

79 lines
2.6 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { InvalidBrowserNavigationUrlError } from "./navigation-guard.js";
import {
getPwToolsCoreSessionMocks,
installPwToolsCoreTestHooks,
setPwToolsCoreCurrentPage,
} from "./pw-tools-core.test-harness.js";
installPwToolsCoreTestHooks();
const mod = await import("./pw-tools-core.snapshot.js");
describe("pw-tools-core.snapshot navigate guard", () => {
it("blocks unsupported non-network URLs before page lookup", async () => {
const goto = vi.fn(async () => {});
setPwToolsCoreCurrentPage({
goto,
url: vi.fn(() => "about:blank"),
});
await expect(
mod.navigateViaPlaywright({
cdpUrl: "http://127.0.0.1:18792",
url: "file:///etc/passwd",
}),
).rejects.toBeInstanceOf(InvalidBrowserNavigationUrlError);
expect(getPwToolsCoreSessionMocks().getPageForTargetId).not.toHaveBeenCalled();
expect(goto).not.toHaveBeenCalled();
});
it("navigates valid network URLs with clamped timeout", async () => {
const goto = vi.fn(async () => {});
setPwToolsCoreCurrentPage({
goto,
url: vi.fn(() => "https://example.com"),
});
const result = await mod.navigateViaPlaywright({
cdpUrl: "http://127.0.0.1:18792",
url: "https://example.com",
timeoutMs: 10,
ssrfPolicy: { allowPrivateNetwork: true },
});
expect(goto).toHaveBeenCalledWith("https://example.com", { timeout: 1000 });
expect(result.url).toBe("https://example.com");
});
it("reconnects and retries once when navigation detaches frame", async () => {
const goto = vi
.fn<(...args: unknown[]) => Promise<void>>()
.mockRejectedValueOnce(new Error("page.goto: Frame has been detached"))
.mockResolvedValueOnce(undefined);
setPwToolsCoreCurrentPage({
goto,
url: vi.fn(() => "https://example.com/recovered"),
});
const result = await mod.navigateViaPlaywright({
cdpUrl: "http://127.0.0.1:18792",
targetId: "tab-1",
url: "https://example.com/recovered",
ssrfPolicy: { allowPrivateNetwork: true },
});
expect(getPwToolsCoreSessionMocks().getPageForTargetId).toHaveBeenCalledTimes(2);
expect(getPwToolsCoreSessionMocks().forceDisconnectPlaywrightForTarget).toHaveBeenCalledTimes(
1,
);
expect(getPwToolsCoreSessionMocks().forceDisconnectPlaywrightForTarget).toHaveBeenCalledWith({
cdpUrl: "http://127.0.0.1:18792",
targetId: "tab-1",
reason: "retry navigate after detached frame",
});
expect(goto).toHaveBeenCalledTimes(2);
expect(result.url).toBe("https://example.com/recovered");
});
});