As someone who has just started their learning in software testing, how would you tackle the following scenario – elements loading at different times to save bandwidth and increase load speeds? You might say that we target the ID of the element as even if its visibility is set to none, the element would still exist in the code. However, this is not true each time. A lot of the time the developers create a new element while the user is browsing the page. Sometimes the user’s actions themselves define what types of elements will be created and their respective IDs. So, we can conclude that targeting ID directly is probably not a good idea. If we ask the same question to a QA expert, the first they might say is, “What about WebDriverWait or explicit waits in Selenium?”
This is probably true. What could seem like a complex problem as per today’s web development standard can easily be resolved by working with Selenium Waits. However, to cater to different needs, Selenium developers have provided two different types of Waits in their arsenal:
- Implicit Wait – One that is implicit or understood for each element.
- Explicit Wait – One that is explicit or declared with conditions.
The first one has been covered extensively in our implicit wait tutorial along with examples and code. Before starting this tutorial, it is recommended to go through implicit waits in Selenium once as a reference to compare the two. Nevertheless, in this post, we will focus on Explicit wait, its types and code implementation using Selenium and IntelliJ.
Table of Contents
- What is explicit wait in Selenium?
- When to use explicit wait in Selenium?
- Types of explicit wait in Selenium
- WebDriverWait Class in Selenium
- How to check the internal polling time for WebDriverWait?
- FluentWait in Selenium
What is Explicit Wait in Selenium?
LS: I think it is still not clear to you what is the difference:
Implicitly wait for the element but not on the property of the element, There can be a situation where the element is present in DOM but not visible, in that case, Implicit wait won’t work. This just waits for the element to be present in the DOM, nothing else. SO ideally even if u put implicit time out as 500 seconds, it won’t do any harm. The only harm would be in case of failed test it is going to take 500 seconds to fail a test.Just saying.
ExplicitWait waits on the condition mean it waits for the specific property. All of these properties are in ExpectedCondiotions.
Changes are made but no specific reference to implicit has been given. Assuming that the above written para was for my understanding.
Explicit wait in Selenium is a mechanism to wait for an element based on a condition before executing the script ahead. So, if I have an element that loads in 5 seconds, I can implement explicit wait with that specific condition and maximum time as 5 seconds before executing the click statement. Since I am looking for a specific element here (through XPath or ID etc.), explicit wait in Selenium would not affect other elements naturally. However, if the element is found before the specified duration, the execution resumes from that point without waiting till the maximum specified time. As in the above instance, even if the specified duration is 7 seconds, Selenium will find the element in the 5th second and then continue with the code.
As far as explicit waits are concerned, the above definition completes only half of the process. The next half is the polling time. A polling time is the time duration that tells Selenium about how frequently it should wait for the element. If it is set to 2 seconds, Selenium looks for the element every two seconds. However, it is defined differently in different types of explicit waits.
When to use Explicit Wait in Selenium?
The next question that arises here is when should I use explicit wait in Selenium? Can it be used any time or do some specific conditions require you to fulfil explicit wait? The following popular reasons may satisfy this query based on the community’s responses on various forums.
When you need to on conditions rather than visibility
The first reason is hidden in the core working methodology of explicit wait. Implicit waits in Selenium get applied to all the elements and depend on an element’s availability in the DOM. Explicit waits, on the other hand, work along with the given condition i.e. seeking out for the condition to become true. If your current requirement wants you to implement waits based on a condition or a specific property for a specific element (not for all of them), it would be better to use explicit wait. You can improve this with the above understanding. say condition/property makes more sense.
When there are a large number of elements
In the above-mentioned scenario, you can also implement implicit wait with waiting time as the maximum of all the element’s load times. So if there are two elements loading in 4 seconds and 7 seconds respectively, you can put the wait time as 7 seconds and that will cover both of them. However, this method can only work when the web page is relatively simple with very few elements on board. Practically, this would never happen. If you are opting for automation testing using Selenium, you are working on pages that actually require automation and they will be very complex with hundreds of elements.
When elements use AJAX to appear
One of the most common reasons (or the standard) has become to choose WebDriverWait is when the web page uses AJAX elements. An AJAX element works asynchronously and therefore its time of appearance depends on different things defined by the developer in the AJAX functions. For example, like Facebook, the data populates only when you scroll down to save the bandwidth. When such elements are on the web page, the explicit wait is the way to go.
Types of explicit wait in Selenium
Selenium offers a lot of commands in the explicit wait section. However, they are confined into two major classes:
- WebdriverWait
- FluentWait
Let’s explore them individually.
WebDriverWait Class in Selenium
The WebDriverWait class extends the Selenium Wait interface that implements explicit waits. The class takes the WebDriver instance and the specified duration as an argument to work.
The syntax of WebDriverWait looks as follows:
1 |
WebDriverWait finder = new WebDriverWait(driver, Duration.ofSeconds(5)); |
Here “driver” is a WebDriver instance and the maximum specified time is 5 seconds. Also, to inherit all the functions and constructors of WebDriverWait, you need to import WebDriverWait. Adding the following import will work:
1 |
import org.openqa.selenium.support.ui.WebDriverWait; |
Next, we need to specify the condition for which WebDriverWait will look and halt the execution based on it. The conditions can be called with the same WebDriverWait instance initialized in the code. In our syntax example, it is defined as “finder”.
1 |
finder.until(ExpectedConditions.titleIs("ToolsQA")); |
In the above code, we have put the condition for the title of the page to be equal to the string “ToolsQA”. The following import will help achieve the same:
1 |
import org.openqa.selenium.support.ui.ExpectedConditions; |
If we combine all the above codes, in theory, we are looking to wait for a maximum of 5 seconds until the webpage’s title becomes “ToolsQA” if it is not already. If it becomes before or during 5 seconds, it is well and good. Otherwise, the test fails.
We will try to test our code but before that, we need to answer one simple question. If the WebDriverWait waits for 5 seconds (with reference to our example), then what is the frequency (or interval or polling time) in which it looks for our element before the timeout?
How to check the internal polling time for WebDriverWait?
To answer this question, Press Ctrl + Click on WebDriverWait in IntelliJ and the definition of the class will open up. It looks as follows:
In this definition, the duration of thread sleep is defined as DEFAULT_SLEEP_TIMEOUT which is a macro and hovering over it will show the number 500. Hence, with this, we can conclude that when we look for an element with WebDriverWait, internally, it keeps looking for it every 500 milliseconds.
WebDriverWait Example Code
Coming back, let’s run the code and check the results of our WebDriverWait class. In the following code, we will make use of WebDriverWait class to check if the page we are accessing has the title name “Tools QA” or not.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package org.example; import java.time.Duration; import org.junit.Test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; public class ExplicitWait { protected WebDriver driver; @Test public void ExplicitWait() { driver = new ChromeDriver(); driver.get("https://demoqa.com"); WebDriverWait finder = new WebDriverWait(driver, Duration.ofSeconds(5)); finder.until(ExpectedConditions.titleIs("Tools QA")); //close browser driver.close(); } } |
Execute the above test and observe the following events:
- The Chrome browser opens up and URL is set to https://demoqa.com.
- Selenium checks for the title as “Tools QA” but the actual title is found as “ToolsQA”.
- Selenium waits for 5 seconds for the title to change to “Tools QA”.
- Since the title remains “ToolsQA” even after 5 seconds, our test fails.
- You can also observe the same in the log that would look similar to the following:
As the log says, Selenium “tried for 5 seconds with 500 ms interval” which is what we expected.
The tester can also use other types of conditions available in the class explained in detail in Expected conditions in Selenium Wait. Additionally, you may also change the syntax and write the same function (specifically WebDriverWait initialization) in the following alternate ways:
1 2 3 4 5 6 7 8 |
public void ExplicitWait() { driver = new ChromeDriver(); driver.get("https://demoqa.com"); Boolean finder = new WebDriverWait(driver, Duration.ofSeconds(5)).until(ExpectedConditions.titleIs("Tools QA")); //close browser driver.close(); } |
Or skip the LHS part completely as follows:
1 2 3 4 5 6 7 8 |
public void ExplicitWait() { driver = new ChromeDriver(); driver.get("https://demoqa.com"); new WebDriverWait(driver, Duration.ofSeconds(5)).until(ExpectedConditions.titleIs("Tools QA")); //close browser driver.close(); } |
Note: All these snippets are just the variation of the same thing that we demonstrated above. The outcomes and execution still remain the same.
FluentWait in Selenium
Another type of class in Selenium is FluentWait. It extends the Wait interface also extended by WebDriverWait. Since both are deriving from the same interface, they both are almost similar with similar functions beneath them except for minor changes that make FluentWait a bit more flexible and controllable.
The syntax of FluentWait is as follows:
1 2 3 4 |
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver) .withTimeout(Duration.ofSeconds(30)) .pollingEvery(Duration.ofSeconds(5)) .ignoring(NoSuchElementException.class); |
This syntax contains 3 function calls:
- withTimeout – Defines the maximum time to wait.
- pollingEvery – Defines the interval frequency in seconds.
- ignoring – Defines the exception the tester wants to ignore.
Also, observe that the LHS contains the Wait instance which signifies the inheritance hierarchy.
FluentWait Example Code
To demonstrate the working of FluentWait, we will use the page https://demoqa.com/dynamic-properties in which one element appears after five seconds. Use the below code on the same page using ChromeDriver to locate that element:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package org.example; import java.time.Duration; import org.openqa.selenium.NoSuchElementException; import java.util.concurrent.TimeUnit; import java.util.function.Function; import org.junit.Test; 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.*; public class ExplicitWait { protected WebDriver driver; @Test public void ExplicitWait() { driver = new ChromeDriver(); driver.get("https://demoqa.com/dynamic-properties"); Wait<WebDriver> wait = new FluentWait<WebDriver>(driver) .withTimeout(Duration.ofSeconds(5)) .pollingEvery(Duration.ofSeconds(1)) .ignoring(NoSuchElementException.class); WebElement elementFinder = wait.until(new Function<WebDriver, WebElement>() { public WebElement apply(WebDriver driver) { return driver.findElement(By.id("enableAfter2")); } }); //close browser driver.close(); } } |
In the findElement section, we are finding the element with the id “enableAfter2”. There is no such element on the page with this ID. But to know FluentWait’s working, we need to fail our test case knowingly.
Execute the above code and witness the test fail. But in the log section, we can witness exactly what FluentWait was doing:
As mentioned, Selenium (Wait) tried for 5 seconds with a 1 sec (1000 ms) interval. Since it could not find in 5 seconds, it failed.
FluentWait or WebDriver wait – Which one to choose?
FluentWait and WebDriver do not look that much apart from each other except for a few changes. Breaking down those changes briefly gives us an idea of which one to use in what situation while writing test automation scripts.
Setting Polling Time
The first thing you learn about the working of FluentWait is its characteristic of letting the user set the polling time. Such requirements may arise in executing the test for various reasons including saving the CPU cycles. If this is one of your requirements, FluentWait serves very well.
Inclusion of functions
FluentWait involves the usage of functions as determined by:
1 2 3 |
public WebElement apply(WebDriver driver) { return driver.findElement(By.id("enableAfter2")); } |
With the use of functions, this part of the script can be structured well with more control. However, the nature of our intentions remains the same as in WebDriverWait. Whatever we may write here in functions can be converted to what WebDriverWait accepts. It becomes a method of choice and preference. To know in detail about the function and its usage, please refer to Advance WebDriver Waits.
Ignoring Exceptions
The third important aspect of FluentWait is the “ignoring” function that takes the name of an exception that needs to be ignored. In our example above, we have taken NoSuchElementException. This exception is ignored in WebDriverWait by default. So if you have the requirement to ignore just NoSuchElementException, you can use either of them but WebDriverWait will take fewer lines of code.
If your requirement is for other exceptions, FluentWait could serve as your preference.
Apart from these, FluentWait and WebDriverWait may be used synonymously.
You can add a title “What to chosse between the FLuent or Webdriver” Predicates are now not available in the way Virender Singh has shown in his post or in the documentation available. The newer version may have merged them.
Answer: Both implements Wait interface, both almost peform same thing, From coding prepective webdriver wait is easy to apply and for fluent we need the knoweldge of functions and predecates in java(you can tag SMart wait chapter of toolsqa, in which viru taught how to write fluent wait) . ALmost everything is possible from Webdriver waits, But if there is requirement to change the pooling time or if you want to ignore other exceptions during the wait, other than NoSuchELementException, as this one is also ignored by default in WebDriverWait, at that time you can use FLuent wait over webdriver wait.
Key Takeaways
- Explicit wait in Selenium halts the execution of the script and waits for a specified time or until the condition is satisfied.
- The explicit wait is recommended when there are elements that load on DOM at various times depending on the code.
- The explicit wait is implemented either through WebDriverWait or FluentWait.
- Both WebDriverWait and FluentWait extend the Wait interface.
- WebDriverWait does not require a polling time to be specified by the tester. However, it does the polling through intervals set internally.
- A tester can specify polling time as well in FluentWait which is the time intervals in which Selenium would look for the element on the page.
Excercise
CHoose a better example dude,there are other elements on that page that first well for Ecplicitwait, sharing the cdeo
driver.get(“https://demoqa.com/dynamic-properties”);
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.ignoring(NoSuchElementException.class);
wait.pollingEvery(Duration.ofSeconds(1));
//wait.until(ExpectedConditions.elementToBeClickable(By.id(“enableAfter”))).click();
wait.until(ExpectedConditions.attributeContains(driver.findElement(By.id(“colorChange”)), “class”, “text-danger”));
driver.findElement(By.id(“colorChange”)).click();
The following exercise will help you make your basics stronger in explicit wait. Try to imitate these steps using code before analysing the given code.
- Launch a new browser using a driver (such as ChromeDriver).
- Open URL “https://demoqa.com/dynamic-properties”.
- Wait until the element represented by id “colorChange” contains a “text-danger” in the class name.
- Set the maximum time as 100 seconds and polling time as 5 seconds.
- Analyse the log.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package org.example; import java.time.Duration; import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; import org.junit.Test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.support.ui.*; public class ExplicitWait { protected WebDriver driver; @Test public void ExplicitWait() { driver = new ChromeDriver(); driver.get("https://demoqa.com/dynamic-properties"); Wait<WebDriver> wait = new FluentWait<WebDriver>(driver) .withTimeout(Duration.ofSeconds(100)) .pollingEvery(Duration.ofSeconds(5)) .ignoring(NoSuchElementException.class); Boolean elementFinder = wait.until(ExpectedConditions.attributeContains(driver.findElement(By.id("colorChange")), "class", "text-danger")); driver.findElement(By.id("colorChange")).click(); //close browser driver.close(); } } |
Also, verify whether Selenium waits for 100 seconds by intentionally failing the test by changing the “text-danger“. You can also repeat the same exercise with WebDriverWait.