JavaScript has three native dialog types: alert (shows a message), confirm (OK/Cancel), and prompt (text input). Playwright auto-dismisses dialogs by default. If your test does not handle a dialog, Playwright clicks "Cancel" and moves on. Your test passes, but the dialog was silently dismissed. This is dangerous because you miss testing the actual dialog behavior.
import { test, expect } from '@playwright/test';
test('handle alert dialog', async ({ page }) => {
await page.goto('/topics/dialogs');
// Register the dialog handler BEFORE the click
page.once('dialog', async (dialog) => {
// Verify it is an alert
expect(dialog.type()).toBe('alert');
// Check the message text
expect(dialog.message()).toBe('Item has been saved!');
// Accept the alert (clicks OK)
await dialog.accept();
});
// Now trigger the dialog
await page.getByRole('button', { name: 'Show Alert' }).click();
// Verify the page state after alert was accepted
await expect(page.getByText('Alert accepted')).toBeVisible();
});import { test, expect } from '@playwright/test';
test('accept confirm dialog', async ({ page }) => {
await page.goto('/topics/dialogs');
page.once('dialog', async (dialog) => {
expect(dialog.type()).toBe('confirm');
expect(dialog.message()).toBe('Are you sure you want to delete?');
await dialog.accept(); // Clicks OK
});
await page.getByRole('button', { name: 'Delete Item' }).click();
await expect(page.getByText('Item deleted')).toBeVisible();
});
test('dismiss confirm dialog', async ({ page }) => {
await page.goto('/topics/dialogs');
page.once('dialog', async (dialog) => {
await dialog.dismiss(); // Clicks Cancel
});
await page.getByRole('button', { name: 'Delete Item' }).click();
await expect(page.getByText('Deletion cancelled')).toBeVisible();
});import { test, expect } from '@playwright/test';
test('enter text in prompt dialog', async ({ page }) => {
await page.goto('/topics/dialogs');
page.once('dialog', async (dialog) => {
expect(dialog.type()).toBe('prompt');
expect(dialog.message()).toBe('Enter your name:');
// Check the default value
expect(dialog.defaultValue()).toBe('');
// Type a value and accept
await dialog.accept('Shivam');
});
await page.getByRole('button', { name: 'Show Prompt' }).click();
await expect(page.getByText('Hello, Shivam!')).toBeVisible();
});| Method | Behavior | Use When |
|---|---|---|
| page.on('dialog', handler) | Handles every dialog that appears | Multiple dialogs expected in the test |
| page.once('dialog', handler) | Handles only the next dialog, then removes itself | Single dialog expected |
| No handler registered | Playwright auto-dismisses the dialog | You do not care about the dialog (risky!) |
Register the handler with page.once() or page.on() BEFORE the triggering action
Check dialog.type() to confirm it is the expected dialog type
Check dialog.message() to verify the text content
Call dialog.accept() or dialog.dismiss() to respond
For prompts, pass the input text to dialog.accept('your text')
Verify the page state after the dialog is handled
Dialog handlers MUST be registered before the action that triggers the dialog. If you click first and then register the handler, Playwright auto-dismisses the dialog instantly. Your handler never runs. This is the number one mistake with dialogs.
Use page.once() for single dialogs. If you use page.on() and forget to remove it, it will handle future dialogs you did not expect. page.once() is self-cleaning -- it removes itself after the first dialog.
Q: How do you handle JavaScript dialogs in Playwright?
A: I use page.once('dialog', handler) for single dialogs and page.on('dialog', handler) for multiple. The handler receives a Dialog object with type(), message(), defaultValue(), accept(), and dismiss() methods. The critical rule: register the handler BEFORE the action that triggers the dialog. For prompts, I pass the input text to dialog.accept('my text'). Playwright auto-dismisses unhandled dialogs by default, which can mask bugs, so I always register explicit handlers.
Key Point: Register dialog handlers BEFORE the triggering action. Use page.once() for single dialogs. dialog.accept() for OK, dialog.dismiss() for Cancel, dialog.accept('text') for prompts.