Working Mechanism of Explicit Wait in Selenium WebDriver – Java

Selenium WebDriver provides two types of waits mechanisms:-

  1. Implicit Wait
  2. Explicit WaitWebDriverWait and FluentWait

You can know about them in detail by going through the linked posts.

The default polling interval is 500 MS in explicit wait which can be overridden. We understand that the polling interval defines how often the condition should be evaluated. For example – If we set timeout as 10 seconds and polling interval as 2 seconds then the condition should be evaluated at 0th, 2nd,4th,6th,8th and 10th-second (which is not exactly correct) assuming the condition is not being satisfied in previous pollings.

Remember explicit wait is a dynamic wait that means waiting will be terminated as soon as the condition is satisfied or timeout exceeds. For example- If the explicit wait is defined as 20 seconds and within 5 seconds condition is satisfied then it will not wait for the remaining 15 seconds.

Example Program

package MixingWaitsExamples;

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

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;

public class GameOfPollingIntervalWithoutDelay {

	WebDriver driver;
		
	@Test
	public void mixinfWaitsForLocatingElement()
	{
		// Launching browser
		WebDriverManager.chromedriver().setup();
		driver = new ChromeDriver();
		
		// Loading URL
		driver.get("http://www.demoqa.com/");
		
		// Setting up explicit wait with polling interval as 2 seconds
		WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
		wait.pollingEvery(Duration.ofSeconds(2));
		
		// Timer starts
		System.out.println("Wait starts at : "+new Date());
	
		// Explicitly failing condition without any delay
		wait.until(new Function() {
			@Override
			public Boolean apply(WebDriver driver) {
				// Just to show you how polling works
				System.out.println("Retrying at : "+new Date());
				return false;
			}
		});
	}
	
	@AfterMethod
	public void printExitTime()
	{
		System.out.println("Wait ends at : "+new Date());
		driver.quit();
	}
}

As we can see condition was checked 6 times with an interval of 2 seconds.

If you observe apply() method above where I am returning ‘false’ without any delay. Let’s twist it little and return false after some delay.

package MixingWaitsExamples;

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

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;

public class GameOfPollingIntervalWithDelay {

	WebDriver driver;

	@Test
	public void mixinfWaitsForLocatingElement() {
		// Launching browser
		WebDriverManager.chromedriver().setup();
		driver = new ChromeDriver();
		
		// Loading URL
		driver.get("http://www.demoqa.com/");
		
		// Setting up explicit wait with polling interval as 2 seconds
		WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
		wait.pollingEvery(Duration.ofSeconds(2));
		
		// Timer starts
		System.out.println("Wait starts at : " + new Date());

		// Explicitly failing condition with 2 seconds delay
		wait.until(new Function() {
			@Override
			public Boolean apply(WebDriver driver) {
				System.out.println("Retrying at : " + new Date());
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return false;
			}
		});
	}

	@AfterMethod
	public void printExitTime() {
		System.out.println("Wait ends at : " + new Date());
		driver.quit();
	}
}

Output

Did you observe that the actual polling interval is 4 seconds instead of 2 seconds?

Polling Interval in Explicit Wait = Time Taken To Return Response Of Previous Poll + Polling Interval

In the apply() method, I have delayed the result of the condition by 2 seconds. When it polls the first time i.e. 0th second then the result of condition evaluation comes after 2 seconds. Now from here, polling interval of 2 seconds will start and at 4th second another polling will happen not at 2nd second. Refer below flow diagram:-

Internal code implementtaion

We know FluentWait class implements the Wait interface and overrides the “until()” method as shown below.

CompletableFuture is a class that allows you to run a function asynchronously or non-blocking or on a different thread other than the main thread. The expected condition is checked asynchronously by calling supplyAsync() method and get() is to wait if necessary for at most the given time for this condition to complete, and then returns its result, if available. Please note here that the timeout passed to this get() method in until() method is explicit timeout + polling interval. See the code snippet below:-

get() method will terminate the waiting abruptly if timeout exceeds. An example program is below:-

package MixingWaitsExamples;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.testng.annotations.Test;

public class CompletableFutureExample {
	
	
	@Test
	public void thenApplyAsync() throws InterruptedException, ExecutionException, TimeoutException {  
	    // A function which will be completed in 10 seconds but in get method I have timeout as 5.
		String completableFuture = CompletableFuture.supplyAsync(() -> {
	    		try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	    		return "Amod";
	    
	    }).get(5, TimeUnit.SECONDS);

	    System.out.println(completableFuture);
		

	}

}

Output

Now see the implementation in simple words for checkConditionInLoop() method.

  1. Explicit Timeout is added to the current time (Instant end) to get the end time. In simple words, if we define explicit timeout as 30 seconds and the current time is 12:30:30 then after adding 30 seconds of the timeout, the end time will be 12:31:00. Cut off time.
  2. In a loop, check for the condition. If it is a true or not null return it and No more waiting. If the condition is not evaluated either in true or not null then check if explicit time out is reached (Step 1) i.e. if end.isBefore(clock.instant()). If yes exit loop with a timeout message. If the timeout is not reached, sleep for a specified interval.

From the above implementation there are some important points to be noted:-

  1. When the condition is not satisfied and timeout is not reached then thread will be sleeping for a specified polling interval. It means if 5 seconds are taken by apply() method to return a result (either false or null) then the polling interval will start from 6th seconds onward.
  2. There is no check on the remaining timeout before we make a thread sleep. For example:- If the polling interval is defined as 10 seconds and we have only 2 seconds left for explicit timeout then also it will go for a complete 10 seconds sleep. After sleep, it will go for the checking of condition again which will be abruptly terminated by get() method after some seconds as explicit timeout was already reached. This increases the explicit timeout.
  3. While a thread is sleeping and it crosses explicit timeout then also condition checking will be started. get() method will make a decision here to terminate it.

Scenarios to understand the above concepts

Scenario 1:-

Defined explicit wait timeout = 10 seconds
Polling interval = 2 seconds
Time taken for condition to be evaluated = 20 Seconds

Expected output

get() method of CompletableFuture class will have timeout as 10s (Explicit timeout) +2s (Polling interval) = 12 seconds. Since the condition will be evaluated in 20 seconds and there is no chance to go to a statement where end time is checked to terminate waiting. get() method will act here. When the condition evaluation reaches 12 seconds, waiting should be terminated by get() by throwing TimeoutException with the message as “Supplied function might have stalled”.

package MixingWaitsExamples;

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

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;

public class GameOfPollingIntervalWithLongerDelay {

	WebDriver driver;

	@Test
	public void pollingIntervalExample() {
		
		// Launching browser
		WebDriverManager.chromedriver().setup();
		driver = new ChromeDriver();
		
		// Loading URL
		driver.get("http://www.demoqa.com/");
		
		// Setting up explicit wait polling interval as 2 seconds
		WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
		wait.pollingEvery(Duration.ofSeconds(2));
		// Timer starts
		System.out.println("Wait starts at : " + new Date());
		
		// Explicitly failing condition with 20 seconds delay
		wait.until(new Function() {

			@Override
			public Boolean apply(WebDriver driver) {
				System.out.println("Retrying at : " + new Date());
				try {
					Thread.sleep(20000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return false;
			}
		});
	}

	@AfterMethod
	public void printExitTime() {
		System.out.println("Wait ends at : " + new Date());
		driver.quit();
	}
}

Actual output:-

Expected Output = Actual Output

Scenario 2:-

Defined explicit wait timeout = 10 seconds
Polling interval = 8 seconds
Time taken for condition to be evaluated = 20 Seconds

There is no difference between scenario 1 and scenario 2 except increased polling interval. The expected output should be timeout by get() method after 18 seconds. The explanation is the same as above.

package MixingWaitsExamples;

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

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;

public class GameOfPollingIntervalWithLongerDelay {

	WebDriver driver;

	@Test
	public void pollingIntervalExample() {
		
		// Launching browser
		WebDriverManager.chromedriver().setup();
		driver = new ChromeDriver();
		
		// Loading URL
		driver.get("http://www.demoqa.com/");
		
		// Setting up explicit wait polling interval as 8 seconds
		WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
		wait.pollingEvery(Duration.ofSeconds(8));
		// Timer starts
		System.out.println("Wait starts at : " + new Date());
		
		// Explicitly failing condition with 20 seconds delay
		wait.until(new Function() {

			@Override
			public Boolean apply(WebDriver driver) {
				System.out.println("Retrying at : " + new Date());
				try {
					Thread.sleep(20000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return false;
			}
		});
	}

	@AfterMethod
	public void printExitTime() {
		System.out.println("Wait ends at : " + new Date());
		driver.quit();
	}
}

Output

Expected Output = Actual Output

Scenario 3:-

Defined explicit wait timeout = 10 seconds
Polling interval = 15 seconds
Time taken for condition to be evaluated = 20 Seconds

Again there is no difference between Scenario 1, 2, and 3 except increased polling interval. But note here that polling interval is greater than the explicit timeout which was not in the first two scenarios.

Expected output

get() method of CompletableFuture class will have timeout as 10s (Explicit timeout) +15s (Polling interval) = 25 seconds. The condition will be evaluated in 20 seconds which is lesser than timeout for get() method i.e. 25 seconds. In this case, the condition will be evaluated for 20 seconds without any interruption and it will go to next check of end of the timeout. Since it has crossed timeout ( 10 seconds ) already, it will throw TimeoutException with a message “Expected condition failed”.

package MixingWaitsExamples;

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

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;

public class GameOfPollingIntervalWithLongerDelay {

	WebDriver driver;

	@Test
	public void pollingIntervalExample() {
		
		// Launching browser
		WebDriverManager.chromedriver().setup();
		driver = new ChromeDriver();
		
		// Loading URL
		driver.get("http://www.demoqa.com/");
		
		// Setting up explicit wait polling interval as 15 seconds
		WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
		wait.pollingEvery(Duration.ofSeconds(15));
		// Timer starts
		System.out.println("Wait starts at : " + new Date());
		
		// Explicitly failing condition with 20 seconds delay
		wait.until(new Function() {

			@Override
			public Boolean apply(WebDriver driver) {
				System.out.println("Retrying at : " + new Date());
				try {
					Thread.sleep(20000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return false;
			}
		});
	}

	@AfterMethod
	public void printExitTime() {
		System.out.println("Wait ends at : " + new Date());
		driver.quit();
	}
}

Actual Output

Expected output = = Actual Output

Scenario 4:-

Defined explicit wait timeout = 30 seconds
Polling interval = 15 seconds
Time taken for condition to be evaluated = 5 Seconds

Expected output:-

get() method of CompletableFuture class will have timeout as 30s (Explicit timeout) +15s (Polling interval) = 45 seconds. The condition will be evaluated in 5 seconds. It will go in below flow:-

At 0th second => 5 seconds to evaluate condition => 5 seconds gone

At 6th second => Explicit timeout not reached => Sleep for 15 seconds = 20 Seconds gone

At 21st second => 5 seconds to evaluate condition => 25 seconds gone

At 26th second => Explicit timeout not reached ( Only 5 seconds more left but still) => Sleep for 15 seconds = 40 Seconds gone

At 41st second => Again condition will be evaluated after sleep =As soon as it reaches 45 seconds , get() will terminate waiting and it will throw TimeoutException with a message “Expected condition failed”.

package MixingWaitsExamples;

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

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;

public class GameOfPollingIntervalWithLongerDelay {

	WebDriver driver;

	@Test
	public void pollingIntervalExample() {
		
		// Launching browser
		WebDriverManager.chromedriver().setup();
		driver = new ChromeDriver();
		
		// Loading URL
		driver.get("http://www.demoqa.com/");
		
		// Setting up explicit wait polling interval as 15 seconds
		WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
		wait.pollingEvery(Duration.ofSeconds(15));
		// Timer starts
		System.out.println("Wait starts at : " + new Date());
		
		// Explicitly failing condition with 5 seconds delay
		wait.until(new Function() {

			@Override
			public Boolean apply(WebDriver driver) {
				System.out.println("Retrying at : " + new Date());
				try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return false;
			}
		});
	}

	@AfterMethod
	public void printExitTime() {
		System.out.println("Wait ends at : " + new Date());
		driver.quit();
	}
}

Actual Output

Expected output = = Actual Output

If you observe output carefully you will see different stack traces for above-discussed scenarios. You see sometimes as “Supplied function might have stalled” or “Expected condition failed“. If WebDriver terminates in between or without evaluating the condition you get “Supplied function might have stalled” and when the condition is evaluated as false or null after timeout you get ” Expected condition failed “.

Selenium WebDriver says that:-

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.

The reason for the above statement is implementation which we have seen already. Custom polling interval may cause an extended timeout. I will cover this in different topic.

You can download/clone the above sample project from here.

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

Find all Selenium related posts here, all API manual and automation related posts here, and find frequently asked Java Programs here.

Many other topics you can navigate through the menu.

1 thought on “Working Mechanism of Explicit Wait in Selenium WebDriver – Java

  1. How to overcome “supplied function might have stalled”…in my case explicit time out is 240 with default polling. Also expected condition is waitfor visibilityof(element).

Leave a Reply

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