đ Playwright Waiting Strategies: The Art of Perfect Timing
Imagine youâre at a bus stop. You wouldnât just run into the street hoping a bus appearsâyouâd WAIT for it to arrive. Thatâs exactly what Playwright waiting strategies do: they help your code WAIT for the right moment before taking action.
đ The Big Picture
When you automate a website, things donât happen instantly. Pages load, buttons appear, URLs change. If your code rushes ahead before the page is ready, it crashesâlike trying to board a bus that hasnât arrived yet!
Playwrightâs waiting strategies are your patient helpers. Each one waits for something specific:
| Wait Method | What It Waits For |
|---|---|
waitForSelector |
An element to appear |
waitForLoadState |
Page to finish loading |
waitForURL |
URL to change |
waitForFunction |
A condition to become true |
waitForEvent |
Something to happen |
waitForTimeout |
A set amount of time |
đ page.waitForSelector
What Is It?
This is like waiting for your friend to show up at a meeting spot. You stand there until you SEE them.
Simple Example
// Wait for a button to appear
await page.waitForSelector('#submit-btn');
// Now click it safely!
await page.click('#submit-btn');
Real Life Scenario
A shopping cart icon appears AFTER you add an item. You need to wait for it:
await page.click('.add-to-cart');
// Wait for cart badge to show
await page.waitForSelector('.cart-badge');
console.log('Item added!');
Options You Can Use
await page.waitForSelector('.popup', {
state: 'visible', // visible, hidden, attached
timeout: 5000 // wait max 5 seconds
});
đ page.waitForLoadState
What Is It?
Think of a website like a restaurant kitchen. There are different stages:
- domcontentloaded: The menu is ready (HTML loaded)
- load: All dishes are on the table (images, scripts done)
- networkidle: The kitchen is quiet (no more requests)
Simple Example
// Wait for page to fully load
await page.waitForLoadState('load');
// Now the page is complete!
When to Use Each State
// Fast: Just need HTML structure
await page.waitForLoadState('domcontentloaded');
// Medium: Need all images and scripts
await page.waitForLoadState('load');
// Slow but thorough: Wait for all network quiet
await page.waitForLoadState('networkidle');
Real Life Scenario
After clicking a link, wait for the new page:
await page.click('a.next-page');
await page.waitForLoadState('networkidle');
// Now scrape the fully loaded content
đ page.waitForURL
What Is It?
Like waiting at an airport departure screen until YOUR flight number appears. You watch the URL bar until it shows what you expect.
Simple Example
// After login, wait for dashboard URL
await page.click('#login-button');
await page.waitForURL('**/dashboard');
// Now we're on the dashboard!
Different Ways to Match URLs
// Exact match
await page.waitForURL('https://example.com/home');
// Pattern match with glob
await page.waitForURL('**/products/*');
// Regex match
await page.waitForURL(/\/order\/\d+/);
// Function match
await page.waitForURL(url => url.includes('success'));
Real Life Scenario
After placing an order, wait for confirmation page:
await page.click('#place-order');
await page.waitForURL('**/order-confirmation*');
const orderId = await page.textContent('.order-id');
đ§Ş page.waitForFunction
What Is It?
This is the SMARTEST waiter. It checks a condition over and over until it becomes TRUE. Like waiting until a pot of water starts boiling!
Simple Example
// Wait until counter shows 5
await page.waitForFunction(() => {
const el = document.querySelector('#counter');
return el && el.textContent === '5';
});
Why Is It Special?
It runs YOUR custom JavaScript inside the page. You can check ANYTHING:
// Wait for array to have 3 items
await page.waitForFunction(() => {
return window.myData && window.myData.length >= 3;
});
// Wait for animation to complete
await page.waitForFunction(() => {
const box = document.querySelector('.animated-box');
return box.classList.contains('animation-done');
});
With Arguments
You can pass data from your test into the page:
const expectedText = 'Welcome, John!';
await page.waitForFunction(
(text) => document.body.innerText.includes(text),
expectedText
);
đĄ page.waitForEvent
What Is It?
Like a detective with their ear to the ground, waiting for a specific SOUND. This waits for browser events like popups, downloads, or console messages.
Simple Example
// Wait for a popup window
const popupPromise = page.waitForEvent('popup');
await page.click('#open-popup');
const popup = await popupPromise;
// Now work with the popup!
Common Events to Wait For
// Wait for file download
const downloadPromise = page.waitForEvent('download');
await page.click('#download-btn');
const download = await downloadPromise;
// Wait for console message
const consolePromise = page.waitForEvent('console');
await page.click('#log-something');
const msg = await consolePromise;
console.log(msg.text());
// Wait for dialog (alert/confirm)
page.on('dialog', d => d.accept());
const dialogPromise = page.waitForEvent('dialog');
await page.click('#show-alert');
await dialogPromise;
With Filters
// Wait for a specific console error
const error = await page.waitForEvent('console',
msg => msg.type() === 'error'
);
â° page.waitForTimeout
What Is It?
This is the SIMPLEST waiterâjust a plain timer. Like setting an alarm and doing nothing until it rings.
Simple Example
// Wait for 2 seconds
await page.waitForTimeout(2000);
â ď¸ Important Warning!
This should be your LAST resort! Itâs like guessing how long something takes instead of actually checking.
// â BAD: Guessing wait times
await page.waitForTimeout(5000);
await page.click('.button');
// â
GOOD: Wait for actual condition
await page.waitForSelector('.button');
await page.click('.button');
When Itâs Okay to Use
- Debugging: Slow down to see whatâs happening
- Rate limiting: Wait between API calls
- Animations: When no other signal exists
// Acceptable: Rate limit protection
for (const item of items) {
await page.click(item);
await page.waitForTimeout(500); // Prevent spam
}
đŻ Quick Decision Guide
graph TD A["What are you waiting for?"] --> B{Element?} B -->|Yes| C["waitForSelector"] B -->|No| D{Page load?} D -->|Yes| E["waitForLoadState"] D -->|No| F{URL change?} F -->|Yes| G["waitForURL"] F -->|No| H{Custom condition?} H -->|Yes| I["waitForFunction"] H -->|No| J{Browser event?} J -->|Yes| K["waitForEvent"] J -->|No| L["waitForTimeout â ď¸"]
đ Pro Tips
- Always prefer smart waits over
waitForTimeout - Combine waits when needed:
await page.waitForLoadState('networkidle'); await page.waitForSelector('.content'); - Set reasonable timeouts to fail fast:
await page.waitForSelector('.slow-thing', { timeout: 10000 });
đŹ Summary
| Method | Use When⌠|
|---|---|
waitForSelector |
Need an element to exist |
waitForLoadState |
Page needs to finish loading |
waitForURL |
Navigation should complete |
waitForFunction |
Custom condition must be true |
waitForEvent |
Browser event should fire |
waitForTimeout |
Last resort only! |
Remember: Good waiting = Reliable tests. Donât rushâlet Playwright wait for the perfect moment! đ
