


























@@ -6,6 +6,7 @@ import os from "node:os";
66import path from "node:path";
77import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
88import { WebSocketServer } from "ws";
9+import { rawDataToString } from "../infra/ws.js";
910import {
1011parseBrowserMajorVersion,
1112resolveGoogleChromeExecutableForPlatform,
@@ -56,7 +57,7 @@ async function withMockChromeCdpServer(params: {
5657run: (baseUrl: string) => Promise<void>;
5758}) {
5859const server = createServer((req, res) => {
59-if (req.url === "/json/version") {
60+if (req.url?.startsWith("/json/version")) {
6061const addr = server.address() as AddressInfo;
6162res.writeHead(200, { "Content-Type": "application/json" });
6263res.end(
@@ -71,7 +72,7 @@ async function withMockChromeCdpServer(params: {
7172});
7273const wss = new WebSocketServer({ noServer: true });
7374server.on("upgrade", (req, socket, head) => {
74-if (req.url !== params.wsPath) {
75+if (!req.url?.startsWith(params.wsPath)) {
7576socket.destroy();
7677return;
7778}
@@ -630,6 +631,37 @@ describe("browser chrome helpers", () => {
630631});
631632});
632633634+it("uses HTTP discovery before readiness checks for a bare ws:// CDP URL", async () => {
635+await withMockChromeCdpServer({
636+wsPath: "/devtools/browser/READY",
637+onConnection: (wss) => {
638+wss.on("connection", (ws) => {
639+ws.on("message", (raw) => {
640+const message = JSON.parse(rawDataToString(raw)) as { id?: number; method?: string };
641+if (message.method === "Browser.getVersion" && message.id === 1) {
642+ws.send(
643+JSON.stringify({
644+id: 1,
645+result: { product: "Chrome/Mock" },
646+}),
647+);
648+}
649+});
650+});
651+},
652+run: async (baseUrl) => {
653+const url = new URL(baseUrl);
654+const wsOnlyBase = `ws://${url.host}?token=abc`;
655+await expect(isChromeCdpReady(wsOnlyBase, 300, 400)).resolves.toBe(true);
656+const diagnostic = await diagnoseChromeCdp(wsOnlyBase, 300, 400);
657+expect(diagnostic).toMatchObject({
658+ok: true,
659+wsUrl: `ws://${url.host}/devtools/browser/READY?token=abc`,
660+});
661+},
662+});
663+});
664+633665it("reports unreachable when a bare ws:// CDP URL points at a server with no /json/version and refuses WS", async () => {
634666// Negative counterpart to the #68027 happy path — a bare ws URL
635667// pointed at a port that neither serves /json/version nor accepts
@@ -664,6 +696,36 @@ describe("browser chrome helpers", () => {
664696}
665697});
666698699+it("falls back to a direct WS readiness check when /json/version has no debugger URL", async () => {
700+vi.stubGlobal(
701+"fetch",
702+vi.fn().mockResolvedValue({
703+ok: true,
704+json: async () => ({}),
705+} as unknown as Response),
706+);
707+const wss = new WebSocketServer({ port: 0, host: "127.0.0.1" });
708+wss.on("connection", (ws) => {
709+ws.on("message", (raw) => {
710+const message = JSON.parse(rawDataToString(raw)) as { id?: number; method?: string };
711+if (message.method === "Browser.getVersion" && message.id === 1) {
712+ws.send(JSON.stringify({ id: 1, result: { product: "Browserless/Mock" } }));
713+}
714+});
715+});
716+await new Promise<void>((resolve) => wss.once("listening", () => resolve()));
717+const port = (wss.address() as AddressInfo).port;
718+try {
719+await expect(isChromeCdpReady(`ws://127.0.0.1:${port}`, 500, 500)).resolves.toBe(true);
720+await expect(diagnoseChromeCdp(`ws://127.0.0.1:${port}`, 500, 500)).resolves.toMatchObject({
721+ok: true,
722+wsUrl: `ws://127.0.0.1:${port}`,
723+});
724+} finally {
725+await new Promise<void>((resolve) => wss.close(() => resolve()));
726+}
727+});
728+667729it("returns the original ws:// URL from getChromeWebSocketUrl when /json/version provides no debugger URL", async () => {
668730// Covers the getChromeWebSocketUrl WS-fallback: discovery succeeds but
669731// webSocketDebuggerUrl is absent — the original URL is returned as-is.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。