How does FluentWait work with ExpectedConditions in Selenium WebDriver Java in details

There are several ways how people usually implement explicit waits in their Selenium tests. The way how Selenium developers suggest us to adhere is to implement Wait interface that defines the only one method until taking the object that incorporates the logic that is being checked as "until" condition in form of Function parameter. Fortunately there are some implementations of that interface. One of them is FluentWait class which we’ll be talking about here in the article.

FluentWait concept

FluentWait implements the interface Wait<F> demonstrated below with my comments.

wait interface en

Class that would implement this interface will have to describe the logic for until method that uses object of Function<? super F, T> as the parameter. According to the design until method returns the object of the same class as that function does.

One of the implementations of Wait interface is FluentWait class which logic is designed in the way to poll the conditional function with certain intervals until the code implemented as that Function's apply method returns either True, or not null object (of class T). That logic is applied to ? super F which means that the parameter of conditional function has to be either of class F or of its super class.

So basically when we want to use until method we need to pass some object which implements Function interface where the implementation logic has to handle object of F type as a parameter to that function and return object of T type.

Such design allows to use described waiting mechanism for any sort of events you’re able to capture, not only related to Selenium components and entities. However the thing we’re going to talk about is ExpectedConditions class that is designed to process events related to browser’s UI hence limit waiter usage.

How FluentWait works with ExpectedConditions

There are some set of predefined conditional functions in Selenium Java bindings. Each such predefined conditional function is defined by the interface

public interface ExpectedCondition<T> extends Function<WebDriver, T> {}

Basically this is the same Function but with fixed type of what we pass to that function as a parameter, namely - only WebDriver objects

So any of those predefined functions can be obtained by executing particular static method of ExpectedConditions class. For example lets see what is going on here:

public void testExpectedConditions(){
    Wait<WebDriver> waiter = new FluentWait<>(driver)
            .withTimeout(Duration.ofSeconds(10))
            .pollingEvery(Duration.ofSeconds(1));
    waiter.until(ExpectedConditions.titleIs("Expected Title"));
}

First of all by Wait<WebDriver> waiter = new FluentWait<>(…​); we are saying that our FluentWait will be working with conditional functions which accept WebDriver as a parameter. Then we pass driver object to FluentWait constructor so that it preserves the object the conditional function would be applied to.

We also configure timeout and polling interval. Note that we could do it in a one line (here I split it down into several lines for the sake of readability) because each method is doing two things: change the state of the object and returns the object itself. Such design has a special name. It is called Builder design pattern.

Then we call until method and pass the object that is returned by titleIs("Expected Title") static method of ExpectedConditions class.

Examining one of predefined conditions from ExpectedConditions class

Lets drill to that method and check how it is implemented:

  public static ExpectedCondition<Boolean> titleIs(final String title) {
    return new ExpectedCondition<Boolean>() {
      private String currentTitle = "";

      @Override
      public Boolean apply(WebDriver driver) {
        currentTitle = driver.getTitle();
        return title.equals(currentTitle);
      }

      @Override
      public String toString() {
        return String.format("title to be \"%s\". Current title: \"%s\"", title, currentTitle);
      }
    };
  }

We can see that it returns an object of ExpectedCondition<Boolean> class which is basically a Function<WebDriver, Boolean>.

FluentWait takes that object and calls public Boolean apply(WebDriver driver) method of that object passing a WebDriver that has been preserved using FluentWait constructor.

expectedconditions titleis en

If that method returns either Boolean.FALSE or null then FluentWait attempts to rerun the apply method unless the timeout has exceeded or either Boolean.TRUE or non-null object will be returned.

This is the logic how FluentWait works. Hope this will help you to use ExpectedConditions more effectively or even implement your own conditions. You can also check my another post where I explain how to implement custom conditions for FluentWait waiter in Selenium Java bindings.

If you still have the questions please send them to me using this form. I will amend the article according to your feedback.