Skip to main content

Waits & Synchronization

Modern web apps load content asynchronously. If Selenium tries to click an element before it exists, the test fails with NoSuchElementException. Waits tell Selenium to pause until a condition is met.

The Problem

driver.get("https://app.example.com/dashboard")
#  fails if the table hasn't loaded yet
rows = driver.find_elements(By.CSS_SELECTOR, "table tbody tr")

Implicit Wait

driver.implicitly_wait(10)   # seconds  set once per session

Tells Selenium to poll the DOM for up to 10 seconds before raising NoSuchElementException. Simple, but applies globally to every find_element call — which can mask real bugs.

Explicit Wait (Preferred)

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, timeout=10)

# Wait until element is visible
el = wait.until(EC.visibility_of_element_located((By.ID, "results")))

# Wait until element is clickable
btn = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".submit-btn")))
btn.click()

# Wait for text to appear
wait.until(EC.text_to_be_present_in_element((By.ID, "status"), "Done"))

# Wait for URL to change
wait.until(EC.url_contains("/dashboard"))

Explicit waits target a specific element for a specific condition — much more precise.

Common Expected Conditions

ConditionUse when
visibility_of_element_locatedElement must be visible
element_to_be_clickableElement must be enabled and visible
presence_of_element_locatedElement in DOM (may be hidden)
text_to_be_present_in_elementText appears inside element
url_containsURL changes after navigation
staleness_ofOld element is replaced by a new one

Wait Timing Visualiser

Async page load simulation
Ctrl+Enter
HTML
CSS
JS
Preview

Fluent Wait (Advanced)

from selenium.webdriver.support.ui import WebDriverWait

wait = WebDriverWait(
    driver,
    timeout=15,
    poll_frequency=0.5,                    # check every 500ms
    ignored_exceptions=[StaleElementReferenceException],
)
el = wait.until(EC.visibility_of_element_located((By.ID, "content")))

Use fluent wait when elements are expected to go stale (e.g., after a partial page re-render).