Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
nl.hsac.fitnesse.fixture.slim.web.BrowserTest Maven / Gradle / Ivy
package nl.hsac.fitnesse.fixture.slim.web;
import fitnesse.slim.fixtureInteraction.FixtureInteraction;
import nl.hsac.fitnesse.fixture.slim.HttpTest;
import nl.hsac.fitnesse.fixture.slim.SlimFixture;
import nl.hsac.fitnesse.fixture.slim.SlimFixtureException;
import nl.hsac.fitnesse.fixture.slim.StopTestException;
import nl.hsac.fitnesse.fixture.slim.web.annotation.TimeoutPolicy;
import nl.hsac.fitnesse.fixture.slim.web.annotation.WaitUntil;
import nl.hsac.fitnesse.fixture.util.ReflectionHelper;
import nl.hsac.fitnesse.fixture.util.selenium.AllFramesDecorator;
import nl.hsac.fitnesse.fixture.util.selenium.PageSourceSaver;
import nl.hsac.fitnesse.fixture.util.selenium.SelectHelper;
import nl.hsac.fitnesse.fixture.util.selenium.SeleniumHelper;
import nl.hsac.fitnesse.fixture.util.selenium.StaleContextException;
import nl.hsac.fitnesse.fixture.util.selenium.by.AltBy;
import nl.hsac.fitnesse.fixture.util.selenium.by.AriaGridBy;
import nl.hsac.fitnesse.fixture.util.selenium.by.ContainerBy;
import nl.hsac.fitnesse.fixture.util.selenium.by.GridBy;
import nl.hsac.fitnesse.fixture.util.selenium.by.ListItemBy;
import nl.hsac.fitnesse.fixture.util.selenium.by.OptionBy;
import nl.hsac.fitnesse.fixture.util.selenium.by.XPathBy;
import nl.hsac.fitnesse.fixture.util.selenium.by.relative.RelativeMethod;
import nl.hsac.fitnesse.slim.interaction.ExceptionHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.HasAuthentication;
import org.openqa.selenium.InvalidElementStateException;
import org.openqa.selenium.Keys;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UnhandledAlertException;
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Pattern;
public class BrowserTest extends SlimFixture {
private final List currentSearchContextPath = new ArrayList<>();
private SeleniumHelper seleniumHelper = getEnvironment().getSeleniumHelper();
private ReflectionHelper reflectionHelper = getEnvironment().getReflectionHelper();
private NgBrowserTest ngBrowserTest;
private boolean implicitWaitForAngular = false;
private boolean implicitFindInFrames = true;
private boolean continueIfReadyStateInteractive = false;
private boolean scrollElementToCenter = false;
private boolean waiAriaTables = false;
private boolean containersAsShadowRoot = false;
private int secondsBeforeTimeout;
private int secondsBeforePageLoadTimeout;
private int waitAfterScroll = 150;
private String screenshotBase = new File(filesDir, "screenshots").getPath() + "/";
private String screenshotHeight = "200";
private String pageSourceBase = new File(filesDir, "pagesources").getPath() + "/";
private boolean sendCommandForControlOnMac = false;
private boolean trimOnNormalize = true;
private Long dragPressDelay;
private Integer dragDistance;
private static final String CHROME_HIDDEN_BY_OTHER_ELEMENT_ERROR = "Other element would receive the click",
EDGE_HIDDEN_BY_OTHER_ELEMENT_ERROR = "Element is obscured";
private static final Pattern FIREFOX_HIDDEN_BY_OTHER_ELEMENT_ERROR_PATTERN =
Pattern.compile("Element.+is not clickable.+because another element.+obscures it");
protected List getCurrentSearchContextPath() {
return currentSearchContextPath;
}
protected int minStaleContextRefreshCount = 5;
@Override
protected void beforeInvoke(Method method, Object[] arguments) {
super.beforeInvoke(method, arguments);
waitForAngularIfNeeded(method);
}
@Override
protected Object invoke(FixtureInteraction interaction, Method method, Object[] arguments)
throws Throwable {
try {
Object result;
WaitUntil waitUntil = reflectionHelper.getAnnotation(WaitUntil.class, method);
if (waitUntil == null) {
result = superInvoke(interaction, method, arguments);
} else {
result = invokedWrappedInWaitUntil(waitUntil, interaction, method, arguments);
}
return result;
} catch (StaleContextException e) {
// current context was no good to search in
if (getCurrentSearchContextPath().isEmpty()) {
throw e;
} else {
refreshSearchContext();
return invoke(interaction, method, arguments);
}
}
}
protected Object invokedWrappedInWaitUntil(WaitUntil waitUntil, FixtureInteraction interaction, Method method, Object[] arguments) {
ExpectedCondition condition = webDriver -> {
try {
return superInvoke(interaction, method, arguments);
} catch (Throwable e) {
Throwable realEx = ExceptionHelper.stripReflectionException(e);
if (realEx instanceof RuntimeException) {
throw (RuntimeException) realEx;
} else if (realEx instanceof Error) {
throw (Error) realEx;
} else {
throw new RuntimeException(realEx);
}
}
};
condition = wrapConditionForFramesIfNeeded(condition);
Object result;
switch (waitUntil.value()) {
case STOP_TEST:
result = waitUntilOrStop(condition);
break;
case RETURN_NULL:
result = waitUntilOrNull(condition);
break;
case RETURN_FALSE:
result = waitUntilOrNull(condition) != null;
break;
case THROW:
default:
result = waitUntil(condition);
break;
}
return result;
}
protected Object superInvoke(FixtureInteraction interaction, Method method, Object[] arguments) throws Throwable {
return super.invoke(interaction, method, arguments);
}
/**
* Determines whether the current method might require waiting for angular given the currently open site,
* and ensure it does if needed.
*
* @param method
*/
protected void waitForAngularIfNeeded(Method method) {
if (isImplicitWaitForAngularEnabled()) {
try {
if (ngBrowserTest == null) {
ngBrowserTest = new NgBrowserTest(secondsBeforeTimeout());
ngBrowserTest.secondsBeforePageLoadTimeout(secondsBeforePageLoadTimeout());
}
if (ngBrowserTest.requiresWaitForAngular(method) && currentSiteUsesAngular()) {
try {
ngBrowserTest.waitForAngularRequestsToFinish();
} catch (Exception e) {
// if something goes wrong, just use normal behavior: continue to invoke()
System.err.print("Found Angular, but encountered an error while waiting for it to be ready. ");
e.printStackTrace();
}
}
} catch (UnhandledAlertException e) {
System.err.println("Cannot determine whether Angular is present while alert is active.");
} catch (Exception e) {
// if something goes wrong, just use normal behavior: continue to invoke()
System.err.print("Error while determining whether Angular is present. ");
e.printStackTrace();
}
}
}
protected boolean currentSiteUsesAngular() {
Object windowHasAngular = getSeleniumHelper().executeJavascript("return window.angular?1:0;");
return Long.valueOf(1).equals(windowHasAngular);
}
@Override
protected Throwable handleException(Method method, Object[] arguments, Throwable t) {
Throwable result;
if (t instanceof UnhandledAlertException) {
UnhandledAlertException e = (UnhandledAlertException) t;
String alertText = e.getAlertText();
if (alertText == null) {
alertText = alertText();
}
String msgBase = "Unhandled alert: alert must be confirmed or dismissed before test can continue. Alert text: " + alertText;
String msg = getSlimFixtureExceptionMessage("alertException", msgBase, e);
result = new StopTestException(false, msg, t);
} else if (t instanceof SlimFixtureException) {
result = super.handleException(method, arguments, t);
} else if (t instanceof WebDriverException
&& getSeleniumHelper().exceptionIndicatesConnectionLost((WebDriverException) t)) {
Throwable msgT = t.getCause() != null ? t.getCause() : t;
String msg = "Problem communicating with webdriver: " + msgT;
result = new StopTestException(false, msg, t);
} else {
String msg = getSlimFixtureExceptionMessage("exception", null, t);
result = new SlimFixtureException(false, msg, t);
}
return result;
}
public BrowserTest() {
secondsBeforeTimeout(getEnvironment().getSeleniumDriverManager().getDefaultTimeoutSeconds());
if (!ensureActiveTabIsNotClosed()) {
confirmAlertIfAvailable();
}
}
public BrowserTest(int secondsBeforeTimeout) {
this(secondsBeforeTimeout, true);
}
public BrowserTest(int secondsBeforeTimeout, boolean confirmAlertIfAvailable) {
secondsBeforeTimeout(secondsBeforeTimeout);
if (!ensureActiveTabIsNotClosed() && confirmAlertIfAvailable) {
confirmAlertIfAvailable();
}
}
public boolean open(String address) {
String url = getUrl(address);
try {
getNavigation().to(url);
} catch (TimeoutException e) {
handleTimeoutException(e);
} finally {
switchToDefaultContent();
}
waitUntil(webDriver -> {
String readyState = getSeleniumHelper().executeJavascript("return document.readyState").toString();
// IE 7 is reported to return "loaded"
boolean done = "complete".equalsIgnoreCase(readyState) || "loaded".equalsIgnoreCase(readyState);
if (!done) {
System.err.printf("Open of %s returned while document.readyState was %s", url, readyState);
System.err.println();
if (isContinueIfReadyStateInteractive() && "interactive".equals(readyState)) {
done = true;
}
}
return done;
});
return true;
}
public String location() {
return driver().getCurrentUrl();
}
public boolean back() {
getNavigation().back();
switchToDefaultContent();
// firefox sometimes prevents immediate back, if previous page was reached via POST
waitMilliseconds(500);
WebElement element = findElement(By.id("errorTryAgain"));
if (element != null) {
element.click();
// don't use confirmAlert as this may be overridden in subclass and to get rid of the
// firefox pop-up we need the basic behavior
getSeleniumHelper().getAlert().accept();
}
return true;
}
public boolean forward() {
getNavigation().forward();
switchToDefaultContent();
return true;
}
public boolean refresh() {
getNavigation().refresh();
switchToDefaultContent();
return true;
}
private WebDriver.Navigation getNavigation() {
return getSeleniumHelper().navigate();
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String alertText() {
Alert alert = getAlert();
String text = null;
if (alert != null) {
text = alert.getText();
}
return text;
}
@WaitUntil
public boolean confirmAlert() {
Alert alert = getAlert();
boolean result = false;
if (alert != null) {
alert.accept();
onAlertHandled(true);
result = true;
}
return result;
}
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean confirmAlertIfAvailable() {
return confirmAlert();
}
@WaitUntil
public boolean dismissAlert() {
Alert alert = getAlert();
boolean result = false;
if (alert != null) {
alert.dismiss();
onAlertHandled(false);
result = true;
}
return result;
}
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean dismissAlertIfAvailable() {
return dismissAlert();
}
/**
* Called when an alert is either dismissed or accepted.
*
* @param accepted true if the alert was accepted, false if dismissed.
*/
protected void onAlertHandled(boolean accepted) {
// if we were looking in nested frames, we could not go back to original frame
// because of the alert. Ensure we do so now the alert is handled.
getSeleniumHelper().resetFrameDepthOnAlertError();
}
protected Alert getAlert() {
return getSeleniumHelper().getAlert();
}
public boolean openInNewTab(String url) {
String cleanUrl = getUrl(url);
int tabCount = tabCount();
getSeleniumHelper().executeJavascript("window.open('%s', '_blank')", cleanUrl);
// ensure new window is open
waitUntil(webDriver -> tabCount() > tabCount);
return switchToNextTab();
}
@WaitUntil
public boolean switchToNextTab() {
boolean result = false;
List tabs = getTabHandles();
int currentTab = getCurrentTabIndex(tabs);
if (tabs.size() > 1 || currentTab < 0) {
int nextTab = currentTab + 1;
if (nextTab == tabs.size() || nextTab < 0) {
nextTab = 0;
}
goToTab(tabs, nextTab);
result = true;
}
return result;
}
@WaitUntil
public boolean switchToPreviousTab() {
boolean result = false;
List tabs = getTabHandles();
int currentTab = getCurrentTabIndex(tabs);
if (tabs.size() > 1 || currentTab < 0) {
int nextTab = currentTab - 1;
if (nextTab < 0) {
nextTab = tabs.size() - 1;
}
goToTab(tabs, nextTab);
result = true;
}
return result;
}
public boolean closeTab() {
boolean result = false;
List tabs = getTabHandles();
int currentTab = getCurrentTabIndex(tabs);
int tabToGoTo = -1;
if (currentTab > 0) {
tabToGoTo = currentTab - 1;
} else {
if (tabs.size() > 1) {
tabToGoTo = 1;
}
}
if (tabToGoTo > -1) {
WebDriver driver = driver();
driver.close();
goToTab(tabs, tabToGoTo);
result = true;
}
return result;
}
public void ensureOnlyOneTab() {
ensureActiveTabIsNotClosed();
int tabCount = tabCount();
for (int i = 1; i < tabCount; i++) {
closeTab();
}
}
public boolean ensureActiveTabIsNotClosed() {
boolean result = false;
List tabHandles = getTabHandles();
int currentTab = getCurrentTabIndex(tabHandles);
if (currentTab < 0) {
result = true;
goToTab(tabHandles, 0);
}
return result;
}
public int tabCount() {
return getTabHandles().size();
}
public int currentTabIndex() {
return getCurrentTabIndex(getTabHandles()) + 1;
}
protected int getCurrentTabIndex(List tabHandles) {
return getSeleniumHelper().getCurrentTabIndex(tabHandles);
}
protected void goToTab(List tabHandles, int indexToGoTo) {
getSeleniumHelper().goToTab(tabHandles, indexToGoTo);
}
protected List getTabHandles() {
return getSeleniumHelper().getTabHandles();
}
/**
* Activates main/top-level iframe (i.e. makes it the current frame).
*/
public void switchToDefaultContent() {
getSeleniumHelper().switchToDefaultContent();
clearSearchContext();
}
/**
* Activates specified child frame of current iframe.
*
* @param technicalSelector selector to find iframe.
* @return true if iframe was found.
*/
public boolean switchToFrame(String technicalSelector) {
boolean result = false;
T iframe = getElement(technicalSelector);
if (iframe != null) {
getSeleniumHelper().switchToFrame(iframe);
result = true;
}
return result;
}
/**
* Activates parent frame of current iframe.
* Does nothing if when current frame is the main/top-level one.
*/
public void switchToParentFrame() {
getSeleniumHelper().switchToParentFrame();
}
public String pageTitle() {
return getSeleniumHelper().getPageTitle();
}
/**
* @return current page's content type.
*/
public String pageContentType() {
String result = null;
Object ct = getSeleniumHelper().executeJavascript("return document.contentType;");
if (ct != null) {
result = ct.toString();
}
return result;
}
/**
* Replaces content at place by value.
*
* @param value value to set.
* @param place element to set value on.
* @return true, if element was found.
*/
@WaitUntil
public boolean enterAs(String value, String place) {
return enterAsIn(value, place, null);
}
/**
* Replace content of given (technical) locator, found left of a reference element
* Usage: | enter | [value] | as | [technicalLocator] | left of | [referencePlace] |
*
* @param value value to enter
* @param technicalLocator element to find to find (i.e. css=input)
* @param referencePlace the element to us as a reference to search from
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsLeftOf(String value, String technicalLocator, String referencePlace) {
return enterAsLeftOfIn(value, technicalLocator, referencePlace, null);
}
/**
* Replace content of given (technical) locator, found left of a reference element
* Usage: | enter | [value] | as | [technicalLocator] | left of | [referencePlace] | in | [container] |
*
* @param value value to enter
* @param technicalLocator element to find to find (i.e. css=input)
* @param referencePlace the element to us as a reference to search from
* @param container the container to search in
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsLeftOfIn(String value, String technicalLocator, String referencePlace, String container) {
return enterRelativeImp(value, technicalLocator, referencePlace, RelativeMethod.TO_LEFT_OF, container);
}
/**
* Replace content of given tag, found right of a reference element
* Usage: | enter | [value] | as | [technicalLocator] | right of | [referencePlace] |
*
* @param value value to enter
* @param technicalLocator tag to find (i.e. input)
* @param referencePlace the element to us as a reference to search from
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsRightOf(String value, String technicalLocator, String referencePlace) {
return enterAsRightOfIn(value, technicalLocator, referencePlace, null);
}
/**
* Replace content of given tag, found right of a reference element
* Usage: | enter | [value] | as | [technicalLocator] | right of | [referencePlace] | in | [container] |
*
* @param value value to enter
* @param technicalLocator tag to find (i.e. input)
* @param referencePlace the element to us as a reference to search from
* @param container the container to search in
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsRightOfIn(String value, String technicalLocator, String referencePlace, String container) {
return enterRelativeImp(value, technicalLocator, referencePlace, RelativeMethod.TO_RIGHT_OF, container);
}
/**
* Replace content of given tag, found above a reference element
*
* @param value value to enter
* @param technicalLocator tag to find (i.e. input)
* @param referencePlace the element to us as a reference to search from
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsAbove(String value, String technicalLocator, String referencePlace) {
return enterAsAboveIn(value, technicalLocator, referencePlace, null);
}
/**
* Replace content of given tag, found above a reference element, in a container
*
* @param value value to enter
* @param technicalLocator tag to find (i.e. input)
* @param referencePlace the element to us as a reference to search from
* @param container the container to search in
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsAboveIn(String value, String technicalLocator, String referencePlace, String container) {
return enterRelativeImp(value, technicalLocator, referencePlace, RelativeMethod.ABOVE, container);
}
/**
* Replace content of given tag, found below a reference element
*
* @param value value to enter
* @param technicalLocator tag to find (i.e. input)
* @param referencePlace the element to us as a reference to search from
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsBelow(String value, String technicalLocator, String referencePlace) {
return enterAsBelowIn(value, technicalLocator, referencePlace, null);
}
/**
* Replace content of given tag, found below a reference element, in a container
*
* @param value value to enter
* @param technicalLocator tag to find (i.e. input)
* @param referencePlace the element to us as a reference to search from
* @param container the container to search in
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsBelowIn(String value, String technicalLocator, String referencePlace, String container) {
return enterRelativeImp(value, technicalLocator, referencePlace, RelativeMethod.BELOW, container);
}
/**
* Replace content of given tag, found near (within 50px of) a reference element
*
* @param value value to enter
* @param technicalLocator tag to find (i.e. input)
* @param referencePlace the element to us as a reference to search from
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsNear(String value, String technicalLocator, String referencePlace) {
return enterAsNearIn(value, technicalLocator, referencePlace, null);
}
/**
* Replace content of given tag, found near (within 50px of) a reference element, in a container
*
* @param value value to enter
* @param technicalLocator tag to find (i.e. input)
* @param referencePlace the element to us as a reference to search from
* @param container the container to search in
* @return true if the element was found and the value was sent
*/
@WaitUntil
public boolean enterAsNearIn(String value, String technicalLocator, String referencePlace, String container) {
return enterRelativeImp(value, technicalLocator, referencePlace, RelativeMethod.NEAR, container);
}
public boolean enterRelativeImp(String value, String technicalLocator, String referencePlace, RelativeMethod relativeMethod, String container) {
boolean result = false;
try {
T elementToSendValue = doInContainer(container, () -> getSeleniumHelper().getElementRelativeToReference(technicalLocator, cleanupValue(referencePlace), relativeMethod));
result = enter(elementToSendValue, value, true);
} catch (IllegalArgumentException | InvalidElementStateException e) {
// if referenceElement was not yet found, or the element found is not (yet) interactable hold back the exception so WaitUntil is not interrupted
if (!(e instanceof InvalidElementStateException) && !exceptionIsFromRelativeLocator(e)) {
throw e;
}
}
return result;
}
/**
* Replaces content at place by value.
*
* @param value value to set.
* @param place element to set value on.
* @param container element containing place.
* @return true, if element was found.
*/
@WaitUntil
public boolean enterAsIn(String value, String place, String container) {
return enter(value, place, container, true);
}
/**
* Adds content to place.
*
* @param value value to add.
* @param place element to add value to.
* @return true, if element was found.
*/
@WaitUntil
public boolean enterFor(String value, String place) {
return enterForIn(value, place, null);
}
/**
* Adds content to place.
*
* @param value value to add.
* @param place element to add value to.
* @param container element containing place.
* @return true, if element was found.
*/
@WaitUntil
public boolean enterForIn(String value, String place, String container) {
return enter(value, place, container, false);
}
protected boolean enter(String value, String place, boolean shouldClear) {
return enter(value, place, null, shouldClear);
}
protected boolean enter(String value, String place, String container, boolean shouldClear) {
WebElement element = getElementToSendValue(place, container);
return enter(element, value, shouldClear);
}
protected boolean enter(WebElement element, String value, boolean shouldClear) {
boolean result = element != null && isInteractable(element);
if (result) {
if (isSelect(element)) {
result = clickSelectOption(element, value);
} else {
if (shouldClear) {
result = clear(element);
}
if (result) {
sendValue(element, value);
}
}
}
return result;
}
@WaitUntil
public boolean enterDateAs(String date, String place) {
WebElement element = getElementToSendValue(place);
boolean result = element != null && isInteractable(element);
if (result) {
getSeleniumHelper().fillDateInput(element, date);
}
return result;
}
protected T getElementToSendValue(String place) {
return getElementToSendValue(place, null);
}
protected T getElementToSendValue(String place, String container) {
return getElement(place, container);
}
/**
* Simulates pressing the 'Tab' key.
*
* @return true, if an element was active the key could be sent to.
*/
public boolean pressTab() {
return sendKeysToActiveElement(Keys.TAB);
}
/**
* Simulates pressing the 'Enter' key.
*
* @return true, if an element was active the key could be sent to.
*/
public boolean pressEnter() {
return sendKeysToActiveElement(Keys.ENTER);
}
/**
* Simulates pressing the 'Esc' key.
*
* @return true, if an element was active the key could be sent to.
*/
public boolean pressEsc() {
return sendKeysToActiveElement(Keys.ESCAPE);
}
/**
* Simulates typing a text to the current active element.
*
* @param text text to type.
* @return true, if an element was active the text could be sent to.
*/
public boolean type(String text) {
String value = cleanupValue(text);
return sendKeysToActiveElement(value);
}
/**
* Simulates pressing a key (or a combination of keys).
* (Unfortunately not all combinations seem to be accepted by all drivers, e.g.
* Chrome on OSX seems to ignore Command+A or Command+T; https://code.google.com/p/selenium/issues/detail?id=5919).
*
* @param key key to press, can be a normal letter (e.g. 'M') or a special key (e.g. 'down').
* Combinations can be passed by separating the keys to send with '+' (e.g. Command + T).
* @return true, if an element was active the key could be sent to.
*/
public boolean press(String key) {
CharSequence s;
String[] parts = key.split("\\s*\\+\\s*");
if (parts.length > 1
&& !"".equals(parts[0]) && !"".equals(parts[1])) {
CharSequence[] sequence = new CharSequence[parts.length];
for (int i = 0; i < parts.length; i++) {
sequence[i] = parseKey(parts[i]);
}
s = Keys.chord(sequence);
} else {
s = parseKey(key);
}
return sendKeysToActiveElement(s);
}
protected CharSequence parseKey(String key) {
CharSequence s;
try {
s = Keys.valueOf(key.toUpperCase());
if (Keys.CONTROL.equals(s) && sendCommandForControlOnMac) {
s = getSeleniumHelper().getControlOrCommand();
}
} catch (IllegalArgumentException e) {
s = key;
}
return s;
}
/**
* Simulates pressing keys.
*
* @param keys keys to press.
* @return true, if an element was active the keys could be sent to.
*/
protected boolean sendKeysToActiveElement(CharSequence... keys) {
boolean result = false;
WebElement element = getSeleniumHelper().getActiveElement();
if (element != null) {
element.sendKeys(keys);
result = true;
}
return result;
}
/**
* Sends Fitnesse cell content to element.
*
* @param element element to call sendKeys() on.
* @param value cell content.
*/
protected void sendValue(WebElement element, String value) {
if (StringUtils.isNotEmpty(value)) {
String keys = cleanupValue(value);
element.sendKeys(keys);
}
}
@WaitUntil
public boolean selectAs(String value, String place) {
WebElement element = getElementToSelectFor(place);
if (element != null) {
Select select = new Select(element);
if (select.isMultiple()) {
select.deselectAll();
}
}
return clickSelectOption(element, value);
}
@WaitUntil
public boolean selectAsIn(String value, String place, String container) {
return Boolean.TRUE.equals(doInContainer(container, () -> selectAs(value, place)));
}
@WaitUntil
public boolean selectFor(String value, String place) {
WebElement element = getElementToSelectFor(place);
return clickSelectOption(element, value);
}
@WaitUntil
public boolean selectForIn(String value, String place, String container) {
return Boolean.TRUE.equals(doInContainer(container, () -> selectFor(value, place)));
}
@WaitUntil
public boolean enterForHidden(String value, String idOrName) {
return getSeleniumHelper().setHiddenInputValue(idOrName, value);
}
protected T getElementToSelectFor(String selectPlace) {
return getElement(selectPlace);
}
protected boolean clickSelectOption(WebElement element, String optionValue) {
boolean result = false;
if (element != null) {
if (isSelect(element)) {
optionValue = cleanupValue(optionValue);
By optionBy = new OptionBy(optionValue);
WebElement option = optionBy.findElement(element);
result = clickSelectOption(element, option);
}
}
return result;
}
protected boolean clickSelectOption(WebElement element, WebElement option) {
boolean result = false;
if (option != null) {
// we scroll containing select into view (not the option)
// based on behavior for option in https://www.w3.org/TR/webdriver/#element-click
scrollIfNotOnScreen(element);
if (isInteractable(option)) {
option.click();
result = true;
}
}
return result;
}
@WaitUntil
public boolean click(String place) {
return clickImp(place, null);
}
public void clickAtOffsetXY(String place, Integer xOffset, Integer yOffset) {
place = cleanupValue(place);
try {
WebElement element = getElementToClick(place);
getSeleniumHelper().clickAtOffsetXY(element, xOffset, yOffset);
} catch (WebDriverException e) {
if (!this.clickExceptionIsAboutHiddenByOtherElement(e)) {
throw e;
}
}
}
public void doubleClickAtOffsetXY(String place, Integer xOffset, Integer yOffset) {
place = cleanupValue(place);
try {
WebElement element = getElementToClick(place);
getSeleniumHelper().doubleClickAtOffsetXY(element, xOffset, yOffset);
} catch (WebDriverException e) {
if (!this.clickExceptionIsAboutHiddenByOtherElement(e)) {
throw e;
}
}
}
public void rightClickAtOffsetXY(String place, Integer xOffset, Integer yOffset) {
place = cleanupValue(place);
try {
WebElement element = getElementToClick(place);
getSeleniumHelper().rightClickAtOffsetXY(element, xOffset, yOffset);
} catch (WebDriverException e) {
if (!this.clickExceptionIsAboutHiddenByOtherElement(e)) {
throw e;
}
}
}
public void dragAndDropToOffsetXY(String place, Integer xOffset, Integer yOffset) {
place = cleanupValue(place);
try {
WebElement element = getElementToClick(place);
if (dragPressDelay == null && dragDistance == null) {
getSeleniumHelper().dragAndDropToOffsetXY(element, xOffset, yOffset);
} else if (dragDistance != null) {
getSeleniumHelper().dragWithDistanceAndDropToOffsetXY(element, dragDistance, xOffset, yOffset);
} else {
getSeleniumHelper().dragWithDelayAndDropToOffsetXY(element, dragPressDelay, xOffset, yOffset);
}
} catch (WebDriverException e) {
if (!this.clickExceptionIsAboutHiddenByOtherElement(e)) {
throw e;
}
}
}
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean clickIfAvailable(String place) {
return clickIfAvailableIn(place, null);
}
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean clickIfAvailableIn(String place, String container) {
return clickImp(place, container);
}
@WaitUntil
public boolean clickIn(String place, String container) {
return clickImp(place, container);
}
/**
* Click an element found by it's technicalLocator, below its reference place
*
* @param technicalLocator The technicalLocator to look for (i.e. css=input)
* @param referencePlace The element to use as a reference
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickBelow(String technicalLocator, String referencePlace) {
return clickBelowIn(technicalLocator, referencePlace, null);
}
/**
* Click an element found by it's technicalLocator, below its reference place, in a container
*
* @param technicalLocator The technicalLocator to look for (i.e. css=input)
* @param referencePlace The element to use as a reference
* @param container A reference to the container to search in
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickBelowIn(String technicalLocator, String referencePlace, String container) {
return relativeClickImp(technicalLocator, referencePlace, RelativeMethod.BELOW, container);
}
/**
* Click an element found by it's technicalLocator name, above its reference place
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickAbove(String technicalLocator, String referencePlace) {
return clickAboveIn(technicalLocator, referencePlace, null);
}
/**
* Click an element found by it's technicalLocator name, above its reference place, in a container
*
* @param technicalLocator The technicalLocator to look for (i.e. css=input)
* @param referencePlace The element to use as a reference
* @param container A reference to the container to search in
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickAboveIn(String technicalLocator, String referencePlace, String container) {
return relativeClickImp(technicalLocator, referencePlace, RelativeMethod.ABOVE, container);
}
/**
* Click an element found by it's technicalLocator name, left of its reference place
* Usage: | click | [technicalLocator] | right of | [referencePlace] |
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickRightOf(String technicalLocator, String referencePlace) {
return clickRightOfIn(technicalLocator, referencePlace, null);
}
/**
* Click an element found by it's technicalLocator name, left of its reference place, in a container
* Usage: | click | [technicalLocator] | right of | [referencePlace] | in | [container] |
*
* @param technicalLocator The technicalLocator to look for (i.e. css= input)
* @param referencePlace The element to use as a reference
* @param container A reference to the container to search in
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickRightOfIn(String technicalLocator, String referencePlace, String container) {
return relativeClickImp(technicalLocator, referencePlace, RelativeMethod.TO_RIGHT_OF, container);
}
/**
* Click an element found by it's technicalLocator name, right of its reference place
* Usage: | click | [technicalLocator] | left of | [referencePlace] |
*
* @param technicalLocator The technicalLocator to look for (i.e. css=input)
* @param referencePlace The element to use as a reference
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickLeftOf(String technicalLocator, String referencePlace) {
return clickLeftOfIn(technicalLocator, referencePlace, null);
}
/**
* Click an element found by it's technicalLocator name, right of its reference place, in a container
* Usage: | click | [technicalLocator] | left of | [referencePlace] | in | [container] |
*
* @param technicalLocator The technicalLocator to look for (i.e. css=input)
* @param referencePlace The element to use as a reference
* @param container A reference to the container to search in
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickLeftOfIn(String technicalLocator, String referencePlace, String container) {
return relativeClickImp(technicalLocator, referencePlace, RelativeMethod.TO_LEFT_OF, container);
}
/**
* Click an element found by it's technicalLocator name, near (within 50px of) its reference place
*
* @param technicalLocator The technicalLocator to look for (i.e. css=input)
* @param referencePlace The element to use as a reference
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickNear(String technicalLocator, String referencePlace) {
return clickNearIn(technicalLocator, referencePlace, null);
}
/**
* Click an element found by it's technicalLocator name, near (within 50px of) its reference place, in a container
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @param container A reference to the container to search in
* @return true if the element was found and clicked
*/
@WaitUntil
public boolean clickNearIn(String technicalLocator, String referencePlace, String container) {
return relativeClickImp(technicalLocator, referencePlace, RelativeMethod.NEAR, container);
}
protected boolean relativeClickImp(String technicalLocator, String referencePlace, RelativeMethod relativeMethod, String container) {
boolean result = false;
try {
T elementToClick = doInContainer(container,
() -> getSeleniumHelper().getElementRelativeToReference(technicalLocator, cleanupValue(referencePlace), relativeMethod));
result = clickElement(elementToClick);
} catch (IllegalArgumentException | WebDriverException e) {
// if other element hides the element, or referenceElement was not yet found, hold back the exception so WaitUntil is not interrupted
if (!clickExceptionIsAboutHiddenByOtherElement(e) && !exceptionIsFromRelativeLocator(e)) {
throw e;
}
}
return result;
}
protected boolean clickImp(String place, String container) {
boolean result = false;
place = cleanupValue(place);
try {
WebElement element = getElementToClick(place, container);
result = clickElement(element);
} catch (WebDriverException e) {
// if other element hides the element, hold back the exception so WaitUntil is not interrupted
if (!clickExceptionIsAboutHiddenByOtherElement(e)) {
throw e;
}
}
return result;
}
protected boolean exceptionIsFromRelativeLocator(Exception e) {
return e.getMessage().startsWith("Element to search") && e.getMessage().endsWith("must be set");
}
protected boolean clickExceptionIsAboutHiddenByOtherElement(Exception e) {
String msg = e.getMessage();
return msg != null
&& (msg.contains(CHROME_HIDDEN_BY_OTHER_ELEMENT_ERROR)
|| msg.contains(EDGE_HIDDEN_BY_OTHER_ELEMENT_ERROR)
|| FIREFOX_HIDDEN_BY_OTHER_ELEMENT_ERROR_PATTERN.matcher(msg).find()
// IE does not throw an exception, so no need to detect any
// Safari does throw an exception, but not one specific to this event. Too bad :/
);
}
@WaitUntil
public boolean doubleClick(String place) {
return doubleClickIn(place, null);
}
@WaitUntil
public boolean doubleClickIn(String place, String container) {
place = cleanupValue(place);
WebElement element = getElementToClick(place, container);
return doubleClick(element);
}
protected boolean doubleClick(WebElement element) {
return doIfInteractable(element, () -> getSeleniumHelper().doubleClick(element));
}
@WaitUntil
public boolean rightClick(String place) {
return rightClickIn(place, null);
}
@WaitUntil
public boolean rightClickIn(String place, String container) {
place = cleanupValue(place);
WebElement element = getElementToClick(place, container);
return rightClick(element);
}
protected boolean rightClick(WebElement element) {
return doIfInteractable(element, () -> getSeleniumHelper().rightClick(element));
}
@WaitUntil
public boolean shiftClick(String place) {
return shiftClickIn(place, null);
}
@WaitUntil
public boolean shiftClickIn(String place, String container) {
place = cleanupValue(place);
WebElement element = getElementToClick(place, container);
return shiftClick(element);
}
protected boolean shiftClick(WebElement element) {
return doIfInteractable(element, () -> getSeleniumHelper().clickWithKeyDown(element, Keys.SHIFT));
}
@WaitUntil
public boolean controlClick(String place) {
return controlClickIn(place, null);
}
@WaitUntil
public boolean controlClickIn(String place, String container) {
place = cleanupValue(place);
WebElement element = getElementToClick(place, container);
return controlClick(element);
}
protected boolean controlClick(WebElement element) {
return doIfInteractable(element, () -> getSeleniumHelper().clickWithKeyDown(element, controlKey()));
}
public void setSendCommandForControlOnMacTo(boolean sendCommand) {
sendCommandForControlOnMac = sendCommand;
}
public boolean sendCommandForControlOnMac() {
return sendCommandForControlOnMac;
}
protected Keys controlKey() {
return sendCommandForControlOnMac ? getSeleniumHelper().getControlOrCommand() : Keys.CONTROL;
}
protected Long getDragPressDelay() {
return dragPressDelay;
}
protected Integer getDragDistance() {
return dragDistance;
}
public void setDragDistance(int dragDistance) {
this.dragDistance = dragDistance;
}
public void setDragPressDelay(long dragPressDelay) {
this.dragPressDelay = dragPressDelay;
}
public void clearDragSetup() {
this.dragPressDelay = null;
this.dragDistance = null;
}
@WaitUntil
public boolean dragAndDropTo(String source, String destination) {
return this.dragAndDropImpl(source, destination, false);
}
@WaitUntil
public boolean html5DragAndDropTo(String source, String destination) {
return dragAndDropImpl(source, destination, true);
}
protected boolean dragAndDropImpl(String source, String destination, boolean html5) {
boolean result = false;
Long dragPressDelay = getDragPressDelay();
Integer dragDistance = getDragDistance();
source = cleanupValue(source);
WebElement sourceElement = getElementToClick(source);
destination = cleanupValue(destination);
WebElement destinationElement = getElementToClick(destination);
if ((sourceElement != null) && (destinationElement != null)) {
scrollIfNotOnScreen(sourceElement);
if (isInteractable(sourceElement) && destinationElement.isDisplayed()) {
if (html5 || sourceElement.getAttribute("draggable").equalsIgnoreCase("true")) {
try {
getSeleniumHelper().html5DragAndDrop(sourceElement, destinationElement);
} catch (IOException e) {
throw new SlimFixtureException(false, "The drag and drop simulator javascript could not be found.", e);
}
} else if (dragPressDelay == null && dragDistance == null) {
getSeleniumHelper().dragAndDrop(sourceElement, destinationElement);
} else if (dragDistance != null) {
getSeleniumHelper().dragWithDistanceAndDrop(sourceElement, dragDistance, destinationElement);
} else {
getSeleniumHelper().dragWithDelayAndDrop(sourceElement, dragPressDelay, destinationElement);
}
result = true;
}
}
return result;
}
protected T getElementToClick(String place) {
return getSeleniumHelper().getElementToClick(place);
}
protected T getElementToClick(String place, String container) {
return doInContainer(container, () -> getElementToClick(place));
}
/**
* Convenience method to create custom heuristics in subclasses.
*
* @param container container to use (use null
for current container), can be a technical selector.
* @param place place to look for inside container, can be a technical selector.
* @param suppliers suppliers that will be used in turn until an element is found, IF place is not a technical selector.
* @return first hit of place, technical selector or result of first supplier that provided result.
*/
protected T findFirstInContainer(String container, String place, Supplier extends T>... suppliers) {
return doInContainer(container, () -> getSeleniumHelper().findByTechnicalSelectorOr(place, suppliers));
}
protected R doInContainer(String container, Supplier action) {
R result = null;
if (container == null) {
result = action.get();
} else {
String cleanContainer = cleanupValue(container);
result = doInContainer(() -> getContainerElement(cleanContainer), action);
}
return result;
}
protected R doInContainer(Supplier containerSupplier, Supplier action) {
R result = null;
int retryCount = minStaleContextRefreshCount;
do {
try {
T containerElement = containerSupplier.get();
if (containerElement != null) {
result = doInContainer(containerElement, action);
}
retryCount = 0;
} catch (StaleContextException e) {
// containerElement went stale
retryCount--;
if (retryCount < 1) {
throw e;
}
}
} while (retryCount > 0);
return result;
}
protected R doInContainer(T container, Supplier action) {
SearchContext containerContext = container;
if (containersAsShadowRoot && container.getShadowRoot() != null) {
containerContext = container.getShadowRoot();
}
return getSeleniumHelper().doInContext(containerContext, action);
}
@WaitUntil
public boolean setSearchContextTo(String container) {
container = cleanupValue(container);
WebElement containerElement = getContainerElement(container);
boolean result = false;
if (containerElement != null) {
getCurrentSearchContextPath().add(container);
if (containersAsShadowRoot && containerElement.getShadowRoot() != null) {
setSearchContextTo(containerElement.getShadowRoot());
} else {
setSearchContextTo(containerElement);
}
result = true;
}
return result;
}
protected void setSearchContextTo(SearchContext containerElement) {
getSeleniumHelper().setCurrentContext(containerElement);
}
public void clearSearchContext() {
getCurrentSearchContextPath().clear();
getSeleniumHelper().setCurrentContext(null);
}
protected T getContainerElement(String container) {
return findByTechnicalSelectorOr(container, this::getContainerImpl);
}
protected T getContainerImpl(String container) {
return findElement(ContainerBy.heuristic(container));
}
protected boolean clickElement(WebElement element) {
return doIfInteractable(element, () -> element.click());
}
protected boolean doIfInteractable(WebElement element, Runnable action) {
boolean result = false;
if (element != null) {
scrollIfNotOnScreen(element);
if (isInteractable(element)) {
action.run();
result = true;
}
}
return result;
}
protected boolean isInteractable(WebElement element) {
return getSeleniumHelper().isInteractable(element);
}
@WaitUntil(TimeoutPolicy.STOP_TEST)
public boolean waitForPage(String pageName) {
return pageTitle().equals(pageName);
}
public boolean waitForTagWithText(String tagName, String expectedText) {
return waitForElementWithText(By.tagName(tagName), expectedText);
}
public boolean waitForClassWithText(String cssClassName, String expectedText) {
return waitForElementWithText(By.className(cssClassName), expectedText);
}
protected boolean waitForElementWithText(By by, String expectedText) {
String textToLookFor = cleanExpectedValue(expectedText);
return waitUntilOrStop(webDriver -> {
boolean ok = false;
List elements = webDriver.findElements(by);
if (elements != null) {
for (WebElement element : elements) {
// we don't want stale elements to make single
// element false, but instead we stop processing
// current list and do a new findElements
ok = hasText(element, textToLookFor);
if (ok) {
// no need to continue to check other elements
break;
}
}
}
return ok;
});
}
protected String cleanExpectedValue(String expectedText) {
return cleanupValue(expectedText);
}
protected boolean hasText(WebElement element, String textToLookFor) {
boolean ok;
String actual = getElementText(element);
if (textToLookFor == null) {
ok = actual == null;
} else {
if (StringUtils.isEmpty(actual)) {
String value = element.getAttribute("value");
if (!StringUtils.isEmpty(value)) {
actual = value;
}
}
if (actual != null) {
actual = actual.trim();
}
ok = textToLookFor.equals(actual);
}
return ok;
}
@WaitUntil(TimeoutPolicy.STOP_TEST)
public boolean waitForClass(String cssClassName) {
boolean ok = false;
WebElement element = findElement(By.className(cssClassName));
if (element != null) {
ok = true;
}
return ok;
}
@WaitUntil(TimeoutPolicy.STOP_TEST)
public boolean waitForVisible(String place) {
return waitForVisibleIn(place, null);
}
@WaitUntil(TimeoutPolicy.STOP_TEST)
public boolean waitForVisibleIn(String place, String container) {
Boolean result = Boolean.FALSE;
WebElement element = getElementToCheckVisibility(place, container);
if (element != null) {
scrollIfNotOnScreen(element);
result = element.isDisplayed();
}
return result;
}
/**
* @deprecated use #waitForVisible(xpath=) instead
*/
@Deprecated
public boolean waitForXPathVisible(String xPath) {
By by = By.xpath(xPath);
return waitForVisible(by);
}
@Deprecated
protected boolean waitForVisible(By by) {
return waitUntilOrStop(webDriver -> {
Boolean result = Boolean.FALSE;
WebElement element = findElement(by);
if (element != null) {
scrollIfNotOnScreen(element);
result = element.isDisplayed();
}
return result;
});
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOf(String place) {
return valueFor(place);
}
/**
* Get the value of an element found by it's technicalLocator, to the left of its reference place
* Usage: | value of | [technicalLocator] | left of | [referencePlace] |
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfLeftOf(String technicalLocator, String referencePlace) {
return valueOfLeftOfIn(technicalLocator, referencePlace, null);
}
/**
* Get the value of an element found by it's technicalLocator, to the left of its reference place, in a container
* Usage: | value of | [technicalLocator] | left of | [referencePlace] | in | [container] |
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @param container The container to search inside of
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfLeftOfIn(String technicalLocator, String referencePlace, String container) {
return valueOfRelativeImp(technicalLocator, referencePlace, RelativeMethod.TO_LEFT_OF, container);
}
/**
* Get the value of an element found by it's technicalLocator, to the right of its reference place
* Usage: | value of | [technicalLocator] | right of | [referencePlace] |
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfRightOf(String technicalLocator, String referencePlace) {
return valueOfRightOfIn(technicalLocator, referencePlace, null);
}
/**
* Get the value of an element found by it's technicalLocator, to the right of its reference place, in a container
* Usage: | value of | [technicalLocator] | right of | [referencePlace] | in | [container] |
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @param container The container to search inside of
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfRightOfIn(String technicalLocator, String referencePlace, String container) {
return valueOfRelativeImp(technicalLocator, referencePlace, RelativeMethod.TO_RIGHT_OF, container);
}
/**
* Get the value of an element found by it's technicalLocator, above its reference place
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfAbove(String technicalLocator, String referencePlace) {
return valueOfAboveIn(technicalLocator, referencePlace, null);
}
/**
* Get the value of an element found by it's technicalLocator, above its reference place, in a container
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @param container The container to search in
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfAboveIn(String technicalLocator, String referencePlace, String container) {
return valueOfRelativeImp(technicalLocator, referencePlace, RelativeMethod.ABOVE, container);
}
/**
* Get the value of an element found by it's technicalLocator, below its reference place
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfBelow(String technicalLocator, String referencePlace) {
return valueOfBelowIn(technicalLocator, referencePlace, null);
}
/**
* Get the value of an element found by it's technicalLocator, below its reference place, in a container
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @param container The container to search inside of
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfBelowIn(String technicalLocator, String referencePlace, String container) {
return valueOfRelativeImp(technicalLocator, referencePlace, RelativeMethod.BELOW, container);
}
/**
* Get the value of an element found by it's technicalLocator, near (within 50px of) its reference place
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfNear(String technicalLocator, String referencePlace) {
return valueOfNearIn(technicalLocator, referencePlace, null);
}
/**
* Get the value of an element found by it's technicalLocator, near (within 50px of) its reference place, in a container
*
* @param technicalLocator The technicalLocator to look for (i.e. input)
* @param referencePlace The element to use as a reference
* @param container The container to search inside of
* @return the value of the element if found
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfNearIn(String technicalLocator, String referencePlace, String container) {
return valueOfRelativeImp(technicalLocator, referencePlace, RelativeMethod.NEAR, container);
}
protected String valueOfRelativeImp(String technicalLocator, String referencePlace, RelativeMethod relativeMethod, String container) {
String result = null;
try {
T elementToRetrieveValueFrom = doInContainer(container,
() -> getSeleniumHelper().getElementRelativeToReference(technicalLocator, cleanupValue(referencePlace), relativeMethod));
result = valueFor(elementToRetrieveValueFrom);
} catch (IllegalArgumentException | WebDriverException e) {
// if referenceElement was not yet found, hold back the exception so WaitUntil is not interrupted
if (!exceptionIsFromRelativeLocator(e)) {
throw e;
}
}
return result;
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueFor(String place) {
return valueForIn(place, null);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfIn(String place, String container) {
return valueForIn(place, container);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueForIn(String place, String container) {
WebElement element = getElementToRetrieveValue(place, container);
return valueFor(element);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String normalizedValueOf(String place) {
return normalizedValueFor(place);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String normalizedValueFor(String place) {
return normalizedValueForIn(place, null);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String normalizedValueOfIn(String place, String container) {
return normalizedValueForIn(place, container);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String normalizedValueForIn(String place, String container) {
String value = valueForIn(place, container);
return normalizeValue(value);
}
protected ArrayList normalizeValues(ArrayList values) {
if (values != null) {
for (int i = 0; i < values.size(); i++) {
String value = values.get(i);
String normalized = normalizeValue(value);
values.set(i, normalized);
}
}
return values;
}
protected String normalizeValue(String value) {
String text = XPathBy.getNormalizedText(value);
if (text != null && trimOnNormalize) {
text = text.trim();
}
return text;
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String tooltipFor(String place) {
return tooltipForIn(place, null);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String tooltipForIn(String place, String container) {
return valueOfAttributeOnIn("title", place, container);
}
@WaitUntil
public String targetOfLink(String place) {
WebElement linkElement = getSeleniumHelper().getLink(place);
return getLinkTarget(linkElement);
}
protected String getLinkTarget(WebElement linkElement) {
String target = null;
if (linkElement != null) {
target = linkElement.getAttribute("href");
if (target == null) {
target = linkElement.getAttribute("src");
}
}
return target;
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfAttributeOn(String attribute, String place) {
return valueOfAttributeOnIn(attribute, place, null);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfAttributeOnIn(String attribute, String place, String container) {
String result = null;
WebElement element = getElementToRetrieveValue(place, container);
if (element != null) {
result = element.getAttribute(attribute);
}
return result;
}
protected T getElementToRetrieveValue(String place, String container) {
return getElement(place, container);
}
protected String valueFor(By by) {
WebElement element = getSeleniumHelper().findElement(by);
return valueFor(element);
}
protected String valueFor(WebElement element) {
String result = null;
if (element != null) {
if (isSelect(element)) {
WebElement selected = getFirstSelectedOption(element);
result = getElementText(selected);
} else {
String elementType = element.getAttribute("type");
if ("checkbox".equals(elementType)
|| "radio".equals(elementType)) {
result = String.valueOf(element.isSelected());
} else if ("li".equalsIgnoreCase(element.getTagName())) {
result = getElementText(element);
} else {
result = element.getAttribute("value");
if (result == null) {
result = getElementText(element);
}
}
}
}
return result;
}
protected WebElement getFirstSelectedOption(WebElement selectElement) {
SelectHelper s = new SelectHelper(selectElement);
return s.getFirstSelectedOption();
}
protected List getSelectedOptions(WebElement selectElement) {
SelectHelper s = new SelectHelper(selectElement);
return s.getAllSelectedOptions();
}
protected boolean isSelect(WebElement element) {
return SelectHelper.isSelect(element);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList valuesOf(String place) {
return valuesFor(place);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList valuesOfIn(String place, String container) {
return valuesForIn(place, container);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList valuesFor(String place) {
return valuesForIn(place, null);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList valuesForIn(String place, String container) {
ArrayList values = null;
WebElement element = getElementToRetrieveValue(place, container);
if (element != null) {
values = new ArrayList();
String tagName = element.getTagName();
if ("ul".equalsIgnoreCase(tagName)
|| "ol".equalsIgnoreCase(tagName)) {
List items = element.findElements(By.tagName("li"));
for (WebElement item : items) {
if (item.isDisplayed()) {
values.add(getElementText(item));
}
}
} else if (isSelect(element)) {
List options = getSelectedOptions(element);
for (WebElement item : options) {
values.add(getElementText(item));
}
} else {
values.add(valueFor(element));
}
}
return values;
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList normalizedValuesOf(String place) {
return normalizedValuesFor(place);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList normalizedValuesOfIn(String place, String container) {
return normalizedValuesForIn(place, container);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList normalizedValuesFor(String place) {
return normalizedValuesForIn(place, null);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList normalizedValuesForIn(String place, String container) {
ArrayList values = valuesForIn(place, container);
return normalizeValues(values);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public Integer numberFor(String place) {
Integer number = null;
WebElement element = findElement(ListItemBy.numbered(place));
if (element != null) {
scrollIfNotOnScreen(element);
number = getSeleniumHelper().getNumberFor(element);
}
return number;
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public Integer numberForIn(String place, String container) {
return doInContainer(container, () -> numberFor(place));
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList availableOptionsFor(String place) {
ArrayList result = null;
WebElement element = getElementToSelectFor(place);
if (element != null) {
scrollIfNotOnScreen(element);
result = getSeleniumHelper().getAvailableOptions(element);
}
return result;
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public ArrayList normalizedAvailableOptionsFor(String place) {
return normalizeValues(availableOptionsFor(place));
}
@WaitUntil
public boolean clear(String place) {
return clearIn(place, null);
}
@WaitUntil
public boolean clearIn(String place, String container) {
boolean result = false;
WebElement element = getElementToClear(place, container);
if (element != null) {
result = clear(element);
}
return result;
}
protected boolean clear(WebElement element) {
boolean result = false;
String tagName = element.getTagName();
if ("input".equalsIgnoreCase(tagName) || "textarea".equalsIgnoreCase(tagName)) {
element.clear();
result = true;
}
return result;
}
protected T getElementToClear(String place, String container) {
return getElementToSendValue(place, container);
}
@WaitUntil
public boolean enterAsInRowWhereIs(String value, String requestedColumnName, String selectOnColumn, String selectOnValue) {
By cellBy = waiAriaTables ?
AriaGridBy.columnInRowWhereIs(requestedColumnName, selectOnColumn, selectOnValue) :
GridBy.columnInRowWhereIs(requestedColumnName, selectOnColumn, selectOnValue);
WebElement element = findElement(cellBy);
return enter(element, value, true);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfColumnNumberInRowNumber(int columnIndex, int rowIndex) {
By by = waiAriaTables ?
AriaGridBy.coordinates(columnIndex, rowIndex) :
GridBy.coordinates(columnIndex, rowIndex);
return valueFor(by);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfInRowNumber(String requestedColumnName, int rowIndex) {
By by = waiAriaTables ?
AriaGridBy.columnInRow(requestedColumnName, rowIndex) :
GridBy.columnInRow(requestedColumnName, rowIndex);
return valueFor(by);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String valueOfInRowWhereIs(String requestedColumnName, String selectOnColumn, String selectOnValue) {
By by = waiAriaTables ?
AriaGridBy.columnInRowWhereIs(requestedColumnName, selectOnColumn, selectOnValue) :
GridBy.columnInRowWhereIs(requestedColumnName, selectOnColumn, selectOnValue);
return valueFor(by);
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String normalizedValueOfColumnNumberInRowNumber(int columnIndex, int rowIndex) {
return normalizeValue(valueOfColumnNumberInRowNumber(columnIndex, rowIndex));
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String normalizedValueOfInRowNumber(String requestedColumnName, int rowIndex) {
return normalizeValue(valueOfInRowNumber(requestedColumnName, rowIndex));
}
@WaitUntil(TimeoutPolicy.RETURN_NULL)
public String normalizedValueOfInRowWhereIs(String requestedColumnName, String selectOnColumn, String selectOnValue) {
return normalizeValue(valueOfInRowWhereIs(requestedColumnName, selectOnColumn, selectOnValue));
}
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean rowExistsWhereIs(String selectOnColumn, String selectOnValue) {
return waiAriaTables ?
findElement(AriaGridBy.rowWhereIs(selectOnColumn, selectOnValue)) != null :
findElement(GridBy.rowWhereIs(selectOnColumn, selectOnValue)) != null;
}
@WaitUntil
public boolean clickInRowNumber(String place, int rowIndex) {
By rowBy = waiAriaTables ?
AriaGridBy.rowNumber(rowIndex) :
GridBy.rowNumber(rowIndex);
return clickInRow(rowBy, place);
}
@WaitUntil
public boolean clickInRowWhereIs(String place, String selectOnColumn, String selectOnValue) {
By rowBy = waiAriaTables ?
AriaGridBy.rowWhereIs(selectOnColumn, selectOnValue) :
GridBy.rowWhereIs(selectOnColumn, selectOnValue);
return clickInRow(rowBy, place);
}
protected boolean clickInRow(By rowBy, String place) {
return Boolean.TRUE.equals(doInContainer(() -> findElement(rowBy), () -> click(place)));
}
/**
* Downloads the target of a link in a grid's row.
*
* @param place which link to download.
* @param rowNumber (1-based) row number to retrieve link from.
* @return downloaded file if any, null otherwise.
*/
@WaitUntil
public String downloadFromRowNumber(String place, int rowNumber) {
return waiAriaTables ?
downloadFromRow(AriaGridBy.linkInRow(place, rowNumber)) :
downloadFromRow(GridBy.linkInRow(place, rowNumber));
}
/**
* Downloads the target of a link in a grid, finding the row based on one of the other columns' value.
*
* @param place which link to download.
* @param selectOnColumn column header of cell whose value must be selectOnValue.
* @param selectOnValue value to be present in selectOnColumn to find correct row.
* @return downloaded file if any, null otherwise.
*/
@WaitUntil
public String downloadFromRowWhereIs(String place, String selectOnColumn, String selectOnValue) {
return waiAriaTables ?
downloadFromRow(AriaGridBy.linkInRowWhereIs(place, selectOnColumn, selectOnValue)) :
downloadFromRow(GridBy.linkInRowWhereIs(place, selectOnColumn, selectOnValue));
}
protected String downloadFromRow(By linkBy) {
String result = null;
WebElement element = findElement(linkBy);
if (element != null) {
result = downloadLinkTarget(element);
}
return result;
}
protected T getElement(String place) {
return getSeleniumHelper().getElement(place);
}
protected T getElement(String place, String container) {
return doInContainer(container, () -> getElement(place));
}
/**
* @deprecated use #click(xpath=) instead.
*/
@WaitUntil
@Deprecated
public boolean clickByXPath(String xPath) {
WebElement element = findByXPath(xPath);
return clickElement(element);
}
/**
* @deprecated use #valueOf(xpath=) instead.
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
@Deprecated
public String textByXPath(String xPath) {
return getTextByXPath(xPath);
}
protected String getTextByXPath(String xpathPattern, String... params) {
WebElement element = findByXPath(xpathPattern, params);
return getElementText(element);
}
/**
* @deprecated use #valueOf(css=.) instead.
*/
@WaitUntil(TimeoutPolicy.RETURN_NULL)
@Deprecated
public String textByClassName(String className) {
return getTextByClassName(className);
}
protected String getTextByClassName(String className) {
WebElement element = findByClassName(className);
return getElementText(element);
}
protected T findByClassName(String className) {
By by = By.className(className);
return findElement(by);
}
protected T findByXPath(String xpathPattern, String... params) {
return getSeleniumHelper().findByXPath(xpathPattern, params);
}
protected T findByCss(String cssPattern, String... params) {
By by = getSeleniumHelper().byCss(cssPattern, params);
return findElement(by);
}
protected T findByJavascript(String script, Object... parameters) {
By by = getSeleniumHelper().byJavascript(script, parameters);
return findElement(by);
}
protected List findAllByXPath(String xpathPattern, String... params) {
By by = getSeleniumHelper().byXpath(xpathPattern, params);
return findElements(by);
}
protected List findAllByCss(String cssPattern, String... params) {
By by = getSeleniumHelper().byCss(cssPattern, params);
return findElements(by);
}
protected List findAllByJavascript(String script, Object... parameters) {
By by = getSeleniumHelper().byJavascript(script, parameters);
return findElements(by);
}
public void waitMilliSecondAfterScroll(int msToWait) {
waitAfterScroll = msToWait;
}
protected int getWaitAfterScroll() {
return waitAfterScroll;
}
protected String getElementText(WebElement element) {
String result = null;
if (element != null) {
scrollIfNotOnScreen(element);
result = getSeleniumHelper().getText(element);
}
return result;
}
/**
* Scrolls browser window so top of place becomes visible.
*
* @param place element to scroll to.
*/
@WaitUntil
public boolean scrollTo(String place) {
return scrollToIn(place, null);
}
/**
* Scrolls browser window so top of place becomes visible.
*
* @param place element to scroll to.
* @param container parent of place.
*/
@WaitUntil
public boolean scrollToIn(String place, String container) {
boolean result = false;
WebElement element = getElementToScrollTo(place, container);
if (element != null) {
scrollTo(element);
result = true;
}
return result;
}
protected T getElementToScrollTo(String place, String container) {
return getElementToCheckVisibility(place, container);
}
/**
* Scrolls browser window so top of element becomes visible.
*
* @param element element to scroll to.
*/
protected void scrollTo(WebElement element) {
getSeleniumHelper().scrollTo(element, scrollElementToCenter);
waitAfterScroll(waitAfterScroll);
}
/**
* Wait after the scroll if needed
*
* @param msToWait amount of ms to wait after the scroll
*/
protected void waitAfterScroll(int msToWait) {
if (msToWait > 0) {
waitMilliseconds(msToWait);
}
}
/**
* Scrolls browser window if element is not currently visible so top of element becomes visible.
*
* @param element element to scroll to.
*/
protected void scrollIfNotOnScreen(WebElement element) {
if (!element.isDisplayed() || !isElementOnScreen(element)) {
scrollTo(element);
}
}
/**
* Determines whether element is enabled (i.e. can be clicked).
*
* @param place element to check.
* @return true if element is enabled.
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isEnabled(String place) {
return isEnabledIn(place, null);
}
/**
* Determines whether element is enabled (i.e. can be clicked).
*
* @param place element to check.
* @param container parent of place.
* @return true if element is enabled.
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isEnabledIn(String place, String container) {
boolean result = false;
T element = getElementToCheckVisibility(place, container);
if (element != null) {
if ("label".equalsIgnoreCase(element.getTagName())) {
// for labels we want to know whether their target is enabled, not the label itself
T labelTarget = getSeleniumHelper().getLabelledElement(element);
if (labelTarget != null) {
element = labelTarget;
}
}
result = element.isEnabled();
}
return result;
}
/**
* Determines whether element is NOT enabled (i.e. can not be clicked).
*
* @param place element to check.
* @return true if element is disabled.
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isDisabled(String place) {
return isDisabledIn(place, null);
}
/**
* Determines whether element is NOT enabled (i.e. can not be clicked).
*
* @param place element to check.
* @param container parent of place.
* @return true if element is disabled.
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isDisabledIn(String place, String container) {
return !isEnabledIn(place, container);
}
/**
* Determines whether element can be see in browser's window.
*
* @param place element to check.
* @return true if element is displayed and in viewport.
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isVisible(String place) {
return isVisibleIn(place, null);
}
/**
* Determines whether element can be see in browser's window.
*
* @param place element to check.
* @param container parent of place.
* @return true if element is displayed and in viewport.
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isVisibleIn(String place, String container) {
return isVisibleImpl(place, container, true);
}
/**
* Determines whether element is somewhere in browser's window.
*
* @param place element to check.
* @return true if element is displayed.
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isVisibleOnPage(String place) {
return isVisibleOnPageIn(place, null);
}
/**
* Determines whether element is somewhere in browser's window.
*
* @param place element to check.
* @param container parent of place.
* @return true if element is displayed.
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isVisibleOnPageIn(String place, String container) {
return isVisibleImpl(place, container, false);
}
/**
* Determines whether element is not visible (or disappears within the specified timeout)
*
* @param place element to check
* @return true if the element is not displayed (anymore)
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isNotVisible(String place) {
return isNotVisibleIn(place, null);
}
/**
* Determines whether element is not visible (or disappears within the specified timeout)
*
* @param place element to check.
* @param container parent of place.
* @return true if the element is not displayed (anymore)
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isNotVisibleIn(String place, String container) {
return !isVisibleImpl(place, container, true);
}
/**
* Determines whether element is not on the page (or disappears within the specified timeout)
*
* @param place element to check.
* @return true if element is not on the page (anymore).
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isNotVisibleOnPage(String place) {
return isNotVisibleOnPageIn(place, null);
}
/**
* Determines whether element is not on the page (or disappears within the specified timeout)
*
* @param place element to check.
* @param container parent of place.
* @return true if the element is not on the page (anymore)
*/
@WaitUntil(TimeoutPolicy.RETURN_FALSE)
public boolean isNotVisibleOnPageIn(String place, String container) {
return !isVisibleImpl(place, container, false);
}
protected boolean isVisibleImpl(String place, String container, boolean checkOnScreen) {
WebElement element = getElementToCheckVisibility(place, container);
return getSeleniumHelper().checkVisible(element, checkOnScreen);
}
public int numberOfTimesIsVisible(String text) {
return numberOfTimesIsVisibleInImpl(text, true);
}
public int numberOfTimesIsVisibleOnPage(String text) {
return numberOfTimesIsVisibleInImpl(text, false);
}
public int numberOfTimesIsVisibleIn(String text, String container) {
return intValueOf(doInContainer(container, () -> numberOfTimesIsVisible(text)));
}
public int numberOfTimesIsVisibleOnPageIn(String text, String container) {
return intValueOf(doInContainer(container, () -> numberOfTimesIsVisibleOnPage(text)));
}
protected int intValueOf(Integer count) {
if (count == null) {
count = Integer.valueOf(0);
}
return count;
}
protected int numberOfTimesIsVisibleInImpl(String text, boolean checkOnScreen) {
int result;
SeleniumHelper helper = getSeleniumHelper();
if (implicitFindInFrames) {
// sum over iframes
AtomicInteger count = new AtomicInteger();
new AllFramesDecorator(helper)
.apply(() -> count.addAndGet(helper.countVisibleOccurrences(text, checkOnScreen)));
result = count.get();
} else {
result = helper.countVisibleOccurrences(text, checkOnScreen);
}
return result;
}
protected T getElementToCheckVisibility(String place) {
return getSeleniumHelper().getElementToCheckVisibility(place);
}
protected T getElementToCheckVisibility(String place, String container) {
return doInContainer(container, () -> findByTechnicalSelectorOr(place, this::getElementToCheckVisibility));
}
/**
* Checks whether element is in browser's viewport.
*
* @param element element to check
* @return true if element is in browser's viewport.
*/
protected boolean isElementOnScreen(WebElement element) {
Boolean onScreen = getSeleniumHelper().isElementOnScreen(element);
return onScreen == null || onScreen.booleanValue();
}
@WaitUntil
public boolean hoverOver(String place) {
return hoverOverIn(place, null);
}
@WaitUntil
public boolean hoverOverIn(String place, String container) {
WebElement element = getElementToClick(place, container);
return hoverOver(element);
}
protected boolean hoverOver(WebElement element) {
boolean result = false;
if (element != null) {
scrollIfNotOnScreen(element);
if (element.isDisplayed()) {
getSeleniumHelper().hoverOver(element);
result = true;
}
}
return result;
}
/**
* @param timeout number of seconds before waitUntil() and waitForJavascriptCallback() throw TimeOutException.
*/
public void secondsBeforeTimeout(int timeout) {
secondsBeforeTimeout = timeout;
secondsBeforePageLoadTimeout(timeout);
int timeoutInMs = timeout * 1000;
getSeleniumHelper().setScriptWait(timeoutInMs);
}
/**
* @return number of seconds waitUntil() will wait at most.
*/
public int secondsBeforeTimeout() {
return secondsBeforeTimeout;
}
/**
* @param timeout number of seconds before waiting for a new page to load will throw a TimeOutException.
*/
public void secondsBeforePageLoadTimeout(int timeout) {
secondsBeforePageLoadTimeout = timeout;
int timeoutInMs = timeout * 1000;
getSeleniumHelper().setPageLoadWait(timeoutInMs);
}
/**
* @return number of seconds Selenium will wait at most for a request to load a page.
*/
public int secondsBeforePageLoadTimeout() {
return secondsBeforePageLoadTimeout;
}
/**
* Clears HTML5's sessionStorage (for the domain of the current open page in the browser).
*/
public void clearSessionStorage() {
getSeleniumHelper().executeJavascript("sessionStorage.clear();");
}
/**
* Clears HTML5's localStorage (for the domain of the current open page in the browser).
*/
public void clearLocalStorage() {
getSeleniumHelper().executeJavascript("localStorage.clear();");
}
/**
* Deletes all cookies(for the domain of the current open page in the browser).
*/
public void deleteAllCookies() {
getSeleniumHelper().deleteAllCookies();
}
/**
* @param directory sets base directory where screenshots will be stored.
*/
public void screenshotBaseDirectory(String directory) {
if (directory.equals("")
|| directory.endsWith("/")
|| directory.endsWith("\\")) {
screenshotBase = directory;
} else {
screenshotBase = directory + "/";
}
}
/**
* @param height height to use to display screenshot images
*/
public void screenshotShowHeight(String height) {
screenshotHeight = height;
}
/**
* @return (escaped) HTML content of current page.
*/
public String pageSource() {
String html = getSeleniumHelper().getHtml();
return getEnvironment().getHtml(html);
}
/**
* Saves current page's source to the wiki'f files section and returns a link to the
* created file.
*
* @return hyperlink to the file containing the page source.
*/
public String savePageSource() {
String fileName = getSeleniumHelper().getResourceNameFromLocation();
return savePageSource(fileName, fileName + ".html");
}
protected String savePageSource(String fileName, String linkText) {
PageSourceSaver saver = getSeleniumHelper().getPageSourceSaver(pageSourceBase);
// make href to file
String url = saver.savePageSource(fileName);
return String.format("%s ", url, linkText);
}
/**
* Takes screenshot from current page
*
* @param basename filename (below screenshot base directory).
* @return location of screenshot.
*/
public String takeScreenshot(String basename) {
try {
String screenshotFile = createScreenshot(basename);
if (screenshotFile == null) {
throw new SlimFixtureException(false, "Unable to take screenshot: does the webdriver support it?");
} else {
screenshotFile = getScreenshotLink(screenshotFile);
}
return screenshotFile;
} catch (UnhandledAlertException e) {
// standard behavior will stop test, this breaks storyboard that will attempt to take screenshot
// after triggering alert, but before the alert can be handled.
// so we output a message but no exception. We rely on a next line to actually handle alert
// (which may mean either really handle or stop test).
return String.format(
"Unable to take screenshot , alert is active. Alert text: " +
"'%s '
",
StringEscapeUtils.escapeHtml4(alertText()));
}
}
/**
* Take a screenshot and crop it to the provided element
*
* @param basename filename (below screenshot base directory).
* @param place The element to crop the screenshot image to
* @return location of the captured image
*/
@WaitUntil
public String takeScreenshotOf(String basename, String place) {
return takeScreenshotOfIn(basename, place, null);
}
/**
* Take a screenshot and crop it to the provided element
*
* @param basename filename (below screenshot base directory).
* @param place The element to crop the screenshot image to.
* @param container the elemnt to limit the search context to, when searching for place.
* @return location of the captured image
*/
@WaitUntil
public String takeScreenshotOfIn(String basename, String place, String container) {
T element = container == null ? getElement(place) : getElement(place, container);
if (element == null) {
return null;
}
scrollIfNotOnScreen(element);
String name = getScreenshotBasename(basename);
String imageFile = getSeleniumHelper().takeElementScreenshot(name, element);
if (imageFile == null) {
throw new SlimFixtureException(false, "Unable to take screenshot: does the webdriver support it?");
} else {
imageFile = getScreenshotLink(imageFile);
}
return imageFile;
}
protected String getScreenshotLink(String screenshotFile) {
String wikiUrl = getWikiUrl(screenshotFile);
if (wikiUrl != null) {
// make href to screenshot
if ("".equals(screenshotHeight)) {
wikiUrl = String.format("%s ",
wikiUrl, screenshotFile);
} else {
wikiUrl = String.format(" ",
wikiUrl, screenshotFile, screenshotHeight);
}
screenshotFile = wikiUrl;
}
return screenshotFile;
}
private String createScreenshot(String basename) {
String name = getScreenshotBasename(basename);
return getSeleniumHelper().takeScreenshot(name);
}
private String createScreenshot(String basename, Throwable t) {
String screenshotFile;
byte[] screenshotInException = getSeleniumHelper().findScreenshot(t);
if (screenshotInException == null || screenshotInException.length == 0) {
screenshotFile = createScreenshot(basename);
} else {
String name = getScreenshotBasename(basename);
screenshotFile = getSeleniumHelper().writeScreenshot(name, screenshotInException);
}
return screenshotFile;
}
protected String getScreenshotBasename(String basename) {
return screenshotBase + basename;
}
/**
* Waits until the condition evaluates to a value that is neither null nor
* false. Because of this contract, the return type must not be Void.
*
* @param the return type of the method, which must not be Void
* @param condition condition to evaluate to determine whether waiting can be stopped.
* @return result of condition.
* @throws SlimFixtureException if condition was not met before secondsBeforeTimeout.
*/
protected T waitUntil(ExpectedCondition condition) {
try {
return waitUntilImpl(condition);
} catch (TimeoutException e) {
String message = getTimeoutMessage(e);
return lastAttemptBeforeThrow(condition, new SlimFixtureException(false, message, e));
}
}
/**
* Waits until the condition evaluates to a value that is neither null nor
* false. If that does not occur the whole test is stopped.
* Because of this contract, the return type must not be Void.
*
* @param the return type of the method, which must not be Void
* @param condition condition to evaluate to determine whether waiting can be stopped.
* @return result of condition.
* @throws TimeoutStopTestException if condition was not met before secondsBeforeTimeout.
*/
protected T waitUntilOrStop(ExpectedCondition condition) {
try {
return waitUntilImpl(condition);
} catch (TimeoutException e) {
try {
return handleTimeoutException(e);
} catch (TimeoutStopTestException tste) {
return lastAttemptBeforeThrow(condition, tste);
}
}
}
/**
* Tries the condition one last time before throwing an exception.
* This to prevent exception messages in the wiki that show no problem, which could happen if the browser's
* window content has changed between last (failing) try at condition and generation of the exception.
*
* @param the return type of the method, which must not be Void
* @param condition condition that caused exception.
* @param e exception that will be thrown if condition does not return a result.
* @return last attempt results, if not null or false.
* @throws SlimFixtureException throws e if last attempt returns null.
*/
protected T lastAttemptBeforeThrow(ExpectedCondition condition, SlimFixtureException e) {
T lastAttemptResult = null;
try {
// last attempt to ensure condition has not been met
// this to prevent messages that show no problem
lastAttemptResult = condition.apply(getSeleniumHelper().driver());
} catch (Throwable t) {
// ignore
}
if (lastAttemptResult == null || Boolean.FALSE.equals(lastAttemptResult)) {
throw e;
}
return lastAttemptResult;
}
/**
* Waits until the condition evaluates to a value that is neither null nor
* false. If that does not occur null is returned.
* Because of this contract, the return type must not be Void.
*
* @param the return type of the method, which must not be Void
* @param condition condition to evaluate to determine whether waiting can be stopped.
* @return result of condition.
*/
protected T waitUntilOrNull(ExpectedCondition condition) {
try {
return waitUntilImpl(condition);
} catch (TimeoutException e) {
return null;
}
}
protected T waitUntilImpl(ExpectedCondition condition) {
return getSeleniumHelper().waitUntil(secondsBeforeTimeout(), condition);
}
public boolean refreshSearchContext() {
// copy path so we can retrace after clearing it
List fullPath = new ArrayList<>(getCurrentSearchContextPath());
return refreshSearchContext(fullPath, Math.min(fullPath.size(), minStaleContextRefreshCount));
}
protected boolean refreshSearchContext(List fullPath, int maxRetries) {
clearSearchContext();
for (String container : fullPath) {
try {
setSearchContextTo(container);
} catch (RuntimeException se) {
if (maxRetries < 1 || !(se instanceof WebDriverException)
|| !getSeleniumHelper().isStaleElementException((WebDriverException) se)) {
// not the entire context was refreshed, clear it to prevent an 'intermediate' search context
clearSearchContext();
throw new SlimFixtureException("Search context is 'stale' and could not be refreshed. Context was: " + fullPath
+ ". Error when trying to refresh: " + container, se);
} else {
// search context went stale while setting, retry
return refreshSearchContext(fullPath, maxRetries - 1);
}
}
}
return true;
}
protected T handleTimeoutException(TimeoutException e) {
String message = getTimeoutMessage(e);
throw new TimeoutStopTestException(false, message, e);
}
private String getTimeoutMessage(TimeoutException e) {
String messageBase = String.format("Timed-out waiting (after %ss)", secondsBeforeTimeout());
try {
return getSlimFixtureExceptionMessage("timeouts", "timeout", messageBase, e);
} catch (RuntimeException re) {
return messageBase + " and unable to capture screenshot and page source. " + re.toString();
}
}
protected void handleRequiredElementNotFound(String toFind) {
handleRequiredElementNotFound(toFind, null);
}
protected void handleRequiredElementNotFound(String toFind, Throwable t) {
String messageBase = String.format("Unable to find: %s", toFind);
String message = getSlimFixtureExceptionMessage("notFound", toFind, messageBase, t);
throw new SlimFixtureException(false, message, t);
}
protected String getSlimFixtureExceptionMessage(String screenshotFolder, String screenshotFile, String messageBase, Throwable t) {
String screenshotBaseName = String.format("%s/%s/%s", screenshotFolder, getClass().getSimpleName(), screenshotFile);
return getSlimFixtureExceptionMessage(screenshotBaseName, messageBase, t);
}
protected String getSlimFixtureExceptionMessage(String screenshotBaseName, String messageBase, Throwable t) {
String exceptionMsg = getExceptionMessageText(messageBase, t);
// take a screenshot of what was on screen
String screenshotTag = getExceptionScreenshotTag(screenshotBaseName, messageBase, t);
String label = getExceptionPageSourceTag(screenshotBaseName, messageBase, t);
String message = String.format("", exceptionMsg, label, screenshotTag);
return message;
}
protected String getExceptionMessageText(String messageBase, Throwable t) {
String message = messageBase;
if (message == null) {
if (t == null) {
message = "";
} else {
message = ExceptionUtils.getStackTrace(t);
}
}
return formatExceptionMsg(message);
}
protected String getExceptionScreenshotTag(String screenshotBaseName, String messageBase, Throwable t) {
String screenshotTag = "(Screenshot not available)";
try {
String screenShotFile = createScreenshot(screenshotBaseName, t);
screenshotTag = getScreenshotLink(screenShotFile);
} catch (UnhandledAlertException e) {
// https://code.google.com/p/selenium/issues/detail?id=4412
System.err.println("Unable to take screenshot while alert is present for exception: " + messageBase);
} catch (Exception sse) {
System.err.println("Unable to take screenshot for exception: " + messageBase);
sse.printStackTrace();
}
return screenshotTag;
}
protected String getExceptionPageSourceTag(String screenshotBaseName, String messageBase, Throwable t) {
String label = "Page content";
try {
String fileName;
if (t != null) {
fileName = t.getClass().getName();
} else if (screenshotBaseName != null) {
fileName = screenshotBaseName;
} else {
fileName = "exception";
}
label = savePageSource(fileName, label);
} catch (UnhandledAlertException e) {
// https://code.google.com/p/selenium/issues/detail?id=4412
System.err.println("Unable to capture page source while alert is present for exception: " + messageBase);
} catch (Exception e) {
System.err.println("Unable to capture page source for exception: " + messageBase);
e.printStackTrace();
}
return label;
}
protected String formatExceptionMsg(String value) {
return StringEscapeUtils.escapeHtml4(value);
}
private WebDriver driver() {
return getSeleniumHelper().driver();
}
private WebDriverWait waitDriver() {
return getSeleniumHelper().waitDriver();
}
/**
* @return helper to use.
*/
protected SeleniumHelper getSeleniumHelper() {
return seleniumHelper;
}
/**
* Sets SeleniumHelper to use, for testing purposes.
*
* @param helper helper to use.
*/
protected void setSeleniumHelper(SeleniumHelper helper) {
seleniumHelper = helper;
}
public int currentBrowserWidth() {
return getWindowSize().getWidth();
}
public int currentBrowserHeight() {
return getWindowSize().getHeight();
}
public void setBrowserWidth(int newWidth) {
int currentHeight = currentBrowserHeight();
setBrowserSizeToBy(newWidth, currentHeight);
}
public void setBrowserHeight(int newHeight) {
int currentWidth = currentBrowserWidth();
setBrowserSizeToBy(currentWidth, newHeight);
}
public void setBrowserSizeToBy(int newWidth, int newHeight) {
getSeleniumHelper().setWindowSize(newWidth, newHeight);
Dimension actualSize = getWindowSize();
if (actualSize.getHeight() != newHeight || actualSize.getWidth() != newWidth) {
String message = String.format("Unable to change size to: %s x %s; size is: %s x %s",
newWidth, newHeight, actualSize.getWidth(), actualSize.getHeight());
throw new SlimFixtureException(false, message);
}
}
protected Dimension getWindowSize() {
return getSeleniumHelper().getWindowSize();
}
public void setBrowserSizeToMaximum() {
getSeleniumHelper().setWindowSizeToMaximum();
}
/**
* Downloads the target of the supplied link.
*
* @param place link to follow.
* @return downloaded file if any, null otherwise.
*/
@WaitUntil
public String download(String place) {
WebElement element = getElementToDownload(place);
return downloadLinkTarget(element);
}
protected WebElement getElementToDownload(String place) {
SeleniumHelper helper = getSeleniumHelper();
return helper.findByTechnicalSelectorOr(place,
() -> helper.getLink(place),
() -> helper.findElement(AltBy.exact(place)),
() -> helper.findElement(AltBy.partial(place)));
}
/**
* Downloads the target of the supplied link.
*
* @param place link to follow.
* @param container part of screen containing link.
* @return downloaded file if any, null otherwise.
*/
@WaitUntil
public String downloadIn(String place, String container) {
return doInContainer(container, () -> download(place));
}
protected T findElement(By selector) {
return getSeleniumHelper().findElement(selector);
}
protected List findElements(By by) {
return getSeleniumHelper().findElements(by);
}
public T findByTechnicalSelectorOr(String place, Function supplierF) {
return getSeleniumHelper().findByTechnicalSelectorOr(place, () -> supplierF.apply(place));
}
/**
* Downloads the target of the supplied link.
*
* @param element link to follow.
* @return downloaded file if any, null otherwise.
*/
protected String downloadLinkTarget(WebElement element) {
String result;
String href = getLinkTarget(element);
if (href != null) {
result = downloadContentFrom(href);
} else {
throw new SlimFixtureException(false, "Could not determine url to download from");
}
return result;
}
/**
* Downloads binary content from specified url (using the browser's cookies).
*
* @param urlOrLink url to download from
* @return link to downloaded file
*/
public String downloadContentFrom(String urlOrLink) {
String result = null;
if (urlOrLink != null) {
HttpTest httpTest = new HttpTest();
httpTest.copyBrowserCookies();
result = httpTest.getFileFrom(urlOrLink);
}
return result;
}
/**
* Selects a file using the first file upload control.
*
* @param fileName file to upload
* @return true, if a file input was found and file existed.
*/
@WaitUntil
public boolean selectFile(String fileName) {
return selectFileFor(fileName, "css=input[type='file']");
}
/**
* Selects a file using a file upload control.
*
* @param fileName file to upload
* @param place file input to select the file for
* @return true, if place was a file input and file existed.
*/
@WaitUntil
public boolean selectFileFor(String fileName, String place) {
return selectFileForIn(fileName, place, null);
}
/**
* Selects a file using a file upload control.
*
* @param fileName file to upload
* @param place file input to select the file for
* @param container part of screen containing place
* @return true, if place was a file input and file existed.
*/
@WaitUntil
public boolean selectFileForIn(String fileName, String place, String container) {
boolean result = false;
if (fileName != null) {
String fullPath = getFilePathFromWikiUrl(fileName);
if (new File(fullPath).exists()) {
WebElement element = getElementToSelectFile(place, container);
if (element != null) {
element.sendKeys(fullPath);
result = true;
}
} else {
throw new SlimFixtureException(false, "Unable to find file: " + fullPath);
}
}
return result;
}
protected T getElementToSelectFile(String place, String container) {
T result = null;
T element = getElement(place, container);
if (element != null
&& "input".equalsIgnoreCase(element.getTagName())
&& "file".equalsIgnoreCase(element.getAttribute("type"))) {
result = element;
}
return result;
}
/**
* Gets the value of the cookie with the supplied name.
*
* @param cookieName name of cookie to get value from.
* @return cookie's value if any.
*/
public String cookieValue(String cookieName) {
String result = null;
Cookie cookie = getSeleniumHelper().getCookie(cookieName);
if (cookie != null) {
result = cookie.getValue();
}
return result;
}
public boolean refreshUntilValueOfIs(String place, String expectedValue) {
return repeatUntil(getRefreshUntilValueIs(place, expectedValue));
}
public boolean refreshUntilValueOfIsNot(String place, String expectedValue) {
return repeatUntilNot(getRefreshUntilValueIs(place, expectedValue));
}
protected RepeatCompletion getRefreshUntilValueIs(String place, String expectedValue) {
return new ConditionBasedRepeatUntil(false, d -> refresh(),
true, d -> checkValueIs(place, expectedValue));
}
/**
* Refreshes current page until 'place' is found somewhere on the page. Do not forget to set 'repeat at most times', or else the loop may run endlessly.
* Usage: | refresh until | [place] | is visible on page |
*
* @param place The place to find.
* @return true if place is found while repeating
*/
public boolean refreshUntilIsVisibleOnPage(String place) {
return repeatUntil(getRefreshUntilIsVisibleOnPage(place));
}
/**
* Refreshes current page until 'place' is not found somewhere on the page. Do not forget to set 'repeat at most times', or else the loop may run endlessly.
* Usage: | refresh until | [place] | is not visible on page |
*
* @param place The place you would not like to find anymore.
* @return true if place is not found while repeating
*/
public boolean refreshUntilIsNotVisibleOnPage(String place) {
return repeatUntilNot(getRefreshUntilIsVisibleOnPage(place));
}
protected RepeatCompletion getRefreshUntilIsVisibleOnPage(String place) {
return new ConditionBasedRepeatUntil(false, d -> refresh(),
true, d -> isVisibleOnPage(place));
}
public boolean clickUntilValueOfIs(String clickPlace, String checkPlace, String expectedValue) {
return repeatUntil(getClickUntilValueIs(clickPlace, checkPlace, expectedValue));
}
public boolean clickUntilValueOfIsNot(String clickPlace, String checkPlace, String expectedValue) {
return repeatUntilNot(getClickUntilValueIs(clickPlace, checkPlace, expectedValue));
}
public boolean executeJavascriptUntilIs(String script, String place, String value) {
return repeatUntil(getExecuteScriptUntilValueIs(script, place, value));
}
public boolean executeJavascriptUntilIsNot(String script, String place, String value) {
return repeatUntilNot(getExecuteScriptUntilValueIs(script, place, value));
}
protected RepeatCompletion getExecuteScriptUntilValueIs(String script, String place, String expectedValue) {
return new ConditionBasedRepeatUntil(
false, d -> {
Object r = executeScript(script);
return r != null ? r : true;
},
true, d -> checkValueIs(place, expectedValue));
}
protected RepeatCompletion getClickUntilValueIs(String clickPlace, String checkPlace, String expectedValue) {
String place = cleanupValue(clickPlace);
return getClickUntilCompletion(place, checkPlace, expectedValue);
}
protected RepeatCompletion getClickUntilCompletion(String place, String checkPlace, String expectedValue) {
return new ConditionBasedRepeatUntil(true, d -> click(place), d -> checkValueIs(checkPlace, expectedValue));
}
protected boolean repeatUntil(ExpectedCondition actionCondition, ExpectedCondition finishCondition) {
return repeatUntil(new ConditionBasedRepeatUntil(true, actionCondition, finishCondition));
}
protected boolean repeatUntilIsNot(ExpectedCondition actionCondition, ExpectedCondition finishCondition) {
return repeatUntilNot(new ConditionBasedRepeatUntil(true, actionCondition, finishCondition));
}
protected ExpectedCondition wrapConditionForFramesIfNeeded(ExpectedCondition condition) {
if (implicitFindInFrames) {
condition = getSeleniumHelper().conditionForAllFrames(condition);
}
return condition;
}
@Override
protected boolean repeatUntil(RepeatCompletion repeat) {
// During repeating we reduce the timeout used for finding elements,
// but the page load timeout is kept as-is (which takes extra work because secondsBeforeTimeout(int)
// also changes that.
int previousTimeout = secondsBeforeTimeout();
int pageLoadTimeout = secondsBeforePageLoadTimeout();
try {
int timeoutDuringRepeat = Math.max((Math.toIntExact(repeatInterval() / 1000)), 1);
secondsBeforeTimeout(timeoutDuringRepeat);
secondsBeforePageLoadTimeout(pageLoadTimeout);
return super.repeatUntil(repeat);
} finally {
secondsBeforeTimeout(previousTimeout);
secondsBeforePageLoadTimeout(pageLoadTimeout);
}
}
protected boolean checkValueIs(String place, String expectedValue) {
boolean match;
String actual = valueOf(place);
if (expectedValue == null) {
match = actual == null;
} else {
String cleanExpectedValue = cleanExpectedValue(expectedValue);
match = compareActualToExpected(cleanExpectedValue, actual);
}
return match;
}
protected class ConditionBasedRepeatUntil extends FunctionalCompletion {
public ConditionBasedRepeatUntil(boolean wrapIfNeeded,
ExpectedCondition extends Object> repeatCondition,
ExpectedCondition finishedCondition) {
this(wrapIfNeeded, repeatCondition, wrapIfNeeded, finishedCondition);
}
public ConditionBasedRepeatUntil(boolean wrapRepeatIfNeeded,
ExpectedCondition extends Object> repeatCondition,
boolean wrapFinishedIfNeeded,
ExpectedCondition finishedCondition) {
if (wrapRepeatIfNeeded) {
repeatCondition = wrapConditionForFramesIfNeeded(repeatCondition);
}
ExpectedCondition> finalRepeatCondition = repeatCondition;
if (wrapFinishedIfNeeded) {
finishedCondition = wrapConditionForFramesIfNeeded(finishedCondition);
}
ExpectedCondition finalFinishedCondition = finishedCondition;
setIsFinishedSupplier(() -> waitUntilOrNull(finalFinishedCondition));
setRepeater(() -> waitUntil(finalRepeatCondition));
}
}
protected Object waitForJavascriptCallback(String statement, Object... parameters) {
try {
return getSeleniumHelper().waitForJavascriptCallback(statement, parameters);
} catch (TimeoutException e) {
return handleTimeoutException(e);
}
}
public NgBrowserTest getNgBrowserTest() {
return ngBrowserTest;
}
public void setNgBrowserTest(NgBrowserTest ngBrowserTest) {
this.ngBrowserTest = ngBrowserTest;
}
public boolean isImplicitWaitForAngularEnabled() {
return implicitWaitForAngular;
}
public void setImplicitWaitForAngularTo(boolean implicitWaitForAngular) {
this.implicitWaitForAngular = implicitWaitForAngular;
}
public void setImplicitFindInFramesTo(boolean implicitFindInFrames) {
this.implicitFindInFrames = implicitFindInFrames;
}
public boolean isContinueIfReadyStateInteractive() {
return continueIfReadyStateInteractive;
}
public void setContinueIfReadyStateInteractive(boolean continueIfReadyStateInteractive) {
this.continueIfReadyStateInteractive = continueIfReadyStateInteractive;
}
public void enableShadowrootContainers(boolean enableShadowrootContainers) {
this.containersAsShadowRoot = enableShadowrootContainers;
}
/**
* Executes javascript in the browser.
*
* @param script you want to execute
* @return result from script
*/
public Object executeScript(String script) {
String statement = cleanupValue(script);
return getSeleniumHelper().executeJavascript(statement);
}
/**
* Simulates 'select all' (e.g. Ctrl+A on Windows) on the active element.
*
* @return whether an active element was found.
*/
@WaitUntil
public boolean selectAll() {
return getSeleniumHelper().selectAll();
}
/**
* Simulates 'copy' (e.g. Ctrl+C on Windows) on the active element, copying the current selection to the clipboard.
*
* @return whether an active element was found.
*/
@WaitUntil
public boolean copy() {
return getSeleniumHelper().copy();
}
/**
* Simulates 'cut' (e.g. Ctrl+X on Windows) on the active element, copying the current selection to the clipboard
* and removing that selection.
*
* @return whether an active element was found.
*/
@WaitUntil
public boolean cut() {
return getSeleniumHelper().cut();
}
/**
* Simulates 'paste' (e.g. Ctrl+V on Windows) on the active element, copying the current clipboard
* content to the currently active element.
*
* @return whether an active element was found.
*/
@WaitUntil
public boolean paste() {
return getSeleniumHelper().paste();
}
/**
* @return text currently selected in browser, or empty string if no text is selected.
*/
public String getSelectionText() {
return getSeleniumHelper().getSelectionText();
}
/**
* @return should 'normalized' functions remove starting and trailing whitespace?
*/
public boolean trimOnNormalize() {
return trimOnNormalize;
}
/**
* @param trimOnNormalize should 'normalized' functions remove starting and trailing whitespace?
*/
public void setTrimOnNormalize(boolean trimOnNormalize) {
this.trimOnNormalize = trimOnNormalize;
}
/**
* Set the scroll into view behaviour to 'center of viewport' (true) or 'auto' (false)
*
* @param scrollElementsToCenterOfViewport True to scroll to center, False to use automatic scroll behaviour
*/
public void scrollElementsToCenterOfViewport(boolean scrollElementsToCenterOfViewport) {
scrollElementToCenter = scrollElementsToCenterOfViewport;
}
/**
* Get the current scroll behaviour. True means 'center of viewport', False means 'auto'
*
* @return the current boolean value of scrollElementToCenter
*/
public boolean scrollElementsToCenterOfViewport() {
return scrollElementToCenter;
}
/**
* Configure browser test to expect wai aria style tables made up of divs and spans with roles like table/cell/row/etc.
*
* @param waiAriaTables True to expect aria tables, false to expect classic <table> table tags.
*/
public void useAriaTableStructure(boolean waiAriaTables) {
this.waiAriaTables = waiAriaTables;
}
/**
* Automatically authenticate (using basic auth or digest) for a given host
*
* @param user The username to authenticate with
* @param password The password to authenticate with
* @param host The (partial) hostname to authenticate for (i.e. mywebsite.com or just mywebsite)
*
* Usage: | set username | [user] | and password | [password] | for hostname | [host] |
*/
public void setUsernameAndPasswordForHostname(String user, String password, String host) {
if (driver() instanceof HasAuthentication) {
Predicate uriPredicate = uri -> uri.getHost().contains(host);
((HasAuthentication) driver()).register(uriPredicate, UsernameAndPassword.of(user, password));
} else {
throw new SlimFixtureException("Your browser driver does not support Selenium 4 authentication!");
}
}
}