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

Posted . Visible to the public. Auto-destruct in 15 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
  • ```
Profile picture of Niklas Hasselmeyer
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)