package wtbox.util;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
/**
* Wait tool class. Provides Wait methods for an elements, and AJAX elements to load.
* It uses WebDriverWait (explicit wait) for waiting an element or javaScript.
*
* To use implicitlyWait() and WebDriverWait() in the same test,
* we would have to nullify implicitlyWait() before calling WebDriverWait(),
* and reset after it. This class takes care of it.
*
*
* Generally relying on implicitlyWait slows things down
* so use WaitTool�s explicit wait methods as much as possible.
* Also, consider (DEFAULT_WAIT_4_PAGE = 0) for not using implicitlyWait
* for a certain test.
*
* @author Chon Chung, Mark Collin, Andre, Tarun Kumar
*
* @todo check FluentWait -- http://seleniumsimplified.com/2012/08/22/fluentwait-with-webelement/
*
* Copyright [2012] [Chon Chung]
*
* Licensed under the Apache Open Source License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
public class WaitTool {
/** Default wait time for an element. 7 seconds. */
public static final int DEFAULT_WAIT_4_ELEMENT = 7;
/** Default wait time for a page to be displayed. 12 seconds.
* The average webpage load time is 6 seconds in 2012.
* Based on your tests, please set this value.
* "0" will nullify implicitlyWait and speed up a test. */
public static final int DEFAULT_WAIT_4_PAGE = 12;
/**
* Wait for the element to be present in the DOM, and displayed on the page.
* And returns the first WebElement using the given method.
*
* @param WebDriver The driver object to be used
* @param By selector to find the element
* @param int The time in seconds to wait until returning a failure
*
* @return WebElement the first WebElement using the given method, or null (if the timeout is reached)
*/
public static WebElement waitForElement(WebDriver driver, final By by, int timeOutInSeconds) {
WebElement element;
try{
//To use WebDriverWait(), we would have to nullify implicitlyWait().
//Because implicitlyWait time also set "driver.findElement()" wait time.
//info from: https://groups.google.com/forum/?fromgroups=#!topic/selenium-users/6VO_7IXylgY
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_4_PAGE, TimeUnit.SECONDS); //reset implicitlyWait
return element; //return the element
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Wait for the element to be present in the DOM, regardless of being displayed or not.
* And returns the first WebElement using the given method.
*
* @param WebDriver The driver object to be used
* @param By selector to find the element
* @param int The time in seconds to wait until returning a failure
*
* @return WebElement the first WebElement using the given method, or null (if the timeout is reached)
*/
public static WebElement waitForElementPresent(WebDriver driver, final By by, int timeOutInSeconds) {
WebElement element;
try{
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
element = wait.until(ExpectedConditions.presenceOfElementLocated(by));
driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_4_PAGE, TimeUnit.SECONDS); //reset implicitlyWait
return element; //return the element
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Wait for the List<WebElement> to be present in the DOM, regardless of being displayed or not.
* Returns all elements within the current page DOM.
*
* @param WebDriver The driver object to be used
* @param By selector to find the element
* @param int The time in seconds to wait until returning a failure
*
* @return List<WebElement> all elements within the current page DOM, or null (if the timeout is reached)
*/
public static List<WebElement> waitForListElementsPresent(WebDriver driver, final By by, int timeOutInSeconds) {
List<WebElement> elements;
try{
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
wait.until((new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driverObject) {
return areElementsPresent(driverObject, by);
}
}));
elements = driver.findElements(by);
driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_4_PAGE, TimeUnit.SECONDS); //reset implicitlyWait
return elements; //return the element
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Wait for an element to appear on the refreshed web-page.
* And returns the first WebElement using the given method.
*
* This method is to deal with dynamic pages.
*
* Some sites I (Mark) have tested have required a page refresh to add additional elements to the DOM.
* Generally you (Chon) wouldn't need to do this in a typical AJAX scenario.
*
* @param WebDriver The driver object to use to perform this element search
* @param locator selector to find the element
* @param int The time in seconds to wait until returning a failure
*
* @return WebElement the first WebElement using the given method, or null(if the timeout is reached)
*
* @author Mark Collin
*/
public static WebElement waitForElementRefresh(WebDriver driver, final By by,
int timeOutInSeconds) {
WebElement element;
try{
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
new WebDriverWait(driver, timeOutInSeconds) {
}.until(new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driverObject) {
driverObject.navigate().refresh(); //refresh the page ****************
return isElementPresentAndDisplay(driverObject, by);
}
});
element = driver.findElement(by);
driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_4_PAGE, TimeUnit.SECONDS); //reset implicitlyWait
return element; //return the element
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Wait for the Text to be present in the given element, regardless of being displayed or not.
*
* @param WebDriver The driver object to be used to wait and find the element
* @param locator selector of the given element, which should contain the text
* @param String The text we are looking
* @param int The time in seconds to wait until returning a failure
*
* @return boolean
*/
public static boolean waitForTextPresent(WebDriver driver, final By by, final String text, int timeOutInSeconds) {
boolean isPresent = false;
try{
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
new WebDriverWait(driver, timeOutInSeconds) {
}.until(new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driverObject) {
return isTextPresent(driverObject, by, text); //is the Text in the DOM
}
});
isPresent = isTextPresent(driver, by, text);
driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_4_PAGE, TimeUnit.SECONDS); //reset implicitlyWait
return isPresent;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* Waits for the Condition of JavaScript.
*
*
* @param WebDriver The driver object to be used to wait and find the element
* @param String The javaScript condition we are waiting. e.g. "return (xmlhttp.readyState >= 2 && xmlhttp.status == 200)"
* @param int The time in seconds to wait until returning a failure
*
* @return boolean true or false(condition fail, or if the timeout is reached)
**/
public static boolean waitForJavaScriptCondition(WebDriver driver, final String javaScript,
int timeOutInSeconds) {
boolean jscondition = false;
try{
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
new WebDriverWait(driver, timeOutInSeconds) {
}.until(new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driverObject) {
return (Boolean) ((JavascriptExecutor) driverObject).executeScript(javaScript);
}
});
jscondition = (Boolean) ((JavascriptExecutor) driver).executeScript(javaScript);
driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_4_PAGE, TimeUnit.SECONDS); //reset implicitlyWait
return jscondition;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/** Waits for the completion of Ajax jQuery processing by checking "return jQuery.active == 0" condition.
*
* @param WebDriver - The driver object to be used to wait and find the element
* @param int - The time in seconds to wait until returning a failure
*
* @return boolean true or false(condition fail, or if the timeout is reached)
* */
public static boolean waitForJQueryProcessing(WebDriver driver, int timeOutInSeconds){
boolean jQcondition = false;
try{
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
new WebDriverWait(driver, timeOutInSeconds) {
}.until(new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driverObject) {
return (Boolean) ((JavascriptExecutor) driverObject).executeScript("return jQuery.active == 0");
}
});
jQcondition = (Boolean) ((JavascriptExecutor) driver).executeScript("return jQuery.active == 0");
driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_4_PAGE, TimeUnit.SECONDS); //reset implicitlyWait
return jQcondition;
} catch (Exception e) {
e.printStackTrace();
}
return jQcondition;
}
/**
* Coming to implicit wait, If you have set it once then you would have to explicitly set it to zero to nullify it -
*/
public static void nullifyImplicitWait(WebDriver driver) {
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
}
/**
* Set driver implicitlyWait() time.
*/
public static void setImplicitWait(WebDriver driver, int waitTime_InSeconds) {
driver.manage().timeouts().implicitlyWait(waitTime_InSeconds, TimeUnit.SECONDS);
}
/**
* Reset ImplicitWait.
* To reset ImplicitWait time you would have to explicitly
* set it to zero to nullify it before setting it with a new time value.
*/
public static void resetImplicitWait(WebDriver driver) {
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_4_PAGE, TimeUnit.SECONDS); //reset implicitlyWait
}
/**
* Reset ImplicitWait.
* @param int - a new wait time in seconds
*/
public static void resetImplicitWait(WebDriver driver, int newWaittime_InSeconds) {
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
driver.manage().timeouts().implicitlyWait(newWaittime_InSeconds, TimeUnit.SECONDS); //reset implicitlyWait
}
/**
* Checks if the text is present in the element.
*
* @param driver - The driver object to use to perform this element search
* @param by - selector to find the element that should contain text
* @param text - The Text element you are looking for
* @return true or false
*/
private static boolean isTextPresent(WebDriver driver, By by, String text)
{
try {
return driver.findElement(by).getText().contains(text);
} catch (NullPointerException e) {
return false;
}
}
/**
* Checks if the elment is in the DOM, regardless of being displayed or not.
*
* @param driver - The driver object to use to perform this element search
* @param by - selector to find the element
* @return boolean
*/
private static boolean isElementPresent(WebDriver driver, By by) {
try {
driver.findElement(by);//if it does not find the element throw NoSuchElementException, which calls "catch(Exception)" and returns false;
return true;
} catch (NoSuchElementException e) {
return false;
}
}
/**
* Checks if the List<WebElement> are in the DOM, regardless of being displayed or not.
*
* @param driver - The driver object to use to perform this element search
* @param by - selector to find the element
* @return boolean
*/
private static boolean areElementsPresent(WebDriver driver, By by) {
try {
driver.findElements(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
/**
* Checks if the elment is in the DOM and displayed.
*
* @param driver - The driver object to use to perform this element search
* @param by - selector to find the element
* @return boolean
*/
private static boolean isElementPresentAndDisplay(WebDriver driver, By by) {
try {
return driver.findElement(by).isDisplayed();
} catch (NoSuchElementException e) {
return false;
}
}
}
/*
* References:
* 1. Mark Collin's post on: https://groups.google.com/forum/?fromgroups#!topic/webdriver/V9KqskkHmIs%5B1-25%5D
* Mark's code inspires me to write this class. Thank you! Mark.
* 2. Andre, and Tarun Kumar's post on: https://groups.google.com/forum/?fromgroups=#!topic/selenium-users/6VO_7IXylgY
* 3. Explicit and Implicit Waits: http://seleniumhq.org/docs/04_webdriver_advanced.html
*
* Note:
* 1. Instead of creating new WebDriverWait() instance every time in each methods,
* I tried to reuse a single WebDriverWait() instance, but I found and tested
* that creating 100 WebDriverWait() instances takes less than one millisecond.
* So, it seems not necessary.
*/