Here is our latest submission to the series of Selenium Webdriver commands. In this tutorial, we’ve brought you a new perspective on the Webdriver Fluent Wait command. This post will highlight the most used Fluent Wait methods and provide a step-by-step description of their usage in your projects.
Why should we use fluent wait with Webdriver?
In all modern web applications which use HTML5 and AJAX for their user interface, the Fluent Wait command is the best way to handle dynamic locators. It is an advanced Webdriver wait method that reduces the chances of errors and increases stability. Another Webdriver command which you can use to manage waits is the Webdriver Wait command.
Perhaps you should refer to our post which discusses the Webdriver Wait command at length. After reading both of these posts, you would get a fair idea of the Wait commands. And you’ll be able to choose the right one from these Selenium Webdriver commands as per the context you are working.
Your choice of using the Webdriver Wait command would depend on the nature of the web application. With the introduction of Ajax applications in the Web world, we have web elements which sometimes visible in just a second and sometimes take minutes to appear.
In such cases, it’s better to make use of the Fluent Wait command as this wait tries to find the web element repeatedly at regular intervals until the timeout or till the object gets found.
How to use fluent wait?
Fluent Wait uses the following two parameters.
- Timeout value: The maximum amount of time to wait for a condition, and
- Polling frequency: The frequency to check the success or failure of a specified condition.
If you want to configure the wait to ignore exceptions such as <NoSuchElementException>, then you can add it to the Fluent Wait command syntax. Below is a sample code that shows the implementation of Fluent Wait.
Wait wait = new FluentWait(driver) .withTimeout(30, SECONDS) .pollingEvery(5, SECONDS) .ignoring(NoSuchElementException.class); WebElement foo = wait.until(new Function() { public WebElement apply(WebDriver driver) { return driver.findElement(By.id("foo")); } });
Here is the step-by-step analysis of the above sample code.
Step-1: Fluent Wait starts with capturing the start time to determine the delay.
Step-2: Fluent Wait then checks the condition defined in the until() method.
Step-3: If the condition fails, Fluent Wait makes the application wait as per the value set by the <pollingEvery(5, SECONDS)> method call. Here in this example, it’s 5 seconds.
Step-4: After the wait defined in Step 3 expires, the start time is checked against the current time. If the difference between the wait start time (set in step-1) and the current time is less than the time set in <withTimeout(30, SECONDS)> method, then Step-2 will need to repeat.
The above steps will recur until either the timeout expires or the condition becomes true. In the next section, we’ll see a summary of the most used Fluent Wait methods which could be very useful in implementing Fluent Wait.
Various methods of fluent wait command
a) withTimeout
public FluentWait<T> withTimeout(long duration, java.util.concurrent.TimeUnit unit) Parameters: duration - The timeout duration. unit - The unit of time. Returns: A self-reference.
The above method sets the wait for the condition to become true. The default timeout is FIVE_HUNDRED_MILLIS.
b) withMessage
public FluentWait<T> withMessage(java.lang.String message) Parameters: message - to be appended to default. Returns: A self-reference.
The above method sets the message which would appear after the timeout.
c) pollingEvery
public FluentWait<T> pollingEvery(long duration, java.util.concurrent.TimeUnit unit) Parameters: duration - The timeout duration. unit - The unit of time. Returns: A self-reference.
This method sets the frequency of conditions that should be evaluated. The default polling interval is FIVE_HUNDRED_MILLIS.
d) ignoring
public FluentWait<T> ignoring(java.lang.Class<? extends java.lang.Throwable> firstType, java.lang.Class<? extends java.lang.Throwable> secondType) Parameters: firstType - exception to ignore. secondType - another exception to ignore. Returns: a self-reference.
This method lists the exception that you want to skip when the timeouts.
e) until
public void until(com.google.common.base.Predicate<T> isTrue) Parameters: isTrue - The predicate to wait on. Throws: TimeoutException - If the timeout expires.
It’ll apply the instance’s input value to the given predicate until the timeout occurs or the predicate becomes true.
f) until
public<V>V until(com.google.common.base.Function<? super T,V> isTrue) Specified by: until in interface Wait<T> Type Parameters: V - The function expected return type. Parameters: isTrue - the parameter to pass to the ExpectedCondition. Returns: The functions return value if the function returned something different from null or false before the timeout expired. Throws: TimeoutException- If the timeout expires.
It’ll apply the instance’s input value to the given function until one of the following conditions occurs:
- The function returns neither null nor false.
- The function throws an unignorable exception.
- The timeout expires.
- The current thread gets interrupted.
g) timeoutException
protected java.lang.RuntimeException timeoutException(java.lang.String message, java.lang.Throwable lastException) Parameters: message - The timeout message. lastException - The last exception to be thrown and subsequently suppressed while waiting on a function. Returns: Nothing will ever be returned; this return type is only specified as a convenience.
This method throws a timeout exception.
Note
Recommended – How to create a Selenium Webdriver in Eclipse IDE?
Fluent wait examples with sample code
Since the main logic of Fluent Wait revolves around a function and a predicate, so we’ll take up examples using these constructs. Also, we’ll give ready-to-use sample code so that you can use it directly in your projects.
Using function() to write sample code
Package: com.google.common.base.Function
A Function is a general interface that requires the class to define the following method.
Function < WebDriver, Boolean > function = new Function < WebDriver, Boolean > () { public Boolean apply(WebDriver arg0) { return null; } };
The above apply() method takes the Webdriver as an input argument and returns either true or false. Alternatively, we can derive this info from the below syntax:
Function <WebDriver, Boolean>.
It signifies that the first input parameter is the argument to the apply() method and the second indicates its return type. Also, you must note that without importing the <com.google.common.base.Function> package, your Fluent Wait code may not compile instead will throw errors.
User Case and the HTML Code
Let’s now review the use case which we want to automate.
There is a simple button on the web page. The button gets highlighted in few seconds. We have to verify the color code of the highlighted text.
Below is the HTML code for the web page which we’ll use to demonstrate the given use case scenario.
You must save the HTML code in a file as <fluentWaitCommandDemoPage.html>. And then, you’ll need to add this file to your Selenium Webdriver project. In our samples, we’ll load this file to launch with the Firefox browser for running the tests.
<html> <head> <script> var timer1 = setInterval(dynamicColor, 2000); var timer2 = 0; function dynamicColor() { document.getElementById("dynamicColor").style.color="yellow"; clearInterval(timer1); timer2 = setInterval(dynamicText, 2000); } var counter1 = 0; function dynamicText() { var mydiv = document.getElementById("dynamicText"); var newElement = document.createElement('a'); newElement.setAttribute('href',"http://www.goole.com/"); newElement.setAttribute('id', "target"); newElement.innerHTML = "dynamicText" + counter1; mydiv.appendChild(newElement); if(counter1 > 5) { clearInterval(timer2); } counter1 = counter1 + 1; } </script> </head> <body> <h1>Webdriver Commands Example.</h1> <p id="dynamicText"></p> <p> <button id="dynamicColor" style="color: white;">Dynamic Color</button> </p> </body> </html>
Please note- If you have changed the location of this file (i.e. not adding it to the project), then please provide its correct path in the sample code before execution.
// Say, you have put the HTML file to a different location. // Then, don't use the below two lines. Instead, use the code given next. String workingDir = System.getProperty("user.dir"); driver.get(workingDir + "\\fluentWaitCommandDemoPage.html"); // Update HTML file path and use the below code. driver.get("<Absolute Path of> fluentWaitCommandDemoPage.html");
When you would run the sample code, it’ll launch the HTML page. The page would look like the one given below at runtime.
Below is the code implementing the apply() method for the above scenario. It will return false if the condition fails. And will return true if the condition becomes true. The apply() method will return false if the button is not highlighted (yellow) else it will return true.
Fluent wait: sample code using the function()
This code is fully functional. And you only need to copy/paste it to your project in Eclipse.
package com.techbeamers.fluentwait; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.support.ui.FluentWait; import com.google.common.base.Function; public class TestFunction { public static void main(String[] args) throws InterruptedException { WebDriver driver = new FirefoxDriver(); String workingDir = System.getProperty("user.dir"); driver.get(workingDir + "\\fluentWaitCommandDemoPage.html"); FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver); wait.pollingEvery(250, TimeUnit.MILLISECONDS); wait.withTimeout(2, TimeUnit.SECONDS); Function<WebDriver, Boolean> function = new Function<WebDriver, Boolean>() { public Boolean apply(WebDriver arg0) { WebElement element = arg0.findElement(By.id("dynamicColor")); String color = element.getCssValue("color"); System.out.println("The button text has color :" + color); if (color.equals("rgba(255, 255, 0, 1)")) { return true; } return false; } }; wait.until(function); } }
After you run the above code, it’ll display the following output.
The button text has color :rgba(255, 255, 255, 1) The button text has color :rgba(255, 255, 255, 1) The button text has color :rgba(255, 255, 255, 1) The button text has color :rgba(255, 255, 0, 1)
You can see that the function made four attempts to check the color of the button. And in the last attempt, it found the target color which is yellow. It’s a success case which would cause the wait condition to end.
Fluent wait: sample code – part 2
You can also use a function to return objects in place of a Boolean value. In this case, the apply() method will return null until the time object is not available. Let’s take an example code. In the same HTML test page, we have a new object added dynamically after every few seconds. This object has an <id=”dynamicText”>. In this example, we will wait for this object using a fluent wait.
package com.techbeamers.fluentwait; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.support.ui.FluentWait; import com.google.common.base.Function; public class CheckElement { public static void main(String[] args) throws InterruptedException { WebDriver driver = new FirefoxDriver(); String workingDir = System.getProperty("user.dir"); driver.get(workingDir + "\\fluentWaitCommandDemoPage.html"); FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver); wait.pollingEvery(250, TimeUnit.MILLISECONDS); wait.withTimeout(2, TimeUnit.MINUTES); wait.ignoring(NoSuchElementException.class); // We need to ignore this exception. Function<WebDriver, WebElement> function = new Function<WebDriver, WebElement>() { public WebElement apply(WebDriver arg0) { System.out.println("Checking for the object!!"); WebElement element = arg0.findElement(By.id("dynamicText")); if (element != null) { System.out.println("A new dynamic object is found."); } return element; } }; wait.until(function); } }
Here is the result.
Checking for the object!! A new dynamic object is found.
Fluent wait: sample code – part 3 using predicate
A predicate is similar to a function. But it always returns a Boolean expression. You can use it in the following manner.
Predicate < WebDriver > predicate = new Predicate < WebDriver > () { public boolean apply(WebDriver arg0) { return false; } };
Now see some real action in the example below. The code for the above scenario using Predicate is like this.
package com.techbeamers.fluentwait; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.support.ui.FluentWait; import com.google.common.base.Predicate; public class PredicateTest { public static void main(String[] args) throws InterruptedException { WebDriver driver = new FirefoxDriver(); String workingDir = System.getProperty("user.dir"); driver.get(workingDir + "\\fluentWaitCommandDemoPage.html"); FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver); wait.pollingEvery(250, TimeUnit.MILLISECONDS); wait.withTimeout(2, TimeUnit.MINUTES); wait.ignoring(NoSuchElementException.class); // We need to ignore this exception. Predicate<WebDriver> predicate = new Predicate<WebDriver>() { public boolean apply(WebDriver arg0) { WebElement element = arg0.findElement(By.id("dynamicColor")); String color = element.getCssValue("color"); System.out.println("The button text has color :" + color); if (color.equals("rgba(255, 255, 0, 1)")) { return true; } return false; } }; wait.until(predicate); } }
Here si the output.
The button text has color :rgba(255, 255, 255, 1) The button text has color :rgba(255, 255, 255, 1) The button text has color :rgba(255, 255, 255, 1) The button text has color :rgba(255, 255, 0, 1)
Footnote – Webdriver Fluent Wait with Examples
We hope that the post “Selenium Webdriver Fluent Wait Command with Examples” would drive you on using the Fluent Wait in current projects. We have verified all the code used in this post is compilable and should run without any errors.
If you have any queries on the post or otherwise, then please don’t hesitate and write to us. We’ll try our best to respond as early as possible.
Best,
TechBeamers