Synchronizing Tests

In this article by Unmesh Gundecha, author of Selenium Testing Tools Cookbook Second Edition, you will cover the following topics:

  • Synchronizing a test with an implicit wait
  • Synchronizing a test with an explicit wait
  • Synchronizing a test with custom-expected conditions

While building automated scripts for a complex web application using Selenium WebDriver, we need to ensure that the test flow is maintained for reliable test automation.

When tests are run, the application may not always respond with the same speed. For example, it might take a few seconds for a progress bar to reach 100 percent, a status message to appear, a button to become enabled, and a window or pop-up message to open.

You can handle these anticipated timing problems by synchronizing your test to ensure that Selenium WebDriver waits until your application is ready before performing the next step. There are several options that you can use to synchronize your test. In this article, we will see various features of Selenium WebDriver to implement synchronization in tests.

(For more resources related to this topic, see here.)

Synchronizing a test with an implicit wait

The Selenium WebDriver provides an implicit wait for synchronizing tests. When an implicit wait is implemented in tests, if WebDriver cannot find an element in the Document Object Model (DOM), it will wait for a defined amount of time for the element to appear in the DOM. Once the specified wait time is over, it will try searching for the element once again. If the element is not found in specified time, it will throw NoSuchElement exception.

In other terms, an implicit wait polls the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available. The default setting is 0.

Once set, the implicit wait is set for the life of the WebDriver object's instance.

In this recipe, we will briefly explore the use of an implicit wait; however, it is recommended to avoid or minimize the use of an implicit wait.

How to do it...

Let's create a test on a demo AJAX-enabled application as follows:

@Test
public void testWithImplicitWait()
{
  //Go to the Demo AjAX Application
  WebDriver driver = new FirefoxDriver();
    driver.get("http://dl.dropbox.com/u/55228056/AjaxDemo.html");

      //Set the Implicit Wait time Out to 10 Seconds
  driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

  try {

    //Get link for Page 4 and click on it
    WebElement page4button = driver.findElement(By.linkText("Page 
4"));
    page4button.click();

    //Get an element with id page4 and verify it's text
    WebElement message = driver.findElement(By.id("page4"));
    assertTrue(message.getText().contains("Nunc nibh tortor"));

  } catch (NoSuchElementException e) {
    fail("Element not found!!");
    e.printStackTrace();
  } finally {
    driver.quit();
  }
}

How it works...

The Selenium WebDriver provides the Timeouts interface for configuring the implicit wait. The Timeouts interface provides an implicitlyWait() method, which accepts the time the driver should wait when searching for an element. In this example, a test will wait for an element to appear in DOM for 10 seconds:

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Until the end of a test or an implicit wait is set back to 0, every time an element is searched using the findElement() method, the test will wait for 10 seconds for an element to appear.

Using implicit wait may slow down tests when an application responds normally, as it will wait for each element appearing in the DOM and increase the overall execution time. Minimize or avoid using an implicit wait. Use Explicit wait, which provides more control when compared with an implicit wait.

See also

  • Synchronizing a test with an explicit wait
  • Synchronizing a test with custom-expected conditions

Synchronizing a test with an explicit wait

The Selenium WebDriver provides an explicit wait for synchronizing tests, which provides a better way to wait over an implicit wait. Unlike an implicit wait, you can use predefined conditions or custom conditions or wait before proceeding further in the code.

The Selenium WebDriver provides WebDriverWait and ExpectedConditions classes for implementing an explicit wait.

The ExpectedConditions class provides a set of predefined conditions to wait before proceeding further in the code. The following table shows some common conditions that we frequently come across when automating web browsers supported by the ExpectedConditions class:

  Predefined condition

   Selenium method

An element is visible and enabled

elementToBeClickable(By locator)

An element is selected

elementToBeSelected(WebElement element)

Presence of an element

presenceOfElementLocated(By locator)

Specific text present in an element

textToBePresentInElement(By locator, java.lang.String text)

Element value

textToBePresentInElementValue(By locator, java.lang.String text)

Title

titleContains(java.lang.String title)

 For more conditions, visit http://seleniumhq.github.io/selenium/docs/api/java/index.html.

In this recipe, we will explore some of these conditions with the WebDriverWait class.

How to do it...

Let's implement a test that uses the ExpectedConditions.titleContains() method to implement an explicit wait as follows:

@Test
public void testExplicitWaitTitleContains()
{
  //Go to the Google Home Page
  WebDriver driver = new FirefoxDriver();
  driver.get("http://www.google.com");

  //Enter a term to search and submit
  WebElement query = driver.findElement(By.name("q"));
  query.sendKeys("selenium");
  query.click();

  //Create Wait using WebDriverWait.
  //This will wait for 10 seconds for timeout before title is updated 
with search term
  //If title is updated in specified time limit test will move to the 
text step
  //instead of waiting for 10 seconds
  WebDriverWait wait = new WebDriverWait(driver, 10);
  wait.until(ExpectedConditions.titleContains("selenium"));

  //Verify Title
  assertTrue(driver.getTitle().toLowerCase().startsWith("selenium"));

  driver.quit();
}

How it works...

We can define an explicit wait for a set of common conditions using the ExpectedConditions class. First, we need to create an instance of the WebDriverWait class by passing the driver instance and timeout for a wait as follows:

WebDriverWait wait = new WebDriverWait(driver, 10);

Next, ExpectedCondition is passed to the wait.until() method as follows:

wait.until(ExpectedConditions.titleContains("selenium"));

The WebDriverWait object will call the ExpectedConditions class object every 500 milliseconds until it returns successfully.

See also

  • Synchronizing a test with an implicit wait
  • Synchronizing a test with custom-expected conditions

Synchronizing a test with custom-expected conditions

With the explicit wait mechanism, we can also build custom-expected conditions along with common conditions using the ExpectedConditions class. This comes in handy when a wait cannot be handled with a common condition supported by the ExpectedConditions class.

In this recipe, we will explore how to create a custom condition.

How to do it...

We will create a test that will create a wait until an element appears on the page using the ExpectedCondition class as follows:

@Test
public void testExplicitWait()
{
  WebDriver driver = new FirefoxDriver();
      driver.get("http://dl.dropbox.com/u/55228056/AjaxDemo.html");

      try {
    WebElement page4button = driver.findElement(By.linkText("Page 
4"));
    page4button.click();

    WebElement message = new WebDriverWait(driver, 5)
      .until(new ExpectedCondition<WebElement>(){
        public WebElement apply(WebDriver d) {
          return d.findElement(By.id("page4"));
      }});
    assertTrue(message.getText().contains("Nunc nibh tortor"));

  } catch (NoSuchElementException e) {
    fail("Element not found!!");
    e.printStackTrace();
  } finally {
    driver.quit();
  }
}

How it works...

The Selenium WebDriver provides the ability to implement the custom ExpectedCondition interface along with the WebDriverWait class for creating a custom-wait condition, as needed by a test. In this example, we created a custom condition, which returns a WebElement object once the inner findElement() method locates the element within a specified timeout as follows:

WebElement message = new WebDriverWait(driver, 5)
.until(new ExpectedCondition<WebElement>(){
    @Override
    public WebElement apply(WebDriver d) {
    return d.findElement(By.id("page4"));
}});

There's more...

A custom wait can be created in various ways. In the following section, we will explore some common examples for implementing a custom wait.

Waiting for element's attribute value update

Based on the events and actions performed, the value of an element's attribute might change at runtime. For example, a disabled textbox gets enabled based on the user's rights. A custom wait can be created on the attribute value of the element. In the following example, the ExpectedCondition waits for a Boolean return value, based on the attribute value of an element:

new WebDriverWait(driver, 10).until(new 
ExpectedCondition<Boolean>() {
    public Boolean apply(WebDriver d) {
        return 
d.findElement(By.id("userName")).getAttribute("readonly").contains("true");
}});

Waiting for an element's visibility

Developers hide or display elements based on the sequence of actions, user rights, and so on. The specific element might exist in the DOM, but are hidden from the user, and when the user performs a certain action, it appears on the page. A custom-wait condition can be created based on the element's visibility as follows:

new WebDriverWait(driver, 10).until(new ExpectedCondition<Boolean>() {
    public Boolean apply(WebDriver d) {
        return d.findElement(By.id("page4")).isDisplayed();
}});

Waiting for DOM events

The web application may be using a JavaScript framework such as jQuery for AJAX and content manipulation. For example, jQuery is used to load a big JSON file from the server asynchronously on the page. While jQuery is reading and processing this file, a test can check its status using the active attribute. A custom wait can be implemented by executing the JavaScript code and checking the return value as follows:

new WebDriverWait(driver, 10).until(new 
ExpectedCondition<Boolean>() {
    public Boolean apply(WebDriver d) {
        JavascriptExecutor js = (JavascriptExecutor) d;
        return (Boolean)js.executeScript("return jQuery.active == 
0");
}});

See also

  • Synchronizing a test with an implicit wait
  • Synchronizing a test with an explicit wait

Summary

In this article, you have learned how the Selenium WebDriver helps in maintaining a reliable automated test. Using the Selenium WebDriver, you also learned how you can synchronize a test using the implicit and the explicit wait methods. You also saw how to synchronize a test with custom-expected conditions.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Selenium Testing Tools Cookbook - Second Edition

Explore Title