Skip to content

Fix stale element and pending request waits (1.1.0) - #9

Merged
godhiraj-code merged 3 commits into
mainfrom
fix/stale-click-network-1.0.6
Oct 24, 2026
Merged

godhiraj-code merged 3 commits into
mainfrom
fix/stale-click-network-1.0.6

Conversation

@godhiraj-code

@godhiraj-code godhiraj-code commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

What this fixes

A local demo (one checkout flow, 50 seeded runs per version, headless Chrome 156, waitless 1.0.5) found two problems:

  1. Default config ignored a pending request. With the default network_idle_threshold=2, one in flight cart call counted as stable, so Checkout was clicked under a "Saving..." overlay. Default config passed 24/50; all 26 failures were ElementClickInterceptedException at the Checkout click.
  2. find_element could return an element from a list that was still being redrawn. With strictness="strict", network_idle_threshold=0, find_element returned the first button as soon as it appeared, then click() waited for the prices call that redraws the list, so the held element was stale. Strict passed 3/50; all 47 failures were StaleElementReferenceException at the Add to cart click.

On the same seeds: time.sleep(1) style 23/50, hand written WebDriverWait 50/50 (median 4.75 s).

Behavior changes (why this is 1.1.0, not a patch)

  • Default network_idle_threshold is now 0 (was 2), and StabilizationConfig.strict() sets 0 explicitly. All tracked XHR/fetch requests must finish before an interaction. relaxed() still uses 2.
  • click() waits for is_enabled(). A button that never becomes enabled now raises TimeoutException with the tag, text and timeout (for example Element <button> 'Click' was not enabled after 2.0s) instead of a silent no op click.
  • find_element() settles twice: settle, find, settle again, find again, and returns the fresh element.
  • One stale click retry for elements from find_element(): settle, look up again with the same locator, compare a fingerprint captured when the element was found, and click only if it matches. The fingerprint is tag, visible text, id, name, data-testid, aria-label, the element's index among the locator's matches, and its parent's visible text (element and parent text capped at 200 characters), read in one script call inside the timeout budget. Otherwise it raises StaleElementReferenceException saying it refused to click a different element. Elements from find_elements() or execute_script() do not retry.
  • Clearer errors: an element that disappears for good before the retry raises NoSuchElementException saying it is no longer on the page, and a failed find_element() keeps Selenium's original not found message.
  • One timeout budget per click() / find_element() call across stabilization, polling and retry waits.

Upgrade note

Apps with constant polling, analytics or long polling can set StabilizationConfig(network_idle_threshold=2) to get the 1.0.5 allowance back. Tests that click disabled elements on purpose will now wait for the timeout and raise. A stale retry now refuses (raises StaleElementReferenceException, as plain Selenium would) when the replacement's text or parent text changed, for example a row whose counter changed. The fingerprint still cannot tell apart elements that match on all of those fields, including parent text (for example identical Delete buttons in rows that differ only in hidden attributes).

Files

  • waitless/selenium_integration.py: shared deadline helpers, fresh lookup after settle, enabled wait, fingerprint guarded stale retry with a single script snapshot.
  • waitless/config.py: zero default and strict thresholds.
  • Tests: tests/integration/test_click_regressions.py (16 browser regressions), tests/unit/test_selenium_wrappers.py, tests/unit/test_config.py.
  • README (threshold, upgrade note, wrapped element behavior, overhead FAQ), CHANGELOG (1.1.0 Changed and Fixed), version 1.1.0 in pyproject.toml and waitless/__init__.py.

Not released, tagged or published.

@godhiraj-code godhiraj-code changed the title Fix stale element and pending request waits (1.0.6) Fix stale element and pending request waits (1.1.0) Oct 24, 2026
@godhiraj-code
godhiraj-code merged commit b9de2f2 into main Oct 24, 2026
8 checks passed
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.

1 participant