diff --git a/src/browser/server.skips-default-maxchars-explicitly-set-zero.test.ts b/src/browser/server.skips-default-maxchars-explicitly-set-zero.test.ts index a4f8ec22e5..a4f03f81dc 100644 --- a/src/browser/server.skips-default-maxchars-explicitly-set-zero.test.ts +++ b/src/browser/server.skips-default-maxchars-explicitly-set-zero.test.ts @@ -275,7 +275,7 @@ describe("browser control server", () => { await stopBrowserControlServer(); }); - it("covers primary control routes, validation, and attach-only compatibility", async () => { + it("covers primary control routes, validation, and profile compatibility", async () => { const { startBrowserControlServerFromConfig } = await import("./server.js"); const started = await startBrowserControlServerFromConfig(); expect(started?.port).toBe(testPort); @@ -356,78 +356,32 @@ describe("browser control server", () => { }); expect(focusMissing.status).toBe(404); - const [ - navMissing, - actMissing, - clickMissingRef, - scrollMissingRef, - scrollSelectorUnsupported, - clickBadButton, - clickBadModifiers, - typeBadText, - uploadMissingPaths, - dialogMissingAccept, - ] = await Promise.all([ - realFetch(`${base}/navigate`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({}), - }), - realFetch(`${base}/act`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({}), - }), - realFetch(`${base}/act`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ kind: "click" }), - }), - realFetch(`${base}/act`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ kind: "scrollIntoView" }), - }), - realFetch(`${base}/act`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ kind: "scrollIntoView", selector: "button.save" }), - }), - realFetch(`${base}/act`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ kind: "click", ref: "1", button: "nope" }), - }), - realFetch(`${base}/act`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ kind: "click", ref: "1", modifiers: ["Nope"] }), - }), - realFetch(`${base}/act`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ kind: "type", ref: "1", text: 123 }), - }), - realFetch(`${base}/hooks/file-chooser`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({}), - }), - realFetch(`${base}/hooks/dialog`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({}), - }), - ]); + const [navMissing, clickMissingRef, scrollSelectorUnsupported, dialogMissingAccept] = + await Promise.all([ + realFetch(`${base}/navigate`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({}), + }), + realFetch(`${base}/act`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ kind: "click" }), + }), + realFetch(`${base}/act`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ kind: "scrollIntoView", selector: "button.save" }), + }), + realFetch(`${base}/hooks/dialog`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({}), + }), + ]); expect(navMissing.status).toBe(400); - expect(actMissing.status).toBe(400); expect(clickMissingRef.status).toBe(400); - expect(scrollMissingRef.status).toBe(400); expect(scrollSelectorUnsupported.status).toBe(400); - expect(clickBadButton.status).toBe(400); - expect(clickBadModifiers.status).toBe(400); - expect(typeBadText.status).toBe(400); - expect(uploadMissingPaths.status).toBe(400); expect(dialogMissingAccept.status).toBe(400); const snapDefault = (await realFetch(`${base}/snapshot?format=wat`).then((r) => r.json())) as { @@ -499,50 +453,5 @@ describe("browser control server", () => { body: JSON.stringify({}), }); expect(missing.status).toBe(400); - - reachable = false; - cfgAttachOnly = true; - const attachStarted = (await realFetch(`${base}/start`, { - method: "POST", - }).then((r) => r.json())) as { error?: string }; - expect(attachStarted.error ?? "").toMatch(/attachOnly/i); - - const { startBrowserBridgeServer } = await import("./bridge-server.js"); - - const ensured = vi.fn(async () => { - reachable = true; - }); - - const bridge = await startBrowserBridgeServer({ - resolved: { - enabled: true, - controlPort: 0, - cdpProtocol: "http", - cdpHost: "127.0.0.1", - cdpIsLoopback: true, - color: "#FF4500", - headless: true, - noSandbox: false, - attachOnly: true, - defaultProfile: "openclaw", - profiles: { - openclaw: { cdpPort: testPort + 1, color: "#FF4500" }, - }, - }, - onEnsureAttachTarget: ensured, - }); - - const bridgeStarted = (await realFetch(`${bridge.baseUrl}/start`, { - method: "POST", - }).then((r) => r.json())) as { ok?: boolean; error?: string }; - expect(bridgeStarted.error).toBeUndefined(); - expect(bridgeStarted.ok).toBe(true); - const status = (await realFetch(`${bridge.baseUrl}/`).then((r) => r.json())) as { - running?: boolean; - }; - expect(status.running).toBe(true); - expect(ensured).toHaveBeenCalledTimes(1); - - await new Promise((resolve) => bridge.server.close(() => resolve())); }); }); diff --git a/src/canvas-host/server.ts b/src/canvas-host/server.ts index 65b0b83a4c..3dfc83af41 100644 --- a/src/canvas-host/server.ts +++ b/src/canvas-host/server.ts @@ -264,6 +264,10 @@ export async function createCanvasHostHandler( const rootReal = await prepareCanvasRoot(rootDir); const liveReload = opts.liveReload !== false; + const testMode = opts.allowInTests === true; + const reloadDebounceMs = testMode ? 12 : 75; + const writeStabilityThresholdMs = testMode ? 12 : 75; + const writePollIntervalMs = testMode ? 5 : 10; const wss = liveReload ? new WebSocketServer({ noServer: true }) : null; const sockets = new Set(); if (wss) { @@ -293,7 +297,7 @@ export async function createCanvasHostHandler( debounce = setTimeout(() => { debounce = null; broadcastReload(); - }, 75); + }, reloadDebounceMs); debounce.unref?.(); }; @@ -301,8 +305,11 @@ export async function createCanvasHostHandler( const watcher = liveReload ? chokidar.watch(rootReal, { ignoreInitial: true, - awaitWriteFinish: { stabilityThreshold: 75, pollInterval: 10 }, - usePolling: opts.allowInTests === true, + awaitWriteFinish: { + stabilityThreshold: writeStabilityThresholdMs, + pollInterval: writePollIntervalMs, + }, + usePolling: testMode, ignored: [ /(^|[\\/])\../, // dotfiles /(^|[\\/])node_modules([\\/]|$)/,