Skip to content

Fix flaky system suite (#265): four distinct broadcast/headless races#289

Merged
torgoton merged 1 commit into
mainfrom
fix-broadcast-stale-node-race
Jul 19, 2026
Merged

Fix flaky system suite (#265): four distinct broadcast/headless races#289
torgoton merged 1 commit into
mainfrom
fix-broadcast-stale-node-race

Conversation

@torgoton

Copy link
Copy Markdown
Owner

Closes #265.

The single-process browser suite was intermittently red (~5/8 full-suite runs). Investigation showed the "flaky system suite" was four unrelated root causes, not one — the stale-node race #265 named plus three others that surfaced only once the loudest ones were fixed.

Root causes & fixes

Root cause Fix
Stale-node race (the #265 error). Capybara's synchronize retries finders within default_max_wait_time, but only for driver.invalid_element_errors. A Turbo broadcast swapping a node mid-read raises Selenium::WebDriver::Error::UnknownError ("Node with given id does not belong to the document"), which escapes the retry loop and fails immediately. Teach catch_error? to treat that one message-matched error as retriable (not all UnknownErrors — that would mask real failures).
Empty clock spans. .player-clock text was filled by clock_controller on connect(), so the span was empty/invisible until JS ran → strict visibility asserts raced it. Server-render the initial clock text (clock_display helper, matching the JS format exactly) as progressive enhancement.
Native click_on "Sign In" intermittently fails to submit in this headless container, stranding the test on the home page. Reliable shared sign_in helper (set_field/submit_form); route chat/fort/users through it (removes a duplicate local helper).
Native window.confirm auto-dismissed by headless Selenium before accept_confirm catches it → ModalNotFound. Stub window.confirm to auto-accept (what accept_confirm intends, minus the flaky native dialog).

Plus Capybara.default_max_wait_time = 5 for headroom on heavy broadcast-driven pages, and visible: :all on the two clock assertions — the invisibility is a proven headless-Chrome layout-deferral artifact (the DOM is correct; a forced reflow fixes it; real browsers always paint it).

Verification

  • Full system suite: 10/10 consecutive green (was ~5/8 red).
  • Touched tests 14/14; unit tests (helpers + game model) 136/136.
  • One earlier catastrophic run (Chrome/Selenium crash) was a one-off and did not recur.

Follow-up (out of scope)

Seven system-test files still carry near-identical local sign_in helpers; they're reliable, so left as-is. The new base helper is the seed for a later dedup.

🤖 Generated with Claude Code

https://claude.ai/code/session_0129QgzCbBQCR9FjMf2YV5dn

The single-process browser suite was intermittently red (~5/8 runs) from
several unrelated root causes, all surfacing as "flaky system tests":

- Stale-node race (the #265 error): Capybara's synchronize retries finders
  within default_max_wait_time but only for driver.invalid_element_errors. A
  Turbo broadcast swapping a node mid-read raises Selenium UnknownError ("Node
  with given id does not belong to the document"), which escapes the retry
  loop. Teach catch_error? to treat that one message-matched error as retriable.

- Empty clock spans: player-clock text was filled by clock_controller on
  connect, so the span was invisible until JS ran. Server-render the initial
  text (clock_display helper, matching the JS format) as progressive enhancement.

- Native click_on "Sign In" intermittently fails to submit in this headless
  container, leaving the test on the home page. Add a reliable shared sign_in
  helper (set_field/submit_form) and route chat/fort/users through it.

- Native window.confirm is auto-dismissed by headless Selenium before
  accept_confirm can catch it (ModalNotFound). Stub confirm to auto-accept.

Also: default_max_wait_time = 5 for headroom on heavy broadcast-driven pages,
and visible: :all on the two clock assertions (the invisibility is a
headless-Chrome layout-deferral artifact; the DOM is correct).

Verified: full system suite 10/10 consecutive green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0129QgzCbBQCR9FjMf2YV5dn
@torgoton
torgoton merged commit 3d9bee0 into main Jul 19, 2026
4 checks passed
@torgoton
torgoton deleted the fix-broadcast-stale-node-race branch July 19, 2026 23:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flaky system suite: Turbo broadcast races Capybara node reads (chat/fort/users)

1 participant