Reading Time: 4 minutes

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:

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.