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

We are exploring FluentWait of Selenium WebDriver in depth so that we can be fluent in FluentWait. If you have not read Part 1 yet, read it here.

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.

We have already seen a non-selenium related condition evaluating as Boolean. In this post, we will see again a non-selenium related condition evaluating a not null value.

Problem Statement 2 :-

There is a List of Integer values. I would like to pick randomly data from List and asserting with desired one. If it is a match, return otherwise keep checking till timeout.

Solution :-

We can use any loop to do the same but here we will use FluentWait to demonstrate the capability of FluentWaut.

package WaitExamples;

import java.time.Duration;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.function.Function;

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

public class FluentWaitForNotNullExample {
	
	
	public static void main(String[] args) {
		Random r = new Random();
		List numbers = Arrays.asList(1,2,3,4,5);
		
		// Setting FluentWait for Random r
		FluentWait wait = new FluentWait(r)
				// 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
		String word = wait.until(new Function() {
			@Override
			public String apply(Random r) {
				System.out.println("Time while checking condition :"+new Date());
				// It will pick a random index between 0 and size of number
				int current = r.nextInt(numbers.size());
				if(numbers.get( current) == 4)
				{
					// Return not null value
					return "Assigned Some Value "+ current;
				}
				// return null so that checking for condition will be continued
				return null;	
			}
		});

		System.out.println("Condition satisfied and value for word is : "+word);

	}

}

Output:-

Time while checking condition :Sat Apr 18 12:22:54 IST 2020
Time while checking condition :Sat Apr 18 12:22:56 IST 2020
Time while checking condition :Sat Apr 18 12:22:58 IST 2020
Time while checking condition :Sat Apr 18 12:23:00 IST 2020
Time while checking condition :Sat Apr 18 12:23:02 IST 2020
Condition satisfied and value for word is : Assigned Some Value 3

Note here that second type parameter ( String in above example ) matters most because that decides the return type of apply method. First type parameter may or may not be used inside apply method.

But there is a twist. Let’s see that.

From previous post, we are using StringBuiler to store data and we perfrom deletion operation on word. Let’s change the data type from StringBuilder to String.

Updated Code :-

package WaitExamples;

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

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


public class FluentWaitApplyTypeParamters {

	public static void main(String[] args) {

		String word = new String("FluentWait");

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

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

			}
		});

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

	}

}

Output:-

Time while checking condition :Sat Apr 18 14:29:32 IST 2020
Current Length of Word is 9
Time while checking condition :Sat Apr 18 14:29:37 IST 2020
Current Length of Word is 9
Time while checking condition :Sat Apr 18 14:29:42 IST 2020
Current Length of Word is 9
Time while checking condition :Sat Apr 18 14:29:47 IST 2020
Current Length of Word is 9
Time while checking condition :Sat Apr 18 14:29:52 IST 2020
Current Length of Word is 9
Time while checking condition :Sat Apr 18 14:29:57 IST 2020
Current Length of Word is 9
Time while checking condition :Sat Apr 18 14:30:02 IST 2020
Current Length of Word is 9
Exception in thread "main" org.openqa.selenium.TimeoutException: Expected condition failed: waiting for WaitExamples.FluentWaitApplyTypeParamters$1@5cd59c16 (tried for 30 second(s) with 5000 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)

Note above that length of string is not reduced like it was happening for StringBuilder. Reason is very simple. Reason is that String is immutable and StringBuilder is mutable. If you use any Wrapper class for primitive type, you will notice the same. If you use ArrayList, modification on List will impact actual reference. So, the parameter to apply method should be used carefully. When we define FluentWait for an instance , that is passed to apply method as parameter. Modification to this parameter may or may not change actual reference based on whether reference is mutable or immutable.

I hope you get a good idea about FluentWait now. Let’s see some Selenium related scenario where we can use FluentWait.

Problem Statement 3 :-

There is a link text that appears after sometime. So I need to wait till link text is displayed.

HTML Code :-







Wait till link text is displayed here :- 


Selenium Code :-

package WaitExamples;

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

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.FluentWait;

import io.github.bonigarcia.wdm.WebDriverManager;

public class WaitForLinkText {

	public static void main(String[] args) {

		// Browser initialization
		WebDriverManager.chromedriver().setup();
		WebDriver driver = new ChromeDriver();
		String fileURL = System.getProperty("user.dir");
		driver.get(fileURL + "/src/test/resources/htmlFiles/DynamicInnterText.html");
		WebElement linkText = driver.findElement(By.id("dynamicLink"));

		// Setting FluentWait for list
		FluentWait wait = new FluentWait(linkText)
				// Check for condition in every 2 seconds
				.pollingEvery(Duration.ofSeconds(2)).ignoring(IndexOutOfBoundsException.class)
				// Till time out i.e. 30 seconds
				.withTimeout(Duration.ofSeconds(30));
		
		wait.until(new Function() {
			@Override
			public Boolean apply(WebElement ele) {
				System.out.println("Rechecking at time "+new Date());
				return ele.getText().equals("Here You Go....");
			}
		});
		
		System.out.println("Condition satisfied.");
		driver.quit();
	}

}

Output :-

Rechecking at time Sat Apr 18 15:21:00 IST 2020
Rechecking at time Sat Apr 18 15:21:02 IST 2020
Rechecking at time Sat Apr 18 15:21:04 IST 2020
Rechecking at time Sat Apr 18 15:21:06 IST 2020
Rechecking at time Sat Apr 18 15:21:08 IST 2020
Rechecking at time Sat Apr 18 15:21:10 IST 2020
Rechecking at time Sat Apr 18 15:21:12 IST 2020
Rechecking at time Sat Apr 18 15:21:14 IST 2020
Rechecking at time Sat Apr 18 15:21:16 IST 2020
Rechecking at time Sat Apr 18 15:21:18 IST 2020
Rechecking at time Sat Apr 18 15:21:20 IST 2020
Condition satisfied.

Let’s twist the above scenario. Above we have located WebElement and waited for the desired link text. So we used type parameters as WebElement and Boolean. This time we will try to locate element with link text and will ignore NoSuchElementException till element is located or timeout reaches. So type parameters will be WebDriver and WebElement respectively.

package WaitExamples;

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

import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.FluentWait;

import io.github.bonigarcia.wdm.WebDriverManager;

public class WaitForElementWithLinkText {

	public static void main(String[] args) {

		// Browser initialization
		WebDriverManager.chromedriver().setup();
		WebDriver driver = new ChromeDriver();
		String fileURL = System.getProperty("user.dir");
		driver.get(fileURL + "/src/test/resources/htmlFiles/DynamicInnterText.html");

		// Setting FluentWait for list
		FluentWait wait = new FluentWait(driver)
				// Check for condition in every 2 seconds
				.pollingEvery(Duration.ofSeconds(2))
				// We need to ignore bcz element is displayed with delay
				.ignoring(NoSuchElementException.class)
				// Till time out i.e. 30 seconds
				.withTimeout(Duration.ofSeconds(30));
		
		WebElement ele = wait.until(new Function() {
			@Override
			public WebElement apply(WebDriver driver) {
				System.out.println("Rechecking at time "+new Date());
				return driver.findElement(By.linkText("Here You Go...."));
			}
		});
		
		System.out.println("Condition satisfied and text is "+ ele.getText());
		driver.quit();
	}

}

Output:-

Rechecking at time Sat Apr 18 15:29:55 IST 2020
Rechecking at time Sat Apr 18 15:29:57 IST 2020
Rechecking at time Sat Apr 18 15:29:59 IST 2020
Rechecking at time Sat Apr 18 15:30:01 IST 2020
Rechecking at time Sat Apr 18 15:30:03 IST 2020
Rechecking at time Sat Apr 18 15:30:05 IST 2020
Rechecking at time Sat Apr 18 15:30:07 IST 2020
Rechecking at time Sat Apr 18 15:30:09 IST 2020
Rechecking at time Sat Apr 18 15:30:11 IST 2020
Rechecking at time Sat Apr 18 15:30:13 IST 2020
Rechecking at time Sat Apr 18 15:30:15 IST 2020
Condition satisfied and text is Here You Go….

You can use methods of ExpectedConditions class as well with FluentWait if you create FluentWait class instance with WebDriver type. Example is as below :-

package WaitExamples;

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

import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import io.github.bonigarcia.wdm.WebDriverManager;

public class FluentWaitWithExpectedConditionsMethod {

	public static void main(String[] args) {

		// Browser initialization
		WebDriverManager.chromedriver().setup();
		WebDriver driver = new ChromeDriver();
		String fileURL = System.getProperty("user.dir");
		driver.get(fileURL + "/src/test/resources/htmlFiles/DynamicInnterText.html");

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

		WebElement ele = wait.until(ExpectedConditions.presenceOfElementLocated(By.linkText("Here You Go....")));

		System.out.println("Condition satisfied and text is " + ele.getText());
		driver.quit();
	}
}

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.

2 thoughts on “How to Fluent With FluentWait in Selenium WebDriver? – Part 2

  1. Unfortunately you have mentioned String as Mutable and StringBuffer as Immutable… Can you please make it correct. I know it would be a typo.

Leave a Reply

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