Skip to contentPlayForge

What does toPass do in Playwright?

Written by Jatin Thacker, Automation Architect · Updated

toPass runs a block of code again and again until it completes without throwing, or until its timeout runs out. It is for retrying a sequence of steps, such as "click, then check the result", where retrying the check alone would not help.

This answer is one piece of Chapter 11: Assertions.

  • Web-First Assertions Cookbook
  • Retry & Polling Patterns
  • Visual Regression Testing
  • Making a Failure Explain Itself

Sometimes an assertion fails because the action needs repeating, not because the page is slow. Retrying the assertion alone just keeps reading the same failed result. expect(async () => { ... }).toPass() retries the whole block: the actions and the checks inside it.

Two defaults catch people out. The intervals between attempts are 100, 250, 500 and then 1000 milliseconds. The timeout is 0, which means no limit, and toPass() ignores the assertion timeout from your config. Always pass your own, as in toPass({ timeout: 15_000 }).

In the example, ?flake=0.6 makes the practice app's mock API fail some calls with a 503, and ?seed=42 makes the pattern repeat on every run. Inside the block, the test clicks Check health and expects the result to say returned 200, giving that inner check one second. The first four calls return 503, so the block throws four times. On the fifth attempt the call succeeds, and the console shows passed on attempt 5.

Use it for retrying operations that are genuinely retryable. Do not use it to hide a bug that makes the first attempt fail.

topass.spec.js(https://practice.learnplayforge.com)
import { test, expect } from '@playwright/test'; test('retry a health check until the flaky upstream answers', async ({ page }) => { // ?flake=0.6 makes mock calls fail with 503; ?seed=42 makes the sequence repeatable await page.goto('/api-lab.html?seed=42&flake=0.6'); await expect(page.getByTestId('cfg-mock')).toHaveText('service-worker'); let attempts = 0; await expect(async () => { attempts++; await page.getByRole('button', { name: 'Check health' }).click(); await expect(page.getByTestId('scenario-result')) .toContainText('returned 200', { timeout: 1000 }); }).toPass({ timeout: 15_000 }); console.log(`passed on attempt ${attempts}`); });
Output
passed on attempt 5
  1 passed (7.6s)
Test yourself
Your config sets expect: { timeout: 10_000 }. You write await expect(async () => { ... }).toPass() with no options. How long will it keep retrying?

AI can write the test now. The job is knowing whether it checks anything. That's what the course teaches, one chapter at a time.

163 lessons · 226 drills · start free

← All questions

Training a team? Talk to us.