eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – Summer Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

Course – Summer Sale 2026 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

1. Overview

One of the challenges of web application testing is dealing with the dynamic nature of web pages. Web pages can take time to load, and elements may only appear after some time. As a result, Selenium provides wait mechanisms to help us wait for elements to appear, disappear, or be clickable before continuing test execution.

In this article, we’ll explore the differences between the wait types and how to use them in Selenium. We’ll compare implicit wait vs explicit wait and learn a few best practices when using waits in Selenium tests.

2. Wait Types in Selenium

Selenium provides various wait mechanisms to help wait for an element to appear, disappear, or be clickable. These wait mechanisms can be classified into three types: implicit wait, explicit wait, and fluent wait.

For our test cases, we’ll define a few constants for our page locators that we’ll use to navigate through the web page:

private static final By LOCATOR_ABOUT = By.xpath("//a[starts-with(., 'About')]");
private static final By LOCATOR_ABOUT_BAELDUNG = By.xpath("//h3[normalize-space()='About Baeldung']");
private static final By LOCATOR_ABOUT_HEADER = By.xpath("//h1");

2.1. Implicit Wait

An implicit wait is a global setting that applies to all elements in a Selenium script. It waits a specified time before throwing an exception if the element is not found. We can set the wait once per session and can’t change it later. The default value is 0.

We can set the implicit wait to 10 seconds with the following statement. We should set the implicit wait right after initializing the WebDriver instance:

driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));

With implicit wait, we don’t need to explicitly wait for anything in our tests.

The following simple test navigates to www.baeldung.com and navigates to the About page via the header menu. As we can see, there are no explicit wait instructions, and the test passes with an implicit wait of 10 seconds:

void givenPage_whenNavigatingWithImplicitWait_ThenOK() {
    final String expected = "About Baeldung";
    driver.navigate().to("https://www.baeldung.com/");

    driver.findElement(LOCATOR_ABOUT).click();
    driver.findElement(LOCATOR_ABOUT_BAELDUNG).click();

    final String actual = driver.findElement(LOCATOR_ABOUT_HEADER).getText();
    assertEquals(expected, actual);
}

It’s important to note that not setting the implicit wait will lead to a failing test.

2.2. Explicit Wait

An explicit wait is a more flexible wait that allows us to wait for a specific condition to be met before continuing test execution.

We can define the condition, such as the presence or absence of an element, using ExpectedConditions class. An exception is thrown if the condition is not met within the specified time.

The polling frequency of the WebDriver to check the expected condition is fixed at 500 ms. As the explicit wait is not set globally, we can use different conditions and timeouts for everything.

Looking at the previous test case, we noted that the test would fail without an implicit wait. We can adapt the test and introduce explicit waits.

First, we’ll create a Wait instance with a timeout of 10 seconds for our test:

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(TIMEOUT));

Now we can use this Wait instance and call until() with the ExpectedConditions. In this scenario, we can use ExpectedConditions.visibilityOfElementLocated(..).

Before interacting with an element, e.g., clicking, we need to wait for the element to be visible or clickable:

void givenPage_whenNavigatingWithExplicitWait_thenOK() {
    final String expected = "About Baeldung";
    driver.navigate().to("https://www.baeldung.com/");

    driver.findElement(LOCATOR_ABOUT).click();
    wait.until(ExpectedConditions.visibilityOfElementLocated(LOCATOR_ABOUT_BAELDUNG));

    driver.findElement(LOCATOR_ABOUT_BAELDUNG).click(); 
    wait.until(ExpectedConditions.visibilityOfElementLocated(LOCATOR_ABOUT_HEADER));

    final String actual = driver.findElement(LOCATOR_ABOUT_HEADER).getText();
    assertEquals(expected, actual);
}

We need to manage the waits manually, but we are much more flexible. This can improve the test performance significantly.

The ExpectedConditions class provides many methods we can use for checking expected conditions. Let’s see a few:

  • elementToBeClickable()
  • invisibilityOf()
  • presenceOfElementLocated()
  • textToBePresentInElement()
  • visibilityOf()

2.3. Fluent Wait

A fluent wait is another type of explicit wait that allows for more fine-grained control over the waiting mechanism. It enables us to define the expected condition and the polling mechanism to check for the particular condition to be met.

We can again adapt the previous test case and introduce fluent waits. Fluent waits are basically explicit waits, so we only have to adapt the Wait instance. We specify the polling frequency:

Wait<WebDriver> wait = new FluentWait<>(driver)
  .withTimeout(Duration.ofSeconds(TIMEOUT))
  .pollingEvery(Duration.ofMillis(POLL_FREQUENCY));

The test itself will stay the same as for the explicit wait:

void givenPage_whenNavigatingWithFluentWait_thenOK() {
    final String expected = "About Baeldung";
    driver.navigate().to("https://www.baeldung.com/");

    driver.findElement(LOCATOR_ABOUT).click();
    wait.until(ExpectedConditions.visibilityOfElementLocated(LOCATOR_ABOUT_BAELDUNG));

    driver.findElement(LOCATOR_ABOUT_BAELDUNG).click();
    wait.until(ExpectedConditions.visibilityOfElementLocated(LOCATOR_ABOUT_HEADER));

    final String actual = driver.findElement(LOCATOR_ABOUT_HEADER).getText();
    assertEquals(expected, actual);
}

3. Implicit Wait vs. Explicit Wait

The implicit and explicit wait is used to wait for an element to appear on the page. However, there are some differences between them:

  • Timeouts: Implicit wait sets a default timeout for the entire test runtime, while explicit wait sets timeouts for specific conditions.
  • Condition: Implicit wait waits for an element to appear on the page, while explicit wait waits for a specific condition, such as the presence of an element or the element to be clickable.
  • Scope: Implicit wait applies globally, while explicit wait applies locally to a specific element.
  • Exception: Implicit wait throws a NoSuchElementException when the WebDriver cannot find the element within the specified timeout. In contrast, explicit wait throws a TimeoutException when the element doesn’t meet the condition within the specified timeout.

The implicit wait is helpful when we want to wait a certain amount of time for elements to appear on the page. However, the explicit wait is the better option if we need to wait for a specific condition.

According to Selenium documentation, we should not mix them:

Warning: Do not mix implicit and explicit waits. Doing so can cause unpredictable wait times. For example, setting an implicit wait of 10 seconds and an explicit wait of 15 seconds could cause a timeout to occur after 20 seconds.

4. Best Practices

When using waits in Selenium, there are a few best practices to keep in mind:

  • Always use waits: Waiting for elements to load is a crucial step in automated testing.
  • Use explicit wait instead of implicit wait: Implicit waits can cause our tests to take longer than necessary to fail if the element cannot be located. Explicit and fluent waits are better because they allow us to wait for a specific condition to occur before proceeding further.
  • Use fluent waits when necessary: We should use fluent waits when we need to verify a specific condition repeatedly until it becomes true, as they offer greater control over the waiting mechanism.
  • Use reasonable wait times: Wait times that are too short can cause false negatives, while wait times that are too long can unnecessarily increase the total execution time of the test.
  • Use ExpectedConditions: When using explicit or fluent waits, it’s essential to use the ExpectedConditions class to define the conditions we want to wait for. By doing this, we can ensure that our tests wait for the appropriate conditions and fail quickly if the conditions aren’t met.

5. StaleElementReferenceException

The StaleElementReferenceException is a problem that occurs when the previously located element is not available anymore.

This can happen when the DOM changes after we located the element, e.g., when waiting for the specified condition of the element to be true.

To solve the StaleElementReferenceException, we’ll need to relocate the element whenever this exception occurs. Every time a SERE (StaleElementReferenceException) occurs, we’ll catch the exception, relocate the element and retry the step again. Because we can’t be sure that reloading fixes the problem, we need to stop the retry after a few attempts:

boolean stale = true;
int retries = 0;
while(stale && retries < 5) {
    try {
        element.click();
        stale = false;
    } catch (StaleElementReferenceException ex) {
        retries++;
    }
}
if (stale) {
    throw new Exception("Element is still stale after 5 attempts");
}

As this solution is inconvenient when implemented everywhere, we can wrap the WebElement and the WebDriver and handle the StaleElementReferenceException internally.

With this approach, we don’t need to take care of StaleElementReferenceExceptions in our test code. We must wrap the WebDriver to work with the wrapped WebElements. All methods in the WebElement that can throw a StaleElementReferenceException can be adapted.

6. Conclusion

In this tutorial, we learned that waits are an essential part of writing effective and efficient tests in Selenium.

Properly utilizing waits can prevent potential timing problems, ensure the elements load before interacting with them, and decrease the likelihood of test failures.

Explicit waits provide more control over the waiting mechanism than implicit waits. When we need a more fine-grained control, we can use fluent waits to check for a particular condition with a specified frequency until the WebElement meets the specified condition or a timeout occurs.

By following the best practices, we can significantly improve the efficiency and reliability of our automated tests.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – Summer Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

Course – Summer Sale 2026 – NPI (All)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

eBook Jackson – NPI EA – 3 (cat = Jackson)