Do you need some help with Selenium Expected conditions? You need custom expected conditions when the built-in Selenium WebDriver expected conditions are not sufficient for creating complex conditions.
Short review of expected conditions
Explicit waits and expected conditions are a great help for Selenium scripts.
Selenium WebDriver comes with a lot of expected conditions such as:
- ExpectedCondition < WebElement > elementToBeClickable(By locator)
- ExpectedCondition < Boolean > elementToBeSelected(By locator)
- ExpectedCondition < WebElement > presenceOfElementLocated(By locator)
- ExpectedCondition < Boolean > titleContains(String title)
- ExpectedCondition < Boolean > titleIs(String title)
- ExpectedCondition < Boolean > urlContains(String fraction)
- ExpectedCondition < Boolean > urlToBe(String url)
- ExpectedCondition < WebElement > visibilityOfElementLocated(By locator)
There are 2 main expected condition types that can be used with explicit waits:
ExpectedCondition < WebElement >
This is the type of condition which has a web element locator as parameter.
The wait applies the condition which tries finding the web element, depending on its status.
If the condition can find the element, it returns the element as result.
If it cannot find the element, the wait tries the condition again after a short delay.
ExpectedCondition < Boolean >
This type of condition has a string parameter.
The wait applies the condition to the parameter.
If the result of applying the condition is true, true is returned as result.
If the result is false, the wait tries the condition again after a short delay.
While the explicit wait applies the expected condition, the condition code may generate various exceptions.
All these exceptions are ignored by the wait.
Enough theory, let’s see some code.
The following short example uses explicit waits and expected conditions to
- verify whether a page title is correct
- verify if a page url is correct
- find web elements
public class TestClass { WebDriver driver; WebDriverWait wait; By searchFieldXpath = By.id("globalQuery"); By searchButtonXpath = By.className("search_button"); By resultLinkLocator = By.xpath("(//a[@testid='bib_link'])[1]"); String homeUrl = "http://www.vpl.ca"; String homeTitle = "Vancouver Public Library - Home"; String resultsTitle = "Search | Vancouver Public Library | BiblioCommons"; String resultsUrl = "https://vpl.bibliocommons.com/search"; @Before public void setUp() } driver = new FirefoxDriver(); wait = new WebDriverWait(driver, 10); } @After public void tearDown() { driver.quit(); } @Test public void test1() { driver.get(homeUrl); if (!wait.until(titleContains(homeTitle)) || !wait.until(urlContains(homeUrl))) throw new RuntimeException("home page is not displayed"); WebElement searchField = wait.until(elementToBeClickable(searchFieldXpath)); searchField.click(); searchField.sendKeys(keyword); WebElement searchButton = wait.until(elementToBeClickable(searchButtonXpath)); searchButton.click(); if (!wait.until(titleContains(resultsTitle)) || !wait.until(urlContains(resultsUrl))) throw new RuntimeException("results page is not displayed"); } }
We use 2 expected conditions for verifying if a page is displayed.
Selenium does not include by default an expected condition that checks that both the page title and url are correct.
This is where we can create custom expected conditions.
How to create a custom expected condition Selenium
A custom expected condition is a class that
- implements the ExpectedCondition interface
- has a constructor with the parameters of the expected condition
- overrides the apply method
Lets rewrite the previous exercise with a custom expected condition that verifies if a page is displayed:
public class TestClass { WebDriver driver; WebDriverWait wait; By searchFieldXpath = By.id("globalQuery"); By searchButtonXpath = By.className("search_button"); By resultLinkLocator = By.xpath("(//a[@testid='bib_link'])[1]"); String homeUrl = "http://www.vpl.ca"; String homeTitle = "Vancouver Public Library - Home"; String resultsTitle = "Search | Vancouver Public Library | BiblioCommons"; String resultsUrl = "https://vpl.bibliocommons.com/search"; @Before public void setUp() } driver = new FirefoxDriver(); wait = new WebDriverWait(driver, 10); } @After public void tearDown() { driver.quit(); } @Test public void test1() { driver.get(siteUrl); if (!wait.until(new PageLoaded(homeTitle, homeUrl))) throw new RuntimeException("home page is not displayed"); WebElement searchField = wait.until(elementToBeClickable(searchFieldXpath)); searchField.click(); searchField.sendKeys(keyword); WebElement searchButton = wait.until(elementToBeClickable(searchButtonXpath)); searchButton.click(); if (!wait.until(new PageLoaded(resultsTitle, resultsUrl))) throw new RuntimeException("results page is not displayed"); } } public class PageLoaded implements ExpectedCondition { String expectedTitle; String expectedUrl; public PageLoaded(String expectedTitle, String expectedUrl) { this.expectedTitle = expectedTitle; this.expectedUrl = expectedUrl; } @Override public Boolean apply(WebDriver driver) { Boolean isTitleCorrect = driver.getTitle().contains(expectedTitle); Boolean isUrlCorrect = driver.getCurrentUrl().contains(expectedUrl); return isTitleCorrect && isUrlCorrect; } }
The PageLoaded custom expected condition is used for verifying if
- HomePage is displayed
- ResultsPage is displayed
For ResultsPage, we would like to verify not only that the page title and url are correct but also that
- there are 25 results loaded in the page
- total result count is > 0
The following custom expected condition does it all:
public class ResultsPageLoaded implements ExpectedCondition { By resultLocator = By.xpath("//div[contains(@data-analytics, 'SubFeature')]"); By resultCountLocator = By.xpath("//span[@class='items_showing_count']"); String expectedTitle; String expectedUrl; public ResultsPageLoaded(String expectedTitle, String expectedUrl) { this.expectedTitle = expectedTitle; this.expectedUrl = expectedUrl; } @Override public Boolean apply(WebDriver driver) { Boolean isTitleCorrect = driver.getTitle().contains(expectedTitle); Boolean isUrlCorrect = driver.getCurrentUrl().contains(expectedUrl); int resultPerPageCount = driver.findElements(resultLocator).size(); WebElement resultCountElement = driver.findElement(resultCountLocator); return isTitleCorrect && isUrlCorrect && resultPerPageCount == 25 && count(resultCountElement) > 0; } private int count(WebElement element) { String resultCountText = element.getText(); int index1 = resultCountText.indexOf("of") + 3; int index2 = resultCountText.indexOf("items") - 1; resultCountText = resultCountText.substring(index1, index2); return Integer.parseInt(resultCountText); } }
Custom expected conditions can return not only a boolean value but also a WebElement.
Lets define a custom condition that
- finds an element from its parent element
- returns the element if it is displayed
public class ResultField implements ExpectedCondition { By resultLocator; By parentLocator; public ResultField(By resultLocator, By parentLocator) { this.resultLocator = resultLocator; this.parentLocator = parentLocator; } @Override public WebElement apply(WebDriver driver) { WebElement parent = driver.findElement(parentLocator); WebElement result = parent.findElement(resultLocator); return (result.isDisplayed() ? result : null); } }
How do you use it?
WebElement titleLink = wait.until(new ResultField(resultLocator, titleLocator)); titleLink.click(); Find the previous selenium posts:
- How To…Select Elements In Selenium WebDriver Scripts
- How To…Use Explicit Waits In Selenium WebDriver
- How To…Manage Exceptions In Selenium WebDriver
See more articles in the How To Selenium Series
About The Author
Alex Siminiuc lives in Vancouver, Canada. He has worked as a software tester since 2005. Alex teaches manual testers test automation with Selenium WebDriver and Java. Alex blogs on testing and automation at http://test-able.blogspot.ca.