Introduction

Efficient synchronization mechanisms are essential not only for technical accuracy but also for the foundation of successful automation testing strategies. In this blog, we'll explore the importance of implementing waits and how they play a crucial role in automation projects.

Waiting strategy involves adding pauses or delays in your test script to make sure actions are carried out only when the application reaches a specific state or finishes essential tasks. In the world of test automation, the attentive implementation of this approach is the key to ensure the reliability and robustness of test suites.

The Importance of Waiting Strategies

Elements on a page often take different amounts of time to load and become visible or interactive. This unpredictability can cause problems, as the script tries to interact with an element before it is ready, leading to exceptions like Selenium’s inability to locate the element. Since applications can differ in response times or rendering speeds across browsers, devices, or environments, tests may become inconsistent and yield unreliable results. This inconsistency not only undermines the credibility of test suites but also increases the likelihood of overlooking genuine bugs and defects within the application. Thus, a real-world user interaction scenario cannot be simulated, highlighting the need for effective waiting strategies in test automation.

In Selenium, we have 3 different waiting strategies, i.e. implicit, explicit and fluent waits. Let's discuss briefly about when and how to use them.

Implicit Waits

An implicit wait is the synchronization mechanism used to instruct Selenium WebDriver to wait for defined amount of time before throwing "No Such Element Exception". This wait time is applied globally and makes the WebDriver poll the DOM (Document Object Model) for a specified duration when trying to locate an element. If the element is not immediately available, the WebDriver keeps checking until the timeout expires.

Implicit wait operates on the principle of "Set once, apply everywhere." By default, the implicit wait time is set to zero unless a specific duration is defined as:

from selenium import webdriver

# Create a WebDriver instance
driver = webdriver.Firefox()

# Set the implicit wait time to 10 seconds
driver.implicitly_wait(10)

# Navigate to a webpage
driver.get("http://testproject.com")

#Locate and interact with element
driver.find_element(By.XPATH, "//input[@id='login-username']").click()

Sample snippet- Implicit wait

Setting implicit wait won't increase the test duration, as it returns to execute the code block as soon as the desired element is located.

Explicit Waits

An explicit wait in Selenium is a more precise and flexible synchronization mechanism compared to an implicit wait. It allows you to wait for a specific condition to be met before proceeding with the next step in your script.

Selenium WebDriverWait method can be used with Expected Condition class which requires to be imported from selenium.webdriver.support.ui. We can instantiate WebDriverWait with the driver and timeout period as follows:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)

Instance of Selenium wait

Selenium provides some common methods as expected conditions, such as: alert_is_present, element_to_be_clickable, element_to_be_selected, invisibility_of_element, presence_of_element_located, text_to_be_present_in_element, title_is, url_to_be, visibility_of, etc.

We can also customize our own utility package for expected condition if the default methods don't fit our requirements.
Here is the snippet of implementation of the explicit wait in Selenium:

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

# Initialize WebDriver
driver = webdriver.Chrome()

# Open a webpage
driver.get("https://www.testproject.com")

# Create a WebDriverWait object with a 10-second timeout
wait = WebDriverWait(driver, 10)

# Wait until the element is clickable
element = wait.until(EC.element_to_be_clickable((By.ID, 'login-btn')))

# Perform click action
element.click()

# Close the driver
driver.quit()

Sample snippet- Explicit wait


Also Read: Getting started with Alt Tester : Automating Game Test


Fluent Waits

This waiting strategy is all about defining the maximum amount of time, to wait for a condition, as well as the frequency with which to check that condition. Fluent waits can be utilized to set timeout and polling interval, providing flexibility to wait for condition with custom intervals. Fluent waits handle intermittent issues by retrying actions at regular intervals resulting in reduced flakiness of tests.

Selenium-Python does not provide a packaged FluentWait class, as Java does, instead we can implement WebDriverWait class with optional arguments i.e., timeout, poll_frequency and ignored_exceptions as follows:

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
from selenium.common.exceptions import NoSuchElementException

# Initialize WebDriver
driver = webdriver.Chrome() 

# Create a Fluent Wait instance
wait = WebDriverWait(driver, timeout=10, poll_frequency=1, ignored_exceptions=[NoSuchElementException])

# Use Fluent Wait to find an element
element = wait.until(
    EC.presence_of_element_located((By.ID, "login-btn"))
)

# Perform actions on the element
element.click()

Sample Snippet - Fluent Wait

Besides these waiting techniques, using sleep method (time.sleep()) pauses the execution of the script for a specified number of seconds and ignores everything happening in the browser during that time. It introduces a fixed delay, regardless of whether the desired condition has been met. So, even though, it is a quick fix, it's inefficient and hampers the robustness of test execution.

Conclusion

Finally, in order to manage dynamic web applications, Selenium waiting techniques play a critical role in ensuring that scripts interact with items only when they are accessible. By synchronizing the test flow with the application's state, the efficient use of implicit, explicit, and fluent waits improves test reliability and lowers flakiness. In the fast-paced world of test automation, these methods are vital for creating dependable and maintainable test suites, ultimately boosting the efficiency and effectiveness of quality assurance processes.

Thank you for reading this article. See you in the next one.