Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -1430,3 +1430,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.
29 changes: 23 additions & 6 deletions tests/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down
Loading