Add some ‘Weight’ to your Selenium Tests with ‘Waits’! – Part 3: Fluent Waits

In the last blog post we looked at Explicit waits, and we discussed why these are probably the default waits that you want to start with for the majority of your Selenium scripts, especially if you are new to Selenium. Today we are going to look at another type of waits – Fluent waits.

Fluent waits are a little bit more advanced in that they have more customisation available to them than normal Explicit waits and therefore can appear to be a bit more complex. One piece of customisation that can be added to a Fluent wait is that it can be set to poll at different periods, so we could set it to poll every 100 milliseconds or every 5 seconds for example.

Another, more important, piece of customisation that can be added is the ability to ignore certain exceptions. We have not covered much about exceptions in our adventures with Selenium so far, but take it from me, as you use Selenium more and more you are going to run into them ALOT, for good and not so good reasons. If you don’t know much or anything about exceptions at this stage, don’t worry about it too much for now. In the example below, we will look at one of the most common exceptions (NoSuchElementException.class) and investigate the effects of it and how we handle it. Once you have an understanding of how that works, you will be in a good position to start exploring exceptions further. We will also be covering exceptions in greater detail in later blog posts.

Back to Fluent waits – another essential difference with Fluent waits is that you don’t have to pass in a Webdriver, you could use a WebElement or anything else. If you have no clue what I am talking about I highly recommended you read this blog post by Alan Richardson where he explains using Fluent Waits with a Web Element . Since this series of blog posts is geared more towards the beginner / intermediate level, we are going to focus on a more simplified and traditional use of the Fluent wait for now and use it with the WebDriver.

We are going to write our own example code in a moment, and it will be based on the Selenium documentation code for Fluent waits . I recommend you have a browse of that post first and then return here to continue.

Read all that? OK great! Let’s go ahead and write out an example so that we can understand it properly. We are once again going to use the Dynamic Loading example on ‘The Internet’ site. Go ahead and create a new java class as usual called ‘MyFirstFluentWaitTest‘. Add the following setup code:

public class MyFirstFluentWaitTest {

    public static FirefoxDriver driver;

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

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

}

Great. Now we are going to write the same test that we have done previously, to click the start button and wait for the ‘Hello World’ text to appear, but we are going to use a Fluent wait instead. Go ahead and type out the following @Test:

    @Test
    public void fluentWaitTest()
    {
        Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(10, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class);

        driver.get("http://the-internet.herokuapp.com/dynamic_loading/2");

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

            public WebElement apply(WebDriver driver) {
                return driver.findElement(By.cssSelector("#start>button"));
            }
        });

        startButton.click();

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

            public WebElement apply(WebDriver driver) {
                return driver.findElement(By.id("finish"));
            }
        });

        String textFromElement = hellowWorldText.getText();

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

“Woah! That’s a lot of code, and it looks confusing as hell!” …. Maybe you said that, maybe you didn’t, but I remember thinking the same thing the first few times I tried to learn about Fluent waits when I was starting out! Although there is a fair bit of new code here, we are going to break it down line by line to get a better understanding of what is going on.

On the first line we are setting up the Fluent wait for the test that will end up being called a couple of times, when looking for the start button and when looking for the ‘Hello World!’ text:

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

A couple of new concepts stand out to us here right away. On the very top line we can see the <WebDriver> is in arrow brackets ‘<>’ – what does this mean? Using these brackets in Java is a term called GENERICS. Explaining generics is beyond the scope of this blog post, but if you want to learn more I highly recommend you take a look at the comprehensive Generic in Java FAQ from Angelika Langer . If you don’t want to learn more at this stage, just keep going for now!

The second new concept here is that we are using multiple lines for a single command (notice how there is just one ‘;‘, right at the end, and every new line starts with a ‘.‘). This is simply to make the code a bit more readable. I could just as easily have put everything on a single line, but it would be a little more difficult to read.

So on the very top line, we are creating a new Wait called wait (with the generic <WebDriver>) and then assigning to that variable a new FluentWait with the ‘driver’ passed in. We then add a timeout of 30 seconds to the wait and we ask the wait to poll every 10 seconds. Finally we tell the wait to ignore a ‘NoSuchElementException.class‘. What this basically means is that if the wait can’t find the element right away it will throw a NoSuchElementException and that will normally fail the wait, but because we have asked to ignore this, the wait continues instead of failing. We will see later one what happens if we remove this line.

IMPORTANT NOTE – When I was typing out this example, I kept on getting the ‘NoSuchElementException’ thrown when running the test, even though I had said to ignore it. After a lot of messing around, I found that I had added the wrong ‘NoSuchElementException’ class, since there are two with the same name from different packages:

FluentWait1So remember, when you are importing a new class to your script, make sure it is the right one!

The next line just goes to the URL, nothing new here:

driver.get("http://the-internet.herokuapp.com/dynamic_loading/2");

Now the next line will find the start button for us, and it uses our Fluent wait to do it:

WebElement startButton = wait.until(new Function<WebDriver, WebElement>() {
            public WebElement apply(WebDriver driver) {
                return driver.findElement(By.cssSelector("#start>button"));
            }
        });

This code is again introducing a new Java programming concept to us with the ‘new Function<WebDriver, WebElement>‘. This concept is called ANONYMOUS INNER CLASSES. Again this is too much for me to explain in a short blog post. If you want to learn more about anonymous classes, you can start by reading this resource on Anonymous Classes in Java , and going from there. If you don’t have time right now, just keep pressing on.

So let’s talk through the code. We create a WebElement called ‘startButton‘. We then assign the startButton by calling our Fluent wait ‘wait‘ and call the ‘.until()‘ method. We then pass in the anonymous function as we mentioned above.

Inside the anonymous function we have a WebElement function called ‘apply‘, which takes a WebDriver called ‘driver‘. Within that function, we finally use the ‘driver’ and call the ‘.findElement()‘ method with a CSS selector for the start button.

Now these are all quite advanced concepts and you are probably feeling a bit overwhelmed, especially if you are new to programming. If you are, then just relax and keep going. Accept that this example works and keep using it in your scripts and over time it will become clearer. We have done a lot of work in this piece of code in that we have found the start button whilst waiting fluently.

On the next line we click the startButton, nothing new here:

startButton.click();

On the next line we wait fluently for the ‘Hello World!’ text to appear:

WebElement hellowWorldText = wait.until(new Function<WebDriver, WebElement>() {
            public WebElement apply(WebDriver driver) {
                return driver.findElement(By.id("finish"));
            }
        });

This code is essentially the same as the code above for the startButton so I won’t explain it all again, but I will talk through what happens here when the test is running. When we get to this point, this code will look for the ‘Hello World!’ text, will see that it is not there (the element is not there) and throw a ‘NoSuchElementException‘. We set the ‘NoSuchElementException‘ to be ignored by our wait, so no error is thrown and Selenium will continue to wait. After 10 seconds (because we set our polling to be 10 seconds) the test will try again. This time the element is found, it is assigned to the ‘helloWorldText’ WebElement, and the test will continue.

The final two lines we have seen before, they just grab the text from the WebElement and assert that it is correct:

String textFromElement = hellowWorldText.getText();

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

Go ahead and run the test, it should pass with no problems. Notice how long Selenium waits after clicking on the Start button (about 10 seconds, right?).

Before we wrap up this post, I want to make a couple of changes to our initial Fluent wait to see the effects. Firstly, let’s remove the ‘.ignoring(NoSuchElementException.class)‘. Change the code at the top of the @Test to this:

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(10, TimeUnit.SECONDS);

Run the test again. This time it will fail and throw an error that looks like the one below:
ImplicitWait2Since we did not have the .ignoring(NoSuchElementException.class), when Selenium could not find the element it threw the exception and failed the test.

Finally, add the ignoring line back in and this time change the polling to be every 100 milliseconds. Go ahead and change the wait to the following:

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

Run the test one last time, it should pass again. Notice now that almost as soon as the ‘Hello World!’ text appears, the test passes. Originally we had the polling set to 10 seconds and so the ‘Hello World!’ text would appear but Selenium would not detect it for a few seconds (i.e. until the next polling). Now with the polling set to every 100 milliseconds Selenium will find the ‘Hello World!’ text almost instantly after it shows up.

Phew! This was a comprehensive post and we covered a lot of new ground and concepts. Fluent waits are a bit more advanced, but hopefully you now have at least some idea of how and when they can be used and some of the advantages of them. Feel free to read through the post again if you don’t understand anything, or leave a comment below and I will try to answer any questions you have as best I can.

We have now looked at the three main types of Selenium waits; Implict, Explict and Fluent. You might be thinking that our code is not very efficient, particularly with regard to Explict and Fluent waits. I have deliberately written it in this way so that I can explain the concepts in more detail, but as you start to write more and more Selenium tests that use lots of waits, you will want a more efficient way of doing so.

You will be pleased to know that in the next and final blog post of this series, we are going to look into writing our own wait methods that will contain wait code to be executed outside of the normal @Test methods. This will lead to lots of code reuse which is all good stuff and a fundamental concept of all programming. In turn, this will make our tests both more efficient and easier to read.

Click here to go to Part 4: Write your own Waits