Class: Capybara::Simulated::Browser
- Inherits:
-
Object
- Object
- Capybara::Simulated::Browser
- Includes:
- RecordedActions
- Defined in:
- lib/capybara/simulated/browser.rb
Defined Under Namespace
Modules: RecordedActions
Constant Summary collapse
- POLLING_GRACE_POLLS =
Sticky window after timers finish: keep polling? true so a setTimeout firing mid-loop doesn't drop Capybara's synchronize before its own default_max_wait_time kicks in. Counted in poll calls (not wall time) for determinism under GC/load pressure. 1000 polls × Capybara's default 0.01 s retry_interval ≈ 10 s.
1000- IDLE_SETTLE_POLLS =
When
@timers_activeis true but@runtime.settle_genhasn't bumped in this many consecutive polls, treat the page as observably idle and let Capybara's per-find timer give up. Seepolling?for the full rationale. 300 polls ≈ 3 s at Capybara's default 10 ms retry interval — long enough to ride through brief async idle windows during Discourse's ProseMirror editor boot (which sometimes pauses ~1 s mid-load while a webpack chunk + Glimmer reconcile complete) while still cutting the full 4 s wait on tests destined to fail. 300- POST_NAV_POLL_GRACE_POLLS =
Brief window after a Ruby-side navigate (context rebuild) so Capybara's outer synchronize gets one retry against the new context.
10- POLL_TICK_STEP_MS =
Deterministic virtual-clock model (replaces the old wall-sync, where each tick advanced by REAL wall-elapsed and so coupled virtual time to JS/Ruby/GC speed — a faster
visible_textshifted WHEN debounces fired, e.g. Avo actions_spec:464). Now each poll advances by a FIXED step; near-future timers on an otherwise-idle page are fast-forwarded to (horizon-gated).100 ms is empirically the floor that lets a "commit debounce scheduled between two user actions" fire before the next action (Avo actions_spec:464's ~50-75 ms field-commit flips at step 10/50, fixed at >=75). Group-A transient-catch observability does NOT depend on this step — it comes from the
timer_wait_elapsed?FREQUENCY gate (the first find after an action doesn't tick, so the pre-debounce state is observed regardless of step size), so a larger step completes Group-B without losing Group-A (verified green at 100 across gem 1579, WPT 660, Forem, Avo, :464 passing). Clamped=1 so a
CSIM_POLL_TICK_STEP_MS=0misconfig can't freeze the fixed-step path. [(ENV['CSIM_POLL_TICK_STEP_MS'] || '100').to_i, 1].max
- FRAME_STEP_MS =
One animation frame (~60 Hz, whole ms —
run_loop_steptruncates). When a poll advances the clock while the page has work runnable NOW (a rAF chain or a timer burst),tick_real_timeruns the advance in chunks this size so the page's rendering runs at real-browser cadence (one render phase per frame), not onePOLL_TICK_STEP_MSsuper-frame — the same model the WPT drain uses. 16- RUN_LOOP_MAX_ITER =
Per-poll task-iteration cap, mirroring
RuntimeShared#run_loop_step's own default — shared across the frame chunks of one poll so sub-stepping keeps the same per-poll ceiling the single-step path had. 10_000- FF_HORIZON_MS =
Horizon-gated fast-forward: when the page is observably idle (no timer due now, no background IO) but a timer is parked within this horizon, jump the virtual clock straight to it instead of waiting ~delay/step polls. A timer farther out (ahoy 1000 ms, session-timeout, analytics) is LEFT parked. 600 clears every legit must-fire wait (Backburner/DTextField 500, refetch/chart <=200, image-grid 64) while staying BELOW ahoy's 1000.
=0disables FF → pure deterministic fixed-step (the fallback model). (ENV['CSIM_FF_HORIZON_MS'] || '600').to_i
- FF_TRANSIENT_GUARD_POLLS =
Transient guard: hold the page pre-debounce for this many consecutive idle polls before allowing a fast-forward, so "catch the DOM before the 200 ms debounce fires" tests (Discourse refetchForSearch / doubled-filter, Avo filters) still observe the intermediate state across several polls.
(ENV['CSIM_FF_TRANSIENT_GUARD_POLLS'] || '6').to_i
- SETTLE_DRAIN_MS =
32- SETTLE_MAX_ITER =
10- SETTLE_MAX_ITER_TASKS =
Per-
run_loop_steptask cap (itsmaxIter). Bounds a self-rescheduling timer/microtask storm so one settle iter returns to Ruby; large enough for the heaviest legit chain (Mastodon hydrate, Turbo stream batch). 256- BOOT_SCRIPT_DRAIN_MAX_ITER =
Backstop for the post-boot deferred-external-script drain: a dynamically inserted external