Waits with Python in Selenium
Waits are one of the most important concepts in Selenium automation because modern web applications frequently load elements dynamically. An element may exist in the DOM but may not yet be visible, enabled, clickable, or ready for interaction when Selenium attempts to use it.
Selenium waits allow a Python automation script to synchronize browser actions with the actual state of the web application. Instead of assuming that an element will be immediately available, the script can wait until a required condition is satisfied.
In professional Selenium automation, waits help reduce timing-related failures, improve test stability, and make scripts more reliable when working with dynamic pages, AJAX requests, animations, delayed elements, frames, alerts, windows, and asynchronous application behavior.
Course Resource: Selenium Training | Register for Course Demo
1. What are Waits in Selenium?
A Selenium wait is a synchronization mechanism that instructs WebDriver to pause execution until a specified condition is satisfied or a timeout is reached.
Without proper synchronization, Selenium may attempt to interact with an element before the browser has finished rendering or updating the page.
Basic Example
from selenium.webdriver.support.ui import WebDriverWait
wait = WebDriverWait(driver, 10)
The above statement creates a wait that can wait for a condition for up to 10 seconds.
2. Why are Waits Important?
Web applications are rarely completely static. Pages can contain JavaScript, AJAX requests, animations, lazy-loaded components, asynchronous API calls, dynamic tables, popups, and elements that appear after user interaction.
- Synchronize automation with the application.
- Reduce timing-related failures.
- Handle dynamically loaded elements.
- Improve test stability.
- Reduce unnecessary fixed delays.
- Handle asynchronous browser operations.
- Wait for elements to become interactable.
- Improve reliability of regression tests.
- Make automation more maintainable.
3. Selenium Script Without Proper Wait
Consider a page where a login button appears two seconds after the page loads.
driver.get("https://example.com/login")
driver.find_element(
By.ID,
"login"
).click()
If the button is not ready when Selenium searches for it, the script can fail with an exception such as NoSuchElementException or another interaction-related exception.
4. Selenium Script with a Wait
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
login_button = WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.ID, "login")
)
)
login_button.click()
This approach waits for the required condition instead of assuming that the button is immediately ready.
5. Types of Waits in Selenium
Selenium automation commonly uses three synchronization approaches:
| Wait Type | Description | Typical Usage |
| Implicit Wait | Sets a default timeout for element location operations. | Simple global synchronization. |
| Explicit Wait | Waits for a specific condition. | Dynamic elements and application states. |
| Fluent Wait | Provides configurable timeout, polling, and ignored exceptions. | Advanced synchronization requirements. |
6. Implicit Wait
An implicit wait tells WebDriver to wait for a specified amount of time when attempting to locate an element before returning an error.
driver.implicitly_wait(10)
After this configuration, Selenium uses the specified timeout for element-location operations.
Example
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("https://example.com")
username = driver.find_element(
By.ID,
"username"
)
username.send_keys("admin")
7. How Implicit Wait Works
Find Element
|
v
Element Available?
/ \
Yes No
| |
v v
Return Wait
Element |
v
Search Again
|
v
Timeout Reached?
/ \
No Yes
| |
v v
Retry Exception
8. Setting an Implicit Wait
driver.implicitly_wait(10)
The value is specified in seconds.
driver.implicitly_wait(5)
This configures a five-second implicit wait.
9. Advantages of Implicit Wait
- Simple to configure.
- Applies globally to element location.
- Reduces immediate failures when elements take time to appear.
- Requires less repeated code.
10. Limitations of Implicit Wait
- It does not express a specific application condition.
- It is less precise than explicit waits.
- It is not intended for conditions such as waiting for a particular text value.
- Mixing implicit and explicit waits can make timing behavior harder to reason about.
- It may hide synchronization problems when used as the only waiting strategy.
11. Explicit Wait
An explicit wait waits for a specific condition before allowing the script to continue.
Python Selenium provides WebDriverWait for explicit waits, and Selenium's expected conditions module provides commonly used conditions.
Basic Syntax
WebDriverWait(
driver,
timeout
).until(
condition
)
12. Basic Explicit Wait Example
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "username")
)
)
The script waits up to 10 seconds for the username element to become visible.
13. Explicit Wait Flow
Start Wait
|
v
Check Condition
|
v
Condition Satisfied?
/ \
Yes No
| |
v v
Continue Poll Again
|
v
Timeout Reached?
/ \
No Yes
| |
v v
Retry TimeoutException
14. WebDriverWait
WebDriverWait is used to wait for a condition until the timeout is reached.
wait = WebDriverWait(driver, 10)
element = wait.until(
EC.visibility_of_element_located(
(By.ID, "username")
)
)
15. Reusing WebDriverWait
Instead of creating a new wait object repeatedly, a reusable wait object can be created.
wait = WebDriverWait(driver, 10)
username = wait.until(
EC.visibility_of_element_located(
(By.ID, "username")
)
)
password = wait.until(
EC.visibility_of_element_located(
(By.ID, "password")
)
login_button = wait.until(
EC.element_to_be_clickable(
(By.ID, "login")
)
)
16. Expected Conditions
Expected Conditions provide predefined conditions that can be used with explicit waits.
| Condition | Purpose |
presence_of_element_located() | Waits until an element is present in the DOM. |
visibility_of_element_located() | Waits until an element is present and visible. |
element_to_be_clickable() | Waits until an element is visible and enabled for clicking. |
presence_of_all_elements_located() | Waits until matching elements are present. |
visibility_of_all_elements_located() | Waits until matching elements are visible. |
invisibility_of_element_located() | Waits until an element becomes invisible or is no longer present. |
text_to_be_present_in_element() | Waits for specific text in an element. |
title_contains() | Waits until the page title contains specified text. |
title_is() | Waits until the page title matches expected text. |
url_contains() | Waits until the URL contains specified text. |
alert_is_present() | Waits for an alert to appear. |
frame_to_be_available_and_switch_to_it() | Waits for a frame and switches into it. |
number_of_windows_to_be() | Waits until the required number of windows exists. |
17. Presence of Element
presence_of_element_located() waits until an element exists in the DOM. Presence does not necessarily mean that the element is visible or ready for user interaction.
element = WebDriverWait(
driver,
10
).until(
EC.presence_of_element_located(
(By.ID, "username")
)
)
18. Visibility of Element
visibility_of_element_located() waits until the element is present and visible.
username = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "username")
)
)
username.send_keys("admin")
19. Presence vs Visibility
| Presence | Visibility |
| Element exists in DOM. | Element exists and is visible. |
| Element may not be displayed. | Element can be displayed. |
| Useful for DOM-level presence. | Useful before visual interaction. |
20. Element to be Clickable
element_to_be_clickable() is useful when the script needs to click an element after it becomes visible and enabled.
button = WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.ID, "submit")
)
)
button.click()
21. Waiting for Multiple Elements
When a page contains a collection of elements, use presence_of_all_elements_located().
products = WebDriverWait(
driver,
10
).until(
EC.presence_of_all_elements_located(
(By.CSS_SELECTOR, ".product")
)
)
print("Products:", len(products))
22. Waiting for All Elements to be Visible
products = WebDriverWait(
driver,
10
).until(
EC.visibility_of_all_elements_located(
(By.CSS_SELECTOR, ".product")
)
)
23. Waiting for Invisibility
Sometimes the script must wait for a loading spinner, popup, overlay, or progress indicator to disappear.
WebDriverWait(
driver,
10
).until(
EC.invisibility_of_element_located(
(By.ID, "loading")
)
)
24. Waiting for Text
Dynamic applications may initially display one message and later update it. Explicit waits can be used to wait for specific text.
WebDriverWait(
driver,
10
).until(
EC.text_to_be_present_in_element(
(By.ID, "status"),
"Completed"
)
)
25. Waiting for Page Title
WebDriverWait(
driver,
10
).until(
EC.title_is("Dashboard")
)
To wait until the title contains specific text:
WebDriverWait(
driver,
10
).until(
EC.title_contains("Dashboard")
)
26. Waiting for URL
URL-based waits are useful after navigation or login.
WebDriverWait(
driver,
10
).until(
EC.url_contains("/dashboard")
)
27. Waiting for an Alert
When a JavaScript alert appears asynchronously, an explicit wait can be used.
alert = WebDriverWait(
driver,
10
).until(
EC.alert_is_present()
)
alert.accept()
28. Waiting for a Frame
When an iframe is loaded dynamically, Selenium can wait until the frame becomes available and switch into it.
WebDriverWait(
driver,
10
).until(
EC.frame_to_be_available_and_switch_to_it(
(By.ID, "payment-frame")
)
)
29. Waiting for Multiple Windows
When clicking a link opens a new window or tab, the script can wait until the expected number of window handles exists.
original_window = driver.current_window_handle
driver.find_element(
By.ID,
"open-window"
).click()
WebDriverWait(
driver,
10
).until(
EC.number_of_windows_to_be(2)
)
30. Custom Conditions with lambda
Explicit waits can also use custom Python conditions through a lambda expression.
WebDriverWait(
driver,
10
).until(
lambda d: d.find_element(
By.ID,
"status"
).text == "Completed"
)
31. Waiting for an Attribute
Dynamic web applications may update attributes such as class, value, disabled, or custom data attributes.
WebDriverWait(
driver,
10
).until(
lambda d: d.find_element(
By.ID,
"status"
).get_attribute("data-state") == "ready"
)
32. Waiting for an Element's Value
WebDriverWait(
driver,
10
).until(
lambda d: d.find_element(
By.ID,
"search"
).get_attribute("value") == "Selenium"
)
33. Waiting for a Button to Become Enabled
submit = WebDriverWait(
driver,
10
).until(
lambda d: (
element := d.find_element(
By.ID,
"submit"
)
).is_enabled() and element
)
submit.click()
34. Waiting for a Loader to Disappear
WebDriverWait(
driver,
15
).until(
EC.invisibility_of_element_located(
(By.CSS_SELECTOR, ".loader")
)
)
dashboard = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "dashboard")
)
)
35. Waiting for AJAX Content
AJAX-based pages can update content without performing a complete page refresh. The automation script should wait for the application state that indicates the AJAX operation has completed.
WebDriverWait(
driver,
15
).until(
EC.visibility_of_element_located(
(By.ID, "results")
)
)
36. Waiting for Dynamic Search Results
search_box = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "search")
)
)
search_box.send_keys("Laptop")
results = WebDriverWait(
driver,
10
).until(
EC.presence_of_all_elements_located(
(By.CSS_SELECTOR, ".search-result")
)
)
print("Results:", len(results))
37. Waiting for a Dynamic Login
username = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "username")
)
)
password = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "password")
)
)
login_button = WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.ID, "login")
)
)
username.send_keys("admin")
password.send_keys("admin123")
login_button.click()
WebDriverWait(
driver,
10
).until(
EC.url_contains("/dashboard")
)
38. Waiting for a Checkbox
checkbox = WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.ID, "terms")
)
)
if not checkbox.is_selected():
checkbox.click()
39. Waiting for a Dropdown
country = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "country")
)
)
from selenium.webdriver.support.ui import Select
Select(country).select_by_visible_text("India")
40. Waiting for a Link
documentation = WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.LINK_TEXT, "Documentation")
)
)
documentation.click()
41. Waiting for a Modal
Modal dialogs may appear after a button click. Instead of using a fixed delay, wait for the modal to become visible.
driver.find_element(
By.ID,
"open-modal"
).click()
modal = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "modal")
)
)
print(modal.text)
42. Waiting for a Loading Spinner
WebDriverWait(
driver,
15
).until(
EC.invisibility_of_element_located(
(By.CSS_SELECTOR, ".loading-spinner")
)
)
43. Waiting for Page Navigation
After clicking a navigation link, the script can wait for a URL change or a specific element on the destination page.
old_url = driver.current_url
driver.find_element(
By.ID,
"profile"
).click()
WebDriverWait(
driver,
10
).until(
lambda d: d.current_url != old_url
)
44. Waiting for Stale Elements
Dynamic pages may replace DOM elements after an update. Selenium provides conditions that can be used when working with stale elements.
element = driver.find_element(
By.ID,
"status"
)
driver.find_element(
By.ID,
"refresh"
).click()
WebDriverWait(
driver,
10
).until(
EC.staleness_of(element)
)
45. Handling TimeoutException
If an explicit wait cannot satisfy its condition before the timeout, Selenium raises TimeoutException.
from selenium.common.exceptions import TimeoutException
try:
login_button = WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.ID, "login")
)
)
login_button.click()
except TimeoutException:
print("Login button was not ready within the timeout")
46. Waits and Exception Handling
Waits and exception handling have different purposes. A wait synchronizes the script with the application, while exception handling determines how the script responds when an operation fails.
| Concept | Purpose |
| Wait | Synchronize with application state. |
| Exception handling | Handle unexpected execution failures. |
| Assertion | Validate expected test results. |
47. Fluent Wait Concept
Fluent wait is an advanced waiting approach where timeout, polling frequency, and ignored exceptions can be configured.
In Python, WebDriverWait can be configured with timeout, polling frequency, and ignored exceptions when required.
Example
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException
wait = WebDriverWait(
driver,
20,
poll_frequency=1,
ignored_exceptions=[NoSuchElementException]
)
element = wait.until(
EC.visibility_of_element_located(
(By.ID, "username")
)
)
48. Polling Frequency
Polling frequency determines how often the wait checks the condition.
wait = WebDriverWait(
driver,
20,
poll_frequency=1
)
In this example, the condition is checked approximately once per second until it succeeds or the timeout is reached.
49. Ignoring Specific Exceptions During a Wait
In advanced scenarios, a wait may be configured to ignore selected exceptions while repeatedly checking a condition.
from selenium.common.exceptions import NoSuchElementException
wait = WebDriverWait(
driver,
10,
ignored_exceptions=[
NoSuchElementException
]
)
Exception ignoring should be used carefully. Ignoring too many exceptions can hide genuine automation problems.
50. Implicit Wait vs Explicit Wait
| Feature | Implicit Wait | Explicit Wait |
| Scope | Global element location behavior. | Specific operation or condition. |
| Condition | Element location. | Custom or predefined condition. |
| Precision | Lower. | Higher. |
| Dynamic UI Handling | Limited. | Strong. |
| Readability | Simple. | Very expressive. |
| Typical Usage | Basic synchronization. | Professional automation. |
51. Explicit Wait vs sleep()
| sleep() | Explicit Wait |
| Waits for a fixed amount of time. | Waits for a condition. |
| Does not know whether the application is ready. | Checks application state. |
| Can waste execution time. | Continues as soon as condition succeeds. |
| Less flexible. | More flexible. |
| Useful for specific non-Selenium timing needs. | Preferred for Selenium synchronization. |
52. Why Avoid Excessive time.sleep()?
time.sleep(10)
driver.find_element(
By.ID,
"submit"
).click()
If the element becomes ready after two seconds, the script still waits for the complete ten seconds. If the element takes longer than ten seconds, the script may still fail.
A condition-based wait can stop as soon as the required condition becomes true.
53. Better Alternative to sleep()
submit = WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.ID, "submit")
)
)
submit.click()
54. Do Not Mix Wait Strategies Unnecessarily
Using implicit and explicit waits together can make timeout behavior harder to understand. A project should establish a consistent synchronization strategy and use waits according to the needs of the application.
55. Waits Inside Page Object Model
Wait logic can be placed inside Page Object classes so that test cases remain focused on business behavior.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class LoginPage:
USERNAME = (By.ID, "username")
PASSWORD = (By.ID, "password")
LOGIN_BUTTON = (By.ID, "login")
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(
driver,
10
)
def login(self, username, password):
self.wait.until(
EC.visibility_of_element_located(
self.USERNAME
)
).send_keys(username)
self.wait.until(
EC.visibility_of_element_located(
self.PASSWORD
)
).send_keys(password)
self.wait.until(
EC.element_to_be_clickable(
self.LOGIN_BUTTON
)
).click()
56. Reusable Wait Helper
A reusable utility class can centralize common waiting operations.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class WaitHelper:
def __init__(self, driver, timeout=10):
self.driver = driver
self.wait = WebDriverWait(
driver,
timeout
)
def visible(self, locator):
return self.wait.until(
EC.visibility_of_element_located(
locator
)
)
def clickable(self, locator):
return self.wait.until(
EC.element_to_be_clickable(
locator
)
)
def present(self, locator):
return self.wait.until(
EC.presence_of_element_located(
locator
)
)
57. Using a Wait Helper
wait = WaitHelper(driver)
username = wait.visible(
(By.ID, "username")
)
username.send_keys("admin")
login = wait.clickable(
(By.ID, "login")
)
login.click()
58. Waiting for API-Driven UI Updates
Many modern applications use APIs to load or update information after the initial page load. Selenium should normally wait for a user-visible application state that confirms the operation is ready.
driver.find_element(
By.ID,
"load-data"
).click()
WebDriverWait(
driver,
15
).until(
EC.visibility_of_element_located(
(By.ID, "data-table")
)
)
59. Waiting for a Table to Load
rows = WebDriverWait(
driver,
15
).until(
EC.presence_of_all_elements_located(
(By.CSS_SELECTOR, "#users tbody tr")
)
)
print("Rows:", len(rows))
60. Waiting for Search Result Text
WebDriverWait(
driver,
10
).until(
EC.text_to_be_present_in_element(
(By.ID, "result-message"),
"Results found"
)
)
61. Waiting for an Element to Become Enabled
submit = WebDriverWait(
driver,
10
).until(
lambda d: (
element := d.find_element(
By.ID,
"submit"
)
) if element.is_enabled() else False
)
For simpler cases, element_to_be_clickable() is often more readable when the required behavior is simply to wait until an element is visible and enabled for clicking.
62. Waiting for a Checkbox to be Selected
WebDriverWait(
driver,
10
).until(
EC.element_to_be_selected(
(By.ID, "terms")
)
)
63. Waiting for a Specific URL
WebDriverWait(
driver,
10
).until(
EC.url_to_be(
"https://example.com/dashboard"
)
)
64. Waiting for a Partial URL
WebDriverWait(
driver,
10
).until(
EC.url_contains("/dashboard")
)
65. Waiting for a New Window
original_window = driver.current_window_handle
driver.find_element(
By.ID,
"open-report"
).click()
WebDriverWait(
driver,
10
).until(
EC.number_of_windows_to_be(2)
)
for handle in driver.window_handles:
if handle != original_window:
driver.switch_to.window(handle)
break
66. Waiting for a Frame
WebDriverWait(
driver,
10
).until(
EC.frame_to_be_available_and_switch_to_it(
(By.ID, "payment-frame")
)
)
card_number = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "card-number")
)
)
card_number.send_keys(
"4111111111111111"
)
driver.switch_to.default_content()
67. Waiting for an Alert
driver.find_element(
By.ID,
"delete"
).click()
alert = WebDriverWait(
driver,
10
).until(
EC.alert_is_present()
)
print(alert.text)
alert.accept()
68. Waiting for Dynamic Buttons
button = WebDriverWait(
driver,
15
).until(
EC.element_to_be_clickable(
(By.CSS_SELECTOR, "button.submit")
)
)
button.click()
69. Waiting for a Message to Disappear
WebDriverWait(
driver,
10
).until(
EC.invisibility_of_element_located(
(By.ID, "processing-message")
)
)
70. Waiting for an Element to Become Stale
old_element = driver.find_element(
By.ID,
"results"
)
driver.find_element(
By.ID,
"refresh"
).click()
WebDriverWait(
driver,
10
).until(
EC.staleness_of(old_element)
)
71. Handling TimeoutException with Screenshot
from selenium.common.exceptions import TimeoutException
try:
WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "dashboard")
)
)
except TimeoutException:
driver.save_screenshot(
"timeout_failure.png"
)
raise
72. Logging Wait Failures
import logging
from selenium.common.exceptions import TimeoutException
try:
WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.ID, "submit")
)
)
except TimeoutException as e:
logging.error(
"Submit button was not clickable: %s",
e
)
raise
73. Wait Strategy for Login
Open Login Page
|
v
Wait for Username
|
v
Enter Username
|
v
Wait for Password
|
v
Enter Password
|
v
Wait for Login Button
|
v
Click Login
|
v
Wait for Dashboard
|
v
Validate Dashboard
74. Wait Strategy for E-Commerce
Open Store
|
v
Wait for Search Box
|
v
Search Product
|
v
Wait for Search Results
|
v
Select Product
|
v
Wait for Product Page
|
v
Wait for Add to Cart
|
v
Add Product
|
v
Wait for Cart
|
v
Validate Cart
75. Wait Strategy for Dynamic Forms
Open Form
|
v
Wait for Name Field
|
v
Enter Name
|
v
Wait for Email Field
|
v
Enter Email
|
v
Wait for Country Dropdown
|
v
Select Country
|
v
Wait for Submit
|
v
Click Submit
|
v
Wait for Success Message
76. Common Mistakes with Selenium Waits
Mistake 1: Using sleep() Everywhere
time.sleep(10)
Fixed delays do not adapt to actual application state.
Mistake 2: Using Too Short a Timeout
WebDriverWait(
driver,
1
).until(...)
A timeout should be based on realistic application behavior and environment conditions.
Mistake 3: Using Very Large Timeouts Everywhere
WebDriverWait(
driver,
300
).until(...)
Very large timeouts can make failures take unnecessarily long to surface.
Mistake 4: Waiting for the Wrong Condition
For example, waiting only for presence when the actual requirement is that the element must be visible and clickable.
Mistake 5: Mixing Implicit and Explicit Waits Without a Strategy
This can make execution timing harder to predict and debug.
Mistake 6: Using Fixed Delays After Every Action
click()
time.sleep(5)
send_keys()
time.sleep(5)
Use condition-based synchronization where possible.
Mistake 7: Ignoring TimeoutException
try:
WebDriverWait(driver, 10).until(...)
except TimeoutException:
pass
Silently ignoring timeout failures can hide real application or automation problems.
77. Best Practices for Selenium Waits
- Prefer explicit waits for dynamic application conditions.
- Use meaningful expected conditions.
- Choose timeouts based on realistic application behavior.
- Avoid unnecessary
time.sleep() calls.
- Keep wait logic reusable.
- Use Page Object Model for large projects.
- Wait for the state required by the next action.
- Use
element_to_be_clickable() before important clicks when appropriate.
- Use visibility conditions before visual interactions.
- Use presence conditions when DOM presence is sufficient.
- Wait for loaders and overlays to disappear when they block interaction.
- Handle
TimeoutException appropriately.
- Capture screenshots when wait failures are important for debugging.
- Log important synchronization failures.
- Avoid blindly increasing timeout values to hide synchronization problems.
- Keep the synchronization strategy consistent throughout the project.
78. Good Wait Strategy vs Poor Wait Strategy
| Poor Strategy | Better Strategy |
| Use sleep() everywhere | Use condition-based explicit waits |
| Wait 30 seconds for every action | Use appropriate condition-specific timeouts |
| Wait for presence before every click | Use clickable condition when clicking |
| Ignore TimeoutException | Log, diagnose, and handle appropriately |
| Mix waits randomly | Use a consistent synchronization strategy |
| Repeat wait code everywhere | Create reusable wait utilities |
| Wait for arbitrary time | Wait for application state |
79. Practical Project: Dynamic Login Automation
Create a Selenium Python login test for a page where the login form loads dynamically.
Requirements
- Open the login page.
- Wait for the username field.
- Enter the username.
- Wait for the password field.
- Enter the password.
- Wait for the login button to become clickable.
- Click the login button.
- Wait for the dashboard URL.
- Validate the dashboard.
- Capture a screenshot if a timeout occurs.
- Close the browser.
Example
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
driver = webdriver.Chrome()
try:
driver.get(
"https://example.com/login"
)
wait = WebDriverWait(driver, 10)
username = wait.until(
EC.visibility_of_element_located(
(By.ID, "username")
)
)
password = wait.until(
EC.visibility_of_element_located(
(By.ID, "password")
)
)
login_button = wait.until(
EC.element_to_be_clickable(
(By.ID, "login")
)
)
username.send_keys("admin")
password.send_keys("admin123")
login_button.click()
wait.until(
EC.url_contains("/dashboard")
)
assert "/dashboard" in driver.current_url
except TimeoutException:
driver.save_screenshot(
"login_timeout.png"
)
raise
finally:
driver.quit()
80. Practical Project: Dynamic Search Test
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
try:
driver.get(
"https://example.com/search"
)
wait = WebDriverWait(driver, 10)
search = wait.until(
EC.visibility_of_element_located(
(By.ID, "search")
)
)
search.send_keys("Laptop")
search.send_keys(Keys.ENTER)
results = wait.until(
EC.presence_of_all_elements_located(
(By.CSS_SELECTOR, ".result")
)
)
assert len(results) > 0
finally:
driver.quit()
81. Practical Project: Dynamic E-Commerce Cart
Build an e-commerce automation test that waits for each application state before continuing.
Open Store
|
v
Wait for Search
|
v
Search Product
|
v
Wait for Results
|
v
Select Product
|
v
Wait for Product Page
|
v
Wait for Add to Cart
|
v
Add to Cart
|
v
Wait for Cart
|
v
Validate Product
|
v
Validate Price
|
v
Checkout
82. Practical Project: Loader Handling
Many applications display a loading spinner while data is being retrieved. The automation should wait for the spinner to disappear before interacting with the resulting content.
driver.find_element(
By.ID,
"load-data"
).click()
WebDriverWait(
driver,
15
).until(
EC.invisibility_of_element_located(
(By.ID, "loader")
)
)
table = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "data-table")
)
)
83. Practical Project: Frame Wait
WebDriverWait(
driver,
15
).until(
EC.frame_to_be_available_and_switch_to_it(
(By.ID, "payment-frame")
)
)
card = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "card-number")
)
)
card.send_keys(
"4111111111111111"
)
driver.switch_to.default_content()
84. Practical Project: Alert Wait
driver.find_element(
By.ID,
"delete-account"
).click()
alert = WebDriverWait(
driver,
10
).until(
EC.alert_is_present()
)
print(alert.text)
alert.accept()
85. Practical Project: New Window Wait
original_window = driver.current_window_handle
driver.find_element(
By.ID,
"open-report"
).click()
WebDriverWait(
driver,
10
).until(
EC.number_of_windows_to_be(2)
)
for handle in driver.window_handles:
if handle != original_window:
driver.switch_to.window(handle)
break
print(driver.title)
86. Waits in a Professional Selenium Framework
In a professional automation framework, synchronization logic should not be scattered randomly throughout test cases. Common wait operations can be centralized into page objects or utility classes.
selenium_project/
|
+-- tests/
| +-- test_login.py
| +-- test_search.py
| +-- test_cart.py
|
+-- pages/
| +-- login_page.py
| +-- search_page.py
| +-- cart_page.py
|
+-- utilities/
| +-- wait_helper.py
| +-- screenshot_helper.py
| +-- logger.py
|
+-- test_data/
|
+-- screenshots/
|
+-- reports/
|
+-- conftest.py
|
+-- requirements.txt
87. Recommended Wait Architecture
Test Case
|
v
Page Object
|
v
Wait Helper
|
v
WebDriverWait
|
v
Expected Condition
|
v
Web Application State
|
v
Element Ready
|
v
Perform Action
88. Waits with pytest Fixture
import pytest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
@pytest.fixture
def driver():
browser = webdriver.Chrome()
yield browser
browser.quit()
@pytest.fixture
def wait(driver):
return WebDriverWait(
driver,
10
)
Using the Fixture
def test_login(driver, wait):
driver.get(
"https://example.com/login"
)
username = wait.until(
EC.visibility_of_element_located(
(By.ID, "username")
)
)
username.send_keys("admin")
89. Waits and Test Assertions
A wait should synchronize the test before an assertion is performed.
dashboard = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "dashboard")
)
)
assert dashboard.is_displayed()
The wait ensures the expected application state has been reached before the assertion checks the result.
90. Waits and Exception Handling
try:
dashboard = WebDriverWait(
driver,
10
).until(
EC.visibility_of_element_located(
(By.ID, "dashboard")
)
)
assert dashboard.is_displayed()
except TimeoutException:
driver.save_screenshot(
"dashboard_timeout.png"
)
raise
91. Waits and Screenshots
When a wait fails, a screenshot can provide useful information about the browser state at the time of failure.
try:
WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.ID, "checkout")
)
)
except TimeoutException:
driver.save_screenshot(
"checkout_wait_failure.png"
)
raise
92. Waits and Logging
import logging
logging.info(
"Waiting for checkout button"
)
checkout = WebDriverWait(
driver,
10
).until(
EC.element_to_be_clickable(
(By.ID, "checkout")
)
)
logging.info(
"Checkout button is ready"
)
checkout.click()
93. Choosing the Correct Expected Condition
| Requirement | Recommended Condition |
| Element exists in DOM | presence_of_element_located() |
| Element is visible | visibility_of_element_located() |
| Element should be clicked | element_to_be_clickable() |
| Multiple elements exist | presence_of_all_elements_located() |
| All elements visible | visibility_of_all_elements_located() |
| Loader disappears | invisibility_of_element_located() |
| Text appears | text_to_be_present_in_element() |
| Page title changes | title_is() or title_contains() |
| URL changes | url_to_be() or url_contains() |
| Alert appears | alert_is_present() |
| Frame becomes available | frame_to_be_available_and_switch_to_it() |
| New window opens | number_of_windows_to_be() |
| Old element disappears after DOM replacement | staleness_of() |
94. Quick Revision Table
| Concept | Example | Purpose |
| Implicit Wait | driver.implicitly_wait(10) | Global element-location timeout. |
| Explicit Wait | WebDriverWait(driver, 10).until(...) | Wait for a specific condition. |
| Presence | EC.presence_of_element_located() | Element exists in DOM. |
| Visibility | EC.visibility_of_element_located() | Element is visible. |
| Clickable | EC.element_to_be_clickable() | Element is ready for clicking. |
| Invisibility | EC.invisibility_of_element_located() | Element disappears or becomes invisible. |
| Text | EC.text_to_be_present_in_element() | Wait for specific text. |
| URL | EC.url_contains() | Wait for URL condition. |
| Title | EC.title_contains() | Wait for title condition. |
| Alert | EC.alert_is_present() | Wait for alert. |
| Frame | EC.frame_to_be_available_and_switch_to_it() | Wait and switch to frame. |
| Windows | EC.number_of_windows_to_be() | Wait for window count. |
| Stale Element | EC.staleness_of() | Wait for old element to become stale. |
| Timeout | TimeoutException | Handle unsuccessful waits. |
95. Interview Questions on Selenium Waits
Q1. What is a wait in Selenium?
A wait is a synchronization mechanism that allows Selenium to wait for an element or application condition before continuing execution.
Q2. What are the main types of waits?
The commonly discussed Selenium wait mechanisms are implicit waits, explicit waits, and fluent-style configurable waits.
Q3. What is an implicit wait?
An implicit wait sets a global timeout used when WebDriver searches for elements.
Q4. What is an explicit wait?
An explicit wait waits for a specific condition before allowing the script to continue.
Q5. What is WebDriverWait?
WebDriverWait is Selenium's Python wait utility for waiting until a condition succeeds or the timeout is reached.
Q6. What is Expected Conditions?
Expected Conditions are predefined conditions that can be used with explicit waits for common synchronization scenarios.
Q7. What is the difference between presence and visibility?
Presence means that the element exists in the DOM. Visibility means that the element exists and is visible on the page.
Q8. What is element_to_be_clickable()?
It is an expected condition used when an element needs to be visible and enabled for clicking.
Q9. What exception occurs when an explicit wait times out?
Selenium raises TimeoutException when the wait condition is not satisfied before the timeout.
Q10. Why should sleep() not be used everywhere?
sleep() waits for a fixed duration and does not check whether the application is already ready. Condition-based waits are generally more suitable for Selenium synchronization.
Q11. Can Selenium wait for text?
Yes. Expected Conditions provide text-related conditions such as text_to_be_present_in_element().
Q12. Can Selenium wait for a URL?
Yes. Conditions such as url_to_be() and url_contains() can be used.
Q13. Can Selenium wait for an alert?
Yes. EC.alert_is_present() can be used with WebDriverWait.
Q14. Can Selenium wait for a frame?
Yes. frame_to_be_available_and_switch_to_it() can wait for a frame and switch into it.
Q15. How can waits be reused in Page Object Model?
A reusable WebDriverWait object or wait helper class can be maintained inside page objects or utility classes.
Q16. What is polling frequency?
Polling frequency determines how frequently a wait checks the specified condition.
Q17. What is a timeout?
A timeout is the maximum period the wait is allowed to keep checking a condition before failing.
Q18. What is the difference between wait and assertion?
A wait synchronizes execution with application state, while an assertion verifies whether the actual result matches the expected result.
96. Recommended Selenium Wait Flow
Start Test
|
v
Open Application
|
v
Identify Required Element
|
v
Choose Locator
|
v
Choose Correct Wait Condition
|
v
Set Reasonable Timeout
|
v
Wait for Condition
|
v
Condition Satisfied?
/ \
Yes No
| |
v v
Perform Timeout
Action |
v
Capture Evidence
|
v
Log Failure
|
v
Raise Error
97. Professional Selenium Wait Strategy
Requirement
|
v
Identify Application State
|
v
Select Stable Locator
|
v
Select Appropriate Condition
|
v
Configure WebDriverWait
|
v
Wait for Condition
|
v
Perform Action
|
v
Validate Result
|
v
Continue Test
|
v
Cleanup
98. Final Summary
Waits are a fundamental part of reliable Selenium automation with Python. Web applications often contain dynamically loaded elements, asynchronous operations, animations, AJAX requests, overlays, frames, alerts, and changing page states. Selenium scripts therefore need synchronization mechanisms that respond to actual application conditions.
Implicit waits provide a global element-location timeout, while explicit waits allow the automation script to wait for specific conditions. WebDriverWait combined with Expected Conditions is particularly useful for dynamic web applications because it allows the test to wait for the state required by the next operation.
Common conditions include waiting for element presence, visibility, clickability, text, URL changes, title changes, alerts, frames, multiple windows, invisibility, and stale elements. Custom lambda conditions can also be used when a predefined condition does not represent the required application state.
Professional Selenium automation should avoid excessive fixed delays, use appropriate synchronization conditions, handle TimeoutException correctly, capture useful debugging information, and centralize reusable wait logic where appropriate.
The main goal of Selenium waits is to make automation stable, synchronized, reliable, readable, maintainable, and suitable for dynamic web applications.
99. Course Resources
Selenium Training: https://www.justacademy.co/course-detail/selenium-training
Register for Course Demo: https://www.justacademy.co/register-for-course-demo