From 061d2698f5a67d56dfdfae1efa9b493a86ee46e1 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Mon, 5 Oct 2026 04:46:15 +0100 Subject: [PATCH] test(ui): lift the CCTV window from where the pointer grabbed it The panel gate read the docked box after a fixed 600 ms sleep and expected the lifted window 100 px above it. On the Linux CI runner the rail was still moving and the panel sat 8 px lower when the drag began, so the gate failed ("lifted top: expected 156.5, got 164.8") although the window followed the pointer exactly. Wait for the box to hold still for ten frames, record it at pointerdown, and compare the lifted window against that. Co-Authored-By: Claude Opus 5.5 --- scripts/qa-panel-resize.mjs | 52 +++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/scripts/qa-panel-resize.mjs b/scripts/qa-panel-resize.mjs index 572773aaa..d3cb7af7f 100644 --- a/scripts/qa-panel-resize.mjs +++ b/scripts/qa-panel-resize.mjs @@ -131,6 +131,22 @@ async function main() { stored: localStorage.getItem(`godsEyeView.v8.panelPos.${id}`), }; }, PANEL_ID); + /** Wait until the CCTV box has held still for ten animation frames. */ + const settle = () => + page.waitForFunction( + (id) => { + const r = document.getElementById(id).getBoundingClientRect(); + const box = `${r.left},${r.top},${r.width},${r.height}`; + if (window.__qaLastBox === box) window.__qaStill += 1; + else { + window.__qaLastBox = box; + window.__qaStill = 0; + } + return window.__qaStill >= 10; + }, + { polling: 'raf', timeout: 15_000 }, + PANEL_ID, + ); const headerPoint = async () => { const rect = await page.evaluate((id) => { const title = document.querySelector( @@ -170,23 +186,49 @@ async function main() { {}, PANEL_ID, ); - await new Promise((resolve) => setTimeout(resolve, 600)); + // The rail animates panel heights, and on a slow software renderer the + // panels above CCTV can still be moving after a fixed sleep. + await settle(); const docked = await readPanel(); assert.equal(docked.floating, false); assert.equal(docked.inRail, true); - // Lift out: drag the header 200px left and 100px up. + // Lift out: drag the header 200px left and 100px up. The window must lift + // from wherever the panel sits when the pointer goes down, so record that + // box in the page instead of trusting the earlier read. + await page.evaluate((id) => { + window.addEventListener( + 'pointerdown', + () => { + const r = document.getElementById(id).getBoundingClientRect(); + window.__qaPressBox = { left: r.left, top: r.top, width: r.width }; + }, + { capture: true, once: true }, + ); + }, PANEL_ID); await drag(await headerPoint(), -200, -100); const lifted = await readPanel(); + const pressed = await page.evaluate(() => window.__qaPressBox); assert.equal(lifted.floating, true, 'a header drag lifts the panel out'); assert.equal( lifted.collapsed, false, 'the drag-ending click must not collapse', ); - near(lifted.left, Math.max(6, docked.left - 200), 2, 'lifted left'); - near(lifted.top, Math.max(6, docked.top - 100), 2, 'lifted top'); - near(lifted.width, docked.width, 2, 'lifted width'); + const moved = `docked at ${docked.left},${docked.top}; pressed at ${pressed.left},${pressed.top}`; + near( + lifted.left, + Math.max(6, pressed.left - 200), + 2, + `lifted left (${moved})`, + ); + near( + lifted.top, + Math.max(6, pressed.top - 100), + 2, + `lifted top (${moved})`, + ); + near(lifted.width, pressed.width, 2, 'lifted width'); await new Promise((resolve) => setTimeout(resolve, 700)); const afterLayout = await readPanel(); assert.equal(afterLayout.allocated, '', 'the rail no longer allocates it');