Mix & Match for Wait?

Can we mix&match implicitWait with explicit waits? Sure you can, if you enjoy the thrilling of ‘Uncertainty’.

Implicit waits are often implemented on the “remote” side of the WebDriver system, i.e they’re “baked in” to IEDriverServer.exe, chromedriver.exe, the WebDriver Firefox extension that gets installed into the anonymous Firefox profile, and the Java remote WebDriver server (selenium-server-standalone.jar).

Explicit waits are implemented exclusively in the “local” language bindings. Things get much more complicated when using RemoteWebDriver, because you could be using both the local and remote sides of the system multiple times.

This is how that would work: local code -> Java remote server -> local Java language bindings on the remote server -> “remote” component like the Firefox extension, chromedriver.exe or IEDriverServer.exe. It’s even more complex in the grid case, since there could be other hops in between.

Thus, when you try to mix implicit and explicit waits, you’ve strayed into “undefined behavior”. You might be able to figure out what the rules of that behavior are, but they’ll be subject to change as the implementation details of the drivers change. So don’t do it.

You shouldn’t be experiencing “hangs” when an element can’t be found if you’re not using implicit waits. The driver should throw a NoSuchElement exception immediately.

Here is a quick rundown on the differences between explicit and implicit wait:

Explicit wait:

  • documented and defined behaviour.
  • runs in the local part of selenium (in the language of your code).
  • works on any condition you can think of.
  • returns either success or timeout error.
  • can define absence of element as success condition.
  • can customize delay between retries and exceptions to ignore.

Implicit wait:

  • undocumented and practically undefined behaviour.
  • runs in the remote part of selenium (the part controlling the browser).
  • only works on find element(s) methods.
  • returns either element found or (after timeout) not found.
  • if checking for absence of element must always wait until timeout.
  • cannot be customized other than global timeout.

Let’s see the difference between explicit wait and implicit wait in the actual source code of selenium.
The code of FluentWait.until() (explicit wait):

/**
* Repeatedly applies this instance’s input value to the given function until one of the following
* occurs:
* . the function returns neither null nor false,
* . the function throws an unignored exception,
* . the timeout expires,
* . the current thread is interrupted
*

*
* @param isTrue the parameter to pass to the {@link ExpectedCondition}
* @param The function’s expected return type.
* @return The functions’ return value if the function returned something different
* from null or false before the timeout expired.
* @throws TimeoutException If the timeout expires.
*/
public V until(Function isTrue) {
long end = clock.laterBy(timeout.in(MILLISECONDS));
Throwable lastException = null;
while (true) {
try {
V value = isTrue.apply(input);
if (value != null && Boolean.class.equals(value.getClass())) {
if (Boolean.TRUE.equals(value)) {
return value;
}
} else if (value != null) {
return value;
}
} catch (Throwable e) {
lastException = propagateIfNotIngored(e);
}

// Check the timeout after evaluating the function to ensure conditions
// with a zero timeout can succeed.
if (!clock.isNowBefore(end)) {
String message = messageSupplier != null ?
messageSupplier.get() : null;

String toAppend = message == null ?
” waiting for ” + isTrue.toString() : “: ” + message;

String timeoutMessage = String.format(“Timed out after %d seconds%s”,
timeout.in(SECONDS), toAppend);
throw timeoutException(timeoutMessage, lastException);
}

try {
sleeper.sleep(interval);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new WebDriverException(e);
}
}
}

In plain English: explicit wait expects a method which returns a truish value if successful. It then repeatedly executes the given method with a delay in between. Expected errors from the given method are supressed. If the given method returns a truish value then explicit wait will return that value. If the time runs out a timeout exception is raised.

Now let’s see code of RemoteWebDriver.implicitlyWait():

public Timeouts implicitlyWait(long time, TimeUnit unit) {
execute(DriverCommand.SET_TIMEOUT, ImmutableMap.of(
“type”, “implicit”,
“ms”, TimeUnit.MILLISECONDS.convert(time, unit)));
return this;
}

and RemoteWebDriver.execute() (part of the method only):

Implicit wait sends a command message to remote webdriver. The remote side of the selenium webdriver is the part of selenium which is actually controlling the browser. What does the remote side do with the message? “It depends”. It depends on the operating system and on the browser and on the version of selenium. As far as I can tell there is no guarantee about the actual behaviour of a specific implementation.

Possible implementations are:

  • repeatedly try to find element until timeout. return as soon as element is found.
  • try to find element. wait until timeout. try again.
  • wait until timeout. try to find element.

Note that implicit wait only takes effect on find element(s) methods.

My conclusion: Implicit wait is bad. The capabilities are limited. The behaviour is undocumented and implementation dependent.

Explicit wait can do everything implicit wait can and more. The only disadvantage of explicit wait is a bit more overhead because of multiple remote procedure calls. Also the explicit wait is a bit more verbose. But that verbosity makes the code explicit. And explicit is better that implicit.

So, don’t mix implicitWait with explicit waits.

Leave a Reply

Your email address will not be published. Required fields are marked *