How to Fluent With FluentWait in Selenium WebDriver? – Part 1

Agenda :-

  1. Introduction of FluentWait
  2. Using FluentWait with a string
  3. Working mechanism of FluentWait

FluentWait is the most powerful wait mechanism provided by Selenium WebDriver but we may not able to take its whole advantages without knowledge of working mechanism of it.

Official document of FluentWait says that :-

Each FluentWait instance defines the maximum amount of time to wait for a condition, as well as the frequency with which to check the condition. Furthermore, the user may configure the wait to ignore specific types of exceptions whilst waiting.

Above definition states “wait for a condition” which is key idea behind FluentWait. Want to wait for ANYTHING irrespective of whether or not it is a selenium WebDriver scenario, use FluentWait.

FluentWait<T> implements a generic functional interface Wait<T>. A functional interface consists of only one abstract method. Wait interface consists of only method “until”. This interface is for waiting until a condition is true or not null.until” method implementation should wait until the condition evaluates to a value that is neither null nor false. Because of this contract, the return type must not be Void.

Let me point out some key points about FluentWait working mechanism :-

  1. Suppose We define a FluentWait instance for a type with a timeout , a polling interval for checking condition and a list of ignored exceptions.
  2. Condition will be checked and if it does not evaluates in either true or a not null value ( depends on what is specified ) , it will check for condition again after specified interval.
  3. If an exception is occurred which is in ignored list remaining statements in “apply” method will be skipped ( It is normal behavior in Java when an exception occurs.) and waiting for condition will be continued after specified interval.
  4. If occurred exception is not in ignored list, it will terminate waiting for condition. But remember we can handle that exception in try catch block within “apply” method. In that case execution will be continued.
  5. If condition is not satisfied within timeout, it will throw timeout exception.

Let’s try FluentWait for a condition which is not related to Selenium WebDriver.

Problem statement 1:-

There is a string with some initial value and periodically a character is removed from it. Now I need to wait till the length of string equals to an expected length i.e. if initial size of string is 10 , I want to wait till the length becomes 4. I would like to wait for sometime before checking length of string again i.e. a gap or time interval between two checks. I also would like to keep retrying for checking conditions for a maximum specific time i.e. 30 seconds. I am not ignoring any exception.

Solution :-

When Condition is satisfied

package WaitExamples;

import java.time.Duration;
import java.util.Date;

import org.openqa.selenium.support.ui.FluentWait;
import java.util.function.Function;

public class FluentWaitForStringLengthExample {

	public static void main(String[] args) {

		StringBuilder word = new StringBuilder("FluentWait");

		// Setting FluentWait for word
		FluentWait wait = new FluentWait(word)
				// Check for condition in every 2 seconds
				.pollingEvery(Duration.ofSeconds(2))
				// Till time out i.e. 30 seconds
				.withTimeout(Duration.ofSeconds(30));

		// Defining conditions to be checked
		wait.until(new Function() {
			@Override
			public Boolean apply(StringBuilder t) {
				System.out.println("Time while checking condition :"+new Date());
				// Delete first char of string
				t.deleteCharAt(0);
				System.out.println("Current Length of Word is " + t.length());
				return t.length() == 4;

			}
		});

		System.out.println("Condition satisfied.");

	}

}

Output :-

Observe that at every 2 seconds, condition is being checked.

Time while checking condition :Fri Apr 17 10:11:38 IST 2020
Current Length of Word is 9
Time while checking condition :Fri Apr 17 10:11:40 IST 2020
Current Length of Word is 8
Time while checking condition :Fri Apr 17 10:11:42 IST 2020
Current Length of Word is 7
Time while checking condition :Fri Apr 17 10:11:44 IST 2020
Current Length of Word is 6
Time while checking condition :Fri Apr 17 10:11:46 IST 2020
Current Length of Word is 5
Time while checking condition :Fri Apr 17 10:11:48 IST 2020
Current Length of Word is 4
Condition satisfied.

When Condition is not satisfied

Let’s change expected condition to some value which is not going to be true within specified time which will cause TimeOutException.

package WaitExamples;

import java.time.Duration;
import java.util.Date;

import org.openqa.selenium.support.ui.FluentWait;
import java.util.function.Function;

public class FluentWaitForStringLengthExampleTimeOut {

	public static void main(String[] args) {

		StringBuilder word = new StringBuilder("FluentWait");

		// Setting FluentWait for word
		FluentWait wait = new FluentWait(word)
				// Check for condition in every 2 seconds
				.pollingEvery(Duration.ofSeconds(2))
				// Till time out i.e. 10 seconds
				.withTimeout(Duration.ofSeconds(10));

		// Defining conditions to be checked
		wait.until(new Function() {
			@Override
			public Boolean apply(StringBuilder t) {
				System.out.println("Time while checking condition :"+new Date());
				// append a char of string
				t.append("F");
				System.out.println("Current Length of Word is " + t.length());
				// This is not possible within 10 seconds 
				return t.length() == 100;

			}
		});

		System.out.println("Condition satisfied.");

	}

}

Output:-

It will throw an exception on timeout.

Time while checking condition :Fri Apr 17 10:24:56 IST 2020
Current Length of Word is 11
Time while checking condition :Fri Apr 17 10:24:58 IST 2020
Current Length of Word is 12
Time while checking condition :Fri Apr 17 10:25:00 IST 2020
Current Length of Word is 13
Time while checking condition :Fri Apr 17 10:25:02 IST 2020
Current Length of Word is 14
Time while checking condition :Fri Apr 17 10:25:04 IST 2020
Current Length of Word is 15
Time while checking condition :Fri Apr 17 10:25:06 IST 2020
Current Length of Word is 16
Exception in thread "main" org.openqa.selenium.TimeoutException: Expected condition failed: waiting for WaitExamples.FluentWaitForStringLengthExampleTimeOut$1@50d0d1e9 (tried for 10 second(s) with 2000 milliseconds interval)
Build info: version: '4.0.0-alpha-5', revision: 'b3a0d621cc'
System info: host: 'WKWIN6962993', ip: '192.168.0.6', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_231'
Driver info: driver.version: unknown
	at org.openqa.selenium.support.ui.FluentWait.timeoutException(FluentWait.java:293)
	at org.openqa.selenium.support.ui.FluentWait.lambda$checkConditionInLoop$2(FluentWait.java:255)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

Little about method ‘until’ :-

until” method accepts a type Function from util package of Java.

It repeatedly applies this instance’s input value to the given function until one of the following occurs:

  1. the function returns neither null nor false
  2. the function throws an unignored exception
  3. the timeout expires
  4. the current thread is interrupted

Function interface represents a function i.e. apply that accepts one argument and produces a result. It has two type Parameters: <T> the type of the input to the function and <R> the type of the result of the function.

So in above example programs, we passed two type parameters “StringBuilder” and “Boolean“. “StringBuilder” is input to a function while Boolean is result of the function “apply“.

If you specify ‘R’ as a Boolean, it will return only if it finds true and If you use a non Boolean like a String or a reference variable, it will return only if it finds a not null value and it will keep looking for values till timeout expires.

When an exception is thrown while checking for a condition :-

We will not ignoring any exception which may occur while checking for a condition. There will be a situation in below program when length of string will be zero and while we try to delete a char at zeroth index it will give IndexOutOfBoundException. As it is not ignored or handled using try-catch ( You can not throw in apply method here – Read more about overriding of methods in Java.) , checking for condition will be terminated at line of exception.

package WaitExamples;

import java.time.Duration;
import java.util.Date;
import java.util.function.Function;

import org.openqa.selenium.support.ui.FluentWait;


public class FluentWaitForStringLengthExampleExceptionOccured {

	public static void main(String[] args) {

		StringBuilder word = new StringBuilder("FluentWait");

		// Setting FluentWait for word
		FluentWait wait = new FluentWait(word)
				// Check for condition in every 2 seconds
				.pollingEvery(Duration.ofSeconds(2))
				// Till time out i.e. 30 seconds
				.withTimeout(Duration.ofSeconds(30));

		// Defining conditions to be checked
		wait.until(new Function() {
			@Override
			public Boolean apply(StringBuilder t) {
				System.out.println("Time while checking condition :"+new Date());
				// Delete first char of string. This will give IndexOutOfBoundException when string size is 0
				t.deleteCharAt(0);
				System.out.println("Current Length of Word is " + t.length());
				return t.length() == 100;

			}
		});

		System.out.println("Condition satisfied.");

	}

}

Output :-

We will see that waiting for condition will be terminated when a unignored exception is thrown.

Time while checking condition :Fri Apr 17 11:04:23 IST 2020
Current Length of Word is 9
Time while checking condition :Fri Apr 17 11:04:25 IST 2020
Current Length of Word is 8
Time while checking condition :Fri Apr 17 11:04:27 IST 2020
Current Length of Word is 7
Time while checking condition :Fri Apr 17 11:04:29 IST 2020
Current Length of Word is 6
Time while checking condition :Fri Apr 17 11:04:31 IST 2020
Current Length of Word is 5
Time while checking condition :Fri Apr 17 11:04:33 IST 2020
Current Length of Word is 4
Time while checking condition :Fri Apr 17 11:04:35 IST 2020
Current Length of Word is 3
Time while checking condition :Fri Apr 17 11:04:37 IST 2020
Current Length of Word is 2
Time while checking condition :Fri Apr 17 11:04:39 IST 2020
Current Length of Word is 1
Time while checking condition :Fri Apr 17 11:04:41 IST 2020
Current Length of Word is 0
Time while checking condition :Fri Apr 17 11:04:43 IST 2020
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 0
	at java.lang.AbstractStringBuilder.deleteCharAt(AbstractStringBuilder.java:824)
	at java.lang.StringBuilder.deleteCharAt(StringBuilder.java:253)
	at WaitExamples.FluentWaitForStringLengthExampleExceptionOccured$1.apply(FluentWaitForStringLengthExampleExceptionOccured.java:29)
	at WaitExamples.FluentWaitForStringLengthExampleExceptionOccured$1.apply(FluentWaitForStringLengthExampleExceptionOccured.java:1)
	at org.openqa.selenium.support.ui.FluentWait.lambda$checkConditionInLoop$2(FluentWait.java:233)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

When expected exception is ignored

We will ignore IndexOutOfBoundException. When exception occurs, it will not stop waiting for condition but will skip remaining statement in apply method.

package WaitExamples;

import java.time.Duration;
import java.util.Date;
import java.util.function.Function;

import org.openqa.selenium.support.ui.FluentWait;


public class FluentWaitForStringLengthExampleExceptionOccured {

	public static void main(String[] args) {

		StringBuilder word = new StringBuilder("FluentWait");

		// Setting FluentWait for word
		FluentWait wait = new FluentWait(word)
				// Check for condition in every 2 seconds
				.pollingEvery(Duration.ofSeconds(2))
				// Till time out i.e. 15 seconds
				.withTimeout(Duration.ofSeconds(15))
				.ignoring(IndexOutOfBoundsException.class);

		// Defining conditions to be checked
		wait.until(new Function() {
			@Override
			public Boolean apply(StringBuilder t) {
				System.out.println("Time while checking condition :"+new Date());
				// Delete seventh char of string. This will give IndexOutOfBoundException when string has no chat at index 7
				t.deleteCharAt(7);
				System.out.println("Current Length of Word is " + t.length());
				return t.length() == 100;

			}
		});

		System.out.println("Condition satisfied.");

	}

}

Output:-

Time while checking condition :Fri Apr 17 11:17:58 IST 2020
Current Length of Word is 9
Time while checking condition :Fri Apr 17 11:18:00 IST 2020
Current Length of Word is 8
Time while checking condition :Fri Apr 17 11:18:02 IST 2020
Current Length of Word is 7
Time while checking condition :Fri Apr 17 11:18:04 IST 2020
Time while checking condition :Fri Apr 17 11:18:06 IST 2020
Time while checking condition :Fri Apr 17 11:18:08 IST 2020
Time while checking condition :Fri Apr 17 11:18:10 IST 2020
Time while checking condition :Fri Apr 17 11:18:12 IST 2020
Time while checking condition :Fri Apr 17 11:18:14 IST 2020
Exception in thread "main" org.openqa.selenium.TimeoutException: Expected condition failed: waiting for WaitExamples.FluentWaitForStringLengthExampleExceptionOccured$1@23ef2547 (tried for 15 second(s) with 2000 milliseconds interval)
Build info: version: '4.0.0-alpha-5', revision: 'b3a0d621cc'
System info: host: 'WKWIN6962993', ip: '192.168.0.6', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_231'
Driver info: driver.version: unknown
	at org.openqa.selenium.support.ui.FluentWait.timeoutException(FluentWait.java:293)
	at org.openqa.selenium.support.ui.FluentWait.lambda$checkConditionInLoop$2(FluentWait.java:255)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: 7
	at java.lang.AbstractStringBuilder.deleteCharAt(AbstractStringBuilder.java:824)
	at java.lang.StringBuilder.deleteCharAt(StringBuilder.java:253)
	at WaitExamples.FluentWaitForStringLengthExampleExceptionOccured$1.apply(FluentWaitForStringLengthExampleExceptionOccured.java:30)
	at WaitExamples.FluentWaitForStringLengthExampleExceptionOccured$1.apply(FluentWaitForStringLengthExampleExceptionOccured.java:1)
	at org.openqa.selenium.support.ui.FluentWait.lambda$checkConditionInLoop$2(FluentWait.java:233)
	... 6 more

You can handle exception in try catch as well.

There can be a tricky question. What will happen if you ignore TimeOutException only? Will check of condition continued even after specified timeout?

Answer is in definition only. We can ignore an exception which may occur during checking for a condition and after each check, it checks first if timeout is not reached. If it is reached, it will throw TimeoutException. It will not be ignored as it did not occur while checking condition, It was after checking condition.

We will continue this topic in part 2. Stay tuned.

You can clone the above example from my repo.

If you have any doubt, feel free to comment below.
If you like my posts, please like, comment, share and subscribe.
#ThanksForReading
#HappyLearning

You can find all Selenium related post here.
You can find all API manual and automation related posts here.
You can find frequently asked Java Programs here.

Leave a Reply

Your email address will not be published. Required fields are marked *