/**
* Candybean is a next generation automation and testing framework suite.
* It is a collection of components that foster test automation, execution
* configuration, data abstraction, results illustration, tag-based execution,
* top-down and bottom-up batches, mobile variants, test translation across
* languages, plain-language testing, and web service testing.
* Copyright (C) 2013 SugarCRM, Inc. <candybean@sugarcrm.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sugarcrm.candybean.automation.webdriver;
import com.sugarcrm.candybean.automation.Candybean;
import com.sugarcrm.candybean.automation.element.Hook;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import com.sugarcrm.candybean.exceptions.CandybeanException;
import java.text.DecimalFormat;
import java.util.logging.Logger;
import static java.lang.System.currentTimeMillis;
/**
* Utility class that provides several methods for an element to pause until a
* condition is satisfied
*
* @author Eric Tam
* @author Jason Mittertreiner
*/
public class WebDriverPause {
private WebDriver wd;
private long defaultTimeoutMs;
private long defaultPollingIntervalS;
public Logger logger;
public WebDriverPause(WebDriver wd, long defaultTimeoutMs, long defaultPollingIntervalS) {
this.wd = wd;
this.defaultTimeoutMs = defaultTimeoutMs;
this.defaultPollingIntervalS = defaultPollingIntervalS;
this.logger = Logger.getLogger(Candybean.class.getSimpleName());
}
/**
* Accepts any ExpectedCondition and poll under this condition is satisfied within timeout
* @param timeoutMs Timeout in Milliseconds
* @param condition The condition to poll
* @return Returning the object that is returned from ExpectedCondition when the condition is met
* @throws CandybeanException
*/
public Object waitUntil(ExpectedCondition condition, long timeoutMs) throws CandybeanException {
// This is done by double-polling. WebDriverWait waits for wdPollingInterval amount of time.
// This is done repetitively until the time reaches timeoutMs.
final long pollingIntervalS = Math.min(defaultPollingIntervalS, Math.max(timeoutMs/1000, 1));
final long seleniumPollingIntervalMs = 250;
final long startTime = currentTimeMillis();
String toThrow = null;
Object toReturn = null;
logger.info("Waiting until " + condition.toString() + " is satisfied.");
while(currentTimeMillis() - startTime <= timeoutMs) {
try {
toReturn = (new WebDriverWait(this.wd, pollingIntervalS, seleniumPollingIntervalMs)).until(condition);
toThrow = null;
break;
} catch (WebDriverException wdException) {
logger.info(currentTimeMillis() - startTime+ "ms have passed. Waiting until " + condition.toString() + " is satisfied.");
toThrow = wdException.toString();
}
}
if(toThrow != null) {
logger.severe("The timeout of " + timeoutMs + "ms was reached. Throwing Exception.");
throw new CandybeanException("Timed out after "+ timeoutMs + " seconds");
}
return toReturn;
}
public Object waitUntil(ExpectedCondition<?> condition) throws CandybeanException {
return this.waitUntil(condition, defaultTimeoutMs);
}
/**
* Wait until an element is present on the DOM for up to timeoutMs seconds
*
* @param hook Hook to find the element
* @param timeoutMs Max wait time
* @return The located element
* @throws CandybeanException
*/
public WebDriverElement waitForElement(Hook hook, long timeoutMs) throws CandybeanException {
return (WebDriverElement) this.waitUntil(WaitConditions.present(hook), timeoutMs);
}
/**
* Wait until an element is present on the DOM for up to 15 seconds
*
* @param hook Hook to find the element
* @return The located element
* @throws CandybeanException
*/
public WebDriverElement waitForElement(Hook hook) throws CandybeanException {
return (WebDriverElement) this.waitUntil(WaitConditions.present(hook), defaultTimeoutMs);
}
/**
* wait until an element is no present on the dom for up to timeoutMs seconds
*
* @param hook hook to find the element
* @param timeoutMs max wait time
* @throws CandybeanException
*/
public void waitForElementRemoved(Hook hook, long timeoutMs) throws CandybeanException {
waitUntil(WaitConditions.not(WaitConditions.present(hook)), timeoutMs);
}
/**
* wait until an element is no present on the dom for up to 15 seconds
*
* @param hook hook to find the element
* @throws CandybeanException
*/
public void waitForElementRemoved(Hook hook) throws CandybeanException {
waitUntil(WaitConditions.not(WaitConditions.present(hook)), defaultTimeoutMs);
}
/**
* Provides a simple method to wait for visible as it is often used
* @param hook
* @param timeoutMs
* @throws CandybeanException
*/
public WebDriverElement waitForVisible(Hook hook, long timeoutMs) throws CandybeanException {
return (WebDriverElement) this.waitUntil(WaitConditions.visible(hook), timeoutMs);
}
/**
* Provides a simple method to wait for visible as it is often used
* @param hook
* @return
* @throws CandybeanException
*/
public WebDriverElement waitForVisible(Hook hook) throws CandybeanException {
return this.waitForVisible(hook, defaultTimeoutMs);
}
/**
* Provides a simple method to wait for visible as it is often used
* @param wde
* @param timeoutMs
* @throws CandybeanException
*/
public WebDriverElement waitForVisible(WebDriverElement wde, long timeoutMs) throws CandybeanException {
return (WebDriverElement) this.waitUntil(WaitConditions.visible(wde), timeoutMs);
}
/**
* Provides a simple method to wait for visible as it is often used
* @param wde
* @return
* @throws CandybeanException
*/
public WebDriverElement waitForVisible(WebDriverElement wde) throws CandybeanException {
return this.waitForVisible(wde, defaultTimeoutMs);
}
/**
* Provides a simple method to wait for invisible
*
* @param hook The hook used to find the element
* @param timeoutMs The max wait time
* @throws CandybeanException If the element is visible after timeout
*/
public void waitForInvisible(Hook hook, long timeoutMs) throws CandybeanException {
waitUntil(WaitConditions.invisible(hook), timeoutMs);
}
/**
* Provides a simple method to wait for invisible
*
* @param hook The hook used to find the element
* @throws CandybeanException If the element is visible after timeout
*/
public void waitForInvisible(Hook hook) throws CandybeanException {
waitForInvisible(hook, defaultTimeoutMs);
}
/**
* Provides a simple method to wait for invisible
*
* @param wde The WebDriverElement to wait for
* @param timeoutMs The max wait time
* @throws CandybeanException
* If the element visible after timeout
*/
public void waitForInvisible(WebDriverElement wde, long timeoutMs) throws CandybeanException {
waitUntil(WaitConditions.invisible(wde), timeoutMs);
}
/**
* Provides a simple method to wait for invisible
*
* @param wde The WebDriverElement to wait for
* @throws CandybeanException If the element visible after timeout
*/
public void waitForInvisible(WebDriverElement wde) throws CandybeanException {
waitForInvisible(wde, defaultTimeoutMs);
}
/**
* Wait for an element to have the specified attribute with the specified value if expectValue is true, and the
* reverse if false, waiting for up to timeoutMS milliseconds.
*
* @param hook Hook used to search for the element
* @param attribute Attributed used to check for value
* @param value Specified value of the attribute
* @param expectValue If the value is expected or not
* @param timeoutMS Max wait time before timeout
* @return The found matching element
* @throws CandybeanException If element not found or attribute has the wrong value
*/
public WebDriverElement waitForAttribute(Hook hook, String attribute, String value, boolean expectValue, long timeoutMS)
throws CandybeanException {
return (WebDriverElement) waitUntil(WaitConditions.hasAttribute(hook, attribute, value, expectValue), timeoutMS);
}
/**
* Wait for an element to have the specified attribute with the specified value if expectValue is true, and the
* reverse if false, waiting for up to 15s
*
* @param hook Hook used to search for the element
* @param attribute Attributed used to check for value
* @param value Specified value of the attribute
* @param expectValue If the value is expected or not
* @return The found matching element
* @throws CandybeanException If element not found or attribute has the wrong value
*/
public WebDriverElement waitForAttribute(Hook hook, String attribute, String value, boolean expectValue)
throws CandybeanException {
return (WebDriverElement) waitUntil(WaitConditions.hasAttribute(hook, attribute, value, expectValue), defaultTimeoutMs);
}
/**
* Wait for an element to have the specified attribute with the specified value if expectValue is true, and the
* reverse if false, waiting for up to timeoutMS milliseconds.
*
* @param hook Hook used to search for the element
* @param attribute Attributed used to check for value
* @param regex Speecified regex pattern of the attribute
* @param expectValue If the value is expected or not
* @param timeoutMS Max wait time before timeout
* @return The found matching element
* @throws CandybeanException If element not found or attribute has the wrong value
*/
public WebDriverElement waitForRegexAttribute(Hook hook, String attribute, String regex, boolean expectValue, long timeoutMS)
throws CandybeanException {
return (WebDriverElement) waitUntil(WaitConditions.hasRegexAttribute(hook, attribute, regex, expectValue), timeoutMS);
}
/**
* Wait for an element to have the specified attribute with the specified value if expectValue is true, and the
* reverse if false, waiting for up to 15s
*
* @param hook Hook used to search for the element
* @param attribute Attributed used to check for value
* @param regex Specified regex pattern of the attribute
* @param expectValue If the value is expected or not
* @return The found matching element
* @throws CandybeanException If element not found or attribute has the wrong value
*/
public WebDriverElement waitForRegexAttribute(Hook hook, String attribute, String regex, boolean expectValue)
throws CandybeanException {
return (WebDriverElement) waitUntil(WaitConditions.hasRegexAttribute(hook, attribute, regex, expectValue), defaultTimeoutMs);
}
/**
* Waits until a specified element is on(off) screen for up to 15 seconds
*
* @param hook Hook used to search for the element
* @param isOnScreen Whether to check is the element is on or off screen
* @return The element
* @throws CandybeanException
*/
public WebDriverElement waitForOnScreen(Hook hook, boolean isOnScreen) throws CandybeanException {
return this.waitForOnScreen(hook, defaultTimeoutMs, isOnScreen);
}
/**
* Waits until a specified element is on(off) screen for up to timeoutMS seconds
*
* @param hook Hook used to search for the element
* @param timeoutMs Maximum time to wait for the element
* @param isOnScreen Whether to check is the element is on or off screen
* @return The element
* @throws CandybeanException
*/
public WebDriverElement waitForOnScreen(Hook hook, long timeoutMs, boolean isOnScreen) throws CandybeanException {
return (WebDriverElement) this.waitUntil(WaitConditions.onScreen(hook, isOnScreen), timeoutMs);
}
}