perf(test): trim browser smoke and speed canvas test reload

This commit is contained in:
Peter Steinberger
2026-02-14 01:47:47 +00:00
parent db8cabedde
commit c4f550ef2a
2 changed files with 34 additions and 118 deletions

View File

@@ -275,7 +275,7 @@ describe("browser control server", () => {
await stopBrowserControlServer(); 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 { startBrowserControlServerFromConfig } = await import("./server.js");
const started = await startBrowserControlServerFromConfig(); const started = await startBrowserControlServerFromConfig();
expect(started?.port).toBe(testPort); expect(started?.port).toBe(testPort);
@@ -356,78 +356,32 @@ describe("browser control server", () => {
}); });
expect(focusMissing.status).toBe(404); expect(focusMissing.status).toBe(404);
const [ const [navMissing, clickMissingRef, scrollSelectorUnsupported, dialogMissingAccept] =
navMissing, await Promise.all([
actMissing, realFetch(`${base}/navigate`, {
clickMissingRef, method: "POST",
scrollMissingRef, headers: { "Content-Type": "application/json" },
scrollSelectorUnsupported, body: JSON.stringify({}),
clickBadButton, }),
clickBadModifiers, realFetch(`${base}/act`, {
typeBadText, method: "POST",
uploadMissingPaths, headers: { "Content-Type": "application/json" },
dialogMissingAccept, body: JSON.stringify({ kind: "click" }),
] = await Promise.all([ }),
realFetch(`${base}/navigate`, { realFetch(`${base}/act`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({}), body: JSON.stringify({ kind: "scrollIntoView", selector: "button.save" }),
}), }),
realFetch(`${base}/act`, { realFetch(`${base}/hooks/dialog`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({}), 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({}),
}),
]);
expect(navMissing.status).toBe(400); expect(navMissing.status).toBe(400);
expect(actMissing.status).toBe(400);
expect(clickMissingRef.status).toBe(400); expect(clickMissingRef.status).toBe(400);
expect(scrollMissingRef.status).toBe(400);
expect(scrollSelectorUnsupported.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); expect(dialogMissingAccept.status).toBe(400);
const snapDefault = (await realFetch(`${base}/snapshot?format=wat`).then((r) => r.json())) as { const snapDefault = (await realFetch(`${base}/snapshot?format=wat`).then((r) => r.json())) as {
@@ -499,50 +453,5 @@ describe("browser control server", () => {
body: JSON.stringify({}), body: JSON.stringify({}),
}); });
expect(missing.status).toBe(400); 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<void>((resolve) => bridge.server.close(() => resolve()));
}); });
}); });

View File

@@ -264,6 +264,10 @@ export async function createCanvasHostHandler(
const rootReal = await prepareCanvasRoot(rootDir); const rootReal = await prepareCanvasRoot(rootDir);
const liveReload = opts.liveReload !== false; 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 wss = liveReload ? new WebSocketServer({ noServer: true }) : null;
const sockets = new Set<WebSocket>(); const sockets = new Set<WebSocket>();
if (wss) { if (wss) {
@@ -293,7 +297,7 @@ export async function createCanvasHostHandler(
debounce = setTimeout(() => { debounce = setTimeout(() => {
debounce = null; debounce = null;
broadcastReload(); broadcastReload();
}, 75); }, reloadDebounceMs);
debounce.unref?.(); debounce.unref?.();
}; };
@@ -301,8 +305,11 @@ export async function createCanvasHostHandler(
const watcher = liveReload const watcher = liveReload
? chokidar.watch(rootReal, { ? chokidar.watch(rootReal, {
ignoreInitial: true, ignoreInitial: true,
awaitWriteFinish: { stabilityThreshold: 75, pollInterval: 10 }, awaitWriteFinish: {
usePolling: opts.allowInTests === true, stabilityThreshold: writeStabilityThresholdMs,
pollInterval: writePollIntervalMs,
},
usePolling: testMode,
ignored: [ ignored: [
/(^|[\\/])\../, // dotfiles /(^|[\\/])\../, // dotfiles
/(^|[\\/])node_modules([\\/]|$)/, /(^|[\\/])node_modules([\\/]|$)/,