...
×

Wait, Timeouts, Custom wait 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.

At the bottom of this tutorial, there is a custom wait, it is bit important do check that.

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.

Wait For Element Playwright Python 40

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.

Auto Waiting Playwright Python
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

Wait For Element Playwright Python 40
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.

Wait For Element State Playwright Python

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")

Custom wait using sleep

So far we have been using built-in functions from Playwright. Sometimes, in reality, those waits are not enough or do not serve your purpose. In such cases, we have to build our own waits. That is what we are going to do, trust me, this will be way too helpful in your automation.

When do I use it?

When the wait and timeout periods reach their specified times, the step will fail. However, sometimes all you want is to check whether the element is present or not. If it’s present, do one thing; if it’s not there, then do another thing. This is quite a common case in automation.

Let’s build a custom click that should wait for the given time if the element is not present, this sounds like timeout isn’t it, yes it is, but in our own terms.

  • Decide what function or what kind of custom wait you want; We decided to create a wait function to wait for an element to be present
  • As part of the function accept two parameters
    • locator: For which locator we will be waiting for
    • timeout_in_seconds: a parameter for total wait time, set the default value to 30 seconds (or a usual wait time of your application)
  • Create a loop with a range, the range of timeout_in_seconds
  • Write a try-except block, this block will be helpful if there is no element then the test will not fail
  • Find the element inside a try block, following a return True. Meaning if the element is present then the control should exit the method. Here you should use a timeout of 1000ms so that we can keep trying after every second.
  • If an error occurs control will reach except, here either use “pass” or some log statement
  • Now outside the loop, write return False, control will reach this step only when the playwright cannot find the element within the given time.
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")

def custom_wait(locator: Locator, timeout_in_seconds=30):
    for i in range(timeout_in_seconds):
        try:
            page.locator(locator).click(timeout=1000) # 1000 ms = 1 s
            print(f"'{locator}' Element is present")
            return True
        except Exception as e:
            print(f"Element not present Trying for {i} time and the error is {e}")
    return False

present_or_not = custom_wait("#delayed", timeout_in_seconds=45)
if present_or_not:
    page.locator("#delayed").click()
else:
    pass # do something else
Custom Wait

Author :

Pavankumar Nagaraj is an automation testing expert with over 12 years of experience, specializing in tools like Selenium, Protractor, Puppeteer, and Playwright, and skilled in Java, Python, and JavaScript

Pavankumar Nagaraj
Pavankumar Nagaraj

Pavankumar Nagaraj is an automation testing expert with over 12 years of experience, specializing in tools like Selenium, Protractor, Puppeteer, and Playwright, and skilled in Java, Python, and JavaScript

Seraphinite AcceleratorOptimized by Seraphinite Accelerator
Turns on site high speed to be attractive for people and search engines.