Playwright expect.poll() and expect.toPass(): Polling Assertions for Async Operations
Some conditions cannot be checked by auto-retry assertions alone. API processing, background jobs, eventual consistency — these need polling. expect.poll() and expect.toPass() solve this.
🎭 Want to master this with real projects? Join the Playwright Automation Mastery course at The Testing Academy.
Contents
expect.poll(): Poll Until Condition Met
// Poll API until order status changes
test('order processes eventually', async ({ request }) => {
const orderId = await createOrder(request);
await expect.poll(async () => {
const res = await request.get('/api/orders/' + orderId);
const order = await res.json();
return order.status;
}, {
message: 'Order should reach "completed" status',
intervals: [1000, 2000, 5000], // Poll at 1s, 2s, 5s intervals
timeout: 30000, // Give up after 30s
}).toBe('completed');
});
expect.toPass(): Retry Entire Block
// Retry a block of assertions until all pass
test('dashboard data loads eventually', async ({ page }) => {
await page.goto('/dashboard');
await expect(async () => {
await expect(page.getByTestId('user-count')).not.toHaveText('0');
await expect(page.getByTestId('revenue')).not.toHaveText('$0');
await expect(page.getByTestId('chart')).toBeVisible();
}).toPass({
intervals: [1000, 2000, 5000],
timeout: 30000,
});
});
🚀 Level Up Your Playwright
From locators to CI pipelines — build a production-grade Playwright + TypeScript framework step by step.
When to Use Which
| Pattern | Use For | Example |
|---|---|---|
| expect(locator) | DOM element state | Button visible, text matches |
| expect.poll() | Non-DOM async value | API status, DB state, job completion |
| expect().toPass() | Multiple conditions together | Dashboard fully loaded with all data |
Real-World Patterns
// Wait for email to arrive (via Mailhog API)
await expect.poll(async () => {
const res = await request.get('http://mailhog:8025/api/v2/messages');
const messages = await res.json();
return messages.total;
}, { timeout: 15000 }).toBeGreaterThan(0);
// Wait for file to appear on disk
await expect.poll(async () => {
return fs.existsSync('/tmp/export.csv');
}, { timeout: 10000 }).toBe(true);
// Wait for background job to complete
await expect.poll(async () => {
const res = await request.get('/api/jobs/' + jobId);
return (await res.json()).progress;
}, { timeout: 60000 }).toBe(100);
🎓 Master Playwright End to End
Join hundreds of SDETs building real automation frameworks. Lifetime access, hands-on projects, and a job-ready portfolio.
