Master Playwright’s waitForLoadState

Learn about Playwright's waitForLoadState to enhance test reliability and performance.

Get Started free
Home Guide Understanding Playwright waitforloadstate

Understanding Playwright waitforloadstate

By Priyanka Bhat, Community Contributor -

Playwright is a modern open-source framework developed and maintained by Microsoft. Due to its advanced architecture, Playwright tests are faster and more stable. Playwright has many features in-built, auto waiting is one of the unique features.

The Playwright automatically waits for element stability and actionability before performing any interactions. This reduces the additional code and complex logic of implicit waits.

Playwright also supports different mechanisms to wait for specific elements. WaitForLoadState() is one such advanced method that allows waiting for DOM content to load, network calls to resolve, or complete a web page to load.

Why do Load States Matter in Web Testing?

Load states are indications or different states of web applications. By understating and handling these intelligently, you can achieve highly reliable automation execution output.

Modern web development uses this advanced mechanism to provide a smoother user experience. Dynamic loading is one such approach where the contents are loaded dynamically after the initial payload. This can have multiple API calls, or loading images from resources etc.

Waiting for specific load states, such as DOM content loaded, network idle, or load, tests can verify that the content and elements they depend on are ready before interacting. This reduces test failures that occur because of incomplete loading or interaction that happens before page load.

What is waitForLoadState in Playwright?

The waitForLoadState() is a method in Playwright that waits for the page to trigger specific states such as load, DOMcontentloaded, and networkidle.

waitForLoadState is particularly useful in the navigation of web pages. Instead of using the hard-coded waits, you can dynamically wait for the page to be loaded completely. For example, if you want to interact with one of the UI elements after the page loads, then if you put the hard wait, the Playwright might look for the element as soon as navigation happens or as soon as the timeout occurs.

Playwright may attempt to interact with the element before it loads. If the element is not loaded, then the tests may fail, which can cause flaky tests.

How waitForLoadState improves Test Stability and Accuracy?

waitForLoadState() can greatly influence the test stability and accuracy, as the page load is the initial step to perform any action on the page.

waitForLoadState() allows us to ensure the page is completely loaded before proceeding further. The test flakiness is a common challenge in automation testing.

Most of the flakiness originates from the element loading or presence. The waitForLoadState() reduces such errors. Additionally, waitForLoadState() can be placed inside the script based on scenarios.

Playwright also allows definition of custom timeout for load state, which can be helpful in specific pages where it takes longer than usual time.

When waitForLoadState() is used with networkidle, it ensures there is no ongoing network call in the backend. These waiting strategies in Playwright can reduce the flakiness drastically. However, it may need to be handled on a case-by-case basis.

Dealing with waits and timeouts in Playwright

The Playwright allows different ways to handle the wait and timeouts. This mechanism includes element-level waits, network call waits, and the complete DOM tree-level waits. Based on the specific requirements these waits and timeouts can be used intelligently.

1. Element level waits and timeouts

Locator.waitFor(): This method enables waiting for a specific element to be visible or hidden in the DOM tree. If the specific element is taking a lot of time to load, you can use this method before interacting with such elements. The locator.waitFor() accepts timeout in milliseconds as a parameter that can be used for a timeout before throwing an exception.

Example:

const subBtn = page.locator('#btn')

subBtn.waitFor({ state: 'visible', timeout: 5000 })

2. Page level waits

waitForLoadState(): This method provides a wait at page level with state-based waits. You can wait for specific states of a web page such as domcontentloaded, networkidle, load, etc. This is helpful when you freshly navigate to pages.

The waitForLoadState() also accepts timeout as a parameter along with state.

Example:

await page.waitForLoadState('load', { timeout: 10000 });

3. Network call wait

waitForResponse(): This method helps to wait for specific API calls to resolve before proceeding further. For example, if your UI test depends on a specific API call, you can wait for that API to be called and resolved before performing action on that UI element.

The waitForResponse() can be combined with the timeout option to achieve highly reliable tests

Example:

await page.waitForResponse('https://example.com/api/getCustomerDetails, { timeout: 10000 });

4. Hard waits

Playwright allows the execution to be paused for a specific duration using the page.waitForTimeout(). This method is helpful in debugging. However, it is not recommended to use this for real-time scripts as tests may become flaky.

Example:

await page.waitForTimeout(90000);

Talk to an Expert

Types of waits in Playwright

Playwright provides different types of wait to handle dynamic content loading and achieve stable test outputs; this helps to ensure the interaction with web elements only when specific elements, events, or network responses are ready.

1. Explicit waits

Explicit wait in Playwright allows us to wait for specific elements to be ready before interacting with such elements. If a specific element or API response takes a longer time to load, you can use the explicit waits in Playwright.

There are many different methods available to the Playwright to handle the explicit wait

  • locator.waitFor(): Waits for an element to appear, disappear, or be in a certain state
  • page.waitForTimeout(): Pauses execution for a specified amount of time
  • page.waitForEvent(): Waits for a specific event to be emitted
  • page.waitForFunction(): Waits until a custom JavaScript function evaluates to a true
  • page.waitForResponse(): Waits for a specific network response

Example

const submitbtn = await page.locator('#form-submit');

await submitbtn.waitFor({ state: 'visible' });

2. Implicit wait

Unlike traditional automation frameworks, Playwright does not support implicit waits. Instead, it provides an auto-waiting mechanism that automatically waits for specific conditions before performing any actions.

These conditions are automatically waiting for elements to be ready, checks to ensure elements behave as expected, automatic retries until the condition is met, timeout triggers, etc

3. Conditional waits

Conditional waits are typically custom waits, and they loop until a specific condition is met. These conditional waits are helpful while validating dynamic contents. There are many different ways to achieve this, including the following commonly used methods.

  • page.waitForFunction(): Waits for a custom JavaScript function to evaluate to true.
  • page.evaluate(): page.evaluate() can be used to evaluate any custom JavaScript with a wait mechanism. This helps in handling complex scenarios.
  • locator.waitFor(): locator.waitFor() functions allow parameters like visible, hidden, enabled, or disabled, this enables to conditionally check for specific element state.

Example

await page.waitForFunction( (labelText) => document.querySelector('#status').innerText === labelText,'Completed');

What are the problems with Hard Wait?

The Playwright offers hardcoded waits using page.waitForTimeout() function. The limitation of these hard-coded waits is increased flakiness, especially if the web application is developed on a microservice-based architecture.

The API response may vary based on various factors like network, infrastructure, number of requests, etc. In such cases, using hard-coded waits causes slower test execution, test flakiness, difficulty debugging, etc.

Additionally, this may even bypass the real user simulation as the user doesn’t wait a specific time rather, he tries to wait for a particular component before interacting.

Playwright clearly documents with caution on hard-coded waits, mentioning: “Discouraged Never wait for timeout in production. Tests that wait for time are inherently flaky. Use Locator actions and web assertions that wait automatically”.

Take a scenario of a web page loading after navigation, depending on network speed, and application architecture it may take 60 seconds or 30 seconds.

If you put a code page.waitForTimeout(45000) the tests may still fail when it takes longer than 45 seconds. The best approach in such a scenario is to use the page.waitForLoadState() where it dynamically waits for the web page to load.

Types of Load States in Playwright

There are different types of load statuses in Playwright, and one can use them based on the scenario and requirements.

1. domcontentloaded

The domcontentloaded state indicates that the DOMContentLoaded event has fired, meaning the HTML document has been completely loaded and parsed. However, that doesn’t mean that all stylesheets and resources are loaded. This can be considered as the initial page load.

2. load

The load state indicates that the entire page, including all dependent resources such as images, stylesheets, scripts, and other resources, has finished loading. This state is useful when you want to ensure that all content is fully available before interacting with the page. However, this doesn’t track the ongoing network requests. When the load event is fired, there can still be ongoing network requests in the backend.

3. networkidle

Network idle state indicates that there is no ongoing network request of at least 500 milliseconds. This state is beneficial for applications that make multiple asynchronous requests, as it ensures that all network activity has been completed before proceeding. This state is mostly useful in single-page applications.

Note: The Playwright clearly mentions not to use the networkidle unless required by stating official website “Discouraged wait until there are no network connections for at least 500 ms. Don’t use this method for testing, rely on web assertions to assess readiness instead”.

BrowserStack Automate Banner

Basic Usage of waitForLoadState

Syntax:

await page.waitForLoadState(loadStateParameters, options);
loadStateParamters can be one of the below

load‘ – wait for the load event to be fired. This is the default.

domcontentloaded‘ – wait for the DOMContentLoaded event to be fired

networkidle‘ – wait until there are no network connections for at least 500 ms

Options can be one of the below

Timeout: number in milliseconds. Maximum operation time in milliseconds. Defaults to 0 – no timeout.

Example

Consider you want to navigate to bstackdemo.com, and before performing UI interactions, you want to ensure the page is loaded then you can use the below code

test('Wait For Load State - Load', async ({ page }) => {

    await page.goto("https://bstackdemo.com/");

    await page.waitForLoadState('load');

    expect(await page.locator('small[class="products-found"]').innerText()).toEqual("25 Product(s) found.");

});

In the above code, you navigate to bstackdemo.com and wait for the page to load before capturing the inner text which is available on the home page.

Waiting for Specific Load States

As mentioned earlier, playwright waitForLoadState() provides waiting options with different states namely domconentloaded, load, networkidle.

Waiting for DOMContentLoaded

The DOMContentLoaded state indicates that the HTML document has been completely loaded and parsed. This method is suitable when you want to work with DOM-level actions such as title, meta, etc

test('Wait For Load State - Load - DOM Content Loaded', async ({ page }) => {

    await page.goto("https://bstackdemo.com/");

    await page.waitForLoadState('domcontentloaded');

    console.log("Page Title is: "+await page.title())

    expect(await page.title()).toContain('StackDemo')

});

In the above code, navigate to bstackdomo.com and wait for ‘domcontentloaded’ event to be fired before validating the page title.

wait for domcontentloaded event

Waiting for Load

The load state indicates that the page is completely loaded, including stylesheets, images, and other JavaScript. This is the right way to ensure that the page is ready to take any actions. This is suitable for while interacting with UI based elements

test('Wait For Load State - Load', async ({ page }) => {

    await page.goto("https://bstackdemo.com/");

    await page.waitForLoadState('load');

    const productCount = await page.locator("//p[@class='shelf-item__title']").count();

    expect(await page.locator('small[class="products-found"]').innerText()).toEqual("25 Product(s) found.");

    console.log("Total Products in the page is: "+productCount)

});

In the above code, navigate to bstackdemo.com and wait until the page is completely loaded, and then take the count of the product and assert the count text.

take product count

Waiting for Network Idle

The networkidle state indicates no more than 0 network connections for at least 500 milliseconds. This is useful when applications make multiple asynchronous requests. However, Playwright does not recommend using networkidle status.

test('Wait for Response Demo', async ({ page }) => {

    await test.setTimeout(500000);

    await page.goto("https://bstackdemo.com/signin");

    await page.locator('#username').click();

    await page.getByText("demouser").nth(1).click();

    await page.locator('#password').click();

    await page.getByText('testingisfun99').nth(1).click();

    await page.locator('#login-btn').click();

    await page.waitForLoadState('networkidle',{timeout:30000});

    await page.locator("//p[@class='shelf-item__title'][text()='One Plus 6T']/../div[text()='Add to cart']").click();

    console.log("Added One Plus 6T to cart")

});

In the above code navigate to the sign page and log in as a demo user by entering a username and password. Once you hit the submit button, you wait for the load state – network idle, and then perform the click operation on the One Plus 6T Add to Cart button.

Perform click operation

Best Practices for Using waitForLoadState

Mastering waitForLoadState in Playwright is key to building reliable, efficient, and robust automated tests that handle dynamic web applications seamlessly. Here are some best practices to follow:

  • Do not use long timeouts on the page.waitForLoadState() method, this can cause the test execution to slow and may hide the actual loading issues that can be faced by the end-user.
  • Use appropriate load states based on the requirement, such as load, domcontentloaded, etc.
  • Avoid using the networkidle load state. Instead, rely on web assertions to assess readiness.
  • To get consistent test results, try to combine waitForLoadState() with element-level waits.
  • Use custom timeouts based on each scenario or use case
  • Review the page load time regularly and optimize it more frequently

Why should you execute Playwright Tests on Real Devices?

The user experience of the web application may change as the platform and browser change. It is important to test all possible operating systems, browsers, and devices before deploying code to production. Executing test automation scripts on multiple operating systems and browsers has its own challenges.

One of the main challenges is infrastructure. Cross-platform testing requires an environment that supports such kind of testing. This challenge can be overcome easily by using the cloud-based execution provider BrowserStack.

BrowserStack Automate is designed to integrate popular testing frameworks without modifying the actual test script. It requires minimal configuration to execute your tests on multiple browsers and operating systems.

Additionally, BrowserStack manages all of the testing infrastructure, so testers do not need to bother about infrastructure setup or monitoring. The BrowserStack Automate infrastructure is highly scalable, it allocates the resources on a demand basis. This can help in saving the cost considerably. As of today, BrowserStack has 20000+ real devices on the cloud which can be used for test execution.

Conclusion

Playwright is an advanced testing framework that provides different ways to handle complex scenarios. It has an inbuilt auto-waiting mechanism. However, if anyone wants to handle waiting explicitly it supports them using the various methods. waitForLoadState() is one such method where one can put the logic to wait for a specific page status.

Irrespective of the logic you use, it is important to execute the tests on the real devices, so that it helps to simulate the real user scenarios under different network conditions. BrowserStack is a recommended tool to validate such scenarios with ease.

Try BrowserStack Now

Tags
Automation Testing Playwright Website Testing

Featured Articles

Cross Browser Testing using Playwright

How to perform End to End Testing using Playwright

Simplify Playwright Testing

Automate Playwright tests on BrowserStack. Get fast test execution on real devices with no setup hassle