Java tutorial
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 WaitTools 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. */