⚠️ Playwright Dialogs: 90% of engineers block their tests here:
How do you robustly handle browser-native dialogs (alert, confirm, prompt) that might appear conditionally in Playwright tests, without causing flaky failures?
📌 Problem Statement
Browser-native dialogs (like alert(), confirm(), prompt()) are common in web applications. Playwright effectively handles them using page.on('dialog').
The core challenge arises when these dialogs appear conditionally—meaning an action might sometimes trigger a dialog and sometimes not, based on application state.
❌ A naive approach using await page.waitForEvent('dialog') will cause tests to hang indefinitely if the dialog doesn't appear, leading to frustrating timeouts and flaky failures.
💡 Solution & Code Walkthrough
✅ The robust solution involves setting up an asynchronous event listener using page.on('dialog') before the action that might trigger the dialog.
This non-blocking approach allows your test to proceed without blocking, while the listener stands ready to handle any dialog that pops up.
• Inside the listener, inspect dialog.type() and dialog.message() for conditional logic (e.g., accept specific confirmations, dismiss others).
import { Page, test, expect } from '@playwright/test';
// Helper function to encapsulate robust dialog handling
async function handleConditionalDialog(page: Page, actionTrigger: () => Promise<void>) {
let dialogAppeared = false;
// 1. Register the listener *BEFORE* performing the action
const dialogListener = async dialog => {
console.log(`Dialog detected: Type='${dialog.type()}', Message='${dialog.message()}'`);
if (dialog.type() === 'confirm' && dialog.message().includes('Proceed?')) {
await dialog.accept(); // Custom logic: Accept specific confirmation
} else {
await dialog.dismiss(); // Default: Dismiss other dialog types
}
dialogAppeared = true; // Flag that a dialog was handled
};
page.on('dialog', dialogListener);
// 2. Perform the action that MIGHT trigger a dialog
await actionTrigger(); // e.g., await page.click('#deleteButton');
// 3. Crucial: Allow a tiny moment for async listener to fire if dialog appeared.
// Avoid long sleeps; this is for the event loop to catch up.
await page.waitForTimeout(50); // Minimal practical delay
// 4. Important: Remove the listener to prevent memory leaks/side effects
page.removeListener('dialog', dialogListener);
// Optional: Assert if a dialog *was* expected under certain test conditions
// if (actionTrigger === someDialogExpectedAction) {
// expect(dialogAppeared).toBe(true);
// }
}
// Example usage within a Playwright test:
test('should gracefully handle a potentially conditional dialog', async ({ page }) => {
await page.goto('https://your-app.com/dialog-page');
// Call helper for the action that might show a dialog
await handleConditionalDialog(page, async () => {
await page.click('#potentiallyTriggerDialogButton');
});
// Continue with assertions based on the UI state AFTER the action,
// regardless of whether a dialog appeared or not.
await expect(page.locator('#statusMessage')).toHaveText('Operation completed.');
});
🔑 Key Takeaways
✅ Always register page.on('dialog') before the action that might trigger the dialog.
❌ NEVER use await page.waitForEvent('dialog') for conditional dialogs; it will block and fail.
• Use dialog.type() and dialog.message() inside your listener for specific handling logic.
• Add a minimal await page.waitForTimeout(50) after the action to ensure the async listener has time to process the dialog.
• Clean up by removing the listener with page.removeListener('dialog', handler) to prevent memory leaks and unintended side effects.
❓ Quick Summary Q&A
Q: Why is page.on('dialog') better for conditional dialogs than page.waitForEvent('dialog')?
A: page.on('dialog') is non-blocking, allowing tests to proceed even if no dialog appears. page.waitForEvent('dialog') blocks and fails if no dialog is found, causing flakiness.
TAGS: playwright, automation, testing, javascript, typescript, sdet, frontend testing
────────────────────────────────────────
Level up your engineering skills on the go!
Download our app today:
────────────────────────────────────────
📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&𝐀𝐬
Practice real-world interview scenarios offline on the free QA Automation & SDET Prep app:
🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):
https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20260928
🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):
https://apps.apple.com/app/id6786760948?pt=128640464&ct=devto_selenium_20260928&mt=8
────────────────────────────────────────
────────────────────────────────────────
Top comments (0)