
com.pojosontheweb.selenium.Findr Maven / Gradle / Ivy
The newest version!
package com.pojosontheweb.selenium;
import org.hamcrest.*;
import org.hamcrest.core.IsCollectionContaining;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Utility for accessing Selenium DOM safely, wait-style.
* Allows to create chains of conditions and execute those conditions
* inside a WebDriverWait, in a transparent fashion.
* Instances are immutable and can be reused safely.
*/
public final class Findr {
/**
* the default wait timeout
*/
public static final Duration WAIT_TIMEOUT = Duration.ofSeconds(10);
/**
* the sys prop name for enabling logs in findr eval(s)
*/
public static final String SYSPROP_VERBOSE = "webtests.findr.verbose";
private static final FindrActions DEFAULT_ACTIONS = new FindrActions();
/**
* ref to the driver
*/
private final WebDriver driver;
/**
* the composed function
*/
private final Function f;
/**
* A list of strings that represent the "path" for this findr,
* used to create meaningful failure messages
*/
private final List path;
private final Duration waitTimeout;
/**
* The sleep interval (between polls)
*/
private final Duration sleep;
private final FindrActions findrActions;
public static boolean isDebugEnabled() {
return Boolean.getBoolean(SYSPROP_VERBOSE);
}
private static Function debugHandler = input -> {
System.out.println(input);
return null;
};
/**
* Pass a function that gets called-back with the logs. By default, logs
* messages to stdout.
*
* @param h the debug log handler function
*/
public static void setDebugHandler(Function h) {
debugHandler = h;
}
static Function getDebugHandler() {
return debugHandler;
}
public static void logDebug(String message) {
if (isDebugEnabled()) {
debugHandler.apply(message);
}
}
/**
* Create a Findr with passed arguments
*
* @param driver the WebDriver
*/
public Findr(WebDriver driver) {
this(driver, WAIT_TIMEOUT);
}
/**
* Create a Findr with passed arguments
*
* @param driver the WebDriver
* @param waitTimeout the wait timeout
*/
public Findr(WebDriver driver, Duration waitTimeout) {
this(
driver,
waitTimeout,
Duration.ofMillis(500),
null,
Collections.emptyList(),
DEFAULT_ACTIONS);
}
/**
* Create a Findr with passed arguments
*
* @param driver the WebDriver
* @param waitTimeoutInSeconds the wait timeout in seconds
* @deprecated use {@link #Findr(WebDriver, Duration)}
*/
@Deprecated
public Findr(WebDriver driver, int waitTimeoutInSeconds) {
this(
driver,
Duration.ofSeconds(waitTimeoutInSeconds),
Duration.ofMillis(500),
null,
Collections.emptyList(),
DEFAULT_ACTIONS);
}
/**
* Return the web driver passed at construction time
*
* @return the web driver
*/
public WebDriver getDriver() {
return driver;
}
/**
* Return the timeout for this findr in seconds
*
* @return the timeout in seconds
*/
public Duration getTimeout() {
return waitTimeout;
}
/**
* Helper for "nested" Findrs. Allows to use a WebElement
as the
* root of a new Findr.
*
* @param driver The WebDriver
* @param webElement the WebElement to use as root
* @return a new Findr that has the specified WebElement as its root
*/
public static Findr fromWebElement(WebDriver driver, final WebElement webElement) {
return fromWebElement(driver, webElement, WAIT_TIMEOUT);
}
/**
* Helper for "nested" Findrs. Allows to use a WebElement
as the
* root of a new Findr.
*
* @param driver The WebDriver
* @param webElement the WebElement to use as root
* @param waitTimeout the wait timeout in seconds
* @return a new Findr that has the specified WebElement as its root
*/
public static Findr fromWebElement(WebDriver driver, final WebElement webElement, Duration waitTimeout) {
Findr f = new Findr(driver, waitTimeout);
return f.compose(input -> webElement, "fromWebElement(" + webElement + ")", null);
}
/**
* Helper for "nested" Findrs. Allows to use a WebElement
as the
* root of a new Findr.
*
* @param driver The WebDriver
* @param webElement the WebElement to use as root
* @param waitTimeout the wait timeout in seconds
* @return a new Findr that has the specified WebElement as its root
* @deprecated use {@link #fromWebElement(WebDriver, WebElement, Duration)}
*/
public static Findr fromWebElement(WebDriver driver, final WebElement webElement, int waitTimeoutMs) {
Findr f = new Findr(driver, Duration.ofMillis(waitTimeoutMs));
return f.compose(input -> webElement, "fromWebElement(" + webElement + ")", null);
}
private Findr(WebDriver driver,
Duration waitTimeout,
Duration sleep,
Function f,
List path,
FindrActions actions) {
this.driver = driver;
this.waitTimeout = waitTimeout;
this.sleep = sleep;
this.f = f;
this.path = path;
this.findrActions = actions;
}
private Function withoutWebDriverException(final Function function) {
return input -> {
try {
return function.apply(input);
} catch (WebDriverException e) {
// retry in case of exception
return null;
}
};
}
private Findr compose(final Function function, final String pathElem,
Function describeFailure) {
final Function newFunction = withoutWebDriverException(function);
ArrayList newPath = new ArrayList(path);
if (pathElem != null) {
newPath.add(pathElem);
}
Function composed;
if (f == null) {
composed = input -> {
SearchContext res = newFunction.apply(input);
if (res == null) {
logDebug("[Findr] ! " + pathElem + " (null)");
} else {
logDebug("[Findr] > " + pathElem + " : " + res);
}
return res;
};
} else {
composed = input -> {
SearchContext res1 = f.apply(input);
if (res1 == null) {
logDebug("[Findr] - " + pathElem);
return null;
} else {
SearchContext res2 = newFunction.apply(res1);
if (res2 == null && isDebugEnabled()) {
if (describeFailure != null) {
var failure = describeFailure.apply(res1);
logDebug("[Findr] ! " + pathElem + ", " + failure);
} else {
logDebug("[Findr] ! " + pathElem);
}
} else {
logDebug("[Findr] > " + pathElem + " : " + res2);
}
return res2;
}
};
}
return new Findr(driver, waitTimeout, sleep, composed, newPath, findrActions);
}
/**
* Set the timeout (in seconds) and return an updated Findr
*
* @param timeout the timeout Duration
* @return an updated Findr instance
*/
public Findr setTimeout(Duration timeout) {
return new Findr(driver, timeout, sleep, f, path, findrActions);
}
/**
* Set the timeout (in seconds) and return an updated Findr
*
* @param seconds the timeout in seconds
* @return an updated Findr instance
* @deprecated use {@link #setTimeout(Duration)}
*/
@Deprecated
public Findr setTimeout(int seconds) {
return this.setTimeout(Duration.ofSeconds(seconds));
}
/**
* Set the WebDriverWait sleep interval. Use to control polling frequency.
*
* @param sleep the sleep interval
* @return an updated Findr instance
*/
public Findr setSleep(Duration sleep) {
return new Findr(driver, waitTimeout, sleep, f, path, findrActions);
}
public Findr setSleep(long ms) {
return this.setSleep(Duration.ofMillis(ms));
}
/**
* Set the WebDriverWait sleep interval (in ms). Use to control polling
* frequency.
*
* @param sleepInMillis the sleep interval in milliseconds
* @return an updated Findr instance
* @deprecated use {@link #setSleep(long)}
*/
@Deprecated
public Findr setSleepInMillis(long ms) {
return this.setSleep(Duration.ofMillis(ms));
}
public Findr setActions(FindrActions actions) {
return new Findr(driver, waitTimeout, sleep, f, path, actions);
}
/**
* Empty the condition chain. Use to create new Findrs with same settings but
* a different condition chain.
*
* @return a new empty Findr with other props untouched
*/
public Findr empty() {
return new Findr(driver, waitTimeout, sleep, null, path, findrActions);
}
/**
* Adds specified single-element selector to the chain, and return a new Findr.
*
* @param by the selector
* @return a new Findr with updated condition chain
*/
public Findr elem(final By by) {
return compose(input -> {
if (input == null) {
return null;
}
try {
return input.findElement(by);
} catch (Exception e) {
return null;
}
},
by.toString(),
null);
}
/**
* Shortcut for elem(By.cssSelector(...))
.
*
* @param selector the css selector
* @return a new Findr with updated chain
*/
public Findr $(String selector) {
return elem(By.cssSelector(selector));
}
/**
* Adds specified multiple element selector to the chain, and return a new
* ListFindr.
*
* @param by the selector
* @return a new ListFindr with updated condition chain
*/
public ListFindr elemList(By by) {
return new ListFindr(by);
}
/**
* Shortcut for elemList(By.cssSelector(selector))
*
* @param selector the css selector
* @return a new ListFindr with updated condition chain
*/
public ListFindr $$(String selector) {
return elemList(By.cssSelector(selector));
}
public ListFindr append(ListFindr lf) {
return new ListFindr(lf.by, lf.filters, lf.checkers);
}
public Findr append(Findr f) {
String sp;
if (f.path != null) {
sp = String.join(", ", f.path);
} else {
sp = "";
}
return compose(f.f, "append[" + sp + "]", null);
}
private static String createPathMsg(List path) {
return String.join("->", path);
}
private T wrapWebDriverWait(final Function callback) throws TimeoutException {
try {
return new WebDriverWait(driver, waitTimeout, sleep).until(callback);
} catch (TimeoutException e) {
// failed to find element(s), build exception message
// and re-throw exception
throw new TimeoutException(
"Timed out trying to find path=" + createPathMsg(path) + ", callback=" + callback, e);
}
}
/**
* Evaluates this Findr, and invokes passed callback if the whole chain
* succeeds. Throws
* a TimeoutException otherwise.
*
* @param callback the callback to invoke (called if the whole chain of
* conditions succeeded)
* @param the return type of the callback
* @return the result of the callback
* @throws TimeoutException if at least one condition in the chain failed
*/
public T eval(final Function callback) throws TimeoutException {
return wrapWebDriverWait(withoutWebDriverException(eval_(callback)));
}
// for testing
Function eval_(final Function callback) throws TimeoutException {
return input -> {
if (f == null) {
throw new EmptyFindrException();
}
logDebug("[Findr] eval");
SearchContext e = f.apply(input);
if (e == null) {
logDebug("[Findr] => Chain STOPPED before callback");
return null;
}
T res = callback.apply((WebElement) e);
if (res == null || (res instanceof Boolean && !((Boolean) res))) {
logDebug("[Findr] => " + callback + " result : " + res + ", will try again");
} else {
logDebug("[Findr] => " + callback + " result : " + res + ", OK");
}
return res;
};
}
public static final Function IDENTITY_FOR_EVAL = (e) -> true;
/**
* Evaluates this Findr, and blocks until all conditions are satisfied. Throws
* a TimeoutException otherwise.
*/
public void eval() throws TimeoutException {
eval(IDENTITY_FOR_EVAL);
}
/**
* Evaluates this Findr, and blocks until all conditions are satisfied. Throws
* a TimeoutException otherwise.
*
* @param failureMessage A message to be included to the timeout exception
*/
public void eval(String failureMessage) throws TimeoutException {
try {
eval();
} catch (TimeoutException e) {
throw new TimeoutException(failureMessage, e);
}
}
/**
* Evaluates this Findr, and invokes passed callback if the whole chain
* succeeds. Throws
* a TimeoutException with passed failure message otherwise.
*
* @param callback the callback to invoke (called if the whole chain of
* conditions succeeded)
* @param the return type of the callback
* @param failureMessage A message to be included to the timeout exception
* @return the result of the callback
* @throws TimeoutException if at least one condition in the chain failed
*/
public T eval(final Function callback, String failureMessage) throws TimeoutException {
try {
return eval(callback);
} catch (TimeoutException e) {
throw new TimeoutException(failureMessage, e);
}
}
/**
* Adds a Predicate (condition) to the chain, and return a new Findr
* with updated chain.
*
* @param predicate the condition to add
* @return a Findr with updated conditions chain
*/
public Findr where(final Predicate super WebElement> predicate) {
if (predicate instanceof Findrs.MatcherPredicate super WebElement> mp) {
return where(mp.matcher());
}
return compose(input -> {
if (input == null) {
return null;
}
if (input instanceof WebElement) {
if (predicate.test((WebElement) input)) {
return input;
}
return null;
} else {
throw new RuntimeException("input is not a WebElement : " + input);
}
},
predicate.toString(),
null);
}
/**
* Adds a matcher (condition) to the chain, and return a new Findr
* with updated chain.
*
* @param matcher the condition to add
* @return a Findr with updated conditions chain
*/
public Findr where(final Matcher super WebElement> matcher) {
return compose(input -> {
if (input == null) {
return null;
}
if (input instanceof WebElement) {
if (matcher.matches(input)) {
return input;
}
return null;
} else {
throw new RuntimeException("input is not a WebElement : " + input);
}
},
matcher.toString(),
input -> {
var d = new StringDescription();
matcher.describeMismatch(input, d);
return d.toString();
});
}
/**
* Shortcut method : evaluates chain, and sends keys to target WebElement of
* this
* Findr. If sendKeys throws an exception, then the whole chain is evaluated
* again, until
* no exception is thrown, or timeout.
*
* @param keys the text to send
* @throws TimeoutException if at least one condition in the chain failed
*/
public void sendKeys(CharSequence... keys) throws TimeoutException {
eval(findrActions.sendKeys(keys));
}
/**
* Shortcut method : evaluates chain, and clicks target WebElement of this
* Findr. If the click throws an exception, then the whole chain is evaluated
* again, until
* no exception is thrown, or timeout.
*
* @throws TimeoutException if at least one condition in the chain failed
*/
public void click() {
eval(findrActions.click());
}
/**
* Shortcut method : evaluates chain, and clears target WebElement of this
* Findr. If clear throws an exception, then the whole chain is evaluated again,
* until
* no exception is thrown, or timeout.
*
* @throws TimeoutException if at least one condition in the chain failed
*/
public void clear() {
eval(findrActions.clear());
}
private static final Function, Object> IDENTITY_LIST = webElement -> webElement;
public Findr shadowRoot() {
return this.compose(sc -> {
if (sc instanceof WebElement) {
return ((WebElement) sc).getShadowRoot();
}
return null;
}, "shadow-root", null);
}
/**
* Findr counterpart for element lists. Instances of this class are created and
* returned by Findr.elemList()
. Allows for index-based and
* filtering.
*/
public class ListFindr {
private final By by;
private final Matcher filters;
private final Matcher> checkers;
private ListFindr(By by) {
this(by, null, null);
}
private ListFindr(By by, Matcher filters, Matcher> checkers) {
this.by = by;
this.filters = filters;
this.checkers = checkers;
}
private static Matcher wrapAndTrap(final Matcher matcher) {
return new DelegateMatcher<>(matcher) {
@Override
public boolean matches(Object input) {
if (input == null) {
return false;
}
try {
return super.matches(input);
} catch (WebDriverException e) {
return false;
}
}
};
}
static class DelegateMatcher extends BaseMatcher {
private final Matcher super T> delegate;
DelegateMatcher(Matcher super T> delegate) {
this.delegate = delegate;
}
@Override
public boolean matches(Object input) {
return delegate.matches(input);
}
@Override
public void describeTo(Description description) {
delegate.describeTo(description);
}
@Override
public void describeMismatch(Object item, Description description) {
delegate.describeMismatch(item, description);
}
};
private T wrapWebDriverWaitList(final Function callback) throws TimeoutException {
try {
return new WebDriverWait(driver, waitTimeout, sleep).until(callback);
} catch (TimeoutException e) {
// failed to find element(s), build exception message
// and re-throw exception
ArrayList newPath = new ArrayList(path);
newPath.add(by.toString());
throw new TimeoutException(
"Timed out trying to find path=" + createPathMsg(newPath) + ", callback=" + callback, e);
}
}
/**
* Adds a filtering predicate, and returns a new ListFindr with updated chain.
*
* @param predicate the predicate used for filtering the list of elements
* (applied on each element)
* @return a new ListFindr with updated chain
* @throws java.lang.IllegalArgumentException if called after
* whereElemCount
.
*/
public ListFindr where(final Predicate super WebElement> predicate) {
if (checkers != null) {
throw new IllegalArgumentException(
"It's forbidden to call ListFindr.where() after a whereXXX() method has been called.");
}
if (predicate instanceof Findrs.MatcherPredicate super WebElement> mp) {
return where(mp.matcher());
}
return new ListFindr(by, composeMatchers(filters, wrap(predicate)), checkers);
}
public ListFindr where(final Matcher super WebElement> matcher) {
if (checkers != null) {
throw new IllegalArgumentException(
"It's forbidden to call ListFindr.where() after a whereXXX() method has been called.");
}
return new ListFindr(by, composeMatchers(filters, matcher), checkers);
}
static private Matcher composeMatchers(final Matcher first, final Matcher super T> matcher) {
return new DelegateMatcher(wrapAndTrap(matcher)) {
@Override
public boolean matches(Object input) {
return (first == null || first.matches(input)) && super.matches(input);
}
@Override
public void describeTo(Description description) {
if (first != null) {
first.describeTo(description);
description.appendText(" + ");
}
super.describeTo(description);
}
@Override
public void describeMismatch(Object item, Description description) {
if (first != null) {
first.describeMismatch(item, description);
description.appendText(" + ");
}
super.describeMismatch(item, description);
}
};
}
/**
* Index-based access to the list of elements in this ListFindr. Allows
* to wait for the n-th elem.
*
* @param index the index of the element to wait for
* @return a new Findr with updated chain
*/
public Findr at(final int index) {
return compose(input -> {
List elements;
List filtered;
try {
elements = input.findElements(by);
filtered = filterElements(elements);
} catch (Exception e) {
return null;
}
if (checkers != null && !checkers.matches(filtered)) {
var d = new StringDescription();
checkers.describeMismatch(filtered, d.appendText(" "));
logDebug("[Findr] ! checkList KO: " + checkers + d);
logDebug("[Findr] => Chain STOPPED before callback");
return null;
} else {
if (isDebugEnabled() && checkers != null) {
logDebug("[Findr] > checkList OK: " + checkers);
}
}
if (index >= filtered.size()) {
return null;
}
return filtered.get(index);
},
by.toString() + "[" + index + "]",
null);
}
private List filterElements(List source) {
List filtered = new ArrayList();
for (WebElement element : source) {
if (filters == null || filters.matches(element)) {
filtered.add(element);
}
}
if (isDebugEnabled() && filters != null) {
int srcSize = source.size();
int filteredSize = filtered.size();
logDebug("[Findr] > [" + by + "]* filter(" + filters + ") : " + srcSize + " -> " + filteredSize);
}
return filtered;
}
/**
* Alias for count
*/
public ListFindr whereElemCount(int elemCount) {
return count(elemCount);
}
/**
* Wait for the list findr to mach passed count
*
* @param elemCount the expected count
* @return a new ListFindr with updated chain
*/
public ListFindr count(int elemCount) {
return whereList(checkElemCount(elemCount));
}
/**
* Wait for the list findr so that at least one of its element match the
* specified predicate. Check is OK if list is empty.
*
* @param predicate the element predicate to match
* @return a new ListFindr with updated chain
*/
public ListFindr whereAny(final Predicate super WebElement> predicate) {
if (predicate instanceof Findrs.MatcherPredicate super WebElement> mp) {
return whereAny(mp.matcher());
}
return whereAny(wrap(predicate));
}
/**
* Wait for the list findr so that at least one of its element match the
* specified matcher. Check is OK if list is empty.
*
* @param matcher the element matcher
* @return a new ListFindr with updated chain
*/
public ListFindr whereAny(final Matcher super WebElement> matcher) {
return whereList(checkAny(matcher));
}
/**
* Wait for the list findr so that all of its element match the specified
* predicate. Check is OK if list is empty.
*
* @param predicate the element predicate to match
* @return a new ListFindr with updated chain
*/
public ListFindr whereAll(final Predicate super WebElement> predicate) {
if (predicate instanceof Findrs.MatcherPredicate super WebElement> mp) {
return whereAll(mp.matcher());
}
return whereAll(wrap(predicate));
}
/**
* Wait for the list findr so that all of its element match the specified
* matcher. Check is OK if list is empty.
*
* @param matcher the element matcher
* @return a new ListFindr with updated chain
*/
public ListFindr whereAll(final Matcher super WebElement> matcher) {
return whereList(checkAll(matcher));
}
/**
* Wait for the list findr so that the list of elements matches the specified
* matcher. Check is OK if list is empty.
*
* @param matcher the list matcher
* @return a new ListFindr with updated chain
*/
public ListFindr whereList(final Matcher> matcher) {
return new ListFindr(by, filters, composeMatchers(checkers, matcher));
}
private Matcher wrap(final Predicate super WebElement> predicate) {
return new BaseMatcher<>() {
@Override
public boolean matches(Object item) {
if (item instanceof WebElement e) {
return predicate.test(e);
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText(predicate.toString());
}
};
}
private Matcher> checkAny(final Matcher super WebElement> matcher) {
return new IsCollectionContaining(matcher) {
@Override
public void describeTo(Description description) {
description.appendText("any(").appendDescriptionOf(matcher).appendText(")");
}
};
}
private Matcher> checkAll(final Matcher super WebElement> matcher) {
// cannot use Every<>, 'cause it has the type paremeters wrong
return new TypeSafeDiagnosingMatcher>() {
@Override
public boolean matchesSafely(Iterable super WebElement> collection, Description mismatchDescription) {
for (Object t : collection) {
if (!matcher.matches(t)) {
mismatchDescription.appendText("an item ");
matcher.describeMismatch(t, mismatchDescription);
return false;
}
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText("all(").appendDescriptionOf(matcher).appendText(")");
}
};
}
private Matcher> checkElemCount(final int expectedCount) {
return new BaseMatcher>() {
@Override
public boolean matches(Object item) {
if (item instanceof List> elements) {
return elements.size() == expectedCount;
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("elemCount(").appendValue(expectedCount).appendText(")");
}
@Override
public void describeMismatch(Object item, Description description) {
if (item instanceof List> elements) {
description.appendText("was ").appendValue(elements.size());
} else {
super.describeMismatch(item, description);
}
}
};
}
/**
* Counts that there's 1 element matching the list findr, and return it.
* Shorthand for count(1).at(0)
.
*
* @return
*/
public Findr expectOne() {
return count(1).at(0);
}
/**
* Evaluates this ListFindr and invokes passed callback if the whole chain
* suceeded. Throws
* a TimeoutException if the condition chain didn't match.
*
* @param callback the callback to call if the chain succeeds
* @param the rturn type of the callback
* @return the result of the callback
* @throws TimeoutException if at least one condition in the chain failed
*/
public T eval(final Function, T> callback) throws TimeoutException {
logDebug("[Findr] ListFindr eval");
return wrapWebDriverWaitList(withoutWebDriverException(eval_(callback)));
}
// for testing
Function eval_(final Function, T> callback) throws TimeoutException {
return input -> {
SearchContext c = f == null ? input : f.apply(input);
if (c == null) {
return null;
}
List elements = c.findElements(by);
if (elements == null) {
return null;
}
List filtered = filterElements(elements);
if (checkers != null && !checkers.matches(filtered)) {
var d = new StringDescription();
checkers.describeMismatch(filtered, d.appendText(" "));
logDebug("[Findr] ! checkList KO: " + checkers + d);
logDebug("[Findr] => Chain STOPPED before callback");
return null;
} else {
if (isDebugEnabled() && checkers != null) {
logDebug("[Findr] > checkList OK: " + checkers);
}
}
T res = callback.apply(filtered);
if (res == null || (res instanceof Boolean && !((Boolean) res))) {
logDebug("[Findr] => " + callback + " result : " + res + ", will try again");
} else {
logDebug("[Findr] => " + callback + " result : " + res + ", OK");
}
return res;
};
}
/**
* Evaluates this ListFindr. Throws
* a TimeoutException if the condition chain didn't match.
*
* @throws TimeoutException if at least one condition in the chain failed
*/
public void eval() throws TimeoutException {
eval(IDENTITY_LIST);
}
/**
* Evaluates this ListFindr. Throws
* a TimeoutException if the condition chain didn't match.
*
* @param failureMessage A message to include in the timeout exception
* @throws TimeoutException if at least one condition in the chain failed
*/
public void eval(String failureMessage) throws TimeoutException {
try {
eval(IDENTITY_LIST);
} catch (TimeoutException e) {
throw new TimeoutException(failureMessage, e);
}
}
/**
* Evaluates this ListFindr and invokes passed callback if the whole chain
* suceeded. Throws
* a TimeoutException with passed failure message if the condition chain didn't
* match.
*
* @param callback the callback to call if the chain succeeds
* @param the rturn type of the callback
* @return the result of the callback
* @throws TimeoutException if at least one condition in the chain failed
*/
public T eval(Function, T> callback, String failureMessage) throws TimeoutException {
try {
return eval(callback);
} catch (TimeoutException e) {
throw new TimeoutException(failureMessage, e);
}
}
@Override
public String toString() {
return "ListFindr{" +
"by=" + by +
", filters=" + filters +
", checkers=" + checkers +
", findr=" + Findr.this +
'}';
}
}
@Override
public String toString() {
return "Findr{" +
"driver=" + driver +
", path=" + path +
", waitTimeout=" + waitTimeout +
'}';
}
// Utility statics
// ---------------
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate attrEquals(final String attrName, final String expectedValue) {
return Findrs.attrEquals(attrName, expectedValue);
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate attrStartsWith(final String attrName, final String expectedStartsWith) {
return Findrs.attrStartsWith(attrName, expectedStartsWith);
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate attrEndsWith(final String attrName, final String expectedEndsWith) {
return Findrs.attrEndsWith(attrName, expectedEndsWith);
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate hasClass(final String className) {
return Findrs.hasClass(className);
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate textEquals(final String expected) {
return Findrs.textEquals(expected);
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate textStartsWith(final String expectedStartsWith) {
return Findrs.textStartsWith(expectedStartsWith);
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate textEndsWith(final String expectedEndsWith) {
return Findrs.textEndsWith(expectedEndsWith);
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate isEnabled() {
return Findrs.isEnabled();
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate isDisplayed() {
return Findrs.isDisplayed();
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate cssValue(final String propName, final String expectedValue) {
return Findrs.cssValue(propName, expectedValue);
}
/**
* @deprecated use Findrs.* instead
*/
@Deprecated
public static Predicate not(final Predicate in) {
return Findrs.not(in);
}
public static final class EmptyFindrException extends IllegalStateException {
public EmptyFindrException() {
super("Calling eval() on an empty Findr ! You need to " +
"specify at least one condition before evaluating.");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy