Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Dealing vs. Not Having to Deal With Selenium Waits

DZone's Guide to

Dealing vs. Not Having to Deal With Selenium Waits

See how the innate differences between man and machine make waits necessary when testing software or sites with Selenium.

· DevOps Zone
Free Resource

The Nexus Suite is uniquely architected for a DevOps native world and creates value early in the development pipeline, provides precise contextual controls at every phase, and accelerates DevOps innovation with automation you can trust. Read how in this ebook.

Waits and timeouts are notoriously painful to deal with. Not that explicit and implicit waits are difficult in of themselves. Rather, it’s the little things that you have to take into account when trying to make waits work for a real-life project. Actually, let’s take a closer look at how Selenium waits work and see what they’re all about.

Why Do We Need Selenium Waits?

The shortest possible answer to this question is patience. Okay, I know this sounds obscure, so bear with me for a little while.

The thing with patience is that it’s inherent for human testers (or, at least, it should be). A machine, on the other hand, is only capable of simulating patience — and only if there are clear instructions on doing so.

When performing a UI test, a human knows that loading some elements may take a while. Say there’s a Rich Media ad unit, or a popup with a subscription form that loads asynchronously. Human testers will automatically know they need to wait for UI element to load.

A machine, on the other hand, need to be instructed to wait. Moreover, it needs to be told how to wait — and that’s exactly where Selenium waits come into play.

How Do We Make Selenium Wait?

Let’s play a little game before we can proceed to answering this question. If you were to design a UI testing framework, like Selenium or Watir, how would you implement waits? How do you tell your tests to wait before firing a failure?

In an ideal world, you’d simply delay test execution for a couple of seconds, right? You know that banner or popup will lag for three seconds max, so you write a script delaying the test for three seconds. Easy peasy. Well, not quite.

The problem with this scenario is that in the case with a real-world suite, you’ll have a second test that depends on the one you’ve delayed. The delay might trigger a false positive in that second test, which means you have to delay it too. Now what if there’s a third test that also needs a delay? Okay, I’m sure you see where this is going…

Now, imagine that you’re working on a complex, AJAX-heavy project, with every suite running on multiple browsers, with multiple screen resolutions. In real life, this will lead to hours needed for a test to run. Yikes!

How Waits Actually Work in Selenium

Okay, I’m certain that at this point, we all can agree there must be some sort of a flexible control mechanism behind waits. Ideally, setting a delay to one test shouldn’t break all other tests down the pipeline. Also, the test shouldn’t initiate a timeout if the element has loaded without a delay.

Seems like a reasonable wishlist, right? Let’s see what Selenium has to offer in this respect. That is, let’s look at Implicit and Explicit waits and see how they work.

Implicit and Explicit Waits

Selenium offers two mechanisms for teaching machines patience. The first one is called the Implicit wait. Waits of this type specify an amount of time during which the WebDriver will periodically read the DOM to check for a desired UI state. Once set, an implicit wait is available for the entire lifecycle of a WebDriver instance.


An Explicit wait, on the other hand, implies making your test continuously check for the fulfillment of a particular condition, for a particular element.


To sum up, the difference between the two comes to two things. On the one hand, Explicit waits are smarter and more flexible. On the other, you have to provide them with an element to target, while Implicit waits only need a specified timeout. Let’s get our hands dirty with some technical detail.

Implicit Waits

As far as technical details are concerned, an implicit wait is a method that takes two parameters:

  1. A number.

  2. A time measurement unit: seconds, minutes, hours.

As you might’ve guessed, the first parameter determines for how many seconds, minutes, or hours a test is going to wait for something to happen. As for the second parameter, it tells the WebDriver if it’s seconds, minutes, or hours that it will count using the first parameter. Simple as that.

Here’s what an implicit wait looks like:

WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
driver.get("http://domain/page_with_a_delay");
WebElement popup = driver.findElement(By.id("popup"));

Basically, we’re setting a wait, and, after that, we’re beginning to target on-page elements. Seems fairly simple, doesn’t it?

Explicit Waits

Let’s start with looking at the code of an explicit wait:

WebDriver driver = new FirefoxDriver();
driver.get("http://domain/page_with_a_delay");
WebElement popup = (new WebDriverWait(driver, 2))
.until(ExpectedConditions.presenceOfElementLocated(By.id("popup")));

Notice how you have to specify the presence of the popup in the wait, and not after it? When working with Explicit waits, we target specific elements, and, ideally, we need to be able to build robust Selenium locators for them.

Any Room for Improvement?

Okay, everything things pretty straightforward for now, so what’s the reason for the complaining about Selenium waits? For starters, it’s the locators-related part that causes lots of headache for testers. There’s arguably no such thing as robust a Selenium locator, which means your Explicit waits will need rewriting at some point.

As for the Implicit ones, their lack of flexibility often means adding hours of running time to large UI testing suites. If you’ve ever been in a project where you start running a test in the evening and check the results in the morning next day, you know about the pitfalls of implicit waits.

So what can you do about it? My answer is start looking for Selenium alternatives that don’t make you hand-code waits… or don’t make you hand-code tests at all. One such platform is Screenster, a tool that we’ve released about a year ago.

Screenster: a Codeless UI Testing Platform With Fully-Automated Waits

Screenster is a cloud-based, solution envisioned as a record-playback IDE that actually works for professional UI testing. The platform is peculiar in many ways, including its mechanism for dealing with waits and timeouts.

Unlike other codeless solutions that make you define waiting time manually, Screenster figures everything out on its own. It has an intelligent mechanism for targeting elements, which allows it to automatically determine optimal waiting time on a per-element basis. At the end of the day, it means that timeouts management happens under the hood, so you don’t have to worry about it.

There’s a bunch of other neat features as well. The platform has a fully-automated way of dealing with locators, and it makes working with dynamic regions significantly simpler. Unlike old-school IDEs of the 2000s, it doesn’t make you fumble through autogenerated code. Rather, the platform saves test as editable codeless steps complete with Visual baselines and intuitive comparisons.

Seems pretty exciting, huh? There’s a simple way to find out of the platform lives up to its promises. Go to Screenster.io and try recording UI tests for your website. I’m sure you’ll see how rewarding UI testing can feel once you’re done with hand-coding timeouts and waits.

The DevOps Zone is brought to you in partnership with Sonatype Nexus.  See how the Nexus platform infuses precise open source component intelligence into the DevOps pipeline early, everywhere, and at scale. Read how in this ebook

Topics:
quality assurance ,regression testing ,selenium ,test automation ,devops

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}