Updated: How to allow testing beforeunload confirmation dialogs with modern ChromeDrivers

Posted . Visible to the public. Auto-destruct in 60 days

ChromeDriver 135 started following the W3C spec more closely, which broke testing beforeunload confirmations again. To get working confirmations in a testing browser again, unhandled_prompt_behavior needs to be set to the hash { default: :ignore }.

Selenium doesn't currently support setting this option to a hash, so a monkey patch is needed.

Changes

  • Starting with ChromeDriver 127, if your application displays a `beforeunload` confirmation dialog, ChromeDriver will immediately close it. In consequence, any automated tests which try to interact with unload prompts will fail.
  • This is because ChromeDriver now follows the [W3C WebDriver spec](https://w3c.github.io/webdriver/#user-prompts) which states that any unload prompts should be closed automatically.
  • However, this applies only to "HTTP" test sessions, i.e. what you're using by default. The spec also defines that bi-directional test sessions (using the "[BiDi](https://w3c.github.io/webdriver-bidi/)" WebDriver) should not automatically accept such dialogs. This means that we want to use the BiDi driver when testing `beforeunload` prompts.
  • ## Enabling the BiDi WebDriver
  • Using Capybara, simply set the `:web_socket_url` option to `true` to enable BiDi mode.
  • Example:
  • ```ruby
  • options = Selenium::WebDriver::Chrome::Options.new(
  • args: ['--headless'],
  • - unhandled_prompt_behavior: 'ignore',
  • + unhandled_prompt_behavior: { default: 'ignore' },
  • # ...
  • )
  • if unload_confirmation
  • options.add_option(:web_socket_url, true)
  • options.add_option(:page_load_strategy, 'none') # required for selenium-webdriver 4.27+
  • end
  • Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
  • ```
  • -In combination with `unhandled_prompt_behavior: 'ignore'` ([which we recommend setting](https://makandracards.com/makandra/617366-configure-selenium-webdriver-automatically-close-alerts)) any unload alerts will now stay open until handled.
  • +In combination with `unhandled_prompt_behavior: { default: 'ignore' }` ([which we recommend setting](https://makandracards.com/makandra/617366-configure-selenium-webdriver-automatically-close-alerts)) any unload alerts will now stay open until handled.
  • Note that you also need to set the `:page_load_strategy` to `"none"` for modern selenium-webdriver ≥ 4.27 since those follow the spec more closely than previous versions and respect the document's [readiness state](https://www.w3.org/TR/webdriver-bidi/#type-browsingContext-ReadinessState) for navigation events.
  • If you do not specify a `:page_load_strategy`, selenium-webdriver defaults to `"complete"` which means it will wait for any `beforeunload` to be handled before e.g. a `page.refresh` statement returns. That that this also applies to wrapped calls like `accept_confirm { page.refresh }`.
  • +### Setting `unhandled_prompt_behavior` to a hash
  • +The [W3C spec](https://w3c.github.io/webdriver/#user-prompt-handler) allows setting the `unhandledPromptBehavior` option to a hash. This allows users to specify different behaviors for different types of alerts (e.g. `alert`, `confirm`, `beforeUnload`). Setting the option to a string is still supported, but doesn't affect `beforeUnload` prompts anymore.
  • +
  • +Currently, Selenium [doesn't support setting the `unhandledPromptBehavior` option to a hash](https://github.com/SeleniumHQ/selenium/issues/16159) and converts the option to a string. The following monkey patch is needed:
  • +```rb
  • +module FixUnhandledPromptBehaviorOption
  • + def process_w3c_options(options)
  • + w3c_options = options.select { |key, val| w3c?(key) && !val.nil? }
  • + options.delete_if { |key, _val| w3c?(key) }
  • + w3c_options
  • + end
  • +end
  • +
  • +Selenium::WebDriver::Options.prepend(FixUnhandledPromptBehaviorOption)
  • +```
  • +
  • ## Recommendation
  • We **do not recommend BiDi mode as a default** because it can have a negative impact on other tests.
  • For example, if your application shows unload confirmations for forms with unsaved changes, all tests would have to ensure they explicitly save or discard any changes before a test finishes. Otherwise, when the driver closes the page, an unload dialog appears which cannot be handled.
  • Also, the BiDi driver does not yet implement all features (see <https://wpt.fyi/results/webdriver/tests/bidi>).
  • Instead, specify a BiDi driver and use that driver when testing unload behavior. Example:
  • ```ruby
  • Capybara.register_driver(:with_unload_confirmation) do |app|
  • # ...
  • end
  • ```
  • ```ruby
  • describe 'unsaved changes confirmation dialog', :js, driver: :with_unload_confirmation do
  • # ...
  • end
  • ```
Niklas Hasselmeyer
Last edit
Niklas Hasselmeyer
License
Source code in this card is licensed under the MIT License.
Posted by Niklas Hasselmeyer to makandra dev (2025-08-12 10:25)