How to Wait in Python: Python Wait Tutorial With Examples
Ini Arthur
Posted On: June 7, 2024
142420 Views
24 Min Read
Waiting for WebElements to load is a fundamental aspect of creating robust automated tests in Python. When testing software applications, it’s essential to ensure the test scripts wait for necessary elements to load before interacting with them.
This mimics real user behavior and prevents common issues like attempting to click a button that hasn’t appeared yet or filling out a form that’s not fully loaded. Therefore, understanding how to implement a Python wait is important.
However, without these strategic Python waits, tests can fail unpredictably, making it difficult to identify issues in the application under test.
In this Python wait tutorial, we look at how to wait in Python using different techniques.
TABLE OF CONTENTS
What Are Python Waits?
Waits in Python comprise the different methods and functions used to halt an ongoing thread for some time. The wait() function is not built-in as implemented in another programming language. However, it is found in the time module and threading library.
Python wait can be achieved for a specified number of seconds by using the sleep() function of the time module. The Event class in the threading library has a wait() method that pauses the execution of a thread until an event object’s flag is set and the paused thread continues test execution.
While Python has handy wait methods, we’ll be exploring waits in terms of test automation. Automation testing tools like Selenium provide methods for pausing the test execution of a thread until a condition is met.
For the rest of this tutorial, we will demonstrate how to use waits with Selenium Python.
Subscribe to the LambdaTest YouTube Channel for quick updates on these tutorials.
Why Use Python Waits?
The sole aim of applying wait mechanisms in Python tests is to ensure less test flakiness and that tests are stable across different network conditions.
We’ll highlight some valid reasons why waits are used in test scripts:
- Varying throttling network conditions: Users may access the software application using varying frequency bands (e.g., 5G, 4G, and 3G). These users will experience different load speeds due to the dynamic switching of networks.
- Dynamic nature of modern web applications: Web development has evolved a lot over the years from static content to more dynamic content. This means content and page elements can be updated based on user actions, such as searching through the website or clicking an element.
- Better simulation of user behavior with page elements: It is common for a user to wait for the web page to load until page elements like buttons, hyperlinks, and images are visible and interactable. However, with test scripts, we’ll have to automate waiting strategically to mirror what a user’s behavior would have been since it is not manual.
- Reduce flaky tests: Some tests require interaction with dynamic content on web pages; due to the asynchronous loading of elements, the tests may interact with elements before fully loading. If elements are unavailable before the tests attempt to interact with them, the test will throw exceptions like NoSuchElementException or ElementNotVisibleException.
This means the software application load time of assets would vary; hence, there is a need to factor in these variations while testing. Waits ensure tests are more reliable under different network conditions, and Document Object Model (DOM) elements are always available before interaction.
For instance, Selenium WebDriver can initiate waiting for updated content and elements before performing operations like extracting data from a web page, such as web scraping.
From the above screenshot, the images on the website are lazy loading and only become visible when they are in a user’s viewport.
When Python waits are used while working with dynamic content and elements, they minimize the chances of having flaky tests.
Types of Waits in Selenium Python
Selenium provides a few methods for handling waits when executing a test case. Using these methods, you can use Selenium wait for page to load to automate waits before any interaction with elements based on the use case in mind.
The type of waits in Selenium are listed below:
- Time Sleep
- Implicit Wait
- Explicit Wait
- Fluent Wait
We’ll look at these waits, what each entails, and how to use them.
Time Sleep
The Python time module has a sleep() function that can achieve waiting in Selenium. The time.sleep() function takes an argument, which signifies the number of seconds that the execution of a test script should wait before it proceeds. When called, it blocks the execution of the main thread until the wait time elapses.
It is the simplest Python wait method to use. However, its function is limited because it is not customizable. It is not the most preferred because it is a blocking call and increases the test execution time.
Syntax:
1 |
time.sleep(secs) |
Argument:
secs: number of seconds
Implicit Wait
Selenium offers another means of achieving waiting in a test script via the use of the implicit_wait() method of the Selenium WebDriverWait module. The implicit wait will search through the DOM for a given amount of time for an element or elements before any automated interaction.
It takes a single argument, which indicates the number of seconds the WebDriver should wait. The default argument is 0 seconds (i.e., no waiting), and an exception is thrown if an element is not found after waiting for the specified time.
Syntax:
1 |
driver.implicitly_wait(secs) |
Argument:
secs: number of seconds
The WebDriver would return a reference to the element as soon as it is located without exhausting the set wait time. For example, when finding a button element before performing a click operation, we can set the implicit wait time to 5 seconds, and the test script will wait for 5 seconds for the button element to become available.
A click action might be taken on the button when found. It is often used because of its simple syntax and non-blocking nature.
Explicit Wait
We can apply explicit waits to test automation scripts using the class WebDriverWait and the until() method of the wait module. Explicit wait provides more control as we can define conditions to wait for, like URL matches or visibility of elements located before any interaction.
The WebDriverWait class is initialized with a driver and timeout in seconds, and the until() method is given an expected condition.
The ExpectedConditions in Selenium has several functions that define an expected condition to be met. The ExpectedConditions is an argument of the until() method and takes the form EC.visibility_of_element_located(). In turn, the visibility_of_element_located() method takes an argument like (By.NAME, “email”).
Selenium provides some ExpectedConditions that you can use in your test scripts. They are listed below:
ExpectedConditions | Description |
---|---|
title_is | Checks for the title of a page, which must be an exact match. It returns True if there is a match and False otherwise. |
title_contains | Checks that the title contains a case-sensitive substring. It returns True if there is a match; otherwise, it returns False. |
presence_of_element_located | Checks that an element is present on the DOM of a page. This does not necessarily mean that the element is visible. |
visibility_of_element_located | Checks that an element is present on the DOM of a page and visible. |
visibility_of | Checks that an element present on the DOM of a page is visible. Visibility means that the element is displayed and has both width and height. |
presence_of_all_elements_located | Checks that there is at least one element present on a web page. |
text_to_be_present_in_element | Checks if the given text is present in the specified element. |
text_to_be_present_in_element_value | Checks if the given text is present in the element’s value. |
frame_to_be_available_and_switch_to_it | Checks whether the given frame is available to switch to. |
invisibility_of_element_located | Checks whether an element is either invisible or not present on the DOM. |
element_to_be_clickable | Checks if an element is visible and enabled such that you can click it. |
staleness_of | Checks and waits until an element is no longer attached to the DOM. |
element_to_be_selected | Checks if the selection is selected. |
element_located_to_be_selected | Checks if the element to be located is selected. |
element_selection_state_to_be | Checks if the given element is selected. |
element_located_selection_state_to_be | Checks to locate an element to see if the selection state specified is in that state. |
alert_is_present | Checks if an alert is currently present and switch to it. |
Syntax:
1 |
WebDriverWait(driver, timeout).until(method) |
Arguments:
- driver: WebDriver
- timeout: number of seconds
- method: callable (WebDriver)
This means of waiting allows us to await the appearance of elements in a more customizable and flexible manner. An exception is thrown when an element is not found or an expected condition is not fulfilled after the set timeout. Assuming an element is visible before a set timeout of 5 seconds, the rest of the test will continue.
Fluent Wait
When you need to be more specific about the Python wait condition in Selenium, fluent waits are the way to go. Unlike explicit waits, fluent waits allow you to customize the wait time for a particular condition to be met (e.g., the visibility of an element) before proceeding to the next operation. This method is flexible because you can define custom Python wait conditions that must be satisfied and not achievable with other wait methods.
Fluent waits differ from explicit waits because we provide an argument for poll_frequency. The value of the poll_frequency defines how often the webdriver would evaluate the wait condition before the timeout.
The default polling frequency is 500 milliseconds. The WebDriverWait class and the chained until() method define how fluent waits can be implemented in an automation script.
Syntax:
1 |
WebDriverWait(driver, timeout, poll_frequency).until(method) |
Arguments:
- driver: WebDriver
- timeout: number of seconds
- poll_frequency: number of seconds
- method: callable (WebDriver)
When using fluent waits, you can specify if you want to ignore certain anticipated exceptions by providing a value for the ignored_exceptions keyword argument.
However, there are scenarios where repetitive waits can increase test execution time, reduce test efficiency, and lead to flaky tests.
Cloud-based testing platforms like LambdaTest offer SmartWait functionality for automation testing with Selenium, eliminating the need for repetitive explicit waits and ExpectedConditions in your test scripts.
This feature ensures that actions are performed only on WebElements that are fully ready for interaction, streamlining the testing process.
SmartWait automatically handles the timing of these interactions, so you don’t have to manually insert waits or repeatedly check conditions. If an element is not ready, the SmartWait feature will throw relevant Selenium exceptions. This helps quickly identify and resolve issues related to test automation, making your tests more efficient and reliable.
Syntax:
1 2 3 4 5 |
LT: Options { ... "smartWait": 10 // It accepts integer values as second ... } |
Check out the tutorial below that demonstrates how to use the SmartWait feature:
There are a few methods available in Selenium that can be used to apply Python waits to automation scripts. These vary from a more general time.sleep() method to the customizable fluent wait.
The time.sleep() method is a blocking wait call, so it is rarely used. The implicit wait is another means to achieve waiting without specific conditions. Explicit and fluent waits offer more flexibility as you can indicate conditions to be met before interactions begin on the web page. The difference is that fluent wait takes an argument for poll_frequency.
SmartWait feature provides a cleaner syntax, efficiency and accuracy as it performs checks before any operation.
Demonstration: How to Use Python Waits With Selenium?
To test the above Python wait methods, we’ll use the pytest framework and run automated tests using Selenium Python on the cloud grid offered by LambdaTest. This will help achieve much-needed scalability and reliability.
It is an AI-powered test orchestration and execution platform that allows devs and testers to perform Python automation at scale on a remote test lab of 3000+ real environments. LambdaTest also has LambdaTest eCommerce Playground, which we will use to demonstrate how to use Python waits with Selenium.
Prerequisites
To use LambdaTest for demonstrating Python waits, follow the below steps:
- Get the LambdaTest Username and Access Key. Go to Account Settings, then click on Password & Security.
- Create a file for your pytest fixture. (.e.g. conftest.py)
- Import the required modules and dependencies.
- Create a function fixture driver using the @pytest.fixture(scope=”function”) decorator.
- Get the variables needed to set up your capabilities.
- test_name: Represents the name of the test.
- build: Represents the name for the test build.
- username: Retrieves the username exported to the local environment.
- access_key: Retrieves the access key exported to the local environment.
- selenium_endpoint: Represents the URL link to connect to LambdaTest.
- After setting up the capabilities, perform the following actions:
- Instantiate the webdriver ChromeOptions class and save it in a variable chrome_options.
- Add the option capabilities dictionary with appropriate key-value pairs.
- Use the chrome_option.set_capability() method to set the capabilities created previously.
- Create a browser instance with webdriver.Remote() class.
- Use the yield statement to create a browser instance.
The code was structured using the Page Object Model (POM).
Page Object Model in Selenium Python is a design pattern used to structure code to reduce code duplication while enhancing modularity and maintainability. POM allows for creating classes out of web pages with instance attributes and methods.
From the code snippet above, we imported all necessary modules for our project, including webdriver. These would be used to create a pytest fixture for use in our project.
Based on your testing requirements, you can also generate capabilities from the LambdaTest Automation Capabilities Generator.
Creating Page Objects to Test Python Wait Methods
Since we use POM, we’ll handle each web page as a class. This class would have element objects, attributes, and methods that can be used on the web page and bundled together. We’ll highlight a few code snippets where necessary.
- Import By from the by module to create the SleepWait class.
- Initialize the WebDriver object and navigate to the LambdaTest eCommerce Playground homepage.
- Create a private instance variable self._elements of the SleepWait class to hold page locator elements objects.:
- The driver.find_elements() function is to locate and retrieve elements in the driver context. It takes two arguments, a locator strategy (e.g. By.CLASS_NAME) and its value (e.g. “info”).
- Find the number of elements returned and save in private a variable self._elements_count.
- Define instance method get_elements_count() that returns self._elements_count.
- Create a private instance variable self._my_account to store the link text element object. The find_element() method will return the first matching element returned by the page element locator.
- Create instance methods click_my_account() and is_email_displayed().
- click_my_account() clicks the self._my_account element earlier retrieved and navigates the account login page.
- is_email_displayed() method returns True or False whether the email input is displayed or not.
- is_displayed() checks if the connected element is displayed and returns a boolean value.
- Create an instance method get_submit_button(). This method will return the submit button element found using the driver.find_element() method and By.XPATH locator strategy.
- The ExplicitWait class has an instance method get_password_input(), which returns the password input element.
- From the above code snippet,
- The click_blog_link() method will click on the blog link element to initiate navigation to the blog section.
- The click_first_post() method will click on the first post in the blog section. We use the find_element() method to pick out the first block post. However, the locator strategy used is By.TAG_NAME with value “h4”.
In the next section, we will now look at the demonstration of various techniques for Python waits.
Using Time Sleep in Python
In this section, we will implement Python waits using the time.sleep() function.
Test Scenario:
|
Implementation:
Code Walkthrough:
Step 1: Import all the modules needed to create the test case.
Step 2: Create the test_sleep_wait() method decorated with @pytest.mark.usefixtures(“driver”). This decorator invokes the fixture “driver” to be used by pytest before executing the test function.
Step 3: Use the time.sleep() method to wait 5 seconds for the page to load completely.
Step 4: Get the number of elements using the elements_count.get_elements_count() method and save it to the variable count. Raise an assert statement to validate the expected number of elements equals the value of the count variable.
Test Execution:
Execute the test using the following command:
1 |
pytest tests/test_sleep_wait.py |
The LambdaTest Web Automation Dashboard shows the status of our test execution.
The 5 seconds of sleep time used in our script means that even when elements on the page are available, the driver will still wait for the time to be exhausted. This can only prolong the wait time than it’s necessary.
Using Implicit Wait in Python
In the previous test, the page load would have been completed before 5 seconds. We can use implicit wait because it does not block the main thread during the specified wait time.
Test Scenario:
|
Implementation:
Code Walkthrough:
Step 1: Use the driver.implicit_wait() method to wait for elements for a given amount of time, usually in seconds. If the page loads before the timeout, the test proceeds to operation in the test script. In case the page fails to load within the timeout, an exception is thrown.
Step 2: Check if the email input field is visible using the is_email_displayed() method.
Assert that the email input field is visible.
Test Execution:
Execute the test using the following command:
1 |
pytest tests/test_implicit_wait.py |
The LambdaTest Web Automation Dashboard shows the status of our test execution.
Using Explicit Wait in Python
In this section, we will implement Python waits using explicit waits.
Test Scenario 1:
|
Test Scenario 2:
|
Implementation:
Code Walkthrough:
Step 1: Use the WebDriverWait class in combination with the until() method to implement explicit wait. The WebDriverWait is initialized with a driver and timeout of 10 seconds. The 10-second timeout represents the time of waiting for an element to become available.
EC allows us to specify the wait condition to be met by the targeted element. In this case, we used the element_to_be_clickable() method, which checks an element is visible, enabled and clickable. By.XPATH is the locator strategy and its accompanying value “//input[@type=’submit’]”.
Step 2: Get the button element by using the explicit_wait.get_submit_button() and save it to the variable button. Retrieve the value attribute of the button element. Assert the value attribute of the button element is Login.
Test Execution:
Execute the test using the following command:
1 |
pytest tests/test_explicit_wait.py |
The LambdaTest Web Automation Dashboard shows the status of our test executions.
Output for Email Input Field:
Output for Login Button:
We can see that from our explicit wait test, we could specify a custom wait condition we want to fulfill. The waiting does not continue until the timeout, even when an element has become available and interactable in the DOM. It can shorten test execution time.
Using Fluent Wait in Python
In this section, we will implement Python waits using fluent waits.
Test Scenario:
|
Implementation:
Code Walkthrough:
Step 1: Use the WebDriverWait class and the until() method to initiate a wait condition. Pass in arguments for driver, timeout, poll_frequency, and the expected condition. The poll_frequency means the WebDriver would continue checking if the expected condition is attained before the timeout elapses.
As seen in the code snippet, the polling frequency is 2 seconds. This means that the driver would check the readiness of a target element at a 2-second interval. The polling begins again if the previous attempt fails. The wait ends once the target element is available, allowing other testing activities.
Python has a polling2 module that is used to wait for a return value from a function after a specific condition is met. It is very often used with Selenium to poll WebDriver elements.
Step 2: Use the assert statement to confirm the expected value of the password element matches the value gotten.
Test Execution:
Execute the test using the following command:
1 |
pytest tests/test_fluent_wait.py |
The LambdaTest Web Automation Dashboard shows the status of our test execution.
Using SmartWait in Python
It is the least complex means of applying Python waits in test scripts through LambdaTest smartWait capability. By default, it uses an intelligent algorithm to pause the execution of an operation until all checks are completed successfully.
Test Scenario:
|
Implementation:
Code Walkthrough:
Step 1: Create a capabilities option dictionary or use the Automation Capabilities Generator.
Step 2: Add a new key-value pair “smartWait”: 10 to the capabilities option dictionary.
Step 3: Replace the previous options argument of the set_capability() method (i.e., in the conftest.py file) with the one with the smartWait key-value pair.
Step 4: Call the smartwait.click_blog_link() method to click on the blog section link.
Step 5: Use the smartwait.click_first_post() method to click on the first blog post.
Step 6: Use the assert statement to confirm that the words amet volutpat are in the page title.
Test Execution:
Execute the test using the following command:
1 |
pytest tests/test_smartwait.py |
The LambdaTest Web Automation Dashboard shows the status of our test execution.
Handle Waits in Selenium Tests With SmartWait. Try LambdaTest Today!
Quick Comparison: Python Waits Types
So far, we have explored techniques for implementing waits in Python automation scripts. We’ll compare these methods and pick out their differences or similarities.
Block and non-blocking
The time.sleep() wait function blocks the wait call. It suspends the thread for the entire wait time. The other wait methods are non-blocking.
Efficiency
The time.sleep() function is the most inefficient wait method as it blocks the entire thread. Meanwhile, the implicit wait is generally more efficient than the time.sleep() function. It will wait until the given timeout for any element to appear or not.
The explicit wait is more efficient than the previous two because it waits for a specific condition to be true or timeout.
Fluent waits offer more efficiency than implicit and explicit waits. The poll_frequency argument in the fluent wait continues to check for the appearance of an element at intervals before the timeout. If the element is available before timeout, the wait ends, and the test script moves to the next line of code.
However, SmartWait by LambdaTest is the most efficient option for implementing Python waits since code can be easily maintained since exceptions (of all applicable types) need not be handled explicitly when performing automated testing on different web browsers online.
Customization
There is no customization with the time.sleep() function. In implicit wait, a flat waiting timeout is given to all elements, and there is no room for adjustment to match specific elements. Explicit wait allows testers to define specific wait conditions targeted at different elements.
The fluent wait is the most customizable wait method, as you can define custom wait conditions for elements with a polling frequency where necessary. SmartWait offers no customization, as an algorithm handles everything.
If you seek an efficient method to use Python waits, the best choice is SmartWait, whereas fluent waits offer the best customization. For simple and general-purpose waiting, the implicit wait is fine. The sleep() method is the least preferred as it blocks the wait mechanism.
Conclusion
There are several reasons why Python wait mechanisms have been used. Some of these reasons include collecting user input, waiting for server responses, fetching web page resources, etc.
Like other programming languages, Python waits can be used with tools like Selenium for web automation. It offers several ways to apply Python waits in test automation scripts.
Frequently Asked Questions (FAQs)
How to wait for 2 seconds in Python?
To wait for 2 seconds in Python, you can use the time.sleep() function from the time module. Here’s how you can do it:
1 2 3 |
import time time.sleep(2) # Wait for 2 seconds |
How do you wait for 1 minute in Python?
To wait for 1 minute in Python, you can use the time.sleep() function from the time module. Since 1 minute is equivalent to 60 seconds, you can do the following:
1 2 3 |
import time time.sleep(60) # Wait for 1 minute (60 seconds) |
Got Questions? Drop them on LambdaTest Community. Visit now