Add some ‘Weight’ to your Selenium Tests with ‘Waits’! – Part 4: Create your own Wait Methods

In the previous three blog posts in this series we have covered three different types of Selenium waits:

Feel free to go back over any of the posts above if you need to refresh your memory or have a recap. In this, the final blog post of the series on Waits, we are going to have a look at how we can write our own wait methods that will be called from within the @Test method, but the actual code will be kept externally from the @Test method. This is the first time that we will have attempted this programming practice during our experience so far with Selenium (i.e. writing our own methods), but it is important to become familiar with this practice if you are going to be successful in your automation efforts!

Ok, we are just going to dive straight in with an example and then talk about what is going on. In this first example we are going to write a custom method for an Explicit wait and then call that a couple of times from our @Test. Start as usual by creating a new test class called ‘MyFirstWaitMethods‘ and add the usual setup code:

public class MyFirstWaitMethods {

    public static FirefoxDriver driver;

    @BeforeClass
    public static void createDriver()
    {
        driver = new FirefoxDriver();
    }

    @AfterClass
    public static void quitDriver()
    {
        driver.quit();
    }

Now instead of writing a @Test method, write the following method instead:

public void waitForElementToBeVisible(By selector, int timeToWaitInSeconds)
    {
        WebDriverWait wait = new WebDriverWait(driver, timeToWaitInSeconds);

        wait.until(ExpectedConditions.visibilityOfElementLocated(selector));
    }

This is our Explicit wait method. It takes two arguments, the ‘By’ selector that finds the elements on the page, and an ‘int’ called timeToWaitInSeconds that controls how long the wait will be. Inside the method, on the first line, a new Explicit wait is created and the driver is passed in as well as the timeToWaitInSeconds from the method call. On the second line we execute the wait, waiting until the element is visible. On this line we pass in the ‘selector’ that we specified when we called the method.

To make things a bit clearer, let’s write out a @Test and call our new methods a couple of times. Once again, we will be using the dynamic loading page on ‘The Internet‘  . Type in the following:

    @Test
    public void clickStartButton_ExplicitWait()
    {
        driver.get("http://the-internet.herokuapp.com/dynamic_loading/2");

        waitForElementToBeVisible(By.cssSelector("#start>button"), 2);

        WebElement startButton = driver.findElement(By.cssSelector("#start>button"));

        startButton.click();

        waitForElementToBeVisible(By.id("finish"), 10);

        WebElement helloWorldText = driver.findElement(By.id("finish"));

        String textFromElement = helloWorldText.getText();

        assertThat(textFromElement, equalTo("Hello World!"));
    }

We have seen all of this code before in the Explicit wait blog post . The only difference is that we have refactored the code slightly so that instead of creating and declaring the Explicit waits inside the test, we just call the method waitForElementToBeVisible a couple of times.

The first time we call it, we pass in the CSS Selector for the start button and tell the method to wait for 2 seconds:

waitForElementToBeVisible(By.cssSelector("#start>button"), 2);

The second time we call it, we pass in the ID for the ‘Hello World!’ text and this time we tell the method to wait for a maximum of 10 seconds:

waitForElementToBeVisible(By.id("finish"), 10);

So the above example is our first taste of writing our own methods, and hopefully you can see straight away what the advantages of this are. However, we could certainly improve this code and refactor it further. If you look at the code above, you can see that when we call the waitForElementToBeVisible method we pass in the selector to find that element on the page. On the next line, where we assign the WebElement to the startButton, we have to type in the CSS selector again. It would be better if we only had to type in the CSS selector once to obtain the WebElement.

In the next example, we are going to write a method that will combine the wait with assigning the WebElement to the variable. This time we will be using a Fluent Wait. Type out the following method:

public WebElement findWebElementWhileWaitingFluently(final By selector, int timeoutInSeconds)
    {
        Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
                .withTimeout(timeoutInSeconds, TimeUnit.SECONDS)
                .pollingEvery(100, TimeUnit.MILLISECONDS)
                .ignoring(NoSuchElementException.class);

        WebElement webElement = wait.until(new Function<WebDriver, WebElement>() {
            public WebElement apply(WebDriver driver) {
                return driver.findElement(selector);
            }
        });

        return webElement;
    }

This method, much like the first one, takes two arguments; the selector and the timeoutInSeconds. On the first line inside the method, we create a new FluentWait. We pass in the timeoutInSeconds for the timeout, but the other variables such as the polling are hardcoded. If we wanted to, we could pass this in with the method as well, but let’s leave it as it is for this example:

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
               .withTimeout(timeoutInSeconds, TimeUnit.SECONDS)
               .pollingEvery(100, TimeUnit.MILLISECONDS)
               .ignoring(NoSuchElementException.class);

The second line combines assigning the WebElement to a variable with the fluent wait. We have already explored how this code works in the previous blog post (here), so we won’t explain it again:

WebElement webElement = wait.until(new Function<WebDriver, WebElement>() {

            public WebElement apply(WebDriver driver) {
                return driver.findElement(selector);
            }
        });

On the final line, we return the webElement that has been assigned:

return webElement;

Let’s again write out a test to show this method in action:

    @Test
    public void clickStartButton_FluentWait()
    {
        driver.get("http://the-internet.herokuapp.com/dynamic_loading/2");

        WebElement startButton = findWebElementWhileWaitingFluently(By.cssSelector("#start>button"), 2);

        startButton.click();

        WebElement helloWorldText = findWebElementWhileWaitingFluently(By.id("finish"), 10);

        String textFromElement = helloWorldText.getText();

        assertThat(textFromElement, equalTo("Hello World!"));
    }

Again, we have seen all this code before, we have just refactored the WebElement lines to use our new method:

WebElement startButton = findWebElementWhileWaitingFluently(By.cssSelector("#start>button"), 2);

WebElement helloWorldText = findWebElementWhileWaitingFluently(By.id("finish"), 10);

So on the first line, we declare a WebElement called startButton. We then assign the WebElement by calling the findWebElementWhileWaitingFluently and passing in the selector and the timeout. We do the same thing on the second line when assigning the helloWorldText WebElement. With our new method, we have made the test both more maintainable and easier to read than it was before.

One final point I want to mention. You might notice that we have not used Implicit waits at all in this post. I used to think that it was a good idea to combine Implicit and Explicit waits, i.e. set an Implicit wait at the start of the test and then override that with Explicit waits when need be. However, this is actually a bad practice and can result in problems, see this post from Jim Evans here on why combining Implict and Explicit Waits is bad for an explanation. To be safe I recommend that you just stick with Explicit and Fluent waits for your final tests, and just use Implicit waits whilst you are knocking the tests together in the script devevlopment phase (removing them later).
I hope that you have found this series on waits to be useful. On a personal level, I have found that taking the time to collect my thoughts and type out these posts has actually dramatically improved my own understanding of waits, and this is encouraging me to continue writing these kind of posts. Stay tuned for more Selenium posts!

  • Pingback: Testing Bits – 6/28/15 – 7/4/15 | Testing Curator Blog()

  • http://test-able.blogspot.ca Alex

    Very nice article again!

    It is difficult to have good test automation code without custom waits.

    The biggest benefit I got from custom waits so far is not with Selenium but with another test automation tool called Ranorex.

    I used it for test automation of Windows applications where Selenium does not work.

    There are no waits in Ranorex so I had to create my own for waiting until certain elements are displayed.

    Looking forward to more articles about Selenium!

    Alex

  • James Willett

    Hi Alex,

    Glad you found the article interesting.

    Can’t say that I have heard much about Ranorex, but it sounds interesting, particularly how you were able to develop your own custom waits for it – do you have any further information I can check out?

    Cheers,

    James