Waits and Timeouts in Playwright Python
Some software is slow, some software is fast and some softwares are normal. So when we try to perform operations using Playwright or any other automation tools, we have to adjust our automation to speed according to the software speed, this can be achieved only by delaying the operations. This process is called waiting.
If the proper wait time is not given the test might fail so to avoid failure, it is important to provide the necessary waits
There are two types of waits: one that applies to a given line alone and the other that applies to the complete script.
Note: Default timeout in clarity, 30 seconds or 30,000 ms.
We will be using the waits practice page: https://demo.testercoder.com/waits.html
Sleep:
Everyone’s favorite weight method is sleep Function. This is the static wait which means if the sleep function is used then that particular thread is going to wait for a given amount of time. It does not matter whether conditions are met or not, nothing matters it just sleeps there for a given time.
Note: Try to avoid using sleep in your test scripts, it is sometimes useful when none of the other waiting methods work.
Let’s write the code keeping in mind that the button loads after 40 seconds
from playwright.sync_api import sync_playwright
pw = sync_playwright().start()
page = pw.chromium.launch(headless=False).new_page()
page.goto("https://demo.testercoder.com/waits.html")
sleep(45)
page.locator("#delayed").click()
Auto-waiting:
Playwright by default waits for a particular element to present or a particular condition to be met. The default wait time for the element to present is 30 seconds and 5 seconds for the condition to be met.
while finding an element playwright makes a few checks like whether
- Only one element is found (Unlike selenium, the playwright will not consider the first element if more than one is present)
- element is interactable
- element is enabled
- element is stable
And all this should happen within 30 seconds. If any of this fails then Playwright will fail the step. Our target element is the below button.
from playwright.sync_api import sync_playwright
pw = sync_playwright().start()
page = pw.chromium.launch(headless=False).new_page()
page.goto("https://demo.testercoder.com/waits.html")
page.locator("#alert").click()
When you execute the above code, the playwright waits for 30 seconds, if the element is present before that then it clicks the element and moves on otherwise fails the test.
wait_for():
wait_for()
method waits for the element to present on the webpage till the given timeout. I have designed the below button that will be created only after 40 seconds, lets try to click it with auto-waiting. This method helps to wait for the element to present, once the element is present then you can write the operations on that element.
Note: Scope is One line
from playwright.sync_api import sync_playwright
pw = sync_playwright().start()
page = pw.chromium.launch(headless=False).new_page()
page.goto("https://demo.testercoder.com/waits.html")
page.locator("#delayed").wait_for(timeout=45000)
page.locator("#delayed").click()
Operations with timeout:
Whenever we perform some operation on any element, the playwright provides a way to give some wait time if the element is not there, these are called timeouts
.
For example, I can rewrite the above program without using wait_for()
.
from playwright.sync_api import sync_playwright
pw = sync_playwright().start()
page = pw.chromium.launch(headless=False).new_page()
page.goto("https://demo.testercoder.com/waits.html")
page.locator("#delayed").click(timeout=45000)
If you want to override the default timeout, then use set_default_timeout()
to override it. In the below code, I am setting the default timeout to 60 seconds.
from playwright.sync_api import sync_playwright, Locator
pw = sync_playwright().start()
page = pw.chromium.launch(headless=False).new_page()
page.set_default_timeout(timeout=60000)
page.goto("https://demo.testercoder.com/waits.html")
Wait for Url:
In Playwright, we click elements and submit forms, these actions sometimes trigger navigation to a different webpage containing a different URL. In such cases, wait_for_url()
will be helpful.
from playwright.sync_api import sync_playwright
pw = sync_playwright().start()
page = pw.chromium.launch(headless=False).new_page()
page.goto("https://demo.testercoder.com/waits.html")
page.locator("#xyz").click()
page.wait_for_url("http://google.com")
We can also use regex to wait for the URL.
page.locator("#xyz").click()
page.wait_for_url("**/shopping.html")
Wait for the element state:
wait_for_element_state()
waits till the element reaches the specific state. The element state could be “disabled”, “editable”, “enabled”, “hidden”, “stable”, “visible”. Please notice this method will work only when you are using element handle function.
Now below code wait for the button to be visible, the default wait time is 30 seconds
from playwright.sync_api import sync_playwright
pw = sync_playwright().start()
page = pw.chromium.launch(headless=False).new_page()
page.goto("https://demo.testercoder.com/waits.html")
page.locator("#display-other-button").click()
page.locator("#hidden").element_handle().wait_for_element_state(state="visible", timeout=45000)
Wait for the selector:
We can wait_for_selector()
wait for a specific locator to present, which is the same as wait_for(), but we just apply it on the element handle.
from playwright.sync_api import sync_playwright
pw = sync_playwright().start()
page = pw.chromium.launch(headless=False).new_page()
page.goto("https://demo.testercoder.com/waits.html")
page.locator("#display-other-button").element_handle().wait_for_selector("#abc", timeout=45000)
Wait for the page load state:
We can wait till the page reaches a certain state, we can see the state of the page in the developer console. Use document.readyState
on the dev console.
The webpage goes through multiple states:
- load: Page load is over (response started flowing in)
- domcontentloaded: All the dom(page) elements loaded
- networkidle: No request is going to sever or no response is coming back
Note: Based on my experience with this, this doesn’t work accurately, be careful of that
from playwright.sync_api import sync_playwright
pw = sync_playwright().start()
page = pw.chromium.launch(headless=False).new_page()
page.goto("https://demo.testercoder.com/waits.html")
page.wait_for_load_state(state="load")
Posts You Might Like
- Why playwright is better than selenium webdriver, is it?
- Handle dropdowns in Playwright Python
- Open the browser and Close in Playwright Python
- Handle checkbox in Playwright Python
- Handle IFrames in Playwright Python
- Element Operations in Playwright Python
- Page level commands in Playwright Python
- Element State with Playwright Python