Class: Capybara::Simulated::Browser

Inherits:
Object
  • Object
show all
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_active is true but @runtime.settle_gen hasn't bumped in this many consecutive polls, treat the page as observably idle and let Capybara's per-find timer give up. See polling? 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_text shifted 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=0 misconfig 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_step truncates). When a poll advances the clock while the page has work runnable NOW (a rAF chain or a timer burst), tick_real_time runs the advance in chunks this size so the page's rendering runs at real-browser cadence (one render phase per frame), not one POLL_TICK_STEP_MS super-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. =0 disables 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_step task cap (its maxIter). 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