From 2333f66ba2a7f5498f3b159864290959bc5ed822 Mon Sep 17 00:00:00 2001 From: MelekTaus Date: Fri, 30 Oct 2026 13:05:46 +0100 Subject: [PATCH] Keep e2e 65 and 67 green in the full suite after #410 Suite 755 for b17a924 was red in three places. Both e2e 65 and e2e 67 were green on their own. Two of the new checks did not fit into the full run. The product is not at fault. - e2e 66 (66s): the per-frame pixel read never stopped. splice(0) emptied the array, so the length bound was never reached. Each pixelAt leaves the stage shifted to its pixel until the next drawing. The editor, idle after Stop, kept it at (-710, -376), so the Play click of e2e 67 hit no object. The loop now ends on a flag while the run still draws each frame. - e2e 65 (65k2, 65k3): the console panel keeps 500 lines and is never cleared in the suite. Lines of earlier steps pushed the first beats out, so the beats began at 1.3. The checks now read the harness's console log since Play, which has no limit. - 65k2 also writes panelBusiest, the three most frequent other lines in the panel. The next CI run names the module that logs that much. Tests (melektaus-atx): - e2e 66+67 before the fix: 67 breaks off as in CI. - e2e 66+67 with the fix: ALL PASSED, 52 checks. - e2e 65 under a flood of 100 lines/s: ALL PASSED, 76 checks. The old reading under the same flood shows the CI picture. - e2e 65+66+67: ALL PASSED, 126 checks (a first run had the known e2e 67 firstAt wobble, 0.1). Co-Authored-By: Claude Opus 5.5 --- tools/e2e/65-song.mjs | 19 ++++++++++++++----- tools/e2e/66-video.mjs | 9 ++++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/tools/e2e/65-song.mjs b/tools/e2e/65-song.mjs index 06af30c0..1733f128 100644 --- a/tools/e2e/65-song.mjs +++ b/tools/e2e/65-song.mjs @@ -1052,6 +1052,7 @@ export async function song(t) { }, }); const playbacks = () => json('__gm.sound.playbacks()'); + const heardFrom = t.consoleLog.length; await play(); const game = await waitFor(playbacks, (list) => list[0]?.planned.length >= 4, 60); const [run] = game; @@ -1102,10 +1103,18 @@ export async function song(t) { // at 120 BPM, bar 2 again after bar 2's last beat as the loop goes round; On song marker // runs each time round; the pause above held them with the clock. "late" is how long ago // the beat was heard, and Song position, read then, stands that far into the beat. - const heardLines = async () => - (await json('__gm.console.lines()')) - .map((line) => line.text) - .filter((text) => /(beat|marker) /.test(text)); + // Read from the page's console as the harness keeps it since Play, not from the panel: the + // panel keeps the last 500 lines, and in the full suite other lines pushed beats out of it. + const heard = (text) => /(beat|marker) /.test(text); + const heardLines = async () => t.consoleLog.slice(heardFrom).filter(heard); + // What else the panel was filled with, the three lines most often there: says in the output of + // the check which leftover of an earlier step logs that much. + const panelBusiest = async () => { + const counts = new Map(); + for (const { text } of await json('__gm.console.lines()')) + if (!heard(text)) counts.set(text.slice(0, 120), (counts.get(text.slice(0, 120)) ?? 0) + 1); + return [...counts].sort((a, b) => b[1] - a[1]).slice(0, 3); + }; const heardSome = await waitFor( heardLines, (lines) => lines.filter((l) => l.includes('marker Round')).length >= 2, @@ -1124,7 +1133,7 @@ export async function song(t) { counted.every((c, i) => c === expected[i]) && markersHeard.length >= 2 && beats.every((b) => b.late >= 0 && b.late <= 0.15 && Math.abs(b.fraction * 0.5 - b.late) < 0.02), - JSON.stringify({ beats, markersHeard: markersHeard.length }), + JSON.stringify({ beats, markersHeard: markersHeard.length, panelBusiest: await panelBusiest() }), ); // 65k3. Music follows the game (#338): W held over a beat asks Switch song for "Half", bar 2 beat 3, // on the next bar. The playing keeps its number on buses of its own, heard from that bar line diff --git a/tools/e2e/66-video.mjs b/tools/e2e/66-video.mjs index fdd223e1..602a4356 100644 --- a/tools/e2e/66-video.mjs +++ b/tools/e2e/66-video.mjs @@ -794,14 +794,21 @@ export async function video(t) { Math.abs(soughtPlayer.time - 0.5) < 0.05, JSON.stringify({ sought, soughtHeld, soughtPlayer }), ); + // The reads end while the run still draws each frame: a read leaves the stage shifted to its pixel + // until the next drawing, and the editor, idle after Stop, would keep it so under every later + // click (e2e 67's Play missed). await t.evaluate(`window.__vd66s = []; + window.__vd66sOn = true; (function read() { + if (!window.__vd66sOn) return; const r = __gm.gameRect('${STEERED}'); if (r) window.__vd66s.push(__gm.pixelAt(Math.round(r.x), Math.round(r.y))); - if (window.__vd66s.length < 150) requestAnimationFrame(read); + requestAnimationFrame(read); })();`); await press('g'); await sleep(2200); + await t.evaluate('window.__vd66sOn = false'); + await sleep(100); const playedFrames = await json('window.__vd66s.splice(0)'); const finished = t.consoleLog.slice(finishedFrom).filter((line) => line.includes('vd66 finished')); await stop();