Waits and Synchronization

Context:

Whenever we hit a URL in a browser, the request is submitted to the server and it returns back with resources (response object, headers, javascript etc.). Ultimately it is the browser engine that parses the response from server and displays the elements like text fields, buttons, links and so on. In other works as defined by W3C, the DOM (document object model) dictates how the content gets displayed on browser. Every time a user performs an operation on the browser, one of the following (not limited to) happens:

1) The request goes all the way to server and entire DOM is refreshed when response comes back

2) The request hits the server and only partial DOM gets refreshed (ajax requests or asynchronous javascript calls)

3) The request is processed on the client side itself by javascript functions

So if we think about the overall workflow, there needs a certain synchronization that happens between the client(aka. browser) and the server (the url)

How is it related to Test Automation?

If we peruse a little deeper, the operations we do on browser has to be aligned with how the server or the web app responds. For example, if I hit a website and it takes 5 seconds for the website to respond, I would have to wait for at least 5 seconds in my script before doing further operations. So every operation is governed by a timeout after which I report a failure in my script and ultimately a defect is a possibility. So while writing my test Automation scripts, I have to have mechanisms to do “Waits” and define “timeouts”, not only at the page level, but also at the element level and sometimes. 

But What am I really waiting for ?

The following will help explain each of the wait scenarios. In the java side of Selenium, you will find an additional wait called FluentWait in addition to the ImplicitWait and ExplicitWait mechanisms we discuss here. So its really ImplicitWait vs ExplicitWait vs FluentWait is what some folks might be looking for. 

With FluentWait , one can specify how frequently selenium should poll for the element. In general, by default selenium polls every 500 ms, but with FluentWait, we can control that. I haven’t found a great need for FluentWait i.e. needing to poll lesser than 500ms so far, so selenium/watir on ruby side OR behave/python NOT having that as an api is totally fine. On the other hand, if we have to implement such a Waiter, we can implement if need be.

Page Load

Page load timeout as the name suggests is setting the max. time until which we will wait for the page to load. We have pageload timeouts in Java and Ruby, but really they seem to be redundant. Think about it. What is page load ? Well for most it means document.readyState=”complete”. With Ajax applications, page load doesn’t need to be true to interact with page. So do we really want to wait for it? The answer is NO. More so, if you really are working with legacy applications and have to do page load, you can simply go for browser.execute_script(“return document.readyState”) and compare it with “complete”. Finally, browser.get(“url”) already looks for that, so having an extra verification for document.readyState in my opinion is NOT a great value add.

Anyways, if you really have to set the page load timeout, you can use the below code

Script Timeout

The script timeout is generally used with ajax waiting commands. For example as seen below, we are setting a max. timeout of 5 seconds for execute_script() method. That means, the webdriver will wait for a max. of 5 seconds for the script to execute and return. If the script execution takes more than 5 seconds, a TimeOut Error is thrown and the execution halts.

Implicit Wait

An implicit wait is to tell WebDriver 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 WebDriver object instance.

Explicit Wait 

Explicit waits are the best practice waits to be used in automation scripts especially since modern web apps have different timeouts on different parts of web page. Explicit timeouts are also a great set of functionality to help us get granular and wait for different elements for different waiting times.

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.

Expected Conditions

There are some common conditions that are frequent 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.

  • title_is
  • title_contains
  • presence_of_element_located
  • visibility_of_element_located
  • visibility_of
  • presence_of_all_elements_located
  • text_to_be_present_in_element
  • text_to_be_present_in_element_value
  • frame_to_be_available_and_switch_to_it
  • invisibility_of_element_located
  • element_to_be_clickable – it is Displayed and Enabled.
  • staleness_of
  • element_to_be_selected
  • element_located_to_be_selected
  • element_selection_state_to_be
  • element_located_selection_state_to_be
  • alert_is_present

Explicit Wait (presence of element using ID)

We create a WebdriverWait and pass driver and timeout as arguments. Then we wait until the element is located. The exceptions that might be thrown are StaleElementReferenceException (if element gets detached from dom) or TimeoutException if element is not found within the timeout

Explicit Wait (wait for text to be present in element)

We create a WebdriverWait and pass driver and timeout as arguments. Then we wait until the expected text is found in the element’s html. The exceptions that might be thrown are StaleElementReferenceException (if element gets detached from dom) or TimeoutException if element is not found within the timeout

Explicit Wait (wait for value html attribute)

We create a WebdriverWait and pass driver and timeout as arguments. Then we wait until the expected text is found in the element’s value attribute. The exceptions that might be thrown are StaleElementReferenceException (if element gets detached from dom) or TimeoutException if element is not found within the timeout

Explicit Wait (wait for alert presence)

We create a WebdriverWait and pass driver and timeout as arguments. Then we wait until the alert is present. The exceptions that might be thrown are TimeoutException if alert is not found within the timeout

Explicit Wait (check for staleness)

We create a WebdriverWait and pass driver and timeout as arguments. Then we wait unti the element gets stale. Exception that might be thrown is TimeoutException. We use this mechanism to handle StaleElementReferenceException and if we want to still continue searching for element and not let the program die.

Race Conditions using python lambda

If we have situations where ExpectedConditions are not sufficient and we want to wait on a custom event, then we can use python lambda. This is very much similar to Java Functions and Ruby closures. Note: The code below is a little flaky and will be modified in time to get it to a mature state.

 

Entire Cucumber Scenario

Step Definitions