A button click can start a request, replace part of the DOM, and update a result several moments later. A fixed sleep guesses how long that sequence will take. It slows fast runs and still loses the race on a busy CI worker.
Start with the condition the test actually needs
Selenium explicit waits can evaluate built-in or custom conditions. They are not limited to checking one element. The important question is whether the chosen condition establishes the precondition for the next action.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def wait_for_orders(driver):
WebDriverWait(driver, 15).until(
EC.text_to_be_present_in_element((By.ID, 'orders-status'), 'Loaded')
)
return driver.find_elements(By.CSS_SELECTOR, '[data-testid="order-row"]')The application’s “Loaded” signal must have a defined meaning. A visible spinner disappearing may be a weaker check than the expected result arriving. Avoid mixing implicit and explicit waits because the combined timeout behavior is harder to reason about.
Where page-level stabilization helps
Waitless wraps supported driver calls and common element actions. Before interaction, it polls configured DOM, network, animation, and layout signals. It can reduce repetitive wait code when the page is still changing, while your test keeps responsibility for business assertions.
from selenium import webdriver
from waitless import stabilize
driver = stabilize(webdriver.Chrome())
try:
driver.get('https://test.example.com/orders')
rows = wait_for_orders(driver)
assert len(rows) == 3 # Expected count in this controlled fixture
finally:
driver.quit()Stability is a threshold, not a promise
Normal mode waits for DOM and network thresholds; strict mode also requires animation and layout checks, while relaxed mode uses DOM activity. Default network settings allow some requests to remain pending. Instrumentation is validated on waits and navigation, rather than continuously proving the application is ready.
Debug other causes of flakiness separately
Retries can collect evidence about intermittent behavior, but a passing retry should remain visible. Retrying a purchase or submission is different from retrying a read. Do not add whole-test retries as a substitute for finding the cause.
Adopt incrementally
- Select a small set of timing-related failures with reproducible fixtures.
- Compare explicit outcome waits with and without stabilization.
- Keep application assertions and failure artifacts.
- Measure first-attempt success separately from eventual success.
- Review wrapper compatibility before applying it across the suite.
See the 1.0.3 release review for optional signals, diagnostics, and current limitations.

