From c5366e9fdd1c28e7aae61d416848863853deeb24 Mon Sep 17 00:00:00 2001 From: theBlanketBaron Date: Sat, 14 Nov 2026 06:40:02 -0500 Subject: [PATCH] RAL-182: the state-bar redraw test waits on what it reads, not on fixed times From the watchman: a_redraw_moves_the_state_bar_with_the_counts failed once under load. Its probe went on without the board after 10 s, read widths after a fixed 1 s while a 0.6 s transition could still be running on a starved timeline, and could be redrawn by the page's own 30 s poll. It now waits for the first draw (20 s, said if missing), for the bar's transitions to finish, and draws again after a poll. With the style update removed it still fails. Co-Authored-By: Claude Opus 5.5 --- docs/roadmap.md | 7 +++++++ tests/web.rs | 29 +++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index 101fa59..8ad242d 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1416,3 +1416,10 @@ principles named were durable, accurate and reactive. Found in rally 0x7 by plus run alongside; observed only, never changing the result; the browser tests carry those lines to their own standard error, so ci-local's log has them; with tests for a segfault retried, a second failing, and a teardown crash with a stand-in coredumpctl. +- [ ] **RAL-182: The state-bar redraw test waits on what it reads, not on fixed times.** From the watchman + (2026-11-14): `a_redraw_moves_the_state_bar_with_the_counts` failed once under full-suite load for jaunty-harrier + (at `in_browser`'s check that the script ended well; its output wasn't kept, and no Chrome core was dumped + then). Done when: the probe waits for the board's first draw and says so if there's none in 20 s, rather than + going on after 10 s without it; reads the widths once the bar's transitions have finished (`getAnimations`), + not after a fixed 1 s, which could read a width mid-transition when frames are starved; and draws its status + again if the page's own 30 s poll redrew the bar in between; and it still fails with the style update removed. diff --git a/tests/web.rs b/tests/web.rs index af1c923..aa05bb3 100644 --- a/tests/web.rs +++ b/tests/web.rs @@ -2436,24 +2436,41 @@ fn a_redraw_moves_the_state_bar_with_the_counts() { write(&["ready", "RAL-2"]); write(&["claim", "RAL-2", "--team", "rally"]); }); + // RAL-182: the probe waits on what it reads, never on a fixed time. It waits for the board's + // first draw and says so if there's none; it reads the widths once the bar's transitions have + // finished, however slowly a loaded machine runs them (a fixed 1 s read a width mid-transition + // when frames were starved); and if the page's own 30 s poll redrew the bar in between, with + // the service's status rather than this one, it draws this one again. let probe = r##"(async () => { - for (let i = 0; i < 100 && !document.querySelector("#ledger .bar.tall"); i++) { + const until = Date.now() + 20000; + const bar = () => document.querySelector("#ledger .bar.tall"); + while (!(lastStatus && bar()) && Date.now() < until) { await new Promise((r) => setTimeout(r, 100)); } - const drawn = () => Object.fromEntries([...document.querySelectorAll("#ledger .bar.tall > div")] + if (!(lastStatus && bar())) return { error: "the board drew no state bar within 20 s" }; + const settled = () => + Promise.all(bar().getAnimations({ subtree: true }).map((a) => a.finished.catch(() => {}))); + const drawn = () => Object.fromEntries([...bar().querySelectorAll(":scope > div")] .map((part) => [part.className, getComputedStyle(part).flexGrow])); + await settled(); const before = drawn(); // One more ready story, as the next poll would bring. const status = structuredClone(lastStatus); status.ledger.stories["RAL-3"] = { ...status.ledger.stories["RAL-1"] }; if (status.rally && status.rally.board) status.rally.board.stories.push("RAL-3"); - show(status, Date.now()); - // The bar's segments ease to their new widths (.bar > div's 0.6 s transition). - await new Promise((r) => setTimeout(r, 1000)); - return { before, after: drawn() }; + let redrawnByPoll = 0; + for (;;) { + const polled = lastStatus; + show(status, Date.now()); + await settled(); + if (lastStatus === polled || redrawnByPoll === 3) break; + redrawnByPoll += 1; + } + return { before, after: drawn(), redrawnByPoll }; })()"##; let seen = in_browser(&viewer, &chrome, Some(probe)); let probe = &seen["probe"]; + assert!(probe["error"].is_null(), "{seen}"); assert_eq!(probe["before"]["s-ready"], "1", "{seen}"); assert_eq!(probe["before"]["s-claimed"], "1", "{seen}"); assert_eq!(