diff --git a/dotnet/src/webdriver/DriverOptions.cs b/dotnet/src/webdriver/DriverOptions.cs index 483ceb03130a4..84942ea73b22f 100644 --- a/dotnet/src/webdriver/DriverOptions.cs +++ b/dotnet/src/webdriver/DriverOptions.cs @@ -26,44 +26,6 @@ namespace OpenQA.Selenium; -/// -/// Specifies the behavior of handling unexpected alerts in the IE driver. -/// -public enum UnhandledPromptBehavior -{ - /// - /// Indicates the behavior is not set. - /// - Default, - - /// - /// Ignore unexpected alerts, such that the user must handle them. - /// - Ignore, - - /// - /// Accept unexpected alerts. - /// - Accept, - - /// - /// Dismiss unexpected alerts. - /// - Dismiss, - - /// - /// Accepts unexpected alerts and notifies the user that the alert has - /// been accepted by throwing an - /// - AcceptAndNotify, - - /// - /// Dismisses unexpected alerts and notifies the user that the alert has - /// been dismissed by throwing an - /// - DismissAndNotify -} - /// /// Specifies the behavior of waiting for page loads in the driver. /// @@ -164,7 +126,7 @@ protected DriverOptions() /// Gets or sets the value for describing how unexpected alerts are to be handled in the browser. /// Defaults to . /// - public UnhandledPromptBehavior UnhandledPromptBehavior { get; set; } = UnhandledPromptBehavior.Default; + public UnhandledPromptBehaviorOption? UnhandledPromptBehavior { get; set; } = Selenium.UnhandledPromptBehavior.Default; /// /// Gets or sets the value for describing how the browser is to wait for pages to load in the browser. @@ -303,7 +265,7 @@ public virtual DriverOptionsMergeResult GetMergeResult(DriverOptions other) return result; } - if (this.UnhandledPromptBehavior != UnhandledPromptBehavior.Default && other.UnhandledPromptBehavior != UnhandledPromptBehavior.Default) + if (this.UnhandledPromptBehavior != other.UnhandledPromptBehavior) { result.IsMergeConflict = true; result.MergeConflictOptionName = "UnhandledPromptBehavior"; @@ -508,29 +470,11 @@ protected IWritableCapabilities GenerateDesiredCapabilities(bool isSpecification capabilities.SetCapability(CapabilityType.PageLoadStrategy, pageLoadStrategySetting); } - if (this.UnhandledPromptBehavior != UnhandledPromptBehavior.Default) - { - string unhandledPropmtBehaviorSetting = "ignore"; - switch (this.UnhandledPromptBehavior) - { - case UnhandledPromptBehavior.Accept: - unhandledPropmtBehaviorSetting = "accept"; - break; + var unhandledPromptBehaviorCapability = this.UnhandledPromptBehavior?.ToCapabilities(); - case UnhandledPromptBehavior.Dismiss: - unhandledPropmtBehaviorSetting = "dismiss"; - break; - - case UnhandledPromptBehavior.AcceptAndNotify: - unhandledPropmtBehaviorSetting = "accept and notify"; - break; - - case UnhandledPromptBehavior.DismissAndNotify: - unhandledPropmtBehaviorSetting = "dismiss and notify"; - break; - } - - capabilities.SetCapability(CapabilityType.UnhandledPromptBehavior, unhandledPropmtBehaviorSetting); + if (unhandledPromptBehaviorCapability != null) + { + capabilities.SetCapability(CapabilityType.UnhandledPromptBehavior, unhandledPromptBehaviorCapability); } if (this.Proxy != null) diff --git a/dotnet/src/webdriver/UnhandledPromptBehaviorOption.cs b/dotnet/src/webdriver/UnhandledPromptBehaviorOption.cs new file mode 100644 index 0000000000000..29e0768fab934 --- /dev/null +++ b/dotnet/src/webdriver/UnhandledPromptBehaviorOption.cs @@ -0,0 +1,214 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System; +using System.Collections.Generic; + +namespace OpenQA.Selenium; + +/// +/// Represents a configuration option that determines how unhandled prompts are managed during automated browser +/// interactions. +/// +/// +/// Use this type to specify whether a single unhandled prompt behavior or multiple behaviors should be applied. +/// The static methods provide convenient ways to create either a single-behavior or multi-behavior option. +/// This abstraction is typically used in scenarios where browser automation frameworks need to control the handling of +/// unexpected dialogs or prompts. +/// +/// Available options: +/// +/// - Wraps a single value applied to all prompt types. Create via the implicit conversion from or by calling . +/// - Allows configuring per-prompt behaviors (Alert, Confirm, Prompt, BeforeUnload, Default). Create via . +/// +/// +/// +public abstract record UnhandledPromptBehaviorOption +{ + /// + /// Converts a value of type to an instance. + /// + /// The value to convert. + public static implicit operator UnhandledPromptBehaviorOption(UnhandledPromptBehavior value) + => Single(value); + + /// + /// Creates an representing a single value. + /// + /// The to apply for all prompt types. + /// An wrapping the provided behavior. + public static UnhandledPromptBehaviorSingleOption Single(UnhandledPromptBehavior value) + => new(value); + + /// + /// Creates an allowing individual values per prompt type. + /// + /// An with per-prompt configurable behaviors. + public static UnhandledPromptBehaviorMultiOption Multi() + => new(); + + internal abstract object? ToCapabilities(); + + internal static string ConvertBehaviorToString(UnhandledPromptBehavior behavior) => + behavior switch + { + UnhandledPromptBehavior.Ignore => "ignore", + UnhandledPromptBehavior.Accept => "accept", + UnhandledPromptBehavior.Dismiss => "dismiss", + UnhandledPromptBehavior.AcceptAndNotify => "accept and notify", + UnhandledPromptBehavior.DismissAndNotify => "dismiss and notify", + _ => throw new ArgumentOutOfRangeException(nameof(behavior), $"UnhandledPromptBehavior value '{behavior}' is not recognized."), + }; +} + +/// +/// Represents an option that specifies a single unhandled prompt behavior to use when interacting with browser dialogs. +/// +/// The unhandled prompt behavior to apply. Specifies how unexpected browser prompts are handled during automation. +public sealed record UnhandledPromptBehaviorSingleOption(UnhandledPromptBehavior Value) : UnhandledPromptBehaviorOption +{ + internal override object? ToCapabilities() + { + if (Value == UnhandledPromptBehavior.Default) + { + return null; + } + + return ConvertBehaviorToString(Value); + } +} + +/// +/// Represents a set of options that specify how unhandled browser prompts are handled for different prompt types. +/// +/// Use this class to configure distinct behaviors for alert, confirm, prompt, and beforeunload dialogs +/// encountered during browser automation. Each property allows you to control the response to a specific type of +/// unhandled prompt, enabling fine-grained handling beyond a single global setting. +public sealed record UnhandledPromptBehaviorMultiOption : UnhandledPromptBehaviorOption +{ + /// + /// Gets or sets the behavior to use when an unexpected alert is encountered during automation. + /// + public UnhandledPromptBehavior Alert { get; set; } = UnhandledPromptBehavior.Default; + + /// + /// Gets or sets the behavior to use when a confirmation prompt is encountered. + /// + /// Set this property to specify how the system should respond to confirmation dialogs, such as + /// JavaScript confirm boxes, during automated operations. The default value is , which applies the standard handling defined by the + /// environment. + public UnhandledPromptBehavior Confirm { get; set; } = UnhandledPromptBehavior.Default; + + /// + /// Gets or sets the behavior to use when an unexpected prompt is encountered during automation. + /// + /// Set this property to control how the system responds to unhandled prompts, such as alerts or + /// confirmation dialogs, that appear unexpectedly. The default behavior is determined by the value of + /// . + public UnhandledPromptBehavior Prompt { get; set; } = UnhandledPromptBehavior.Default; + + /// + /// Gets or sets the behavior to use when an unexpected beforeunload dialog is encountered. + /// + /// Use this property to specify how the application should respond to beforeunload dialogs that + /// appear unexpectedly during automated browser interactions. This setting determines whether such dialogs are + /// automatically accepted, dismissed, or cause an error. + public UnhandledPromptBehavior BeforeUnload { get; set; } = UnhandledPromptBehavior.Default; + + /// + /// Gets or sets the default behavior to use when an unexpected browser prompt is encountered. + /// + public UnhandledPromptBehavior Default { get; set; } = UnhandledPromptBehavior.Default; + + internal override object? ToCapabilities() + { + if (this == new UnhandledPromptBehaviorMultiOption()) + { + return null; + } + + Dictionary capabilities = []; + + if (Alert != default) + { + capabilities["alert"] = ConvertBehaviorToString(Alert); + } + + if (Confirm != default) + { + capabilities["confirm"] = ConvertBehaviorToString(Confirm); + } + + if (Prompt != default) + { + capabilities["prompt"] = ConvertBehaviorToString(Prompt); + } + + if (BeforeUnload != default) + { + capabilities["beforeUnload"] = ConvertBehaviorToString(BeforeUnload); + } + + if (Default != default) + { + capabilities["default"] = ConvertBehaviorToString(Default); + } + + return capabilities; + } +} + +/// +/// Specifies the behavior of handling unexpected alerts in the IE driver. +/// +public enum UnhandledPromptBehavior +{ + /// + /// Indicates the behavior is not set. + /// + Default, + + /// + /// Ignore unexpected alerts, such that the user must handle them. + /// + Ignore, + + /// + /// Accept unexpected alerts. + /// + Accept, + + /// + /// Dismiss unexpected alerts. + /// + Dismiss, + + /// + /// Accepts unexpected alerts and notifies the user that the alert has + /// been accepted by throwing an + /// + AcceptAndNotify, + + /// + /// Dismisses unexpected alerts and notifies the user that the alert has + /// been dismissed by throwing an + /// + DismissAndNotify +} diff --git a/dotnet/test/common/AlertsTest.cs b/dotnet/test/common/AlertsTest.cs index f2255c1964a66..f281b28af4a72 100644 --- a/dotnet/test/common/AlertsTest.cs +++ b/dotnet/test/common/AlertsTest.cs @@ -37,6 +37,22 @@ public void ShouldBeAbleToOverrideTheWindowAlertMethod() driver.FindElement(By.Id("alert")).Click(); } + [Test] + public void ShouldBeAbleToDismissTheWindowAlert() + { + using var driver = EnvironmentManager.Instance.CreateDriverInstance(new CustomAlertDriverOptions + { + UnhandledPromptBehavior = new UnhandledPromptBehaviorMultiOption { Default = UnhandledPromptBehavior.Dismiss } + }); + + driver.Url = CreateAlertPage("cheese"); + + driver.FindElement(By.Id("alert")).Click(); + + // If we can perform any action again, we're good to go + driver.FindElement(By.Id("alert")).Click(); + } + [Test] public void ShouldAllowUsersToAcceptAnAlertManually() { @@ -559,4 +575,16 @@ private Func WindowHandleCountToBe(int count) }; } + class CustomAlertDriverOptions : DriverOptions + { + public CustomAlertDriverOptions() + { + + } + + public override ICapabilities ToCapabilities() + { + return null; + } + } }