Playwright’s dialog handling is more about anticipation than reaction.
Let’s watch a simple dialog appear and get dismissed.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://the-internet.herokuapp.com/javascript_alerts")
# Set up a listener *before* triggering the dialog
page.on("dialog", lambda dialog: dialog.dismiss())
# Trigger the alert
page.locator("button:has-text('Click for JS Alert')").click()
browser.close()
In this example, page.on("dialog", ...) sets up a handler. When any dialog event fires on the page, the provided lambda function is executed. This function receives a dialog object and calls dialog.dismiss(), which programmatically clicks the "Cancel" or "OK" button on the dialog, depending on its type. The key is that this listener is registered before the action that triggers the dialog.
The Mental Model: Event Listeners and Asynchronous Nature
Playwright operates asynchronously. When you click a button that triggers a JavaScript alert(), confirm(), or prompt(), the browser pauses script execution until the user interacts with the dialog. However, Playwright’s underlying automation protocol is still listening for events. The dialog event is Playwright’s way of surfacing these browser-level dialogs to your script.
When a dialog appears, Playwright emits a dialog event. Your script needs to be listening for this event before it happens. If you trigger the dialog first and then set up your listener, you’ll miss the event and your script will hang, waiting for a dialog that’s already visible but unhandled.
The dialog object passed to your handler has several useful methods:
accept(): Clicks "OK" on the dialog. Forpromptdialogs, it can also take atextargument to enter text into the prompt.dismiss(): Clicks "Cancel" on the dialog.type: A string, either"alert","confirm", or"prompt".message: The text displayed in the dialog.
Controlling Dialog Behavior
You can selectively handle dialogs based on their type or message.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://the-internet.herokuapp.com/javascript_alerts")
def handle_dialog(dialog):
print(f"Dialog type: {dialog.type}, Message: {dialog.message}")
if "Are you sure you want to continue?" in dialog.message:
dialog.accept()
else:
dialog.dismiss()
page.on("dialog", handle_dialog)
# Trigger an alert (dismissed by default handler)
page.locator("button:has-text('Click for JS Alert')").click()
# Wait for the result (optional, for verification)
page.wait_for_selector("#result", state="visible")
print(f"Alert result: {page.locator('#result').text_content()}")
# Trigger a confirmation (accepted because of the message)
page.locator("button:has-text('Click for JS Confirm')").click()
page.wait_for_selector("#result", state="visible")
print(f"Confirm result: {page.locator('#result').text_content()}")
# Trigger a prompt (dismissed by default handler)
page.locator("button:has-text('Click for JS Prompt')").click()
page.wait_for_selector("#result", state="visible")
print(f"Prompt result: {page.locator('#result').text_content()}")
browser.close()
This demonstrates how you can inspect the dialog.type and dialog.message to decide whether to accept(), dismiss(), or even provide text for a prompt dialog.
The Nuance of page.evaluate() and Dialogs
While page.on("dialog", ...) is the standard and most robust way to handle dialogs, it’s crucial to remember that page.evaluate() can also trigger them. When using page.evaluate() to execute JavaScript that calls alert(), confirm(), or prompt(), Playwright’s dialog event listener will still fire. However, if you’re not careful, you might wrap the evaluate call itself in a try...except block expecting a JavaScript error, when in reality, a dialog was just presented and your script hung waiting for it. The dialog event is the mechanism to intercept and control these.
The next step after mastering dialogs is understanding how to handle unexpected network requests or responses.