mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
test(street-level): fail only unexplained panel-press misses in CI
CI onfb024d5failed step 24 with QA_FAIL_ON_RETRY=1: the press after a double-click dock landed on the globe because the panel, showing a photo that was still settling, moved 116 px up and lost 46 px of height between the pre-press hit check and the press (box 1058,382 330x471 -> 1058,266 330x425, from the new diagnostics and the uploaded screenshot). That is the panel's own content changing its layout, not the rail race fixed in9dde7b4. - Fail-on-retry now fails a miss only when the panel's box was the same at the hit check and at the press (the pointer missed a header that stood still); a miss the panel moving explains is retried with a ::warning:: naming the move. New harness test with a moving panel. - Step 24 waits for the open photo and its sequence to finish loading before pressing the header again. Verified: strict fixture gate on a production build 28 ok + 2 "no Google 3D" skips and the panel gate 6/6, both with QA_FAIL_ON_RETRY=1. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
fb024d582b
commit
db79027998
4 files changed
+49
-6
No files matched your search
@@ -73,8 +73,9 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
GEV_REQUIRE_ALLOCATION_GATE: '0'
|
||||
# A header press that misses is a real layout shift under the pointer
|
||||
# (the right rail now aligns to where the left rail settles), not noise.
|
||||
# A header press that misses while the panel stood still is a failure
|
||||
# (the right rail now aligns to where the left rail settles); a miss the
|
||||
# panel's own layout change explains is retried with a ::warning::.
|
||||
QA_FAIL_ON_RETRY: '1'
|
||||
steps:
|
||||
- name: Check out source
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
* Every retry is logged with what led to it (the pre-press hit check, the
|
||||
* stillness wait, the panel box at the hit check and at the press) and as a
|
||||
* GitHub `::warning::`. With QA_FAIL_ON_RETRY=1 (or `--fail-on-retry`) a
|
||||
* retry fails the run instead.
|
||||
* miss the panel's own movement cannot explain fails the run instead: if its
|
||||
* box was the same at the hit check and at the press, the pointer missed a
|
||||
* header that stood still. A panel whose content changed its layout between
|
||||
* the two (a photo finishing loading, a live count wrapping a line) is
|
||||
* retried with a warning that names the move.
|
||||
*/
|
||||
|
||||
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
@@ -41,6 +45,14 @@ export function pressMissed(attempt) {
|
||||
}
|
||||
|
||||
/** The panel's box, rounded, as `left,top widthxheight`. */
|
||||
/** Whether the panel's box changed (by more than 2 px) between two reads. */
|
||||
export function panelMoved(before, after) {
|
||||
if (!before || !after) return false;
|
||||
return ['left', 'top', 'width', 'height'].some(
|
||||
(key) => Math.abs((after[key] ?? NaN) - (before[key] ?? NaN)) > 2,
|
||||
);
|
||||
}
|
||||
|
||||
export function formatBox(box) {
|
||||
if (!box) return 'unknown';
|
||||
const r = (value) => Math.round(value ?? NaN);
|
||||
@@ -268,7 +280,7 @@ async function pressUntilDecided(
|
||||
retries,
|
||||
extra: note ? await note() : '',
|
||||
});
|
||||
if (failOnRetry)
|
||||
if (failOnRetry && !panelMoved(box, attempt.pressed))
|
||||
throw new Error(
|
||||
`QA_FAIL_ON_RETRY=1 turns this retry into a failure: ${why}`,
|
||||
);
|
||||
|
||||
@@ -1660,6 +1660,9 @@ async function main() {
|
||||
await step(
|
||||
'collapsing a floating window docks it as the rail strip',
|
||||
async () => {
|
||||
// The double-click just docked a panel showing a photo: let the photo
|
||||
// and its sequence finish loading before pressing the header again.
|
||||
await uiUntil((u) => !u.street.loading && !u.sequence.loading);
|
||||
await floatPanel();
|
||||
await page.click(
|
||||
'.panel-collapse-btn[data-collapse-target="street-level-panel"]',
|
||||
|
||||
@@ -134,7 +134,7 @@ test('the gate requires the server’s real Mapillary status route', async () =>
|
||||
* panel and a header double-click docks it, unless `stuck`.
|
||||
*/
|
||||
function fakePanelPage({ presses = [], floating = false, stuck = false } = {}) {
|
||||
const state = { floating, downs: 0, last: null, dragging: false };
|
||||
const state = { floating, downs: 0, last: null, dragging: false, shift: 0 };
|
||||
const listeners = [];
|
||||
const node = (tagName, id, classes, inHeader) => ({
|
||||
tagName,
|
||||
@@ -154,7 +154,7 @@ function fakePanelPage({ presses = [], floating = false, stuck = false } = {}) {
|
||||
const document = {
|
||||
querySelector: () => ({ getBoundingClientRect: rect(120, 210, 100, 20) }),
|
||||
getElementById: () => ({
|
||||
getBoundingClientRect: rect(100, 200, 300, 400),
|
||||
getBoundingClientRect: () => rect(100, 200 + state.shift, 300, 400)(),
|
||||
classList: {
|
||||
contains: (name) => name === 'panel-floating' && state.floating,
|
||||
},
|
||||
@@ -180,7 +180,10 @@ function fakePanelPage({ presses = [], floating = false, stuck = false } = {}) {
|
||||
// 'none': the pointerdown never reaches the page.
|
||||
if (state.last === 'none') return;
|
||||
const target = state.last === 'header' ? header : other;
|
||||
// 'moved': the panel's layout shifted just before the press landed.
|
||||
if (state.last === 'moved') state.shift = -116;
|
||||
for (const listener of listeners.splice(0)) inPage(listener, { target });
|
||||
state.shift = 0;
|
||||
};
|
||||
return {
|
||||
state,
|
||||
@@ -563,6 +566,30 @@ test('QA_FAIL_ON_RETRY turns a retry into a failure that says why', async () =>
|
||||
assert.equal(page.state.downs, 1);
|
||||
});
|
||||
|
||||
test('QA_FAIL_ON_RETRY retries, with a warning, a miss the panel moving explains', async () => {
|
||||
const { liftPanelByHeader, panelMoved } =
|
||||
await import('../../scripts/qa-panelDrag.mjs');
|
||||
assert.equal(panelMoved({ left: 0, top: 382 }, { left: 0, top: 266 }), true);
|
||||
assert.equal(panelMoved({ left: 0, top: 382 }, { left: 1, top: 383 }), false);
|
||||
const page = fakePanelPage({ presses: ['moved', 'header'] });
|
||||
const lines = [];
|
||||
const attempt = await liftPanelByHeader(page, 'street-level-panel', {
|
||||
dx: -400,
|
||||
dy: 80,
|
||||
log: (line) => lines.push(line),
|
||||
pauseMs: 0,
|
||||
failOnRetry: true,
|
||||
});
|
||||
assert.equal(attempt.done, true, 'the second press lifted it');
|
||||
assert.equal(page.state.downs, 2);
|
||||
assert.ok(
|
||||
lines.some((line) =>
|
||||
/::warning title=Panel press retried::.*-> at press 100,84/.test(line),
|
||||
),
|
||||
lines.join('\n'),
|
||||
);
|
||||
});
|
||||
|
||||
test('both gates save failure evidence and fail on render-loop errors', () => {
|
||||
for (const script of ['qa-street-level.mjs', 'qa-panel-resize.mjs']) {
|
||||
const source = fs.readFileSync(
|
||||
|
||||
Reference in new issue
Block a user