From 59f090b16cc9b41d7484337cf66b21ccdcb246fc Mon Sep 17 00:00:00 2001 From: Michael Render Date: Thu, 26 Dec 2024 15:57:39 -0500 Subject: [PATCH] [dotnet] Align WebDriver errors with specification (#14936) --- .../webdriver/Remote/HttpCommandExecutor.cs | 2 +- dotnet/src/webdriver/UnknownErrorException.cs | 51 ++++++++++++ .../src/webdriver/UnknownMethodException.cs | 49 ++++++++++++ .../UnsupportedOperationException.cs | 50 ++++++++++++ dotnet/src/webdriver/WebDriver.cs | 14 +++- dotnet/src/webdriver/WebDriverError.cs | 44 +++-------- dotnet/src/webdriver/WebDriverResult.cs | 79 +++++++++++++------ 7 files changed, 226 insertions(+), 63 deletions(-) create mode 100644 dotnet/src/webdriver/UnknownErrorException.cs create mode 100644 dotnet/src/webdriver/UnknownMethodException.cs create mode 100644 dotnet/src/webdriver/UnsupportedOperationException.cs diff --git a/dotnet/src/webdriver/Remote/HttpCommandExecutor.cs b/dotnet/src/webdriver/Remote/HttpCommandExecutor.cs index a5d60f67e49ff..0686239405e38 100644 --- a/dotnet/src/webdriver/Remote/HttpCommandExecutor.cs +++ b/dotnet/src/webdriver/Remote/HttpCommandExecutor.cs @@ -326,7 +326,7 @@ private Response CreateResponse(HttpResponseInfo responseInfo) } else { - response.Status = WebDriverResult.UnhandledError; + response.Status = WebDriverResult.UnknownError; response.Value = body; } } diff --git a/dotnet/src/webdriver/UnknownErrorException.cs b/dotnet/src/webdriver/UnknownErrorException.cs new file mode 100644 index 0000000000000..466bc19d9c479 --- /dev/null +++ b/dotnet/src/webdriver/UnknownErrorException.cs @@ -0,0 +1,51 @@ +// +// 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; + +#nullable enable + +namespace OpenQA.Selenium +{ + /// + /// An unknown error occurred in the remote end while processing the command. + /// + [Serializable] + public class UnknownErrorException : WebDriverException + { + /// + /// Initializes a new instance of the class with the specified message. + /// + /// The message of the exception. + public UnknownErrorException(string? message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with the specified message and inner exception. + /// + /// The message of the exception. + /// The inner exception for this exception. + public UnknownErrorException(string? message, Exception? innerException) + : base(message, innerException) + { + } + } +} diff --git a/dotnet/src/webdriver/UnknownMethodException.cs b/dotnet/src/webdriver/UnknownMethodException.cs new file mode 100644 index 0000000000000..168fc2dfedbec --- /dev/null +++ b/dotnet/src/webdriver/UnknownMethodException.cs @@ -0,0 +1,49 @@ +// +// 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; + +#nullable enable + +namespace OpenQA.Selenium +{ + /// + /// Exception that is thrown when the requested command matched a known URL but did not match any method for that URL. + /// + [Serializable] + public class UnknownMethodException : WebDriverException + { + /// + /// Initializes a new instance of the class with the specified message. + /// + /// The message of the exception. + public UnknownMethodException(string? message) : base(message) + { + } + + /// + /// Initializes a new instance of the class with the specified message and inner exception. + /// + /// The message of the exception. + /// The inner exception for this exception. + public UnknownMethodException(string? message, Exception? innerException) : base(message, innerException) + { + } + } +} diff --git a/dotnet/src/webdriver/UnsupportedOperationException.cs b/dotnet/src/webdriver/UnsupportedOperationException.cs new file mode 100644 index 0000000000000..a8d104400d6b3 --- /dev/null +++ b/dotnet/src/webdriver/UnsupportedOperationException.cs @@ -0,0 +1,50 @@ +// +// 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; + +#nullable enable + +namespace OpenQA.Selenium +{ + /// + /// Indicates that a command that should have executed properly cannot be supported for some reason. + /// + public class UnsupportedOperationException : WebDriverException + { + /// + /// Initializes a new instance of the class with the specified message. + /// + /// The message of the exception. + public UnsupportedOperationException(string? message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with the specified message and inner exception. + /// + /// The message of the exception. + /// The inner exception for this exception. + public UnsupportedOperationException(string? message, Exception? innerException) + : base(message, innerException) + { + } + } +} diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 672aa83b5b6e6..57d1a2bab91fc 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -622,7 +622,7 @@ protected virtual async Task ExecuteAsync(string driverCommandToExecut { commandResponse = new Response { - Status = WebDriverResult.UnhandledError, + Status = WebDriverResult.UnknownError, Value = e }; } @@ -782,9 +782,6 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command case WebDriverResult.ElementNotSelectable: throw new InvalidElementStateException(errorMessage); - case WebDriverResult.UnhandledError: - throw new WebDriverException(errorMessage); - case WebDriverResult.NoSuchDocument: throw new NoSuchElementException(errorMessage); @@ -854,6 +851,15 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command case WebDriverResult.InsecureCertificate: throw new InsecureCertificateException(errorMessage); + case WebDriverResult.UnknownError: + throw new UnknownErrorException(errorMessage); + + case WebDriverResult.UnknownMethod: + throw new UnknownMethodException(errorMessage); + + case WebDriverResult.UnsupportedOperation: + throw new UnsupportedOperationException(errorMessage); + default: throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", errorMessage, errorResponse.Status)); } diff --git a/dotnet/src/webdriver/WebDriverError.cs b/dotnet/src/webdriver/WebDriverError.cs index e87f8aeae5253..5811d924f53cb 100644 --- a/dotnet/src/webdriver/WebDriverError.cs +++ b/dotnet/src/webdriver/WebDriverError.cs @@ -27,32 +27,16 @@ namespace OpenQA.Selenium /// internal static class WebDriverError { - /// - /// Represents the detached shadow root error. - /// - public const string DetachedShadowRoot = "detached shadow root"; - /// /// Represents the element click intercepted error. /// public const string ElementClickIntercepted = "element click intercepted"; - /// - /// Represents the element not selectable error. - /// - public const string ElementNotSelectable = "element not selectable"; - /// /// Represents the element not interactable error. /// public const string ElementNotInteractable = "element not interactable"; - /// - /// Represents the element not visible error. - /// - /// TODO: Remove this string; it is no longer valid in the specification. - public const string ElementNotVisible = "element not visible"; - /// /// Represents the insecure certificate error. /// @@ -68,17 +52,6 @@ internal static class WebDriverError /// public const string InvalidCookieDomain = "invalid cookie domain"; - /// - /// Represents the invalid coordinates error. - /// - public const string InvalidCoordinates = "invalid coordinates"; - - /// - /// Represents the invalid element coordinates error. - /// - /// TODO: Remove this string; it is no longer valid in the specification. - public const string InvalidElementCoordinates = "invalid element coordinates"; - /// /// Represents the invalid element state error. /// @@ -149,6 +122,11 @@ internal static class WebDriverError /// public const string StaleElementReference = "stale element reference"; + /// + /// Represents the detached shadow root error. + /// + public const string DetachedShadowRoot = "detached shadow root"; + /// /// Represents the timeout error. /// @@ -194,16 +172,11 @@ internal static class WebDriverError static WebDriverError() { resultMap = new Dictionary(); - resultMap[DetachedShadowRoot] = WebDriverResult.DetachedShadowRoot; resultMap[ElementClickIntercepted] = WebDriverResult.ElementClickIntercepted; - resultMap[ElementNotSelectable] = WebDriverResult.ElementNotSelectable; - resultMap[ElementNotVisible] = WebDriverResult.ElementNotDisplayed; resultMap[ElementNotInteractable] = WebDriverResult.ElementNotInteractable; resultMap[InsecureCertificate] = WebDriverResult.InsecureCertificate; resultMap[InvalidArgument] = WebDriverResult.InvalidArgument; resultMap[InvalidCookieDomain] = WebDriverResult.InvalidCookieDomain; - resultMap[InvalidCoordinates] = WebDriverResult.InvalidElementCoordinates; - resultMap[InvalidElementCoordinates] = WebDriverResult.InvalidElementCoordinates; resultMap[InvalidElementState] = WebDriverResult.InvalidElementState; resultMap[InvalidSelector] = WebDriverResult.InvalidSelector; resultMap[InvalidSessionId] = WebDriverResult.NoSuchDriver; @@ -218,14 +191,15 @@ static WebDriverError() resultMap[ScriptTimeout] = WebDriverResult.AsyncScriptTimeout; resultMap[SessionNotCreated] = WebDriverResult.SessionNotCreated; resultMap[StaleElementReference] = WebDriverResult.ObsoleteElement; + resultMap[DetachedShadowRoot] = WebDriverResult.DetachedShadowRoot; resultMap[Timeout] = WebDriverResult.Timeout; resultMap[UnableToSetCookie] = WebDriverResult.UnableToSetCookie; resultMap[UnableToCaptureScreen] = WebDriverResult.UnableToCaptureScreen; resultMap[UnexpectedAlertOpen] = WebDriverResult.UnexpectedAlertOpen; resultMap[UnknownCommand] = WebDriverResult.UnknownCommand; - resultMap[UnknownError] = WebDriverResult.UnhandledError; - resultMap[UnknownMethod] = WebDriverResult.UnknownCommand; - resultMap[UnsupportedOperation] = WebDriverResult.UnhandledError; + resultMap[UnknownError] = WebDriverResult.UnknownError; + resultMap[UnknownMethod] = WebDriverResult.UnknownMethod; + resultMap[UnsupportedOperation] = WebDriverResult.UnsupportedOperation; } /// diff --git a/dotnet/src/webdriver/WebDriverResult.cs b/dotnet/src/webdriver/WebDriverResult.cs index 962c21d4bac76..a18dcce7c6a42 100644 --- a/dotnet/src/webdriver/WebDriverResult.cs +++ b/dotnet/src/webdriver/WebDriverResult.cs @@ -17,6 +17,8 @@ // under the License. // +using System; + namespace OpenQA.Selenium { /// @@ -32,115 +34,134 @@ public enum WebDriverResult /// /// The index specified for the action was out of the acceptable range. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] IndexOutOfBounds = 1, /// /// No collection was specified. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] NoCollection = 2, /// /// No string was specified. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] NoString = 3, /// /// No string length was specified. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] NoStringLength = 4, /// /// No string wrapper was specified. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] NoStringWrapper = 5, /// - /// No driver matching the criteria exists. + /// Occurs if the given session id is not in the list of active sessions, meaning the session either does not exist or that it's not active. /// NoSuchDriver = 6, /// - /// No element matching the criteria exists. + /// An element could not be located on the page using the given search parameters. /// NoSuchElement = 7, /// - /// No frame matching the criteria exists. + /// A command to switch to a frame could not be satisfied because the frame could not be found. /// NoSuchFrame = 8, /// - /// The functionality is not supported. + /// A command could not be executed because the remote end is not aware of it. /// UnknownCommand = 9, /// - /// The specified element is no longer valid. + /// A command failed because the referenced element is no longer attached to the DOM. /// ObsoleteElement = 10, /// /// The specified element is not displayed. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] ElementNotDisplayed = 11, /// - /// The specified element is not enabled. + /// A command could not be completed because the element is in an invalid state, e.g. attempting to clear an element that isn't both editable and resettable. /// InvalidElementState = 12, + /// + /// An unknown error occurred in the remote end while processing the command. + /// + UnknownError = 13, + /// /// An unhandled error occurred. /// - UnhandledError = 13, + [Obsolete("This value is no longer set for unknown errors: use UnknownError instead. Will be removed in 4.30")] + UnhandledError = UnknownError, /// /// An error occurred, but it was expected. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] ExpectedError = 14, /// /// The specified element is not selected. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] ElementNotSelectable = 15, /// /// No document matching the criteria exists. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] NoSuchDocument = 16, /// - /// An unexpected JavaScript error occurred. + /// An error occurred while executing JavaScript supplied by the user. /// UnexpectedJavaScriptError = 17, /// /// No result is available from the JavaScript execution. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] NoScriptResult = 18, /// /// The result from the JavaScript execution is not recognized. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] XPathLookupError = 19, /// /// No collection matching the criteria exists. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] NoSuchCollection = 20, /// - /// A timeout occurred. + /// An operation did not complete before its timeout expired. /// Timeout = 21, /// /// A null pointer was received. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] NullPointer = 22, /// - /// No window matching the criteria exists. + /// A command to switch to a window could not be satisfied because the window could not be found. /// NoSuchWindow = 23, @@ -150,77 +171,79 @@ public enum WebDriverResult InvalidCookieDomain = 24, /// - /// A request to set a cookie's value could not be satisfied. + /// A command to set a cookie's value could not be satisfied. /// UnableToSetCookie = 25, /// - /// An alert was found open unexpectedly. + /// A modal dialog was open, blocking this operation. /// UnexpectedAlertOpen = 26, /// - /// A request was made to switch to an alert, but no alert is currently open. + /// An attempt was made to operate on a modal dialog when one was not open. /// NoAlertPresent = 27, /// - /// An asynchronous JavaScript execution timed out. + /// A script did not complete before its timeout expired. /// AsyncScriptTimeout = 28, /// /// The coordinates of the element are invalid. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] InvalidElementCoordinates = 29, /// - /// The selector used (CSS/XPath) was invalid. + /// Argument was an invalid selector. /// InvalidSelector = 32, /// - /// A session was not created by the driver + /// A new session could not be created. /// SessionNotCreated = 33, /// - /// The requested move was outside the active view port + /// The target for mouse interaction is not in the browser's viewport and cannot be brought into that viewport. /// MoveTargetOutOfBounds = 34, /// /// The XPath selector was invalid. /// + [Obsolete("This error status is no longer returned by the WebDriver Specification https://www.w3.org/TR/webdriver2/#errors. Will be removed in 4.30")] InvalidXPathSelector = 51, /// - /// An insecure SSl certificate was specified. + /// Navigation caused the user agent to hit a certificate warning, which is usually the result of an expired or invalid TLS certificate. /// InsecureCertificate = 59, /// - /// The element was not interactable + /// A command could not be completed because the element is not pointer- or keyboard interactable. /// ElementNotInteractable = 60, /// - /// An invalid argument was passed to the command. + /// The arguments passed to a command are either invalid or malformed. /// InvalidArgument = 61, /// - /// No cookie was found matching the name requested. + /// No cookie matching the given path name was found amongst the associated cookies of session's current browsing context's active document. /// NoSuchCookie = 62, /// - /// The driver was unable to capture the screen. + /// A screen capture was made impossible. /// UnableToCaptureScreen = 63, /// - /// The click on the element was intercepted by a different element. + /// The Element Click command could not be completed because the element receiving the events is obscuring the element that was requested clicked. /// ElementClickIntercepted = 64, @@ -233,5 +256,15 @@ public enum WebDriverResult /// The referenced shadow root is no longer attached to the DOM. /// DetachedShadowRoot = 66, + + /// + /// The requested command matched a known URL but did not match any method for that URL. + /// + UnknownMethod = 67, + + /// + /// Indicates that a command that should have executed properly cannot be supported for some reason. + /// + UnsupportedOperation = 68, } }