“Advanced Assertions in Playwright: poll() vs toPass() Explained”
playwright synchronous assertions

I am sure you might have come across the scenario where there is a synchronous step present, and you want to assert for some condition but unfortunately the condition will become true after a while but not instantly.
Here is the scenario:
A report is expected to come from some source, and it takes time to receive.
Since this step which is verifying the report file’s presence is a synchronous one and it is not going to retry and fail in first attempt itself
import {test,expect} from "@playwright/test";
import { existsSync } from 'fs';
test('file presence check', () => {
const exists = existsSync('downloads/report.pdf');
// as per scenario , file is going to arrive late at this destination
expect(exists).toBeTruthy();
});
Bad solution:
waiting for 1 minutes by default.
import {test,expect,page} from "@playwright/test";
import { existsSync } from 'fs';
test('file presence check',async ({page}) => {
// as per scenario , file is going to arrive late at this destination
await page.waitForTimeout(1*60*1000);
const exists = existsSync('downloads/report.pdf');
expect(exists).toBeTruthy();
});
If file arrives early, still test will wait for 1 minutes.
Using complex for loops or while loops
unnecessary code complexity
ToPass() assertion
This assertion is going to retry executing a block of code until all the assertions inside the block is passed.
import {test,expect,page} from "@playwright/test";
import { existsSync } from 'fs';
test('file presence check', async () => {
await expect(() => {
const exists = existsSync('downloads/report.pdf');
expect(exists).toBeTruthy();
//here i have only one assertion
}).toPass();
});
Why it is better:
Assertion is going to pass and move to next steps for execution so timing is saved
No complex looping code is required.
Poll() assertion
It is similar to the Pass() but here it works on single assertion. it returns a value, and assertion is done on it.
Scenario:
let’s assume you have a field and it is value is changing and you want to check if it is greater than 5
import {test,expect,page} from "@playwright/test";
test('Number validateion', async () => {
const count = await page.locator('.notification-badge').textContent();
const countInNumber = parseInt(count || '0');
expect(countInNumber).toBeGreaterThan(5);
});
Here also it is not wise to use the waitforTimeout for any other loops for the same reason we discussed before
The better solution would be
import {test,expect,page} from "@playwright/test";
test('Number validateion', async () => {
await expect.poll(async () => {
const count = await page.locator('.notification-badge').textContent();
return parseInt(count || '0');
}).toBeGreaterThan(5);
});
Understanding the difference
This 2 may seem almost close with no difference but based on my experience this is what i have understood as the differences between this 2.
| Poll() | ToPass() |
| 1. it returns single value | it doesn’t return value. |
| 2.The assertion is done on the returned value | Multiple assertions can be placed inside this block |
| 3.Cleaner for value tracking | Suitable for multiple assertions |
Thanks for reading my blog and hope you have learnt something new here.
please subscribe to my newsletter for more.



