There are a few ways to do this, depending on your needs.
Assuming you only have one dialog popping up at a time, you can use a promisified dialog handler and retries:
import {expect, test} from "@playwright/test"; // ^1.30.0
// Warning: doesn't have a timeout (relies on test timeout)
const acceptNextDialog = page =>
new Promise(resolve =>
page.once("dialog", async dialog => {
await dialog.accept();
resolve(await dialog.message());
})
);
test.beforeEach(async ({page}) => {
await page.setContent(`
<button>Click to generate random number from 0 to 9 inclusive</button>
<script>
document.querySelector("button").addEventListener("click", e => {
alert(~~(Math.random() * 10));
});
</script>
`);
});
test("eventually shows '1' in the dialog", async ({page}) => {
await expect(async () => {
const message = acceptNextDialog(page);
await page.getByRole("button").click();
expect(await message).toBe("1");
}).toPass({timeout: 20_000});
});
The example page under test has a button that triggers a dialog that displays a random number from 0-9 in it. We assert that eventually the dialog shows the number "1"
.
Change the test to check for the text "asdf"
and you'll see it fails as expected.
Polling is also possible, and probably a bit more precise than retrying:
await expect.poll(async () => {
const message = acceptNextDialog(page);
await page.getByRole("button").click();
return message;
}).toBe("1");