'Wait' interface has a single method 'until()' implemented by FluentWait class.
Handling explicit wait using FluentWait:
there are two steps to achieve explicit wait using FluentWait-First create a FluentWait object, second using this object call until() method which has an argument of type function interface, so we know that function interface has a method 'apply()', that will have to be implemented while calling until().
Q1) Create a Selenium script to find an element using fluent wait. Make sure maximum time driver can wait is 10 s. Driver need to check the element availability every 1 ms. On every try either element is found or not found. If not found then we know that Selenium throws 'NoSuchElementException'. Make sure driver should ignore this exception and continue looking for the element in subsequent tries. Show that on time out test fails
Ans) Create a web page 'explicit_wait_using_fluent_wait_example1.html', containing java script that creates a button at 15th second. As script has set max time out of 10 s and button appears at 15th seconds test fails. we can see the :
explicit_wait_using_fluent_wait_example1.html:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<script>
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function implicit() {
document.write('<p>Sleeping for 15000 milli seconds');
await sleep(15000);
document.write('<p>wake up, adding a button<br>');
var btn = document.createElement("BUTTON"); // Create a <button> element
btn.id = 'dynamicBtn';
btn.innerHTML = "CLICK ME"; // Insert text
document.body.appendChild(btn); // Append <button> to <body>
}
implicit()
</script>
</body>
</html>
Test:
Open above page in the test:
@Test(description = "page create button in 15 seconds but explicit wait is set (10 seconds) so test fails")
public void check_button_appears_in_10_second_fail_test() {
WebDriver driver = getChromeDriver();
driver.get("file:///" + System.getProperty("user.dir") + "/html/wait/explicit/explicit_wait_using_fluent_wait_example1.html");
Wait wait = new FluentWait(driver)
.withTimeout(Duration.ofMillis(10000))//max time to wait
.pollingEvery(Duration.ofMillis(1000)) // to check element every 1000 ms
.ignoring(NoSuchElementException.class);
WebElement btn = (WebElement) wait.until(new Function<WebDriver, WebElement>() {
int i = 0;
@Override
public WebElement apply(WebDriver webDriver) {
System.out.println("POLLING NUMBER: " + i++);
return driver.findElement(By.id("dynamicBtn"));
}
});
Assert.assertEquals(btn.getText(), "CLICK ME");
}
Result: At the 10th call of apply(), time out occurs and test has failed:
Q2) Re write above test by reducing the button availability time in java script to 10 seconds. Show the pass result where at 10th call to 'apply()' method finds button successfully.
A) Reduce the wait time from 15 seconds to 10 seconds in java script of page 'explicit_wait_using_fluent_wait_example1.html'. Now if we run the above Selenium test. we get the following result:
Handling explicit wait using WebDriverWait:
WebDriverWait class goes ahead one step and simplifies the code by using a class 'ExpectedConditions'. This class has a corresponding method for each condition. each method of this class has overridden the 'apply()' method so no need to define it again. Also code for time out , polling time and ignoring exception are provided by default in the constructor of WebDriverWait. If we don't pass time out value the default time out is is taken 500 ms. WebDriverWait constructor looks as follows:
public WebDriverWait(WebDriver driver, Duration timeout, Duration sleep, Clock clock, Sleeper sleeper) {
super(driver, clock, sleeper);
this.withTimeout(timeout);
this.pollingEvery(sleep);
this.ignoring(NotFoundException.class);
this.driver = driver;
}
Pass clock if want to set specific time zone otherwise system default zone is used.
ExpectedConditions class provides following methods that we can choose as per our requirements:
- titleIs
- titleContains
- urlToBe
- urlContains
- urlMatches
- presenceOfElementLocated
- visibilityOfElementLocated
- visibilityOfAllElementsLocatedBy
- visibilityOfAllElements
- visibilityOfAllElements
- visibilityOf
- elementIfVisible
- presenceOfAllElementsLocatedBy
- textToBePresentInElement
- textToBePresentInElementLocated
- textToBePresentInElementValue
- textToBePresentInElementValue
- frameToBeAvailableAndSwitchToIt
- frameToBeAvailableAndSwitchToIt
- frameToBeAvailableAndSwitchToIt
- frameToBeAvailableAndSwitchToIt
- invisibilityOfElementLocated
- invisibilityOfElementWithText
- elementToBeClickable
- elementToBeClickable
- stalenessOf
- refreshed
- elementToBeSelected
- elementSelectionStateToBe
- elementToBeSelected
- elementSelectionStateToBe
- alertIsPresent
- numberOfWindowsToBe
- not
- attributeToBe
- textToBe
- textMatches
- numberOfElementsToBeMoreThan
- numberOfElementsToBeLessThan
- numberOfElementsToBe
- domPropertyToBe
- domAttributeToBe
- attributeToBe
- attributeContains
- attributeContains
- attributeToBeNotEmpty
- getAttributeOrCssValue
- visibilityOfNestedElementsLocatedBy
- visibilityOfNestedElementsLocatedBy
- presenceOfNestedElementLocatedBy
- presenceOfNestedElementLocatedBy
- presenceOfNestedElementsLocatedBy
- invisibilityOfAllElements
- invisibilityOfAllElements
- invisibilityOf
- isInvisible
- or
- and
Based on above various wait conditions some important scripts are are discussed
Q3) Create a web page to display a title 'MyTitle' in 5 seconds. Create a selenium test that verifies the title where timeout is set to 4 seconds.
Ans) The webpage 'title_test.html' as follows:
<!DOCTYPE html>
<html lang="en">
<body>
<center><h1><br><br><br><br><br><hr>
Title changed in 5000 milliseconds<br><br><br><hr>
</h1>
</center>
<script>
setTimeout(function(){ document.title = 'Title test'; }, 5000);
</script>
</body>
</html>
Test: Below is the Selenium-TestNG test that verifies the title in 4 seconds which is earlier than the time when expected title appears.
@Test(description = "except a title in 4 s but it appears after 5 seconds so test fails")
public void title_is_fail_test() {
WebDriver driver = getChromeDriver();
driver.get("file:///" + System.getProperty("user.dir") + "/html/wait/explicit/title_test.html");
driver.manage().window().maximize();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(4));
wait.until(ExpectedConditions.titleIs("MyTitle"));
}
Result: as expected not found in 4 seconds, time out occurs:
This is complete execution video of the above test:
Q3) To pass the test in Q2 make changes in above selenium test to set time out to 5 s to match the web page java script time so that when test tries to verify the title 'MyTitle' in 5 seconds title of page by that time becomes 'MyTitle'.
Ans) here is the modified Selenium-TestNG test that looks for given title in 5 seconds:
@Test(description = "except a title in 5 s and it appears in 5 seconds test pass")
public void title_is_pass_test() {
WebDriver driver = getFirefoxDriver();
driver.get("file:///" + System.getProperty("user.dir") + "/html/wait/explicit/title_test.html");
driver.manage().window().maximize();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
wait.until(ExpectedConditions.titleIs("MyTitle"));
}
Pass result:
This is complete execution video of the above test:
Q4) Create a Selenium test to wait for an alert and verify the text on alert. Illustrates both fail and pass scenarios.
Ans) Fail scenario: create an html page 'alert.html'. This page runs java script to wait 5 seconds before showing an alert as shown below:
<!DOCTYPE html>
<html>
<head><title>Alert</title></head>
<body>
<center>
<h1><br><br><br><br><hr>
<script>
document.write("Wait 5000 milli seconds to open an alert");
setTimeout(function(){ alert("Alert"); }, 5000);
</script>
</h1><hr>
</center>
</body>
</html>
The Selenium test below set explicit wait of 2 seconds. As alert appears later 'alertIsPresent' constantly returns false that makes timeout occurs in 2 seconds.
Test:
@Test(description = "page opens alert after 5 seconds but explicit wait is set (2 seconds) so test fails")
public void check_alert_appears_in_5_second_fail_test() {
WebDriver driver = getChromeDriver();
driver.get("file:///" + System.getProperty("user.dir") + "/html/wait/explicit/alert.html");
//on page open an alert appears so we can't do any action like max window until alert is dismissed. so comment below line
//driver.manage().window().maximize();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(2));
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
String txt = alert.getText();
alert.dismiss();
Assert.assertEquals(txt, "Alert");
}
Output:
Pass Scenario: Rewrite above test with 5 seconds wait time.
Output: