Alert dialogs are a common part of modern web applications and sites. They are used to display messages, warnings, confirmations, and more to the user. When automating with Playwright, you'll often come across alerts while interacting with pages. Playwright provides a clean API to handle them properly. Let's take a look at how to do it.
What are Alert Dialogs in Playwright?
Alert dialogs refer to the popup modal windows displayed by the browser during webpage interaction. These are created via JavaScript using:
window.alert()
– Shows an alert messagewindow.confirm()
– Displays confirm (yes/no) dialogwindow.prompt()
– Prompts user to enter text
When any of these are called, the browser will halt execution and display the modal dialog, waiting for user action. In Playwright scripts, we want to detect when an alert pops up and programmatically handle it by:
- Closing the alert
- Clicking OK/Cancel on confirms
- Entering text for prompts
This allows the script to continue past the alert instead of hanging indefinitely, waiting for non-existent user input.
Why Handle Alerts in Playwright?
Here are some key reasons you'll want to handle alerts in Playwright properly:
1. Prevent Script Blocking
The main reason is to prevent the script from blocking.
Without handling, the script will pause execution and wait forever at the alert. By detecting and closing/responding to the alert, we allow the script to continue.
2. Verify Alert Contents
Alert handling also lets you read and verify the alert message text.
For example, you may want to confirm a success alert appears after submitting a form. Checking the alert text allows validating it.
3. Click Confirmation Dialogs
For window.confirm()
popups, programmatically clicking OK or Cancel allows testing both code paths.
Your script can first run through clicking OK, then again clicking Cancel to cover all scenarios.
4. Enter Text for Prompts
When testing window.prompt()
you can enter expected text to cover different user inputs.
How to Handle Alerts in Playwright
Playwright provides a straightforward API for handling alerts through the page.on('dialog')
event handler. To use it:
- Attach a callback function to the
dialog
event - Inside the callback, handle the dialog using
dialog.accept()/dismiss()/text()
Here is an example skeleton:
page.on('dialog', handleDialog); function handleDialog(dialog) { // Handle dialog }
This will invoke handleDialog()
each time a dialog appears on the page. Inside the callback, we can handle different dialog types:
Handling Alert Messages
function handleDialog(dialog) { console.log(dialog.message()); dialog.dismiss(); }
dialog.message()
gets the alert textdialog.dismiss()
clicks OK/close
Handling Confirm Dialogs
function handleDialog(dialog) { if (dialog.message() === 'Confirm Delete') { dialog.accept(); // Click OK } else { dialog.dismiss(); // Click Cancel } }
- Check
dialog.message()
to identify the confirm - Call
dialog.accept()
to click OK dialog.dismiss()
for clicking Cancel
Entering Text for Prompts
function handleDialog(dialog) { if (dialog.type() === 'prompt') { dialog.accept('Expected Text'); } else { dialog.dismiss(); } }
- Check
dialog.type()
for the prompt dialog type - Pass text to
dialog.accept()
to enter it
This covers the basics of handling alerts. Next, we'll go over some best practices.
Best Practices for Alert Handling
Here are some tips for smoothly handling alerts in your scripts:
Use a Single Handler
Define one reusable top-level dialog handler instead of repeating the logic. For example:
// dialog.js export default async function handleDialog(dialog) { // shared logic } // script.js import handleDialog from './dialogs'; page.on('dialog', handleDialog);
This avoids duplication and makes alert handling consistent across tests.
Isolate UI Logic
Keep the alert handling logic isolated from your test code. For example, call a separate method from your test:
// tests.js test('submit form', async ({page}) => { // interact with page await handleFormSubmitAlert(page); // assert on results }); // alerts.js export async function handleFormSubmitAlert(page) { page.on('dialog', handleDialog); // ... }
This separates the UI logic from the test and improves maintainability.
Add Context-Specific Logic
While reusing a single top-level handler, add any context-specific logic within the handler:
function handleDialog(dialog) { if (isSubmitAlert(dialog)) { // handle submit alert } else if (isDeleteAlert(dialog)) { // handle delete alert } else { // default handling } }
This keeps the alert handling centralized while allowing custom logic per dialog.
Disable When Not Needed
Dialog handling introduces some overhead. Avoid having it enabled for every test run by:
// Enable for specific test test('alert test', async ({page}) => { page.on('dialog', handleDialog); // steps to cause alert }); // Or conditionally enable if (handleAlerts) { page.on('dialog', handleDialog); }
This prevents unnecessary processing for tests not requiring alerts. By following these best practices, you can implement robust alert handling in your scripts. Next, we'll look at some common issues that may come up.
Common Issues and Solutions
Here are some common problems that may occur with Playwright alert handling:
Alerts Not Getting Handled
If alerts in the browser are not getting handled by your script, the most common reasons are:
- The
page.on('dialog')
handler wasn't added - It was added after the alert occurs on the page
- The page instance changed, and the handler needs to be reattached
Double-check page.on('dialog')
is called early in your test code before any alerts could appear on the page. Reattach it after any page navigations or new page instantiations.
Can't Identify Alert Type
To handle prompts and confirm dialogs, we need to identify the alert type. This can be done via:
dialog.type()
– Returns'alert'
,'confirm'
,'prompt'
dialog.message()
– Text indicates alert typedialog.defaultValue()
– Shows default text for prompt
If these aren't working, double-check for an upstream Playwright issue. Sometimes browser versions and webpages can trigger unexpected alert behavior.
Prompt Text Not Entered
When trying to enter text with dialog.accept('text')
for a prompt, if the input is not appearing in the browser, there are a few possible issues:
- The dialog type is not actually a
'prompt'
. Double check withdialog.type()
. - There is a race condition where the prompt closes before the text can be entered. Slow down the script steps leading up to the prompt.
- An exception is swallowing the error, which would reveal the prompt is not interacting as expected.
Adding some logging and slowing down interactions around the prompt can help troubleshoot unexpected behavior.
Alerts During Navigation
If a page navigation triggers an alert, it can cause tricky behavior:
- The alert appears in the previous page context, not the new one
- The alert may get dismissed automatically without handling
To fix, manually dismiss any alerts before navigating:
await page.dismissAlerts(); await page.goto(url);
And reattach the dialog handler after navigating to the new page. With a few tweaks, these common issues can typically be addressed when handling alerts in Playwright.
Alert Handling Recipes
To put it all together, here are some examples of handling different alert scenarios in Playwright:
Close Alert After Form Submission
// Handle alert after form submit const handleSubmitAlert = async page => { await page.on('dialog', async dialog => { console.log(dialog.message()); await dialog.dismiss(); }); } await handleSubmitAlert(page); await page.fill('#email', '[email protected]'); await page.click('#submitButton');
This handles a generic alert that appears after submitting a form. We attach the dialog handler, log the message, and then dismiss the alert.
Handle Confirm Before Deleting
const handleDeleteConfirm = async page => { await page.on('dialog', async dialog => { if (dialog.type() === 'confirm') { await dialog.accept(); } else { await dialog.dismiss(); } }); } await handleDeleteConfirm(page); await page.click('#deleteButton');
For a window.confirm()
before deleting, we check the dialog type, and then call dialog.accept()
to click OK.
Enter Text for Signup Prompt
const handleSignupPrompt = async page => { await page.on('dialog', async dialog => { if (dialog.type() === 'prompt') { await dialog.accept('MyExpectedText'); } else { await dialog.dismiss(); } }); } await handleSignupPrompt(page); await page.click('#signup');
When a window.prompt()
appears during signup, we verify it's a prompt, then pass our expected string to dialog.accept()
to enter it.
Summary
Handling browser alerts is a key technique for stable automation with Playwright. By listening to the dialog
event and programmatically handling dialogs, we can seamlessly interact with websites that use alerts and prompts.
The examples above demonstrate handling common cases like closing alerts, clicking confirm, and entering prompt text. Following the best practices will lead to robust alert handling in your tests. I hope this guide provides a comprehensive overview of how to smoothly handle browser dialog popups in Playwright using its built-in APIs!