When to use explicit wait vs implicit wait in Selenium Webdriver?
I am using:
driver.manage().timeouts().implicitlyWait(180, TimeUnit.SECONDS);
But it still fails continuously for the below element
driver.findElement(By.id("name")).clear();
driver.findElement(By.id("name")).sendKeys("Create_title_01");
I have added wait code:
for (int second = 0;; second++) {
if (second >= 120) fail("timeout");
try { if (isElementPresent(By.id("name"))) break; } catch (Exception e) {}
Thread.sleep(1000);
}
Shouldn't implicit wait take care of waiting till an element is found?
Also would it be better if I use Explicit wait instead of the code I have added that has Thread.sleep()
?
Solution 1:
TL;DR: Always use explicit wait. Forget that implicit wait exists.
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.
Code examples with explanation. First implicit wait:
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = driver.findElement(By.id("myDynamicElement"));
Now explicit wait:
WebDriver driver = new FirefoxDriver();
driver.get("http://somedomain/url_that_delays_loading");
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement myDynamicElement = wait.until(
ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement")));
Both code examples do the same thing. Find a certain element and give up if not found after 10 seconds. The implicit wait can do only this. It can only try to find an element with a timeout. The strength of explicit wait is that it can wait for all kinds of conditions. Also customize timeout and ignore certain exceptions.
Example of possible conditions: elementToBeClickable
, numberOfElementsToBeMoreThan
or invisibilityOf
. Here is a list of the built in expected conditions: https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html
More explanations:
The implicit wait timeout has effect only on findElement*
methods. If set then all findElement*
will "wait" for the set time before declaring that the element cannot be found.
How a findElement*
will wait is not defined. It depends on browser or operating system or version of selenium. 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.
This list is gathered from observations and reading bug reports and cursory reading of selenium source code.
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 verbose code. But that verbosity makes the code explicit. And explicit is better that implicit. Right?
Further reading:
- Official documentation (does not really explain the problematic other than warning from mixing implicit and explicit wait).
- Answer on a related question from Jim Evans. Jim Evans is a maintainer of selenium. Summary: don't mix implicit and explicit wait.
- Two blog posts explaining implicit and explicit wait in great detail:
- http://vnrtech.blogspot.de/2013/04/selenium-implicit-wait.html
- http://vnrtech.blogspot.de/2013/04/selenium-explicit-wait.html
- Selected bugs about implicit and explicit wait in selenium:
- http://code.google.com/p/selenium/issues/detail?id=2934
- http://code.google.com/p/selenium/issues/detail?id=4471
- http://code.google.com/p/selenium/issues/detail?id=7972
- Code
- explicit wait
- implicit wait
- What Happens When We Mix Implicit Wait And Explicit Wait
- How to create custom expected conditions in Selenium
Solution 2:
Implicit wait - It's global setting applicable for all elements and if element appear before specified time than script will start executing otherwise script will throw NoSuchElementException
. Best way to use in setup method. Only affect By.findelement()
.
Thread.sleep()
- It will sleep time for script, not good way to use in script as it's sleep without condition. What if 2 seconds are not enough in 5% of the cases?
Explicit wait: Wait for specify contains/attribute change. More used when application gives AJAX call to system and gets dynamic data and render on UI. In this case WebDriverWait
is suitable.
Solution 3:
Have you tried fluentWait? An implementation of the Wait interface that may have its timeout and polling interval configured on the fly. Each FluentWait instance defines the maximum amount of time to wait for a condition, as well as the frequency with which to check the condition. Furthermore, the user may configure the wait to ignore specific types of exceptions whilst waiting, such as NoSuchElementExceptions when searching for an element on the page.
see this link fluent wait description
In particular I used fluent wait in this way:
public WebElement fluentWait(final By locator) {
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(
new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
}
);
return foo;
};
As you've noticed fluent wait returns found web element. So you simply pass the locator with By type and then you can perform any actions on the found web element.
fluentWait(By.id("name")).clear();
Hope this helps you)
Solution 4:
Have you tried using 'WebDriverWait' ? I imagine what you want is this:
WebDriverWait _wait = new WebDriverWait(driver, new TimeSpan(0, 0, 2)); //waits 2 secs max
_wait.Until(d => d.FindElement(By.Id("name")));
//do your business on the element here :)
This pretty much will, to my understanding, do what your current code is. It will constantly try the method (while ignoring not found exceptions) until the timeout of the passed in timespan is reached and a third parameter can be entered to specify the sleep in milliseconds. Sorry if this is what implicitlyWait does too!
Edit: I did some reading today and understand your question better and realise that this does exactly what your setting of implicit wait should do. Will leave it here just in case the code itself can help someone else.