The most common problem while performing browser automation testing is ensuring that the web application is stable and can execute automation scripts smoothly.
Synchronization between the web application and the automation scripts can sometimes be problematic. To address this, Selenium has introduced waiting strategies.
Overview
Why use Explicit Wait in Selenium?
- Handles dynamic elements
- Improves test stability
- Optimizes execution time
- Provides granular control
- More flexible than implicit wait
When to use Explicit Wait in Selenium?
- Element visibility: Wait until an element appears on the page.
- Element clickability: Ensure buttons or links are interactive before clicking.
- Element presence in DOM: Wait for elements that load dynamically.
- Alert appearance: Handle pop-ups or JavaScript alerts efficiently.
- Page title validation: Confirm the correct page has loaded before proceeding.
What are Wait Commands in Selenium?
In Selenium, waiting strategies handle synchronization issues between the test script and web elements that may take time to load.
There are three main types of waits in Selenium:
- Implicit wait: It is a built-in wait in Selenium that automatically waits for elements.
Example:
driver.implicitly_wait(10) # Waits up to 10 seconds for elements
- Explicit wait: It waits for a specific condition to be true.
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, "element_id")) )
- Fluent wait: A more advanced form of explicit wait checks for a condition to be true periodically until the timeout is reached. It allows polling intervals and ignores exceptions. It is useful for dynamic elements with varying load times.
Example:
from selenium.webdriver.support.wait import WebDriverWait wait = WebDriverWait(driver, 10, poll_frequency=1, ignored_exceptions=[NoSuchElementException]) element = wait.until(EC.presence_of_element_located((By.ID, "element_id")))
Why are Explicit Waits used?
Explicit Waits are used in Selenium to handle dynamic web elements that take varying amounts of time to appear, load, or become interactive. Unlike fixed waits (time.sleep()), Explicit Waits allow the script to pause only until a specific condition is met, improving test stability and execution time.
Key reasons to use explicit waits :
1. Handles Dynamic Elements: Some web elements load asynchronously (for example, AJAX calls and animations), and explicit wait ensures the element is present and ready before interaction.
2. Improves Test Stability: Reduces test failures caused by elements not fully loaded. It prevents exceptions like NoSuchElementException, ElementNotVisibleException, etc.
3. Optimizes Execution Time: Instead of waiting for a fixed duration, selenium proceeds immediately once the element is ready. It avoids unnecessary delays, making tests faster.
4. Provides Granular Control: Explicit wait can wait for specific conditions like visibility, clickability, or text presence.
It is more flexible than implicit wait, which applies a general wait for all elements.
When to use Explicit Wait in Selenium?
Explicit Wait in Selenium when dealing with dynamic elements that take time to load, appear, or become interactive. It ensures that your script waits only as long as necessary, preventing errors and improving test efficiency.
Scenarios where Explicit wait is useful:
1. Waiting for an element to be visible: Some elements may be present in DOM but not visible yet. visibility_of_element_located() method can be used to wait for them to appear.
wait.until(EC.visibility_of_element_located((By.ID, "element_id")))
2. Waiting for an element to be clickable: This is useful when buttons or links take time to be interactive.
wait.until(EC.element_to_be_clickable((By.XPATH, "//button[text()='Submit']"))).click()
3. Waiting for an element to be present in DOM: The element to be used may not be loaded into DOM yet. Use the presence_of_element_located() method.
wait.until(EC.presence_of_element_located((By.CLASS_NAME, "loading")))
4. Waiting for an Alert to Appear: This is useful when waiting for pop-ups or java alerts.
wait.until(EC.alert_is_present()).accept()
5. Waiting for a Page Title to Contain Specific Text: Ensures that the correct page has loaded before proceeding.
wait.until(EC.title_contains("Dashboard"))
How does Explicit Wait in Selenium work?
Explicit Wait in Selenium makes the WebDriver pause execution until a specified condition is met before proceeding to the next step. They act as loops that are added to the code that poll the application for a specific condition to be evaluated as true before it exits the loop and continues to the next command in the code.
If the condition is not evaluated as true before the timeout, then a timeout error will be thrown.
Here is a step-by-step description of how it works:
Step 1: Initialize the webDriverWait:
The WebDriverWait class is used to define the maximum wait time.
wait = WebDriverWait(driver, 10) # Wait up to 10 seconds
Step 2: Specify Expected Condition:
Selenium checks whether a given condition is met by using expected conditions.
If the condition is met before the timeout, execution proceeds immediately. If the condition is not met within the timeout, an exception (TimeoutException) is raised.
Step 3: Polling Mechanism:
Selenium polls for the condition at regular intervals (default: 500 milliseconds).
It stops waiting as soon as the condition is met.
Step 4: Handling Exceptions:
One can ignore specific exceptions while waiting. (For example, NoSuchElementException)
wait = WebDriverWait(driver, 10, poll_frequency=1,ignored_exceptions=[NoSuchElementException])
Syntax of Explicit Wait in Selenium
In Selenium, Explicit Wait is implemented using the WebDriverWait class in combination with Expected Conditions (expected_conditions).
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # Initialize Explicit Wait wait = WebDriverWait(driver, timeout) # Wait until a condition is met element = wait.until(EC.condition((By.LOCATOR_TYPE, "locator_value")))
- driver → WebDriver instance (for example, webdriver.Chrome())
- timeout → Maximum wait time (in seconds) before throwing TimeoutException
- condition → The expected condition to be checked
- By.LOCATOR_TYPE → Locator strategy (for example, By.ID, By.XPATH)
“locator_value” → Value of the locator
Code Example for Explicit Wait in Selenium
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 # Initialize WebDriver driver = webdriver.Chrome() driver.get("https://example.com") try: # Define Explicit Wait wait = WebDriverWait(driver, 10) # Wait until an element is visible element = wait.until(EC.visibility_of_element_located((By.ID, "element_id"))) # Perform an action element.click() except Exception as e: print(f"Exception occurred: {e}") finally: driver.quit()
Types of ExpectedConditions to be used with Explicit Waits
Selenium provides various Expected Conditions (EC) that can be used with Explicit Wait to handle dynamic elements efficiently.
These conditions are available in the selenium.webdriver.support.expected_conditions package.
1. presence_of_element_located(locator): Waits until the element is present in the DOM (but not necessarily visible).
wait.until(EC.presence_of_element_located((By.ID, "username")))
2. presence_of_all_elements_located(locator): Waits until all matching elements are present in the DOM.
wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, "items")))
3. visibility_of_element_located(locator): Waits until the element is visible on the webpage.
wait.until(EC.visibility_of_element_located((By.ID, "profile_pic")))
4. visibility_of(element): Waits until the given WebElement is visible.
wait.until(EC.visibility_of(driver.find_element(By.NAME, "search")))
5. element_to_be_clickable(locator): Waits until the element is visible and enabled (ready to be clicked).
wait.until(EC.element_to_be_clickable((By.XPATH, "//button[@id='login']")))
6. element_to_be_selected(locator): Waits until a checkbox or radio button is selected.
wait.until(EC.element_to_be_selected((By.CSS_SELECTOR, "#accept_terms")))
7. element_located_to_be_selected(locator): Waits until the located element is selected.
wait.until(EC.element_located_to_be_selected((By.NAME, "gender")))
8. alert_is_present(): Waits until an alert box appears.
wait.until(EC.alert_is_present()).accept()
9. text_to_be_present_in_element(locator, text_): Waits until an element contains the specified text.
wait.until(EC.text_to_be_present_in_element((By.TAG_NAME, "h1"), "Dashboard"))
10. text_to_be_present_in_element_value(locator, text_): Waits until an input field contains a specific value.
wait.until(EC.text_to_be_present_in_element_value((By.ID, "search_box"), "Selenium"))
11. invisibility_of_element_located(locator): Waits until an element disappears or becomes invisible.
wait.until(EC.invisibility_of_element_located((By.CLASS_NAME, "loading-spinner")))
12. frame_to_be_available_and_switch_to_it(locator): Waits until an iframe is available, then switches to it.
wait.until(EC.frame_to_be_available_and_switch_to_it((By.TAG_NAME, "iframe")))
13. new_window_is_opened(driver.window_handles): Waits for a new browser window/tab to open.
wait.until(EC.new_window_is_opened(driver.window_handles))
14. number_of_windows_to_be(num): Waits until a specific number of windows/tabs are open.
wait.until(EC.number_of_windows_to_be(2))
Read More: Best Practices for Selenium Test Automation
Best Practices while using Explicit Waits
Explicit Waits help improve test reliability and stability when dealing with dynamic web elements. To use them efficiently, follow these best practices.
1. Use Explicit Wait Instead of Implicit Wait: It is more efficient because it waits only for specific conditions. Avoid relying too much on Implicit Wait, as it applies to all elements and may cause unnecessary delays. It is a best practice to use explicit wait for dynamic elements.
2. Set an appropriate timeout value: Choose a reasonable maximum wait time (for example, 10: 30 seconds) based on element behavior. Avoid setting excessively high timeouts, which slow down test execution.
3. Use the expected conditions for the scenario: Different elements require different conditions. Avoid using presence_of_element_located() if you need to interact with an element (use visibility_of_element_located() instead.
4. Avoid Using time.sleep(): time.sleep() is a fixed wait and slows down tests unnecessarily. Use Explicit Waits, which wait only as long as necessary.
5. Handle Exceptions Gracefully: Always catch exceptions (like TimeoutException) to prevent test failures.
Avoid assuming elements will always load within the timeout.
from selenium.common.exceptions import TimeoutException try: element = wait.until(EC.element_to_be_clickable((By.ID, "submit"))) element.click() except TimeoutException: print("Element not found within the timeout period")
6. Ensure Elements Are Ready Before Interaction: Wait for elements to be visible and enabled before clicking or typing.
Avoid clicking elements immediately after finding them.
wait.until(EC.element_to_be_clickable((By.ID, "start_button"))).click()
Why run Selenium tests on Real Devices?
Testing on real devices ensures accurate, reliable, and user-centric web automation. While emulators and simulators can help in early development, they fail to replicate real-world conditions like hardware performance, network variability, and OS-specific behaviors.
Platforms like Browserstack Automate provide all these benefits and provide highly reliable results when using real-world devices. It has many other benefits like:
- Instant Access: Run Selenium tests on real mobile and desktop devices without setup.
- Parallel Testing: Speed up execution by running tests concurrently across multiple environments.
- Network & Geolocation Testing: Simulate real-world conditions like low-bandwidth networks and location-based testing.
- Seamless Integration: Works with Selenium, Appium, and CI/CD pipelines for faster releases.
Conclusion
Explicit Waits play a crucial role in stabilizing Selenium tests. They ensure interactions only occur when elements are fully loaded and ready by using appropriate expected conditions.
While Explicit Waits enhance test stability, running Selenium tests on real devices ensures accurate and consistent results.
To build reliable, scalable Selenium automation, use Explicit Waits for element synchronization and BrowserStack Automate for real-world validation. This combination ensures a flawless user experience across all devices and browsers.