From d31b6f545fb584ffc1d72c8ba7a17cc9d6882b27 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Wed, 5 Aug 2026 07:10:57 +0200 Subject: [PATCH] [test](trx-frontend-http): watch the history progress from inside the page The replay-progress check polled the overlay from the test every 100ms. A replay that starts and finishes between two polls is never sampled, and the test then reports that no progress was shown at all -- the source of the intermittent "no progress was shown while the history loaded" failure. Record the samples from a MutationObserver installed before the page's own scripts run, so a fast replay is observed rather than missed. Signed-off-by: Stan Grams --- .../frontend/tests/decode-flow.mjs | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/frontend/tests/decode-flow.mjs b/src/trx-client/trx-frontend/trx-frontend-http/frontend/tests/decode-flow.mjs index 5d70a4ca..ae9ab891 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/frontend/tests/decode-flow.mjs +++ b/src/trx-client/trx-frontend/trx-frontend-http/frontend/tests/decode-flow.mjs @@ -11,7 +11,7 @@ import assert from "node:assert/strict"; import { chromium } from "playwright-core"; import { startBrowser, startWebFixture } from "./web-fixture.mjs"; -/* global document, getComputedStyle, window, location */ +/* global document, getComputedStyle, window, location, requestAnimationFrame, MutationObserver */ const VESSEL = { type: "ais", mmsi: 244660000, lat: 52.37, lon: 4.89, vessel_name: "NEDERLAND", @@ -121,6 +121,27 @@ const historyFixture = await startWebFixture({ }); const replay = await startBrowser(chromium); +// Installed before the page's own scripts, so nothing can be missed: every +// time the progress element becomes visible, its geometry is recorded. +await replay.page.addInitScript(() => { + window.__historyProgressSamples = []; + const watch = () => { + const element = document.getElementById("decode-history-overlay"); + if (!element) { requestAnimationFrame(watch); return; } + const sample = () => { + if (element.classList.contains("is-hidden")) return; + const rect = element.getBoundingClientRect(); + window.__historyProgressSamples.push({ + width: Math.round(rect.width), + coversCentre: document.elementFromPoint(700, 450)?.id === "decode-history-overlay", + }); + }; + new MutationObserver(sample).observe(element, { attributes: true, attributeFilter: ["class"] }); + sample(); + }; + watch(); +}); + try { await replay.page.setViewportSize({ width: 1400, height: 900 }); await replay.page.goto(`${historyFixture.origin}/digital-modes`, { waitUntil: "domcontentloaded" }); @@ -128,20 +149,11 @@ try { // While it loads, the operator can still see the radio. This used to be a // full-screen scrim over everything for as long as the replay ran. - const samples = []; - for (let attempt = 0; attempt < 30; attempt++) { - samples.push(await replay.page.evaluate(() => { - const element = document.getElementById("decode-history-overlay"); - if (!element || element.classList.contains("is-hidden")) return null; - const rect = element.getBoundingClientRect(); - return { - width: Math.round(rect.width), - coversCentre: document.elementFromPoint(700, 450)?.id === "decode-history-overlay", - }; - })); - await replay.page.waitForTimeout(100); - } - const shown = samples.filter(Boolean); + // + // Watched from inside the page rather than polled from here: a fast replay + // can start and finish between two polls, and then the test reports that no + // progress was ever shown when what happened is that it blinked. + const shown = await replay.page.evaluate(() => window.__historyProgressSamples ?? []); assert.ok(shown.length > 0, "no progress was shown while the history loaded"); for (const sample of shown) { assert.ok(sample.width < 700, `the progress covers ${sample.width}px of a 1400px page`);