From b0ee0fe7ce6664b4e28ee8cde5a196b1d050455f Mon Sep 17 00:00:00 2001 From: liugddx Date: Fri, 9 Oct 2026 08:41:17 +0800 Subject: [PATCH] test(desktop): wait for a painted frame before the native smoke's CDP click After Main closes, the WorkHub native browser smoke reparents the live view into the floating window, navigates it, and immediately dispatches one CDP mouse press/release. Under Xvfb the page may not have committed a frame (and hit-test data) in its new window yet, and Chromium drops input it cannot route, so the click was intermittently lost. Wait for load plus two requestAnimationFrame callbacks, capped at 2 s, before the single click, and log which path was taken. Still exactly one click and the same 3 s observation, so a genuinely lost event still fails. Refs #5995. Generated-by: Claude Code Co-Authored-By: Claude Opus 5.5 (1M context) --- .../scripts/workhub-browser-presentation-smoke.mjs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/desktop/scripts/workhub-browser-presentation-smoke.mjs b/apps/desktop/scripts/workhub-browser-presentation-smoke.mjs index db165ba226e..ebbbb9f18d0 100644 --- a/apps/desktop/scripts/workhub-browser-presentation-smoke.mjs +++ b/apps/desktop/scripts/workhub-browser-presentation-smoke.mjs @@ -181,6 +181,18 @@ async function run() { await closedMainLease.ready; await controller.navigate(`${url}/page?main-closed`); const page = ownerParent.children.find((child) => 'webContents' in child && child.webContents !== owner).webContents; + // The view was just reparented into the floating window and navigated. + // Under Xvfb it may not have committed a frame (and hit-test data) in its + // new window yet, and Chromium drops input it cannot route. Wait for the + // page to load and render two frames before the single click. The timer + // only bounds the wait; it never adds a second click. + const readiness = await page.executeJavaScript(`new Promise((resolve) => { + const done = (via) => resolve({ via, visibility: document.visibilityState }); + const frames = () => requestAnimationFrame(() => requestAnimationFrame(() => done('frames'))); + setTimeout(() => done('timeout'), 2000); + if (document.readyState === 'complete') frames(); else addEventListener('load', frames, { once: true }); + })`); + console.log(`Background page input readiness: ${readiness.via}, ${readiness.visibility}`); const point = await page.executeJavaScript(`(() => { const r = document.querySelector('button').getBoundingClientRect(); return {x:r.x+r.width/2,y:r.y+r.height/2}; })()`); await page.debugger.sendCommand('Input.dispatchMouseEvent', { type: 'mousePressed', ...point, button: 'left', buttons: 1, clickCount: 1 }); await page.debugger.sendCommand('Input.dispatchMouseEvent', { type: 'mouseReleased', ...point, button: 'left', buttons: 0, clickCount: 1 });