Fix: CDP profiles prefer cdpPort over stale WebSocket cdpUrl (Resolves #58494) (#58499)

* fix(browser): prefer cdpPort over stale WebSocket cdpUrl for attach-only profiles

* fix(browser): preserve profile host when dropping stale devtools WS path
This commit is contained in:
Han Yang 2026-04-01 09:09:31 +08:00 committed by GitHub
parent 2650ce31fc
commit 68ee3113a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 53 additions and 1 deletions

View File

@ -190,6 +190,43 @@ describe("browser config", () => {
expect(profile?.cdpIsLoopback).toBe(true);
});
it("prefers cdpPort over stale WebSocket devtools cdpUrl when both are set", () => {
const resolved = resolveBrowserConfig({
profiles: {
"chrome-cdp": {
cdpPort: 9222,
cdpUrl: "ws://127.0.0.1:9222/devtools/browser/old-stale-id",
attachOnly: true,
color: "#F59E0B",
},
},
});
const profile = resolveProfile(resolved, "chrome-cdp");
// cdpPort produces a stable HTTP endpoint; the stale WS session ID is dropped.
expect(profile?.cdpUrl).toBe("http://127.0.0.1:9222");
expect(profile?.cdpPort).toBe(9222);
expect(profile?.cdpIsLoopback).toBe(true);
expect(profile?.attachOnly).toBe(true);
});
it("preserves profile host when dropping stale devtools WS path", () => {
const resolved = resolveBrowserConfig({
cdpUrl: "http://devbox.local:9000",
profiles: {
"chrome-local": {
cdpPort: 9222,
cdpUrl: "ws://10.0.0.42:9222/devtools/browser/stale-id",
color: "#0066CC",
},
},
});
const profile = resolveProfile(resolved, "chrome-local");
// Host comes from the profile WS URL, not the global cdpUrl.
expect(profile?.cdpUrl).toBe("http://10.0.0.42:9222");
expect(profile?.cdpHost).toBe("10.0.0.42");
expect(profile?.cdpIsLoopback).toBe(false);
});
it("rejects unsupported protocols", () => {
expect(() => resolveBrowserConfig({ cdpUrl: "ftp://127.0.0.1:18791" })).toThrow(
"must be http(s) or ws(s)",

View File

@ -337,7 +337,22 @@ export function resolveProfile(
};
}
if (rawProfileUrl) {
// When both cdpPort and cdpUrl are set and the URL contains a
// /devtools/browser/ path (a session-specific WebSocket ID), prefer
// cdpPort — the HTTP endpoint is stable across Chrome restarts while the
// WS path goes stale. For cloud CDP services (e.g. Browserbase) that
// use WSS URLs without a devtools path, preserve the full URL.
const hasStaleWsPath =
rawProfileUrl !== "" &&
cdpPort > 0 &&
/^wss?:\/\//i.test(rawProfileUrl) &&
/\/devtools\/browser\//i.test(rawProfileUrl);
if (hasStaleWsPath) {
const parsed = new URL(rawProfileUrl);
cdpHost = parsed.hostname;
cdpUrl = `${resolved.cdpProtocol}://${cdpHost}:${cdpPort}`;
} else if (rawProfileUrl) {
const parsed = parseHttpUrl(rawProfileUrl, `browser.profiles.${profileName}.cdpUrl`);
cdpHost = parsed.parsed.hostname;
cdpPort = parsed.port;