Saturday, April 9, 2016

Introducing FluentLenium (2) - Selenium waiting game


Introducing FluentLenium is so far my most popular technical post and I will continue the series today with very important subject - test waiting. For those who don't know - FluentLenium is actively developed Selenium extension which simplify writing GUI tests. 

Before I delve deeper into FluentLenium powerful waiting methods let me explain why I decided to cover this topic more deeply:

a) Good implementation of waiting makes your tests:
  • stable
  • maintainable
  • readable
  • faster
All dots listed here are extremely important factors to your testing project success/failure. I will come back to those characteristics while discussing various waiting methods.

b) There aren't many reliable sources in this subject (as usual, I recommend Mastering Selenium WebDriver) and a lot of false/obsolete information. For example here post with +11 recommends static 5 seconds waiting.  

c) Topic isn't covered in Java books (because it's framework specific), and most of Selenium courses treat it falsely as advanced topic

The waiting methods are ordered from the worst one to the best one:

1. Sleeping


Most obvious method which you should never, ever use. Probably most of us started our automation journeys with it. Selenium can't find locator so we wait 2 seconds. Then we decide that 4 seconds is necessary. After that our tests become slow so we trim the time to 3 seconds. Then we change machine or run tests on Grid and it's really, really bad.

 See characteristics I have listed in point a) - we meet none of them by using Thread.sleep().

2. Implicit waits

Implicit wait is configured globally (i.e. it's declared per driver), and it defines the time before throwing 'No Such Element Exception'. Default is 0 seconds. Line below configures ImplicitWait for 10 seconds.


So far it looks good. Now imagine that you want to check if loading element disappears on the page in 5 seconds time margin. We will stay in clean Selenium and use explicitWait:


Effect? Element disappears after one second, but test still waits for something. After 5 seconds test fails with Timeout Exception! Why? Unfortunately implicitWait is always associated with driver, and sequence of events is rather undesired:
  1. 0s - First explicitWait poll was made and implicitWait was triggered for element. Element was found so implicitWait ended
  2. 0.5s - Second explicitWait poll was made and implicitWait was triggered for element. Element was found so implicitWait ended
  3. 1s - Third explicitWait poll was made and implicitWait was triggered for element. However since element has disappeared implicitWait doesn't end (it's 10 seconds)
  4. 5s - Test times out due to explicitWait 5 seconds threshold
Not really cool, huh? Don't even think of manipulating those timers. Trust me, you don't want to debug every Timeout Exception.

There is more. Imagine you have huge suite with ~500 tests. Sloppy programmer has committed something bad, and you have obvious mistake on main page. Feedback should be as fast as possible, but with implicitWait every test will most likely have 10 second delay before failure. Even with concurrent test execution your run will be really slow...

3. Explicit Waits

We are getting closer to correct wait usage. ExplicitWait (example above) isn't bad, but supports only limited number of ExpectedConditions. You can find all of them on guru99 blog. If you use them in your project I suggest to treat them as deprecated code. Changes aren't necessary, but recommended.

4. Fluent Waits

Not yet FluentLenium, but we are almost there. Hopefully you use it already in your Selenium project. We have to define two things before using them:

Wait parameters

Guava Predicate or Function

Now if we want to wait for our loading element to disappear (assuming implicitWait was removed) we have to write:

Go back to good test characteristic I have mentioned in a). There is big difference in almost every aspect, don't you think?

5. FluentLenium await() methods

Finally! :)

After this long entry you can probably easily understand why FluentLenium await() methods are very useful. They basically wrap all good things from selenium waiting methods and make one-liners. In my previous FluentLenium post I had already used them. This method verifies that Facebook login was successful.

I love especially await().until(locator).isClickable() method and click() right after it's possible. I will redirect you now to FluentLenium await() readme where you can check more examples. No need to be redundant.

Demo time

I'll give you something to play with at the end. This test clearly shows how important waitings are for Selenium. I bet it would be hard for you to make it pass faster :)


PS1

As you can see on top Pracownia Mondragor made me new logo. Details about that on Awesome Book Reviews blog.

PS2

I'm looking for reviewers who can make my blog posts better when it comes to English language details. Contact me if you want to help. I offer online recognition and good book :)