Native browser dialogs - alert, confirm, prompt, and beforeunload - block a Playwright test until they are handled, so a bare click on a "Delete" button that triggers confirm() would hang the scenario. The dialog steps mirror Playwright's page.on('dialog') API with BDD-friendly phrasing: you pre-register a handler, then perform the action, and the dialog is accepted or dismissed automatically the moment it appears.
The golden rule: attach the handler before the action that triggers the dialog. Handler steps are Givens; the triggering click or press comes after. Every handled dialog is also captured (type, message, and default value) so follow-up Then assertions can inspect what the dialog actually said - the most recent one is stored on this._lastDialog for custom step definitions too.
Handlers come in two flavors: single-shot ("the next dialog"), which detaches itself after handling one dialog, and persistent ("all confirmation dialogs"), which stays attached for the rest of the scenario. Registering a new handler replaces the previous one, so you can switch from accept-all to dismiss-all mid-scenario. Note that these steps are for native browser dialogs only - in-page HTML modals are covered by the modal steps.
Quick reference
| Step | What it does |
|---|---|
Given I will accept the next dialog | Auto-accept the next native dialog (alert / confirm / prompt), then detach. |
Given I will dismiss the next dialog | Auto-dismiss the next native dialog, then detach. |
Given I will accept the next dialog with "alice@example.com" | Auto-accept the next prompt, typing the supplied text. |
Then the last dialog message should be "Are you sure?" | Assert the captured dialog message equals a value exactly. |
Then the last dialog message should contain "Are you sure" | Assert the captured dialog message contains a substring. |
Then the last dialog type should be "confirm" | Assert the captured dialog type (alert, confirm, prompt, beforeunload). |
Given I accept all confirmation dialogs | Auto-accept every dialog for the rest of the scenario. |
Given I do not accept any confirmation dialogs | Auto-dismiss every dialog for the rest of the scenario. |
Steps in detail
Given I will accept the next dialog / Given I will dismiss the next dialog
Single-shot handlers: they accept (OK) or dismiss (Cancel) exactly one dialog, record it for later assertions, then detach themselves. For a confirm(), accept follows the destructive path and dismiss cancels it; for a beforeunload, accept lets the navigation proceed. The we pronoun variant works on all handler steps.
Given I will accept the next dialog
When I click "Delete"
Then I should see "Item deleted"
Given I will dismiss the next dialog
When I click "Leave page"
Given I will accept the next dialog with "<text>"
Prompt-specific single-shot accept: if the next dialog is a prompt(), the supplied text is entered before accepting - equivalent to typing into the prompt and pressing OK. If the dialog turns out not to be a prompt, it is simply accepted and the text is ignored.
Given I will accept the next dialog with "alice@example.com"
When I press "Reset password"
Then the last dialog type should be "prompt"
Then the last dialog message should be / should contain "<text>"
Assert on the message of the most recently captured dialog - exact equality or substring containment. Both fail with "No dialog has been captured." if no handler ran, which usually means the handler step was placed after the triggering action, or the dialog never fired. On mismatch the error shows the actual message.
Given I will accept the next dialog
When I press "Reset"
Then the last dialog message should be "Reset all settings?"
And the last dialog message should contain "Reset"
Then the last dialog type should be "<type>"
Assert the captured dialog's type: one of alert, confirm, prompt, or beforeunload. Useful for verifying the UI escalates correctly - e.g. that a destructive action raises a confirm rather than a plain alert.
Given I will accept the next dialog
When I press "Reset password"
Then the last dialog type should be "confirm"
Given I accept all confirmation dialogs / Given I do not accept any confirmation dialogs
Persistent variants: the handler stays attached for the rest of the scenario, accepting (or dismissing) every dialog raised. Reach for these when a flow fires many confirm()s in a row - bulk deletes, multi-step wizards - where registering a single-shot handler before each click would be noise. Each handled dialog still updates the "last dialog" capture. Registering either replaces any previously attached handler, so you can flip behavior mid-scenario.
Given I accept all confirmation dialogs
When I click "Delete all"
And I press "Reset settings"
Then I should see "Settings reset"
Complete example
Feature: Native browser dialogs
Scenario: Confirm, cancel, and prompt flows
Given I am on "/account.html"
And I will accept the next dialog
When I click "Delete"
Then the last dialog type should be "confirm"
And the last dialog message should contain "Are you sure"
Given I will dismiss the next dialog
When I click "Leave page"
Given I will accept the next dialog with "user@example.com"
When I click "Reset password"
Then the last dialog type should be "prompt"
Tips
- Always register the handler before the triggering action - a dialog with no handler blocks the page and the scenario times out.
- Assertions read the last captured dialog; in multi-dialog flows, assert immediately after the action whose dialog you care about.
- These steps handle native browser dialogs only. For HTML/CSS modals use the modal steps.
- In custom step definitions, the capture is available as
this._lastDialogwithtype,message, anddefaultValuekeys.