Most Viewed Pages

3.11.14

Wait and Sync in Selenium

There are broadly 3 different options to choose from...



Implicit Wait - 
  • An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available. The default setting is 0. Once set, the implicit wait is set for the life of the WebDriver object instance, ie., as long as the browser is opened, all the elements will take the amount of time set as implicit wait to load.
  • Implicit wait is defined at the browser level, and not at an individual element level, hence, Implicit waits will be useful only when entire page loads. (i.e., It won't wait for dynamically loading ajax elements). The implicit wait only waits for an element to appear in the DOM, so it returns immediately, but when you try to interact with the element you get a NoSuchElementException.
  • There can be instances when a particular element takes more than a minute to load. In such a case if we set a huge time for Implicit wait, then the browser may wait for that amount of time for every element. To avoid that situation you can simply put a separate time on the required element only. By following this your browser implicit wait time would be short for every element and it would be large for specific element- and this can be achieved via Explicit Wait.

Syntax -
driver.manage.timeouts().implicitlyWait(10,TimeUnit.SECONDS);



WebDriverWait \ Explicit Wait - 

  • An explicit wait is a code you define to wait for a certain condition to occur before proceeding further in the code. 
  • Explicit waits are intelligent waits that are confined to a particular web element. Instead of instantly looking for an element, we can tell Webdriver to wait for a certain amount of time before we continue with the next step.
  • The worst case of this is Thread.sleep(), which sets the condition to an exact time period to wait. WebDriverWait in combination with ExpectedCondition is a more preferred mode of implementation.

Syntax -
WebDriverWait wait = new WebDriverWait(driver,10);
wait.until(ExpectedConditons.elementToBeClickable(By.xpath("locator"));



FluentWait -

FluentWait uses a Polling Technique to wait i.e, it will keep on Polling every fixed interval for a particular element. But the important feature with FluentWait is that it uses Generics, which means we dont have to pass an instance of the WebDriver - we can directly use the WebElement, of By, or anything else.

Let’s say you have an element which sometime appears in just 1 second and some time it takes minutes to appear. In that case it is better to use fluent wait, as this will try to find element again and again until it find it or until the final timer runs out.

Advantages of FluentWait over WebDriverWait - 
  • You dont have to pass the driver instance in FluentWait. This can be very helpful if you are using the PageObject Pattern for your Framework.
  • You have more control over the wait time with the polling option - because with WebDriverWait, selenium would wait for the entire duration specified [lets say 20s] but with FluentWait we have the option of specifying the wait as well as the polling interval, hence, the actual wait time can be reduced with 5s wait and 4X polling, instead of directly waiting for 20s.
So its advantageous to use FluentWait for all the sync operations, as it gives fine-tuned control.

This is a function that demonstrates the use of FluentWait, and as you can see, we did not have to pass/use an instance of the WebDriver while creating this function.
------------------------------------------------------------
import org.openqa.selenium.support.ui.FluentWait;

//The FluentWait class uses the Function to implement .until
//This Function uses the following package [com.google.common.base.Function]
//There are many packages available for "Function", but only this has to be used,
// otherwise we get all sorts of weird errors
//Also, in the above function, we must use this class 'org.openqa.selenium.NoSuchElementException' instead of the default [import java.util.NoSuchElementException] suggested by IDE because if we use the java.util, then the FluentWait will fail with NoSuchElementException!! since, we did not use the correct package - stupid ide!
//So we should use the full package name anywhere we have to use the class declaration, otherwise, if we copy the code, and it asks us for the package, it might just add the default one again.

public Boolean checkElementIsDisplayedFluentWait(WebElement webElement) {

System.out.println("running checkElementIsDisplayedFluentWait");

Boolean displayStatus = false;

FluentWait<WebElement> fluentWait = new FluentWait<WebElement>(webElement);
fluentWait.ignoring(NoSuchElementException.class);
fluentWait.withTimeout(10, TimeUnit.SECONDS);
fluentWait.pollingEvery(5, TimeUnit.SECONDS);

displayStatus = fluentWait.until(new Function<WebElement, Boolean>() {
public Boolean apply(WebElement webElement) {
return webElement.isDisplayed();
}
});

System.out.println(displayStatus.booleanValue());

return displayStatus;

}

And it can be used as follows -
This will check if the element is displayed, and then capture its displayed text.
if(commonLib.checkElementIsDisplayedFluentWait(webElement)){
System.out.println(webElement.getText());
}
------------------------------------------------------------


Need to explore the option to check for conditions/properties using the FluentWait like in the WebDriveWait

Also, all of the above examples will work when there is a change in the DOM, but there can be situations where the page sends requests for data without changing the DOM. In such cases, we may opt to check for asynchronous events using JQuery or JScript.

Stay tuned for more, as this is still wip...

No comments:

Post a Comment