Java tutorial
// Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The SFC licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package org.openqa.selenium.support.ui; import com.google.common.base.Joiner; import org.openqa.selenium.Alert; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.NoAlertPresentException; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.NoSuchFrameException; import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Canned {@link ExpectedCondition}s which are generally useful within webdriver tests. */ public class ExpectedConditions { private final static Logger log = Logger.getLogger(ExpectedConditions.class.getName()); private ExpectedConditions() { // Utility class } /** * An expectation for checking the title of a page. * * @param title the expected title, which must be an exact match * @return true when the title matches, false otherwise */ public static ExpectedCondition<Boolean> titleIs(final String title) { return new ExpectedCondition<Boolean>() { private String currentTitle = ""; @Override public Boolean apply(WebDriver driver) { currentTitle = driver.getTitle(); return title.equals(currentTitle); } @Override public String toString() { return String.format("title to be \"%s\". Current title: \"%s\"", title, currentTitle); } }; } /** * An expectation for checking that the title contains a case-sensitive substring * * @param title the fragment of title expected * @return true when the title matches, false otherwise */ public static ExpectedCondition<Boolean> titleContains(final String title) { return new ExpectedCondition<Boolean>() { private String currentTitle = ""; @Override public Boolean apply(WebDriver driver) { currentTitle = driver.getTitle(); return currentTitle != null && currentTitle.contains(title); } @Override public String toString() { return String.format("title to contain \"%s\". Current title: \"%s\"", title, currentTitle); } }; } /** * An expectation for the URL of the current page to be a specific url. * * @param url the url that the page should be on * @return <code>true</code> when the URL is what it should be */ public static ExpectedCondition<Boolean> urlToBe(final String url) { return new ExpectedCondition<Boolean>() { private String currentUrl = ""; @Override public Boolean apply(WebDriver driver) { currentUrl = driver.getCurrentUrl(); return currentUrl != null && currentUrl.equals(url); } @Override public String toString() { return String.format("url to be \"%s\". Current url: \"%s\"", url, currentUrl); } }; } /** * An expectation for the URL of the current page to contain specific text. * * @param fraction the fraction of the url that the page should be on * @return <code>true</code> when the URL contains the text */ public static ExpectedCondition<Boolean> urlContains(final String fraction) { return new ExpectedCondition<Boolean>() { private String currentUrl = ""; @Override public Boolean apply(WebDriver driver) { currentUrl = driver.getCurrentUrl(); return currentUrl != null && currentUrl.contains(fraction); } @Override public String toString() { return String.format("url to contain \"%s\". Current url: \"%s\"", fraction, currentUrl); } }; } /** * Expectation for the URL to match a specific regular expression * * @param regex the regular expression that the URL should match * @return <code>true</code> if the URL matches the specified regular expression */ public static ExpectedCondition<Boolean> urlMatches(final String regex) { return new ExpectedCondition<Boolean>() { private String currentUrl; private Pattern pattern; private Matcher matcher; @Override public Boolean apply(WebDriver driver) { currentUrl = driver.getCurrentUrl(); pattern = Pattern.compile(regex); matcher = pattern.matcher(currentUrl); return matcher.find(); } @Override public String toString() { return String.format("url to match the regex \"%s\". Current url: \"%s\"", regex, currentUrl); } }; } /** * An expectation for checking that an element is present on the DOM of a page. This does not * necessarily mean that the element is visible. * * @param locator used to find the element * @return the WebElement once it is located */ public static ExpectedCondition<WebElement> presenceOfElementLocated(final By locator) { return new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver driver) { return driver.findElement(locator); } @Override public String toString() { return "presence of element located by: " + locator; } }; } /** * An expectation for checking that an element is present on the DOM of a page and visible. * Visibility means that the element is not only displayed but also has a height and width that is * greater than 0. * * @param locator used to find the element * @return the WebElement once it is located and visible */ public static ExpectedCondition<WebElement> visibilityOfElementLocated(final By locator) { return new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver driver) { try { return elementIfVisible(driver.findElement(locator)); } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return "visibility of element located by " + locator; } }; } /** * An expectation for checking that all elements present on the web page that match the locator * are visible. Visibility means that the elements are not only displayed but also have a height * and width that is greater than 0. * * @param locator used to find the element * @return the list of WebElements once they are located */ public static ExpectedCondition<List<WebElement>> visibilityOfAllElementsLocatedBy(final By locator) { return new ExpectedCondition<List<WebElement>>() { @Override public List<WebElement> apply(WebDriver driver) { List<WebElement> elements = driver.findElements(locator); for (WebElement element : elements) { if (!element.isDisplayed()) { return null; } } return elements.size() > 0 ? elements : null; } @Override public String toString() { return "visibility of all elements located by " + locator; } }; } /** * An expectation for checking that all elements present on the web page that match the locator * are visible. Visibility means that the elements are not only displayed but also have a height * and width that is greater than 0. * * @param elements list of WebElements * @return the list of WebElements once they are located */ public static ExpectedCondition<List<WebElement>> visibilityOfAllElements(final WebElement... elements) { return visibilityOfAllElements(Arrays.asList(elements)); } /** * An expectation for checking that all elements present on the web page that match the locator * are visible. Visibility means that the elements are not only displayed but also have a height * and width that is greater than 0. * * @param elements list of WebElements * @return the list of WebElements once they are located */ public static ExpectedCondition<List<WebElement>> visibilityOfAllElements(final List<WebElement> elements) { return new ExpectedCondition<List<WebElement>>() { @Override public List<WebElement> apply(WebDriver driver) { for (WebElement element : elements) { if (!element.isDisplayed()) { return null; } } return elements.size() > 0 ? elements : null; } @Override public String toString() { return "visibility of all " + elements; } }; } /** * An expectation for checking that an element, known to be present on the DOM of a page, is * visible. Visibility means that the element is not only displayed but also has a height and * width that is greater than 0. * * @param element the WebElement * @return the (same) WebElement once it is visible */ public static ExpectedCondition<WebElement> visibilityOf(final WebElement element) { return new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver driver) { return elementIfVisible(element); } @Override public String toString() { return "visibility of " + element; } }; } /** * @return the given element if it is visible and has non-zero size, otherwise null. */ private static WebElement elementIfVisible(WebElement element) { return element.isDisplayed() ? element : null; } /** * An expectation for checking that there is at least one element present on a web page. * * @param locator used to find the element * @return the list of WebElements once they are located */ public static ExpectedCondition<List<WebElement>> presenceOfAllElementsLocatedBy(final By locator) { return new ExpectedCondition<List<WebElement>>() { @Override public List<WebElement> apply(WebDriver driver) { List<WebElement> elements = driver.findElements(locator); return elements.size() > 0 ? elements : null; } @Override public String toString() { return "presence of any elements located by " + locator; } }; } /** * An expectation for checking if the given text is present in the specified element. * * @param element the WebElement * @param text to be present in the element * @return true once the element contains the given text */ public static ExpectedCondition<Boolean> textToBePresentInElement(final WebElement element, final String text) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { String elementText = element.getText(); return elementText.contains(text); } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return String.format("text ('%s') to be present in element %s", text, element); } }; } /** * An expectation for checking if the given text is present in the element that matches the given * locator. * * @param locator used to find the element * @param text to be present in the element found by the locator * @return true once the first element located by locator contains the given text */ public static ExpectedCondition<Boolean> textToBePresentInElementLocated(final By locator, final String text) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { String elementText = driver.findElement(locator).getText(); return elementText.contains(text); } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return String.format("text ('%s') to be present in element found by %s", text, locator); } }; } /** * An expectation for checking if the given text is present in the specified elements value * attribute. * * @param element the WebElement * @param text to be present in the element's value attribute * @return true once the element's value attribute contains the given text */ public static ExpectedCondition<Boolean> textToBePresentInElementValue(final WebElement element, final String text) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { String elementText = element.getAttribute("value"); if (elementText != null) { return elementText.contains(text); } return false; } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return String.format("text ('%s') to be the value of element %s", text, element); } }; } /** * An expectation for checking if the given text is present in the specified elements value * attribute. * * @param locator used to find the element * @param text to be present in the value attribute of the element found by the locator * @return true once the value attribute of the first element located by locator contains the * given text */ public static ExpectedCondition<Boolean> textToBePresentInElementValue(final By locator, final String text) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { String elementText = driver.findElement(locator).getAttribute("value"); if (elementText != null) { return elementText.contains(text); } return false; } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return String.format("text ('%s') to be the value of element located by %s", text, locator); } }; } /** * An expectation for checking whether the given frame is available to switch to. <p> If the frame * is available it switches the given driver to the specified frame. * * @param frameLocator used to find the frame (id or name) * @return WebDriver instance after frame has been switched */ public static ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(final String frameLocator) { return new ExpectedCondition<WebDriver>() { @Override public WebDriver apply(WebDriver driver) { try { return driver.switchTo().frame(frameLocator); } catch (NoSuchFrameException e) { return null; } } @Override public String toString() { return "frame to be available: " + frameLocator; } }; } /** * An expectation for checking whether the given frame is available to switch to. <p> If the frame * is available it switches the given driver to the specified frame. * * @param locator used to find the frame * @return WebDriver instance after frame has been switched */ public static ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(final By locator) { return new ExpectedCondition<WebDriver>() { @Override public WebDriver apply(WebDriver driver) { try { return driver.switchTo().frame(driver.findElement(locator)); } catch (NoSuchFrameException e) { return null; } } @Override public String toString() { return "frame to be available: " + locator; } }; } /** * An expectation for checking whether the given frame is available to switch to. <p> If the frame * is available it switches the given driver to the specified frameIndex. * * @param frameLocator used to find the frame (index) * @return WebDriver instance after frame has been switched */ public static ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(final int frameLocator) { return new ExpectedCondition<WebDriver>() { @Override public WebDriver apply(WebDriver driver) { try { return driver.switchTo().frame(frameLocator); } catch (NoSuchFrameException e) { return null; } } @Override public String toString() { return "frame to be available: " + frameLocator; } }; } /** * An expectation for checking whether the given frame is available to switch to. <p> If the frame * is available it switches the given driver to the specified webelement. * * @param frameLocator used to find the frame (webelement) * @return WebDriver instance after frame has been switched */ public static ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(final WebElement frameLocator) { return new ExpectedCondition<WebDriver>() { @Override public WebDriver apply(WebDriver driver) { try { return driver.switchTo().frame(frameLocator); } catch (NoSuchFrameException e) { return null; } } @Override public String toString() { return "frame to be available: " + frameLocator; } }; } /** * An expectation for checking that an element is either invisible or not present on the DOM. * * @param locator used to find the element * @return true if the element is not displayed or the element doesn't exist or stale element */ public static ExpectedCondition<Boolean> invisibilityOfElementLocated(final By locator) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { return !(driver.findElement(locator).isDisplayed()); } catch (NoSuchElementException e) { // Returns true because the element is not present in DOM. The // try block checks if the element is present but is invisible. return true; } catch (StaleElementReferenceException e) { // Returns true because stale element reference implies that element // is no longer visible. return true; } } @Override public String toString() { return "element to no longer be visible: " + locator; } }; } /** * An expectation for checking that an element with text is either invisible or not present on the * DOM. * * @param locator used to find the element * @param text of the element * @return true if no such element, stale element or displayed text not equal that provided */ public static ExpectedCondition<Boolean> invisibilityOfElementWithText(final By locator, final String text) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { return !driver.findElement(locator).getText().equals(text); } catch (NoSuchElementException e) { // Returns true because the element with text is not present in DOM. The // try block checks if the element is present but is invisible. return true; } catch (StaleElementReferenceException e) { // Returns true because stale element reference implies that element // is no longer visible. return true; } } @Override public String toString() { return String.format("element containing '%s' to no longer be visible: %s", text, locator); } }; } /** * An expectation for checking an element is visible and enabled such that you can click it. * * @param locator used to find the element * @return the WebElement once it is located and clickable (visible and enabled) */ public static ExpectedCondition<WebElement> elementToBeClickable(final By locator) { return new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver driver) { WebElement element = visibilityOfElementLocated(locator).apply(driver); try { if (element != null && element.isEnabled()) { return element; } return null; } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return "element to be clickable: " + locator; } }; } /** * An expectation for checking an element is visible and enabled such that you can click it. * * @param element the WebElement * @return the (same) WebElement once it is clickable (visible and enabled) */ public static ExpectedCondition<WebElement> elementToBeClickable(final WebElement element) { return new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver driver) { WebElement visibleElement = visibilityOf(element).apply(driver); try { if (visibleElement != null && visibleElement.isEnabled()) { return visibleElement; } return null; } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return "element to be clickable: " + element; } }; } /** * Wait until an element is no longer attached to the DOM. * * @param element The element to wait for. * @return false if the element is still attached to the DOM, true otherwise. */ public static ExpectedCondition<Boolean> stalenessOf(final WebElement element) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver ignored) { try { // Calling any method forces a staleness check element.isEnabled(); return false; } catch (StaleElementReferenceException expected) { return true; } } @Override public String toString() { return String.format("element (%s) to become stale", element); } }; } /** * Wrapper for a condition, which allows for elements to update by redrawing. * * This works around the problem of conditions which have two parts: find an element and then * check for some condition on it. For these conditions it is possible that an element is located * and then subsequently it is redrawn on the client. When this happens a {@link * StaleElementReferenceException} is thrown when the second part of the condition is checked. * * @param condition ExpectedCondition to wrap * @param <T> return type of the condition provided * @return the result of the provided condition */ public static <T> ExpectedCondition<T> refreshed(final ExpectedCondition<T> condition) { return new ExpectedCondition<T>() { @Override public T apply(WebDriver driver) { try { return condition.apply(driver); } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return String.format("condition (%s) to be refreshed", condition); } }; } /** * An expectation for checking if the given element is selected. * * @param element WebElement to be selected * @return true once the element is selected */ public static ExpectedCondition<Boolean> elementToBeSelected(final WebElement element) { return elementSelectionStateToBe(element, true); } /** * An expectation for checking if the given element is selected. * * @param element WebElement to be selected * @param selected boolean state of the selection state of the element * @return true once the element's selection stated is that of selected */ public static ExpectedCondition<Boolean> elementSelectionStateToBe(final WebElement element, final boolean selected) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { return element.isSelected() == selected; } @Override public String toString() { return String.format("element (%s) to %sbe selected", element, (selected ? "" : "not ")); } }; } public static ExpectedCondition<Boolean> elementToBeSelected(final By locator) { return elementSelectionStateToBe(locator, true); } public static ExpectedCondition<Boolean> elementSelectionStateToBe(final By locator, final boolean selected) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { WebElement element = driver.findElement(locator); return element.isSelected() == selected; } catch (StaleElementReferenceException e) { return null; } } @Override public String toString() { return String.format("element found by %s to %sbe selected", locator, (selected ? "" : "not ")); } }; } public static ExpectedCondition<Alert> alertIsPresent() { return new ExpectedCondition<Alert>() { @Override public Alert apply(WebDriver driver) { try { return driver.switchTo().alert(); } catch (NoAlertPresentException e) { return null; } } @Override public String toString() { return "alert to be present"; } }; } public static ExpectedCondition<Boolean> numberOfWindowsToBe(final int expectedNumberOfWindows) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { return driver.getWindowHandles().size() == expectedNumberOfWindows; } catch (WebDriverException e) { return null; } } @Override public String toString() { return "number of open windows to be " + expectedNumberOfWindows; } }; } /** * An expectation with the logical opposite condition of the given condition. * * Note that if the Condition you are inverting throws an exception that is caught by the Ignored * Exceptions, the inversion will not take place and lead to confusing results. * * @param condition ExpectedCondition to be inverted * @return true once the condition is satisfied */ public static ExpectedCondition<Boolean> not(final ExpectedCondition<?> condition) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { Object result = condition.apply(driver); return result == null || result.equals(Boolean.FALSE); } @Override public String toString() { return "condition to not be valid: " + condition; } }; } /** * An expectation for checking WebElement with given locator has attribute with a specific value * * @param locator used to find the element * @param attribute used to define css or html attribute * @param value used as expected attribute value * @return Boolean true when element has css or html attribute with the value */ public static ExpectedCondition<Boolean> attributeToBe(final By locator, final String attribute, final String value) { return new ExpectedCondition<Boolean>() { private String currentValue = null; @Override public Boolean apply(WebDriver driver) { WebElement element = driver.findElement(locator); currentValue = element.getAttribute(attribute); if (currentValue == null || currentValue.isEmpty()) { currentValue = element.getCssValue(attribute); } return value.equals(currentValue); } @Override public String toString() { return String.format("element found by %s to have value \"%s\". Current value: \"%s\"", locator, value, currentValue); } }; } /** * An expectation for checking WebElement with given locator has specific text * * @param locator used to find the element * @param value used as expected text * @return Boolean true when element has text value equal to @value */ public static ExpectedCondition<Boolean> textToBe(final By locator, final String value) { return new ExpectedCondition<Boolean>() { private String currentValue = null; @Override public Boolean apply(WebDriver driver) { try { currentValue = driver.findElement(locator).getText(); return currentValue.equals(value); } catch (Exception e) { return false; } } @Override public String toString() { return String.format("element found by %s to have text \"%s\". Current text: \"%s\"", locator, value, currentValue); } }; } /** * An expectation for checking WebElement with given locator has text with a value as a part of * it * * @param locator used to find the element * @param pattern used as expected text matcher pattern * @return Boolean true when element has text value containing @value */ public static ExpectedCondition<Boolean> textMatches(final By locator, final Pattern pattern) { return new ExpectedCondition<Boolean>() { private String currentValue = null; @Override public Boolean apply(WebDriver driver) { try { currentValue = driver.findElement(locator).getText(); return pattern.matcher(currentValue).find(); } catch (Exception e) { return false; } } @Override public String toString() { return String.format("text found by %s to match pattern \"%s\". Current text: \"%s\"", locator, pattern.pattern(), currentValue); } }; } /** * An expectation for checking number of WebElements with given locator being more than defined number * * @param locator used to find the element * @param number used to define minimum number of elements * @return Boolean true when size of elements list is more than defined */ public static ExpectedCondition<List<WebElement>> numberOfElementsToBeMoreThan(final By locator, final Integer number) { return new ExpectedCondition<List<WebElement>>() { private Integer currentNumber = 0; @Override public List<WebElement> apply(WebDriver webDriver) { List<WebElement> elements = webDriver.findElements(locator); currentNumber = elements.size(); return currentNumber > number ? elements : null; } @Override public String toString() { return String.format( "number of elements found by %s to be more than \"%s\". Current number: \"%s\"", locator, number, currentNumber); } }; } /** * An expectation for checking number of WebElements with given locator being less than defined * number * * @param locator used to find the element * @param number used to define maximum number of elements * @return Boolean true when size of elements list is less than defined */ public static ExpectedCondition<List<WebElement>> numberOfElementsToBeLessThan(final By locator, final Integer number) { return new ExpectedCondition<List<WebElement>>() { private Integer currentNumber = 0; @Override public List<WebElement> apply(WebDriver webDriver) { List<WebElement> elements = webDriver.findElements(locator); currentNumber = elements.size(); return currentNumber < number ? elements : null; } @Override public String toString() { return String.format( "number of elements found by %s to be less than \"%s\". Current number: \"%s\"", locator, number, currentNumber); } }; } /** * An expectation for checking number of WebElements with given locator * * @param locator used to find the element * @param number used to define number of elements * @return Boolean true when size of elements list is equal to defined */ public static ExpectedCondition<List<WebElement>> numberOfElementsToBe(final By locator, final Integer number) { return new ExpectedCondition<List<WebElement>>() { private Integer currentNumber = 0; @Override public List<WebElement> apply(WebDriver webDriver) { List<WebElement> elements = webDriver.findElements(locator); currentNumber = elements.size(); return currentNumber.equals(number) ? elements : null; } @Override public String toString() { return String.format("number of elements found by %s to be \"%s\". Current number: \"%s\"", locator, number, currentNumber); } }; } /** * An expectation for checking given WebElement has attribute with a specific value * * @param element used to check its parameters * @param attribute used to define css or html attribute * @param value used as expected attribute value * @return Boolean true when element has css or html attribute with the value */ public static ExpectedCondition<Boolean> attributeToBe(final WebElement element, final String attribute, final String value) { return new ExpectedCondition<Boolean>() { private String currentValue = null; @Override public Boolean apply(WebDriver driver) { currentValue = element.getAttribute(attribute); if (currentValue == null || currentValue.isEmpty()) { currentValue = element.getCssValue(attribute); } return value.equals(currentValue); } @Override public String toString() { return String.format(attribute + " to be \"%s\". Current " + attribute + ": \"%s\"", value, currentValue); } }; } /** * An expectation for checking WebElement with given locator has attribute which contains specific * value * * @param element used to check its parameters * @param attribute used to define css or html attribute * @param value used as expected attribute value * @return Boolean true when element has css or html attribute which contains the value */ public static ExpectedCondition<Boolean> attributeContains(final WebElement element, final String attribute, final String value) { return new ExpectedCondition<Boolean>() { private String currentValue = null; @Override public Boolean apply(WebDriver driver) { return getAttributeOrCssValue(element, attribute).map(seen -> seen.contains(value)).orElse(false); } @Override public String toString() { return String.format("value to contain \"%s\". Current value: \"%s\"", value, currentValue); } }; } /** * An expectation for checking WebElement with given locator has attribute which contains specific * value * * @param locator used to define WebElement to check its parameters * @param attribute used to define css or html attribute * @param value used as expected attribute value * @return Boolean true when element has css or html attribute which contains the value */ public static ExpectedCondition<Boolean> attributeContains(final By locator, final String attribute, final String value) { return new ExpectedCondition<Boolean>() { private String currentValue = null; @Override public Boolean apply(WebDriver driver) { return getAttributeOrCssValue(driver.findElement(locator), attribute) .map(seen -> seen.contains(value)).orElse(false); } @Override public String toString() { return String.format("value found by %s to contain \"%s\". Current value: \"%s\"", locator, value, currentValue); } }; } /** * An expectation for checking WebElement any non empty value for given attribute * * @param element used to check its parameters * @param attribute used to define css or html attribute * @return Boolean true when element has css or html attribute with non empty value */ public static ExpectedCondition<Boolean> attributeToBeNotEmpty(final WebElement element, final String attribute) { return driver -> getAttributeOrCssValue(element, attribute).isPresent(); } private static Optional<String> getAttributeOrCssValue(WebElement element, String name) { String value = element.getAttribute(name); if (value == null || value.isEmpty()) { value = element.getCssValue(name); } if (value == null || value.isEmpty()) { return Optional.empty(); } return Optional.of(value); } /** * An expectation for checking child WebElement as a part of parent element to be visible * * @param parent used to check parent element. For example table with locator * By.id("fish") * @param childLocator used to find the ultimate child element. * @return visible nested element */ public static ExpectedCondition<List<WebElement>> visibilityOfNestedElementsLocatedBy(final By parent, final By childLocator) { return new ExpectedCondition<List<WebElement>>() { @Override public List<WebElement> apply(WebDriver driver) { WebElement current = driver.findElement(parent); List<WebElement> allChildren = current.findElements(childLocator); // The original code only checked the first element. Fair enough. if (!allChildren.isEmpty() && allChildren.get(0).isDisplayed()) { return allChildren; } return null; } @Override public String toString() { return String.format("visibility of elements located by %s -> %s", parent, childLocator); } }; } /** * An expectation for checking child WebElement as a part of parent element to be visible * * @param element used as parent element. For example table with locator By.xpath("//table") * @param childLocator used to find child element. For example td By.xpath("./tr/td") * @return visible subelement */ public static ExpectedCondition<List<WebElement>> visibilityOfNestedElementsLocatedBy(final WebElement element, final By childLocator) { return new ExpectedCondition<List<WebElement>>() { @Override public List<WebElement> apply(WebDriver webDriver) { List<WebElement> allChildren = element.findElements(childLocator); // The original code only checked the visibility of the first element. if (!allChildren.isEmpty() && allChildren.get(0).isDisplayed()) { return allChildren; } return null; } @Override public String toString() { return String.format("visibility of element located by %s -> %s", element, childLocator); } }; } /** * An expectation for checking child WebElement as a part of parent element to present * * @param locator used to check parent element. For example table with locator * By.xpath("//table") * @param childLocator used to find child element. For example td By.xpath("./tr/td") * @return subelement */ public static ExpectedCondition<WebElement> presenceOfNestedElementLocatedBy(final By locator, final By childLocator) { return new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver webDriver) { return webDriver.findElement(locator).findElement(childLocator); } @Override public String toString() { return String.format("visibility of element located by %s -> %s", locator, childLocator); } }; } /** * An expectation for checking child WebElement as a part of parent element to be present * * @param element used as parent element * @param childLocator used to find child element. For example td By.xpath("./tr/td") * @return subelement */ public static ExpectedCondition<WebElement> presenceOfNestedElementLocatedBy(final WebElement element, final By childLocator) { return new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver webDriver) { return element.findElement(childLocator); } @Override public String toString() { return String.format("visibility of element located by %s", childLocator); } }; } /** * An expectation for checking child WebElement as a part of parent element to present * * @param parent used to check parent element. For example table with locator * By.xpath("//table") * @param childLocator used to find child element. For example td By.xpath("./tr/td") * @return subelement */ public static ExpectedCondition<List<WebElement>> presenceOfNestedElementsLocatedBy(final By parent, final By childLocator) { return new ExpectedCondition<List<WebElement>>() { @Override public List<WebElement> apply(WebDriver driver) { List<WebElement> allChildren = driver.findElement(parent).findElements(childLocator); return allChildren.isEmpty() ? null : allChildren; } @Override public String toString() { return String.format("visibility of element located by %s -> %s", parent, childLocator); } }; } /** * An expectation for checking all elements from given list to be invisible * * @param elements used to check their invisibility * @return Boolean true when all elements are not visible anymore */ public static ExpectedCondition<Boolean> invisibilityOfAllElements(final WebElement... elements) { return invisibilityOfAllElements(Arrays.asList(elements)); } /** * An expectation for checking all elements from given list to be invisible * * @param elements used to check their invisibility * @return Boolean true when all elements are not visible anymore */ public static ExpectedCondition<Boolean> invisibilityOfAllElements(final List<WebElement> elements) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver webDriver) { return elements.stream().allMatch(ExpectedConditions::isInvisible); } @Override public String toString() { return "invisibility of all elements " + elements; } }; } /** * An expectation for checking the element to be invisible * * @param element used to check its invisibility * @return Boolean true when elements is not visible anymore */ public static ExpectedCondition<Boolean> invisibilityOf(final WebElement element) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver webDriver) { return isInvisible(element); } @Override public String toString() { return "invisibility of " + element; } }; } private static boolean isInvisible(final WebElement element) { try { return !element.isDisplayed(); } catch (StaleElementReferenceException ignored) { // We can assume a stale element isn't displayed. return true; } } /** * An expectation with the logical or condition of the given list of conditions. * * Each condition is checked until at least one of them returns true or not null. * * @param conditions ExpectedCondition is a list of alternative conditions * @return true once one of conditions is satisfied */ public static ExpectedCondition<Boolean> or(final ExpectedCondition<?>... conditions) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { RuntimeException lastException = null; for (ExpectedCondition<?> condition : conditions) { try { Object result = condition.apply(driver); if (result != null) { if (result instanceof Boolean) { if (Boolean.TRUE.equals(result)) { return true; } } else { return true; } } } catch (RuntimeException e) { lastException = e; } } if (lastException != null) { throw lastException; } return false; } @Override public String toString() { StringBuilder message = new StringBuilder("at least one condition to be valid: "); Joiner.on(" || ").appendTo(message, conditions); return message.toString(); } }; } /** * An expectation with the logical and condition of the given list of conditions. * * Each condition is checked until all of them return true or not null * * @param conditions ExpectedCondition is a list of alternative conditions * @return true once all conditions are satisfied */ public static ExpectedCondition<Boolean> and(final ExpectedCondition<?>... conditions) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { for (ExpectedCondition<?> condition : conditions) { Object result = condition.apply(driver); if (result instanceof Boolean) { if (Boolean.FALSE.equals(result)) { return false; } } if (result == null) { return false; } } return true; } @Override public String toString() { StringBuilder message = new StringBuilder("all conditions to be valid: "); Joiner.on(" && ").appendTo(message, conditions); return message.toString(); } }; } /** * An expectation to check if js executable. * * Useful when you know that there should be a Javascript value or something at the stage. * * @param javaScript used as executable script * @return true once javaScript executed without errors */ public static ExpectedCondition<Boolean> javaScriptThrowsNoExceptions(final String javaScript) { return new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { ((JavascriptExecutor) driver).executeScript(javaScript); return true; } catch (WebDriverException e) { return false; } } @Override public String toString() { return String.format("js %s to be executable", javaScript); } }; } /** * An expectation for String value from javascript * * @param javaScript as executable js line * @return true once js return string */ public static ExpectedCondition<Object> jsReturnsValue(final String javaScript) { return new ExpectedCondition<Object>() { @Override public Object apply(WebDriver driver) { try { Object value = ((JavascriptExecutor) driver).executeScript(javaScript); if (value instanceof List) { return ((List<?>) value).isEmpty() ? null : value; } if (value instanceof String) { return ((String) value).isEmpty() ? null : value; } return value; } catch (WebDriverException e) { return null; } } @Override public String toString() { return String.format("js %s to be executable", javaScript); } }; } }