mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-27 00:17:29 +00:00
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
79 lines
2.6 KiB
TypeScript
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");
|
|
});
|
|
});
|