A complete guide to understanding waits in Selenium for better test automation

7 min read

Selenium is a powerful tool for automating web browser interactions, especially for testing web applications. However, automating such interactions involves dealing with the asynchronous nature of web pages, where elements may load at different times, causing potential failures in the automation script. To handle this, Selenium provides various types of “waits” that allow the script to pause until the web elements are ready for interaction. This blog will explore how waits work, why they are essential, the types of waits available, the exceptions related to waits, and best practices for using them effectively. 

1. Understanding Asynchronous vs. Synchronous behavior in web applications 

Web applications today are highly dynamic, often incorporating asynchronous (async) and synchronous (sync) operations to load content. To better understand the role of waits, it is crucial to differentiate between these two behaviors: 

Synchronous behavior: 

Synchronous operations follow a step-by-step process where each operation must be completed before the next one starts. When a web page loads synchronously, the browser retrieves all resources—such as HTML, CSS, JavaScript, and images—sequentially. Only after all resources are fully loaded will the browser render the entire page, making it ready for user interaction. For example, on older or static websites, you can often see the whole page appear all at once, including text, buttons, forms, and other elements. This predictable loading behavior makes it easier for automation scripts to interact with elements because everything is already available when the page load event is triggered. 

However, synchronous loading is less common in modern applications, as it often leads to slower user experiences. Users must wait until all elements are fully loaded before interacting with the page. However, from an automation perspective, synchronous behavior is easier to handle because it is consistent and linear; Selenium can typically find and interact with elements immediately after a page finishes loading. 

Asynchronous behavior: 

Asynchronous operations, by contrast, allow certain tasks to run independently of others, enabling faster, more dynamic web experiences. Modern web applications often rely on AJAX (Asynchronous JavaScript and XML), JavaScript, or Fetch APIs to load resources after the main content has already been displayed. This allows users to interact with the page while certain elements are still loading in the background. For example, when you navigate to an e-commerce site, the page may render the basic layout and initial content, but product images or user reviews may load asynchronously after the main page is visible. 

The challenge with asynchronous operations is that elements can appear at different times, sometimes with significant delays. For instance: 

  • A form field might not be immediately clickable because it’s still being populated by an AJAX request. 
  • A button might become clickable only after specific content has been processed and displayed. 
  • Elements that rely on external APIs (e.g., fetching live stock market prices or real-time chat messages) may not load until after an API call has returned the necessary data. 

Asynchronous behavior often introduces uncertainty into the timing of when elements appear or become interactable, which can cause issues in automation scripts that expect elements to be available immediately 

2. Why use waits in Selenium? 

When automating web interactions, synchronization between the script and the browser is essential. Without waits, the automation script may attempt to interact with web elements that have not fully loaded, are not visible, or are not yet ready for interaction, leading to script failures. Using waits helps avoid such issues by: 

  • Ensuring that Selenium interacts with elements only when they are ready. 
  • Providing a smoother, more reliable testing process by handling delays in page load, AJAX calls, and other dynamic behaviors. 
  • Preventing False Negatives in Test Results. 
  • Handling Edge Cases and Unpredictable Load Times. 

Waits effectively bridge the gap between Selenium’s execution speed and the unpredictable load times of web elements. Without waits, the automation script risks failing or producing inconsistent results. 

3. Types of waits in Selenium 

Selenium provides several types of waits to help manage the timing of element interactions in web applications. These waits are crucial for synchronizing the automation script with the page’s behavior, ensuring that Selenium interacts with elements only when they are ready and fully loaded. The three main types of waits in Selenium are Implicit Wait, Explicit Wait, and Fluent Wait. Each serves a different purpose, offering varying levels of control over how long Selenium should wait before timing out or proceeding with further actions. 

a. Implicit wait 

An implicit wait is a global wait that applies to every element in the Selenium script. When you define an implicit wait, Selenium will pause the script for a specified amount of time before throwing an exception if it cannot find an element. This wait is configured once and applies to all subsequent interactions with elements on the page. 

  • How it works: Once an implicit wait is set, Selenium polls the DOM periodically to check if the desired element has appeared. If the element becomes available before the timeout period expires, the script will proceed immediately; if not, it will wait up to the defined duration before throwing an exception. 

Example: 

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 
  • This example sets a 10-second implicit wait. For every element search, Selenium will wait up to 10 seconds before failing with an exception if the element is not found. 
  • Pros
    • Simple to implement and ideal for static or consistently loading pages where the timing of element appearances is predictable. 
    • Helps avoid script failures due to minor delays in element loading across multiple interactions. 
  • Cons
    • Lack of flexibility. It applies the same wait time to all elements, even if some elements appear almost instantly, leading to unnecessary waiting. 
    • Not suitable for highly dynamic web applications where different elements load at different times. 
  • Best use case: Use implicit waits for pages with relatively stable load times and when you do not need fine-grained control over waiting for specific elements. 

b. Explicit wait 

An explicit wait gives you more precise control over waiting for specific elements or conditions. Unlike implicit waits, which are applied globally, explicit waits are applied to individual elements or conditions. You define an explicit wait for a specific element, and Selenium will wait until a certain condition—such as the element becoming visible, clickable, or present in the DOM—is met. 

  • How it works: When you create an explicit wait, you specify both a maximum wait time and a condition that must be fulfilled. The script will pause and periodically check for the condition until either the element satisfies the condition, or the timeout period expires. If the condition is met before the timeout, the script continues; if not, it throws a TimeoutException. 

Example:

WebDriverWait wait = new WebDriverWait(driver, 20); 

WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("exampleId")) 
  • In this example, Selenium waits up to 20 seconds for the element with the specified id to become visible. If the element becomes visible within the time limit, the script continues; if not, it throws an exception. 
  • Pros
    • Highly flexible, as you can wait for specific conditions (such as visibility, clickability, or the presence of text). 
    • Tailored for dynamic web applications where elements load at varying times. 
    • Provides better resource management compared to implicit waits since it only waits for specific elements rather than applying a blanket wait to all elements. 
  • Cons
    • Requires additional coding effort for each element or condition, as explicit waits must be defined separately. 
    • Can lead to more complex scripts if used excessively or without proper organization. 
  • Best use case: Explicit waits are ideal for pages with dynamic content, where specific elements load after certain actions or events. Use the “explicit waits” when you need fine-tuned control over waiting when faced with some particular conditions, such as AJAX requests, loading spinners, or interactive elements. 

c. Fluent wait 

A fluent wait is an advanced form of explicit wait that provides greater control over polling intervals and exception handling. Fluent waits are particularly useful in situations where element load times are highly variable, or where you want to ignore certain exceptions during the wait period. Fluent waits allow you to specify not only the total timeout period but also how often Selenium should check for the condition, along with the ability to ignore specific exceptions like NoSuchElementException. 

  • How it works: Fluent waits enable you to define the polling frequency (how often the condition is checked), the maximum wait time, and exceptions that should be ignored during the wait. Selenium will repeatedly check for the condition at the specified intervals until either the condition is met or the timeout expires. If certain exceptions (e.g., the element is temporarily unavailable) are encountered during the wait, they are ignored, and Selenium continues polling. 

Example:

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver) 

    .withTimeout(Duration.ofSeconds(30)) 

    .pollingEvery(Duration.ofSeconds(5)) 

    .ignoring(NoSuchElementException.class); 

WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("exampleId")));; 
  • In this example, Selenium waits up to 30 seconds for the element to become clickable, checking every 5 seconds. If the element is not found within the first few polls, Selenium ignores the NoSuchElementException and continues checking. 
  • Pros
    • Offers granular control over how frequently Selenium checks for the condition, allowing for more efficient use of wait times. 
    • Can ignore exceptions that are expected during the wait period, preventing unnecessary script failures. 
    • Best suited for highly dynamic pages with unpredictable load times or complex interactions. 
  • Cons
    • More complex to implement and configure, requiring careful tuning of polling intervals and exception handling. 
    • If not properly configured, frequent polling may lead to performance overheads. 
  • Best use case: Fluent waits are ideal for web applications with highly variable load times or where certain exceptions (like temporary unavailability of elements) are expected and should be ignored. They are particularly useful for dealing with complex, asynchronous elements that may appear or become interactive only after unpredictable delays. 

Conclusion 

In conclusion, waits are essential in Selenium to handle the unpredictable nature of web pages, ensuring that the script interacts with elements only when they are ready. The type of wait you choose depends on the complexity of the web application and the level of control you need. Implicit waits are simple and global, suited for static or predictable pages. Explicit waits offer more control, allowing you to wait for specific conditions, making them ideal for dynamic content. Fluent waits provide the most flexibility, enabling control over polling intervals and exception handling, and are best used in highly dynamic, unpredictable environments. Understanding the appropriate use cases for each type of wait will help ensure that your Selenium scripts run efficiently and reliably, handling both synchronous and asynchronous behaviors in web applications. We even use these types of waits at zen8labs to help manage each project in a controlled environment, but if you want to know more then message us at zen8labs and we can create something awesome together!  

Quynh Le, Quality Assurance Engineer

Related posts

In our latest blog, we revisit Selenium to start creating the tools to allow you to succeed with it. Our guide helps you take the steps to becoming proficient in Selenium!
7 min read
Automation testing has transformed the way software development teams. But how does Python help with the testing? Our latest blog gives you the steps to test.
7 min read
Mock data, also known as artificial data, mirrors the structure, format, and occasionally the content of real data. Learn about the methods we use mock data to our benefit at zen8labs and how it can help you in the future.
8 min read