Selenium: Implicit vs Explicit Waits

implicit_vs_explicit

These days most of the web apps are using AJAX techniques. When a page is loaded to browser, the elements within that page may load at different time intervals. This makes locating elements difficult, if the element is not present in the DOM, it will raise ElementNotVisibleException exception. Using waits, we can solve this issue. Waiting provides some time interval between actions performed - mostly locating element or any other operation with the element.

Selenium Web driver provides two types of waits

  • Implicit waits
  • Explicit waits

Implicit Waits

Selenium Web Driver has borrowed the idea of implicit waits from Watir. An implicit wait is to tell Web Driver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available.The default setting is 0. Once set, the implicit wait is set for the life of the Web Driver object instance until it changed again. This means that we can tell Selenium that we would like it to wait for a certain amount of time before throwing an exception that if it cannot find the element on the page. 

(Web Driver object instance).implicitly_wait(seconds) ###Syntax
>>> from selenium import web driver
>>> driver = webdriver.Firefox()
>>> driver.implicitly_wait(30)
>>> driver.get("https://www.google.co.in/")
>>> driver.find_element_by_id(“lst-ib”)

In the above example the implicit waits value is given as 30sec i.e, if web driver able to find the element with in the given span 30sec it immediately returns true else it raises an exception after 30 seconds.

Here we go some more detail in to how the implicit waits behaves

  • when default implicit wait is not defined for finding non existing element
  • when default implicit wait is defined for finding non existing element
  • when implicit wait is altered for finding non existing element
  • when implicit wait is altered for finding existing element
>>> from selenium import web driver 
>>> import time 
>>> driver = webdriver.Chrome('/home/siva/chromedriver') 
>>> driver.get("https://www.google.co.in/") 
>>> def calculate_implicit_wait_time(driver,wait_value,element): 
        if wait_value: 
            driver.implicitly_wait(wait_value) 
        now=time.time() 
        try: 
            myelement = driver.find_element_by_id(element) 
        except: 
            pass 
        print str(int(time.time()-now))+'--Seconds'

1.When default implicit wait is not defined for finding non existing element:

>>> calculate_implicit_wait_time(driver,False,'element')
#0--Seconds

The function calculate_implicit_wait_time(driver,False,'element') returns '0--Seconds' As the default implicit wait value is 0

2.When default implicit wait is defined for finding non existing element

>>> calculate_implicit_wait_time(driver,30,'element')
#30--Seconds

The function calculate_implicit_wait_time(driver,30,'element') returns '30--Seconds' As I am setting the default implicit wait value as 30

3.When implicit wait is altered for finding non existing element

>>> calculate_implicit_wait_time(driver,50,'element')
#50--Seconds

Here one thing we have to observe is we can alter implicit wait value in any number of times until the web driver instance is available and the function calculate_implicit_wait_time(driver,50,'element') prints '50--Seconds' As I am altering implicit wait value as 50

4.When implicit wait is altered for finding existing element

>>> calculate_implicit_wait_time(driver,500,'lst-ib')
#0--Seconds

What ever the implicit wait value may be when the driver able to find an element given, it immediately returns true. And the function calculate_implicit_wait_time(driver,500,'element') prints '0--Seconds'

Explicit Waits

An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code. The worst case of this is time.sleep(), which sets the condition to an exact time period to wait. There are some convenience methods provided that help you write code that will wait only as long as required. WebDriverWait in combination with ExpectedCondition is one way this can be accomplished.

WebDriverWait(driver, 10).until(conditon) ###Syntax
>>> from selenium import webdriver
>>> from selenium.webdriver.common.by import By
>>> from selenium.webdriver.support.ui import WebDriverWait
>>> from selenium.webdriver.support import expected_conditions as EC
>>> driver = webdriver.Firefox()
>>> driver.get("https://www.google.co.in/")
>>> try:
>>>    WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID,"element")))
>>> except:
>>>    pass

This waits up to 10 seconds before throwing a TimeoutException or if it finds the element will return it in 0 - 10 seconds. WebDriverWait by default calls the ExpectedCondition every 500 milliseconds until it returns successfully. A successful return is for ExpectedCondition type is Boolean return true or not null return value for all other ExpectedCondition types.
There are some common conditions that are frequently come across when automating web browsers. Listed below are Implementations of each. Selenium Python binding provides some convienence methods so you don’t have to code an expected_condition class yourself or create your own utility package for them.

  • alert_is_present 
  • element_located_selection_state_to_be 
  • element_located_to_be_selected 
  • element_selection_state_to_be 
  • element_to_be_clickable 
  • element_to_be_selected 
  • frame_to_be_available_and_switch_to_it 
  • invisibility_of_element_located 
  • presence_of_all_elements_located 
  • presence_of_element_located 
  • staleness_of 
  • text_to_be_present_in_element 
  • text_to_be_present_in_element_value 
  • title_contains 
  • title_is 
  • visibility_of 
  • visibility_of_element_located

As per the requirement we know were to use implicit wait and explicit wait and here comes an intersting thing about waits is why should we avoid usage of both implict waits and explict waits at a time on same web driver instance.

Why to avoid both implict wait and explict wait on same web driver instance ?

when we use both implicit wait and explicit wait.. suppose let us take implicit wait value as x and explicit wait value as y

when x >= y

Here you can expect the behavior I.e the maximum waiting time for finding an element will be x as the driver initially waits for implicit wait to find an element

below here I am giving some source code and out put of that code with Implicit wait time, Explicit wait time and Max time taken by driver to find non existing element presence

>>> from selenium import web driver
>>> from selenium.webdriver.common.by import By
>>> from selenium.webdriver.support.ui import WebDriverWait
>>> from selenium.webdriver.support import expected_conditions as EC
>>> driver = webdriver.Firefox()
>>> driver.get("https://www.google.co.in/")
>>> print 'Explicit Wait\tImplict Wait\tTime taken to find element presence' 
>>> print '___________________________________________________________________' 
>>> for i in range(10): 
>>>     i=i+30 
>>>     driver.implicitly_wait(i) 
>>>     now1 = time.time() 
>>>     try: 
>>>         element = WebDriverWait(driver, 20).until( EC.presence_of_element_located((By.ID, "myDynamicElement"))) 
>>>     except: 
>>>         pass 
>>>     print str(i)+'\t\t20'+'\t\t'+str(int(time.time()-now1))

From the above output we can consider that when explicit wait value is greater than or equal to implicit wait then the Max time taken by driver to find non existing element presence is equal to Explicit wait value I.e, in this case Explicit wait value is directly proportional to Max time taken by driver to find non existing element presence

When x<y

Here we will experience 'hang' for more time than what we are expecting. Part of the problem is that implicit waits are often (but may not always be!) implemented on the "remote" side of the Web Driver system. That means they're "baked in" to IEDriverServer.exe, chromedriver.exe, the Web Driver Firefox extension that gets installed into the anonymous Firefox profile, and the Java remote Web Driver 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 we try to mix implicit and explicit waits, we've strayed into "undefined behavior". we 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.

Source: http://bit.ly/1bh78lA

>>> from selenium import web driver
>>> from selenium.webdriver.common.by import By
>>> from selenium.webdriver.support.ui import WebDriverWait
>>> from selenium.webdriver.support import expected_conditions as EC
>>> driver = webdriver.Firefox()
>>> driver.get("https://www.google.co.in/")
>>> print 'Explicit Wait\tImplict Wait\tTime taken to find element presence' 
>>> print '___________________________________________________________________' 
>>> for i in range(10): 
>>>     i=i+10 
>>>     driver.implicitly_wait(i) 
>>>     now1 = time.time() 
>>>     try: 
>>>         element = WebDriverWait(driver, 20).until( EC.presence_of_element_located((By.ID, "myDynamicElement"))) 
>>>     except: 
>>>         pass
>>>     print str(i)+'\t\t20'+'\t\t'+str(int(time.time()-now1))

From the above output we can consider that when explicit wait value is less than implicit wait value ,Then the max time taken to find an non existing element value will vary between Implicit wait value and sum of (implicit wait value ,explicit wait value) and they'll be subject to change as the implementation details of the drivers change.