Handling Waits and Asynchronous Pages in Serenity BDD

John Ferguson Smart | Mentor | Author | Speaker - Author of 'BDD in Action'.
Helping teams deliver more valuable software sooner12th August 2019

Modern web applications are asynchronous by nature. So knowing how to wait for elements, before trying to interact with them, is an essential skill in modern test automation.


Many testers pepper their web tests with Thread.sleep() statements, but this is the sub-optimal at best. It slows down the tests, makes them more brittle, and can hide genuine application issues. More insidiously, when our steps are artificially slowed by sleep statements, it takes longer not only to run and troubleshoot existing tests, but also to develop new ones.

Fortunately there are many ways we can do better. If you are writing web tests in Java using Selenium and Serenity BDD, you have several options at your disposal.

Implicit and Explicit Waits

The simplest strategy is to define the default timeouts that Serenity and Selenium use when locating and interacting with elements on a page. Implicit Waits are used to ensure that Serenity does not fail a test if a web element is not immediately present on the page when you first try to use it. And Fluent Waits make Serenity wait for an element that is already present on the page to become visible or enabled, before interacting with it. You can easily configure the default values for these waits in your serenity.conf or serenity.properties file, with the webdriver.timeouts.implicitlywait and webdriver.timeouts.fluentwait parameters:

webdriver {
  driver = chrome
  timeouts {
    implicitlywait = 5000
    fluentwait = 10000
  }
}

Programmatic waits

When you need more fine-grained control, you can define timeouts directly within your code, using the withTimeoutOf() method. In any PageObject or Action Class, you can use this method to override the Fluent Wait timeout on-the-fly:

public void clickOnButtonThatWillEventuallyAppear() {
      withTimeoutOf(Duration.ofSeconds(30))
                  .find(By.id("eventually-visible-button"))
                  .click()
}

Waiting for expected conditions

But sometimes it is not enough simply to wait for a button to be enabled. Sometimes you need to wait for something to happen on the page before proceeding.

For example, you might need to wait for a certain text message, overlay or icon to appear or disappear, so that you know that the application has finished processing. Or you might need to wait until a dropdown or a table is populated by data from the server.

You can wait for conditions like this using one of the many built-in Selenium ExpectedConditions functions, such as the one shown here:

public void waitForVisibleTextToAppear() {
    waitForCondition().until(
            ExpectedConditions.textToBePresentInElement(statusBox, "Processing done")
    );
}

Conclusion

But these are just a few of the options - there are many more. You can learn about some of the other options in the Serenity Documentation.

And to help you get your head around all these options, we have just published another Serenity Dojo module in our Automated web testing with WebDriver and Serenity BDD course, called "Handling Asynchronous Applications in Serenity". This module explains the difference between implicit waits, fluent waits, and programmatic waits, and goes through many more advanced asynchronous scenarios. Check it out today!

© 2019 John Ferguson Smart