From 13d222af257ea1747e7c1fca34b683118c8f838b Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 4 Feb 2025 00:59:50 -0500 Subject: [PATCH 01/12] [dotnet] Increment `WebDriver` towards nullability --- dotnet/src/webdriver/WebDriver.cs | 332 ++++++++++++++---------------- 1 file changed, 158 insertions(+), 174 deletions(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index b5e8d5b6437b5..f8f99396c3e45 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -39,9 +39,6 @@ public class WebDriver : IWebDriver, ISearchContext, IJavaScriptExecutor, IFinds /// The default command timeout for HTTP requests in a RemoteWebDriver instance. /// protected static readonly TimeSpan DefaultCommandTimeout = TimeSpan.FromSeconds(60); - - private ICommandExecutor executor; - private ICapabilities capabilities; private IFileDetector fileDetector = new DefaultFileDetector(); private NetworkManager network; private WebElementFactory elementFactory; @@ -52,10 +49,10 @@ public class WebDriver : IWebDriver, ISearchContext, IJavaScriptExecutor, IFinds /// Initializes a new instance of the class. /// /// The object used to execute commands. - /// The object used to configuer the driver session. + /// The object used to configure the driver session. protected WebDriver(ICommandExecutor executor, ICapabilities capabilities) { - this.executor = executor; + this.CommandExecutor = executor; try { @@ -79,7 +76,7 @@ protected WebDriver(ICommandExecutor executor, ICapabilities capabilities) this.network = new NetworkManager(this); this.registeredCommands.AddRange(DriverCommand.KnownCommands); - if ((this as ISupportsLogs) != null) + if (this is ISupportsLogs) { // Only add the legacy log commands if the driver supports // retrieving the logs via the extension end points. @@ -91,18 +88,12 @@ protected WebDriver(ICommandExecutor executor, ICapabilities capabilities) /// /// Gets the which executes commands for this driver. /// - public ICommandExecutor CommandExecutor - { - get { return this.executor; } - } + public ICommandExecutor CommandExecutor { get; } /// /// Gets the that the driver session was created with, which may be different from those requested. /// - public ICapabilities Capabilities - { - get { return this.capabilities; } - } + public ICapabilities Capabilities { get; private set; } /// /// Gets or sets the URL the browser is currently displaying. @@ -129,7 +120,8 @@ public string Title get { Response commandResponse = this.Execute(DriverCommand.GetTitle, null); - object returnedTitle = commandResponse != null ? commandResponse.Value : string.Empty; + object returnedTitle = commandResponse?.Value ?? string.Empty; + return returnedTitle.ToString(); } } @@ -142,10 +134,9 @@ public string PageSource { get { - string pageSource = string.Empty; Response commandResponse = this.Execute(DriverCommand.GetPageSource, null); - pageSource = commandResponse.Value.ToString(); - return pageSource; + + return commandResponse.Value.ToString(); } } @@ -158,6 +149,7 @@ public string CurrentWindowHandle get { Response commandResponse = this.Execute(DriverCommand.GetCurrentWindowHandle, null); + return commandResponse.Value.ToString(); } } @@ -171,7 +163,7 @@ public ReadOnlyCollection WindowHandles { Response commandResponse = this.Execute(DriverCommand.GetWindowHandles, null); object[] handles = (object[])commandResponse.Value; - List handleList = new List(); + List handleList = new List(handles.Length); foreach (object handle in handles) { handleList.Add(handle.ToString()); @@ -184,10 +176,7 @@ public ReadOnlyCollection WindowHandles /// /// Gets a value indicating whether this object is a valid action executor. /// - public bool IsActionExecutor - { - get { return true; } - } + public bool IsActionExecutor => true; /// /// Gets the for the current session of this driver. @@ -198,22 +187,11 @@ public bool IsActionExecutor /// Gets or sets the responsible for detecting /// sequences of keystrokes representing file paths and names. /// + /// If value is set to . public virtual IFileDetector FileDetector { - get - { - return this.fileDetector; - } - - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value), "FileDetector cannot be null"); - } - - this.fileDetector = value; - } + get => this.fileDetector; + set => this.fileDetector = value ?? throw new ArgumentNullException(nameof(value), "FileDetector cannot be null"); } internal INetwork Network @@ -225,10 +203,11 @@ internal INetwork Network /// Gets or sets the factory object used to create instances of /// or its subclasses. /// + /// If value is set to . protected WebElementFactory ElementFactory { - get { return this.elementFactory; } - set { this.elementFactory = value; } + get => this.elementFactory; + set => this.elementFactory = value ?? throw new ArgumentNullException(nameof(value)); } /// @@ -321,7 +300,9 @@ public virtual IWebElement FindElement(string mechanism, string value) Dictionary parameters = new Dictionary(); parameters.Add("using", mechanism); parameters.Add("value", value); + Response commandResponse = this.Execute(DriverCommand.FindElement, parameters); + return this.GetElementFromResponse(commandResponse); } @@ -357,7 +338,9 @@ public virtual ReadOnlyCollection FindElements(string mechanism, st Dictionary parameters = new Dictionary(); parameters.Add("using", mechanism); parameters.Add("value", value); + Response commandResponse = this.Execute(DriverCommand.FindElements, parameters); + return this.GetElementsFromResponse(commandResponse); } @@ -368,6 +351,7 @@ public virtual ReadOnlyCollection FindElements(string mechanism, st public Screenshot GetScreenshot() { Response screenshotResponse = this.Execute(DriverCommand.Screenshot, null); + string base64 = screenshotResponse.Value.ToString(); return new Screenshot(base64); } @@ -386,6 +370,7 @@ public PrintDocument Print(PrintOptions printOptions) } Response commandResponse = this.Execute(DriverCommand.Print, printOptions.ToDictionary()); + string base64 = commandResponse.Value.ToString(); return new PrintDocument(base64); } @@ -409,9 +394,12 @@ public void PerformActions(IList actionSequenceList) Dictionary parameters = new Dictionary(); parameters["actions"] = objectList; + this.Execute(DriverCommand.Actions, parameters); } +#nullable enable + /// /// Resets the input state of the action executor. /// @@ -463,8 +451,6 @@ public INavigation Navigate() return new Navigator(this); } -#nullable enable - /// /// Executes a command with this driver. /// @@ -527,28 +513,25 @@ internal bool RegisterDriverCommand(string commandName, [NotNullWhen(true)] Comm return false; } -#nullable restore - /// /// Find the element in the response /// /// Response from the browser - /// Element from the page - internal IWebElement GetElementFromResponse(Response response) + /// Element from the page, or if the response does not contain a dictionary. + /// If is . + internal IWebElement? GetElementFromResponse(Response response) { if (response == null) { throw new NoSuchElementException(); } - WebElement element = null; - Dictionary elementDictionary = response.Value as Dictionary; - if (elementDictionary != null) + if (response.Value is Dictionary elementDictionary) { - element = this.elementFactory.CreateElement(elementDictionary); + return this.elementFactory.CreateElement(elementDictionary); } - return element; + return null; } /// @@ -559,13 +542,11 @@ internal IWebElement GetElementFromResponse(Response response) internal ReadOnlyCollection GetElementsFromResponse(Response response) { List toReturn = new List(); - object[] elements = response.Value as object[]; - if (elements != null) + if (response.Value is object?[] elements) { - foreach (object elementObject in elements) + foreach (object? elementObject in elements) { - Dictionary elementDictionary = elementObject as Dictionary; - if (elementDictionary != null) + if (elementObject is Dictionary elementDictionary) { WebElement element = this.elementFactory.CreateElement(elementDictionary); toReturn.Add(element); @@ -576,6 +557,8 @@ internal ReadOnlyCollection GetElementsFromResponse(Response respon return toReturn.AsReadOnly(); } +#nullable restore + /// /// Executes commands with the driver /// @@ -621,7 +604,7 @@ protected virtual async Task ExecuteAsync(string driverCommandToExecut { Command commandToExecute = new Command(SessionId, driverCommandToExecute, parameters); - Response commandResponse = await this.executor.ExecuteAsync(commandToExecute).ConfigureAwait(false); + Response commandResponse = await this.CommandExecutor.ExecuteAsync(commandToExecute).ConfigureAwait(false); if (commandResponse.Status != WebDriverResult.Success) { @@ -636,6 +619,7 @@ protected virtual async Task ExecuteAsync(string driverCommandToExecut /// /// Capabilities of the browser [MemberNotNull(nameof(SessionId))] + [MemberNotNull(nameof(Capabilities))] protected void StartSession(ICapabilities capabilities) { Dictionary parameters = new Dictionary(); @@ -645,8 +629,7 @@ protected void StartSession(ICapabilities capabilities) // and end nodes are compliant with the W3C WebDriver Specification, // and therefore will already contain all of the appropriate values // for establishing a session. - RemoteSessionSettings remoteSettings = capabilities as RemoteSessionSettings; - if (remoteSettings == null) + if (capabilities is not RemoteSessionSettings remoteSettings) { Dictionary matchCapabilities = this.GetCapabilitiesDictionary(capabilities); @@ -665,15 +648,13 @@ protected void StartSession(ICapabilities capabilities) Response response = this.Execute(DriverCommand.NewSession, parameters); - Dictionary rawCapabilities = response.Value as Dictionary; - if (rawCapabilities == null) + if (response.Value is not Dictionary rawCapabilities) { string errorMessage = string.Format(CultureInfo.InvariantCulture, "The new session command returned a value ('{0}') that is not a valid JSON object.", response.Value); throw new WebDriverException(errorMessage); } - ReturnedCapabilities returnedCapabilities = new ReturnedCapabilities(rawCapabilities); - this.capabilities = returnedCapabilities; + this.Capabilities = new ReturnedCapabilities(rawCapabilities); string sessionId = response.SessionId ?? throw new WebDriverException($"The remote end did not respond with ID of a session when it was required. {response.Value}"); this.SessionId = new SessionId(sessionId); @@ -686,11 +667,17 @@ protected void StartSession(ICapabilities capabilities) /// A Dictionary consisting of the capabilities requested. /// This method is only transitional. Do not rely on it. It will be removed /// once browser driver capability formats stabilize. + /// If is . protected virtual Dictionary GetCapabilitiesDictionary(ICapabilities capabilitiesToConvert) { + if (capabilitiesToConvert is null) + { + throw new ArgumentNullException(nameof(capabilitiesToConvert)); + } + Dictionary capabilitiesDictionary = new Dictionary(); - IHasCapabilitiesDictionary capabilitiesObject = capabilitiesToConvert as IHasCapabilitiesDictionary; - foreach (KeyValuePair entry in capabilitiesObject.CapabilitiesDictionary) + + foreach (KeyValuePair entry in ((IHasCapabilitiesDictionary)capabilitiesToConvert).CapabilitiesDictionary) { if (CapabilityType.IsSpecCompliantCapabilityName(entry.Key)) { @@ -740,140 +727,144 @@ protected virtual void Dispose(bool disposing) } finally { - this.SessionId = null; + this.SessionId = null!; } - this.executor.Dispose(); + + this.CommandExecutor.Dispose(); } +#nullable enable + private static void UnpackAndThrowOnError(Response errorResponse, string commandToExecute) { // Check the status code of the error, and only handle if not success. - if (errorResponse.Status != WebDriverResult.Success) + if (errorResponse.Status == WebDriverResult.Success) { - Dictionary errorAsDictionary = errorResponse.Value as Dictionary; - if (errorAsDictionary != null) - { - ErrorResponse errorResponseObject = new ErrorResponse(errorAsDictionary); - string errorMessage = errorResponseObject.Message; - switch (errorResponse.Status) - { - case WebDriverResult.NoSuchElement: - throw new NoSuchElementException(errorMessage); + return; + } - case WebDriverResult.NoSuchFrame: - throw new NoSuchFrameException(errorMessage); + if (errorResponse.Value is not Dictionary errorAsDictionary) + { + throw new WebDriverException($"The {commandToExecute} command returned an unexpected error. {errorResponse.Value}"); + } - case WebDriverResult.UnknownCommand: - throw new NotImplementedException(errorMessage); + ErrorResponse errorResponseObject = new ErrorResponse(errorAsDictionary); + string errorMessage = errorResponseObject.Message; + switch (errorResponse.Status) + { + case WebDriverResult.NoSuchElement: + throw new NoSuchElementException(errorMessage); - case WebDriverResult.ObsoleteElement: - throw new StaleElementReferenceException(errorMessage); + case WebDriverResult.NoSuchFrame: + throw new NoSuchFrameException(errorMessage); - case WebDriverResult.ElementClickIntercepted: - throw new ElementClickInterceptedException(errorMessage); + case WebDriverResult.UnknownCommand: + throw new NotImplementedException(errorMessage); - case WebDriverResult.ElementNotInteractable: - throw new ElementNotInteractableException(errorMessage); + case WebDriverResult.ObsoleteElement: + throw new StaleElementReferenceException(errorMessage); - case WebDriverResult.ElementNotDisplayed: - throw new ElementNotVisibleException(errorMessage); + case WebDriverResult.ElementClickIntercepted: + throw new ElementClickInterceptedException(errorMessage); - case WebDriverResult.InvalidElementState: - case WebDriverResult.ElementNotSelectable: - throw new InvalidElementStateException(errorMessage); + case WebDriverResult.ElementNotInteractable: + throw new ElementNotInteractableException(errorMessage); - case WebDriverResult.NoSuchDocument: - throw new NoSuchElementException(errorMessage); + case WebDriverResult.ElementNotDisplayed: + throw new ElementNotVisibleException(errorMessage); - case WebDriverResult.Timeout: - throw new WebDriverTimeoutException(errorMessage); + case WebDriverResult.InvalidElementState: + case WebDriverResult.ElementNotSelectable: + throw new InvalidElementStateException(errorMessage); - case WebDriverResult.NoSuchWindow: - throw new NoSuchWindowException(errorMessage); + case WebDriverResult.NoSuchDocument: + throw new NoSuchElementException(errorMessage); - case WebDriverResult.InvalidCookieDomain: - throw new InvalidCookieDomainException(errorMessage); + case WebDriverResult.Timeout: + throw new WebDriverTimeoutException(errorMessage); - case WebDriverResult.UnableToSetCookie: - throw new UnableToSetCookieException(errorMessage); + case WebDriverResult.NoSuchWindow: + throw new NoSuchWindowException(errorMessage); - case WebDriverResult.AsyncScriptTimeout: - throw new WebDriverTimeoutException(errorMessage); + case WebDriverResult.InvalidCookieDomain: + throw new InvalidCookieDomainException(errorMessage); - case WebDriverResult.UnexpectedAlertOpen: - // TODO(JimEvans): Handle the case where the unexpected alert setting - // has been set to "ignore", so there is still a valid alert to be - // handled. - string alertText = string.Empty; - if (errorAsDictionary.ContainsKey("alert")) - { - Dictionary alertDescription = errorAsDictionary["alert"] as Dictionary; - if (alertDescription != null && alertDescription.ContainsKey("text")) - { - alertText = alertDescription["text"].ToString(); - } - } - else if (errorAsDictionary.ContainsKey("data")) - { - Dictionary alertData = errorAsDictionary["data"] as Dictionary; - if (alertData != null && alertData.ContainsKey("text")) - { - alertText = alertData["text"].ToString(); - } - } + case WebDriverResult.UnableToSetCookie: + throw new UnableToSetCookieException(errorMessage); - throw new UnhandledAlertException(errorMessage, alertText); + case WebDriverResult.AsyncScriptTimeout: + throw new WebDriverTimeoutException(errorMessage); - case WebDriverResult.NoAlertPresent: - throw new NoAlertPresentException(errorMessage); + case WebDriverResult.UnexpectedAlertOpen: + // TODO(JimEvans): Handle the case where the unexpected alert setting + // has been set to "ignore", so there is still a valid alert to be + // handled. + string? alertText = null; + if (errorAsDictionary.TryGetValue("alert", out object? alert)) + { + if (alert is Dictionary alertDescription + && alertDescription.TryGetValue("text", out object? text)) + { + alertText = text?.ToString(); + } + } + else if (errorAsDictionary.TryGetValue("data", out object? data)) + { + if (data is Dictionary alertData + && alertData.TryGetValue("text", out object? dataText)) + { + alertText = dataText?.ToString(); + } + } - case WebDriverResult.InvalidSelector: - throw new InvalidSelectorException(errorMessage); + throw new UnhandledAlertException(errorMessage, alertText ?? string.Empty); - case WebDriverResult.NoSuchDriver: - throw new WebDriverException(errorMessage); + case WebDriverResult.NoAlertPresent: + throw new NoAlertPresentException(errorMessage); - case WebDriverResult.InvalidArgument: - throw new WebDriverArgumentException(errorMessage); + case WebDriverResult.InvalidSelector: + throw new InvalidSelectorException(errorMessage); - case WebDriverResult.UnexpectedJavaScriptError: - throw new JavaScriptException(errorMessage); + case WebDriverResult.NoSuchDriver: + throw new WebDriverException(errorMessage); - case WebDriverResult.MoveTargetOutOfBounds: - throw new MoveTargetOutOfBoundsException(errorMessage); + case WebDriverResult.InvalidArgument: + throw new WebDriverArgumentException(errorMessage); - case WebDriverResult.NoSuchShadowRoot: - throw new NoSuchShadowRootException(errorMessage); + case WebDriverResult.UnexpectedJavaScriptError: + throw new JavaScriptException(errorMessage); - case WebDriverResult.DetachedShadowRoot: - throw new DetachedShadowRootException(errorMessage); + case WebDriverResult.MoveTargetOutOfBounds: + throw new MoveTargetOutOfBoundsException(errorMessage); - case WebDriverResult.InsecureCertificate: - throw new InsecureCertificateException(errorMessage); + case WebDriverResult.NoSuchShadowRoot: + throw new NoSuchShadowRootException(errorMessage); - case WebDriverResult.UnknownError: - throw new UnknownErrorException(errorMessage); + case WebDriverResult.DetachedShadowRoot: + throw new DetachedShadowRootException(errorMessage); - case WebDriverResult.UnknownMethod: - throw new UnknownMethodException(errorMessage); + case WebDriverResult.InsecureCertificate: + throw new InsecureCertificateException(errorMessage); - case WebDriverResult.UnsupportedOperation: - throw new UnsupportedOperationException(errorMessage); + case WebDriverResult.UnknownError: + throw new UnknownErrorException(errorMessage); - case WebDriverResult.NoSuchCookie: - throw new NoSuchCookieException(errorMessage); + case WebDriverResult.UnknownMethod: + throw new UnknownMethodException(errorMessage); - default: - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", errorMessage, errorResponse.Status)); - } - } - else - { - throw new WebDriverException("The " + commandToExecute + " command returned an unexpected error. " + errorResponse.Value.ToString()); - } + case WebDriverResult.UnsupportedOperation: + throw new UnsupportedOperationException(errorMessage); + + case WebDriverResult.NoSuchCookie: + throw new NoSuchCookieException(errorMessage); + + default: + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", errorMessage, errorResponse.Status)); } } +#nullable restore + /// /// Executes JavaScript in the context of the currently selected frame or window using a specific command. /// @@ -903,17 +894,14 @@ protected object ExecuteScriptCommand(string script, string commandName, params private static object ConvertObjectToJavaScriptObject(object arg) { - IWrapsElement argAsWrapsElement = arg as IWrapsElement; IWebDriverObjectReference argAsObjectReference = arg as IWebDriverObjectReference; - IEnumerable argAsEnumerable = arg as IEnumerable; - IDictionary argAsDictionary = arg as IDictionary; - if (argAsObjectReference == null && argAsWrapsElement != null) + if (argAsObjectReference == null && arg is IWrapsElement argAsWrapsElement) { argAsObjectReference = argAsWrapsElement.WrappedElement as IWebDriverObjectReference; } - object converted = null; + object converted; if (arg is string || arg is float || arg is double || arg is int || arg is long || arg is bool || arg == null) { @@ -924,7 +912,7 @@ private static object ConvertObjectToJavaScriptObject(object arg) Dictionary webDriverObjectReferenceDictionary = argAsObjectReference.ToDictionary(); converted = webDriverObjectReferenceDictionary; } - else if (argAsDictionary != null) + else if (arg is IDictionary argAsDictionary) { // Note that we must check for the argument being a dictionary before // checking for IEnumerable, since dictionaries also implement IEnumerable. @@ -938,7 +926,7 @@ private static object ConvertObjectToJavaScriptObject(object arg) converted = dictionary; } - else if (argAsEnumerable != null) + else if (arg is IEnumerable argAsEnumerable) { List objectList = new List(); foreach (object item in argAsEnumerable) @@ -978,12 +966,9 @@ private static object[] ConvertArgumentsToJavaScriptObjects(object[] args) private object ParseJavaScriptReturnValue(object responseValue) { - object returnValue = null; - - Dictionary resultAsDictionary = responseValue as Dictionary; - object[] resultAsArray = responseValue as object[]; + object returnValue; - if (resultAsDictionary != null) + if (responseValue is Dictionary resultAsDictionary) { if (this.elementFactory.ContainsElementReference(resultAsDictionary)) { @@ -1006,15 +991,14 @@ private object ParseJavaScriptReturnValue(object responseValue) returnValue = resultAsDictionary; } } - else if (resultAsArray != null) + else if (responseValue is object[] resultAsArray) { bool allElementsAreWebElements = true; List toReturn = new List(); foreach (object item in resultAsArray) { object parsedItem = this.ParseJavaScriptReturnValue(item); - IWebElement parsedItemAsElement = parsedItem as IWebElement; - if (parsedItemAsElement == null) + if (parsedItem is not IWebElement parsedItemAsElement) { allElementsAreWebElements = false; } From bfa00b37d6f7e6962b9b28a6ef5f3eefcadf9e60 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 4 Feb 2025 01:03:06 -0500 Subject: [PATCH 02/12] minimize some diffs with error throwing --- dotnet/src/webdriver/WebDriver.cs | 172 +++++++++++++++--------------- 1 file changed, 85 insertions(+), 87 deletions(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index f8f99396c3e45..0abb4f439d96e 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -738,128 +738,126 @@ protected virtual void Dispose(bool disposing) private static void UnpackAndThrowOnError(Response errorResponse, string commandToExecute) { // Check the status code of the error, and only handle if not success. - if (errorResponse.Status == WebDriverResult.Success) + if (errorResponse.Status != WebDriverResult.Success) { - return; - } - - if (errorResponse.Value is not Dictionary errorAsDictionary) - { - throw new WebDriverException($"The {commandToExecute} command returned an unexpected error. {errorResponse.Value}"); - } + if (errorResponse.Value is not Dictionary errorAsDictionary) + { + throw new WebDriverException($"The {commandToExecute} command returned an unexpected error. {errorResponse.Value}"); + } - ErrorResponse errorResponseObject = new ErrorResponse(errorAsDictionary); - string errorMessage = errorResponseObject.Message; - switch (errorResponse.Status) - { - case WebDriverResult.NoSuchElement: - throw new NoSuchElementException(errorMessage); + ErrorResponse errorResponseObject = new ErrorResponse(errorAsDictionary); + string errorMessage = errorResponseObject.Message; + switch (errorResponse.Status) + { + case WebDriverResult.NoSuchElement: + throw new NoSuchElementException(errorMessage); - case WebDriverResult.NoSuchFrame: - throw new NoSuchFrameException(errorMessage); + case WebDriverResult.NoSuchFrame: + throw new NoSuchFrameException(errorMessage); - case WebDriverResult.UnknownCommand: - throw new NotImplementedException(errorMessage); + case WebDriverResult.UnknownCommand: + throw new NotImplementedException(errorMessage); - case WebDriverResult.ObsoleteElement: - throw new StaleElementReferenceException(errorMessage); + case WebDriverResult.ObsoleteElement: + throw new StaleElementReferenceException(errorMessage); - case WebDriverResult.ElementClickIntercepted: - throw new ElementClickInterceptedException(errorMessage); + case WebDriverResult.ElementClickIntercepted: + throw new ElementClickInterceptedException(errorMessage); - case WebDriverResult.ElementNotInteractable: - throw new ElementNotInteractableException(errorMessage); + case WebDriverResult.ElementNotInteractable: + throw new ElementNotInteractableException(errorMessage); - case WebDriverResult.ElementNotDisplayed: - throw new ElementNotVisibleException(errorMessage); + case WebDriverResult.ElementNotDisplayed: + throw new ElementNotVisibleException(errorMessage); - case WebDriverResult.InvalidElementState: - case WebDriverResult.ElementNotSelectable: - throw new InvalidElementStateException(errorMessage); + case WebDriverResult.InvalidElementState: + case WebDriverResult.ElementNotSelectable: + throw new InvalidElementStateException(errorMessage); - case WebDriverResult.NoSuchDocument: - throw new NoSuchElementException(errorMessage); + case WebDriverResult.NoSuchDocument: + throw new NoSuchElementException(errorMessage); - case WebDriverResult.Timeout: - throw new WebDriverTimeoutException(errorMessage); + case WebDriverResult.Timeout: + throw new WebDriverTimeoutException(errorMessage); - case WebDriverResult.NoSuchWindow: - throw new NoSuchWindowException(errorMessage); + case WebDriverResult.NoSuchWindow: + throw new NoSuchWindowException(errorMessage); - case WebDriverResult.InvalidCookieDomain: - throw new InvalidCookieDomainException(errorMessage); + case WebDriverResult.InvalidCookieDomain: + throw new InvalidCookieDomainException(errorMessage); - case WebDriverResult.UnableToSetCookie: - throw new UnableToSetCookieException(errorMessage); + case WebDriverResult.UnableToSetCookie: + throw new UnableToSetCookieException(errorMessage); - case WebDriverResult.AsyncScriptTimeout: - throw new WebDriverTimeoutException(errorMessage); + case WebDriverResult.AsyncScriptTimeout: + throw new WebDriverTimeoutException(errorMessage); - case WebDriverResult.UnexpectedAlertOpen: - // TODO(JimEvans): Handle the case where the unexpected alert setting - // has been set to "ignore", so there is still a valid alert to be - // handled. - string? alertText = null; - if (errorAsDictionary.TryGetValue("alert", out object? alert)) - { - if (alert is Dictionary alertDescription - && alertDescription.TryGetValue("text", out object? text)) + case WebDriverResult.UnexpectedAlertOpen: + // TODO(JimEvans): Handle the case where the unexpected alert setting + // has been set to "ignore", so there is still a valid alert to be + // handled. + string? alertText = null; + if (errorAsDictionary.TryGetValue("alert", out object? alert)) { - alertText = text?.ToString(); + if (alert is Dictionary alertDescription + && alertDescription.TryGetValue("text", out object? text)) + { + alertText = text?.ToString(); + } } - } - else if (errorAsDictionary.TryGetValue("data", out object? data)) - { - if (data is Dictionary alertData - && alertData.TryGetValue("text", out object? dataText)) + else if (errorAsDictionary.TryGetValue("data", out object? data)) { - alertText = dataText?.ToString(); + if (data is Dictionary alertData + && alertData.TryGetValue("text", out object? dataText)) + { + alertText = dataText?.ToString(); + } } - } - throw new UnhandledAlertException(errorMessage, alertText ?? string.Empty); + throw new UnhandledAlertException(errorMessage, alertText ?? string.Empty); - case WebDriverResult.NoAlertPresent: - throw new NoAlertPresentException(errorMessage); + case WebDriverResult.NoAlertPresent: + throw new NoAlertPresentException(errorMessage); - case WebDriverResult.InvalidSelector: - throw new InvalidSelectorException(errorMessage); + case WebDriverResult.InvalidSelector: + throw new InvalidSelectorException(errorMessage); - case WebDriverResult.NoSuchDriver: - throw new WebDriverException(errorMessage); + case WebDriverResult.NoSuchDriver: + throw new WebDriverException(errorMessage); - case WebDriverResult.InvalidArgument: - throw new WebDriverArgumentException(errorMessage); + case WebDriverResult.InvalidArgument: + throw new WebDriverArgumentException(errorMessage); - case WebDriverResult.UnexpectedJavaScriptError: - throw new JavaScriptException(errorMessage); + case WebDriverResult.UnexpectedJavaScriptError: + throw new JavaScriptException(errorMessage); - case WebDriverResult.MoveTargetOutOfBounds: - throw new MoveTargetOutOfBoundsException(errorMessage); + case WebDriverResult.MoveTargetOutOfBounds: + throw new MoveTargetOutOfBoundsException(errorMessage); - case WebDriverResult.NoSuchShadowRoot: - throw new NoSuchShadowRootException(errorMessage); + case WebDriverResult.NoSuchShadowRoot: + throw new NoSuchShadowRootException(errorMessage); - case WebDriverResult.DetachedShadowRoot: - throw new DetachedShadowRootException(errorMessage); + case WebDriverResult.DetachedShadowRoot: + throw new DetachedShadowRootException(errorMessage); - case WebDriverResult.InsecureCertificate: - throw new InsecureCertificateException(errorMessage); + case WebDriverResult.InsecureCertificate: + throw new InsecureCertificateException(errorMessage); - case WebDriverResult.UnknownError: - throw new UnknownErrorException(errorMessage); + case WebDriverResult.UnknownError: + throw new UnknownErrorException(errorMessage); - case WebDriverResult.UnknownMethod: - throw new UnknownMethodException(errorMessage); + case WebDriverResult.UnknownMethod: + throw new UnknownMethodException(errorMessage); - case WebDriverResult.UnsupportedOperation: - throw new UnsupportedOperationException(errorMessage); + case WebDriverResult.UnsupportedOperation: + throw new UnsupportedOperationException(errorMessage); - case WebDriverResult.NoSuchCookie: - throw new NoSuchCookieException(errorMessage); + case WebDriverResult.NoSuchCookie: + throw new NoSuchCookieException(errorMessage); - default: - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", errorMessage, errorResponse.Status)); + default: + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", errorMessage, errorResponse.Status)); + } } } From a7ace95bbf84a55593a6e63076667840cef6f42c Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 4 Feb 2025 01:03:48 -0500 Subject: [PATCH 03/12] further minimize some diffs with error throwing --- dotnet/src/webdriver/WebDriver.cs | 166 +++++++++++++++--------------- 1 file changed, 83 insertions(+), 83 deletions(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 0abb4f439d96e..300ef59c139a1 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -740,124 +740,124 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command // Check the status code of the error, and only handle if not success. if (errorResponse.Status != WebDriverResult.Success) { - if (errorResponse.Value is not Dictionary errorAsDictionary) + if (errorResponse.Value is Dictionary errorAsDictionary) { - throw new WebDriverException($"The {commandToExecute} command returned an unexpected error. {errorResponse.Value}"); - } - - ErrorResponse errorResponseObject = new ErrorResponse(errorAsDictionary); - string errorMessage = errorResponseObject.Message; - switch (errorResponse.Status) - { - case WebDriverResult.NoSuchElement: - throw new NoSuchElementException(errorMessage); + ErrorResponse errorResponseObject = new ErrorResponse(errorAsDictionary); + string errorMessage = errorResponseObject.Message; + switch (errorResponse.Status) + { + case WebDriverResult.NoSuchElement: + throw new NoSuchElementException(errorMessage); - case WebDriverResult.NoSuchFrame: - throw new NoSuchFrameException(errorMessage); + case WebDriverResult.NoSuchFrame: + throw new NoSuchFrameException(errorMessage); - case WebDriverResult.UnknownCommand: - throw new NotImplementedException(errorMessage); + case WebDriverResult.UnknownCommand: + throw new NotImplementedException(errorMessage); - case WebDriverResult.ObsoleteElement: - throw new StaleElementReferenceException(errorMessage); + case WebDriverResult.ObsoleteElement: + throw new StaleElementReferenceException(errorMessage); - case WebDriverResult.ElementClickIntercepted: - throw new ElementClickInterceptedException(errorMessage); + case WebDriverResult.ElementClickIntercepted: + throw new ElementClickInterceptedException(errorMessage); - case WebDriverResult.ElementNotInteractable: - throw new ElementNotInteractableException(errorMessage); + case WebDriverResult.ElementNotInteractable: + throw new ElementNotInteractableException(errorMessage); - case WebDriverResult.ElementNotDisplayed: - throw new ElementNotVisibleException(errorMessage); + case WebDriverResult.ElementNotDisplayed: + throw new ElementNotVisibleException(errorMessage); - case WebDriverResult.InvalidElementState: - case WebDriverResult.ElementNotSelectable: - throw new InvalidElementStateException(errorMessage); + case WebDriverResult.InvalidElementState: + case WebDriverResult.ElementNotSelectable: + throw new InvalidElementStateException(errorMessage); - case WebDriverResult.NoSuchDocument: - throw new NoSuchElementException(errorMessage); + case WebDriverResult.NoSuchDocument: + throw new NoSuchElementException(errorMessage); - case WebDriverResult.Timeout: - throw new WebDriverTimeoutException(errorMessage); + case WebDriverResult.Timeout: + throw new WebDriverTimeoutException(errorMessage); - case WebDriverResult.NoSuchWindow: - throw new NoSuchWindowException(errorMessage); + case WebDriverResult.NoSuchWindow: + throw new NoSuchWindowException(errorMessage); - case WebDriverResult.InvalidCookieDomain: - throw new InvalidCookieDomainException(errorMessage); + case WebDriverResult.InvalidCookieDomain: + throw new InvalidCookieDomainException(errorMessage); - case WebDriverResult.UnableToSetCookie: - throw new UnableToSetCookieException(errorMessage); + case WebDriverResult.UnableToSetCookie: + throw new UnableToSetCookieException(errorMessage); - case WebDriverResult.AsyncScriptTimeout: - throw new WebDriverTimeoutException(errorMessage); + case WebDriverResult.AsyncScriptTimeout: + throw new WebDriverTimeoutException(errorMessage); - case WebDriverResult.UnexpectedAlertOpen: - // TODO(JimEvans): Handle the case where the unexpected alert setting - // has been set to "ignore", so there is still a valid alert to be - // handled. - string? alertText = null; - if (errorAsDictionary.TryGetValue("alert", out object? alert)) - { - if (alert is Dictionary alertDescription - && alertDescription.TryGetValue("text", out object? text)) + case WebDriverResult.UnexpectedAlertOpen: + // TODO(JimEvans): Handle the case where the unexpected alert setting + // has been set to "ignore", so there is still a valid alert to be + // handled. + string? alertText = null; + if (errorAsDictionary.TryGetValue("alert", out object? alert)) { - alertText = text?.ToString(); + if (alert is Dictionary alertDescription + && alertDescription.TryGetValue("text", out object? text)) + { + alertText = text?.ToString(); + } } - } - else if (errorAsDictionary.TryGetValue("data", out object? data)) - { - if (data is Dictionary alertData - && alertData.TryGetValue("text", out object? dataText)) + else if (errorAsDictionary.TryGetValue("data", out object? data)) { - alertText = dataText?.ToString(); + if (data is Dictionary alertData + && alertData.TryGetValue("text", out object? dataText)) + { + alertText = dataText?.ToString(); + } } - } - throw new UnhandledAlertException(errorMessage, alertText ?? string.Empty); + throw new UnhandledAlertException(errorMessage, alertText ?? string.Empty); - case WebDriverResult.NoAlertPresent: - throw new NoAlertPresentException(errorMessage); + case WebDriverResult.NoAlertPresent: + throw new NoAlertPresentException(errorMessage); - case WebDriverResult.InvalidSelector: - throw new InvalidSelectorException(errorMessage); + case WebDriverResult.InvalidSelector: + throw new InvalidSelectorException(errorMessage); - case WebDriverResult.NoSuchDriver: - throw new WebDriverException(errorMessage); + case WebDriverResult.NoSuchDriver: + throw new WebDriverException(errorMessage); - case WebDriverResult.InvalidArgument: - throw new WebDriverArgumentException(errorMessage); + case WebDriverResult.InvalidArgument: + throw new WebDriverArgumentException(errorMessage); - case WebDriverResult.UnexpectedJavaScriptError: - throw new JavaScriptException(errorMessage); + case WebDriverResult.UnexpectedJavaScriptError: + throw new JavaScriptException(errorMessage); - case WebDriverResult.MoveTargetOutOfBounds: - throw new MoveTargetOutOfBoundsException(errorMessage); + case WebDriverResult.MoveTargetOutOfBounds: + throw new MoveTargetOutOfBoundsException(errorMessage); - case WebDriverResult.NoSuchShadowRoot: - throw new NoSuchShadowRootException(errorMessage); + case WebDriverResult.NoSuchShadowRoot: + throw new NoSuchShadowRootException(errorMessage); - case WebDriverResult.DetachedShadowRoot: - throw new DetachedShadowRootException(errorMessage); + case WebDriverResult.DetachedShadowRoot: + throw new DetachedShadowRootException(errorMessage); - case WebDriverResult.InsecureCertificate: - throw new InsecureCertificateException(errorMessage); + case WebDriverResult.InsecureCertificate: + throw new InsecureCertificateException(errorMessage); - case WebDriverResult.UnknownError: - throw new UnknownErrorException(errorMessage); + case WebDriverResult.UnknownError: + throw new UnknownErrorException(errorMessage); - case WebDriverResult.UnknownMethod: - throw new UnknownMethodException(errorMessage); + case WebDriverResult.UnknownMethod: + throw new UnknownMethodException(errorMessage); - case WebDriverResult.UnsupportedOperation: - throw new UnsupportedOperationException(errorMessage); + case WebDriverResult.UnsupportedOperation: + throw new UnsupportedOperationException(errorMessage); - case WebDriverResult.NoSuchCookie: - throw new NoSuchCookieException(errorMessage); + case WebDriverResult.NoSuchCookie: + throw new NoSuchCookieException(errorMessage); - default: - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", errorMessage, errorResponse.Status)); + default: + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", errorMessage, errorResponse.Status)); + } } + + throw new WebDriverException($"The {commandToExecute} command returned an unexpected error. {errorResponse.Value}"); } } From 43012fdb679726ad20bb23e14302c846c857ea85 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 4 Feb 2025 01:53:55 -0500 Subject: [PATCH 04/12] Annotate more of `WebDriver`, leaving only the commands where we need to read the spec for --- dotnet/src/webdriver/WebDriver.cs | 106 ++++++++++++++---------------- 1 file changed, 51 insertions(+), 55 deletions(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 300ef59c139a1..1d5cc325badd7 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -183,6 +183,8 @@ public ReadOnlyCollection WindowHandles /// public SessionId SessionId { get; private set; } +#nullable enable + /// /// Gets or sets the responsible for detecting /// sequences of keystrokes representing file paths and names. @@ -194,10 +196,7 @@ public virtual IFileDetector FileDetector set => this.fileDetector = value ?? throw new ArgumentNullException(nameof(value), "FileDetector cannot be null"); } - internal INetwork Network - { - get { return this.network; } - } + internal INetwork Network => this.network; /// /// Gets or sets the factory object used to create instances of @@ -234,7 +233,7 @@ public void Dispose() /// The JavaScript code to execute. /// The arguments to the script. /// The value returned by the script. - public object ExecuteAsyncScript(string script, params object[] args) + public object? ExecuteAsyncScript(string script, params object?[]? args) { return this.ExecuteScriptCommand(script, DriverCommand.ExecuteAsyncScript, args); } @@ -245,7 +244,7 @@ public object ExecuteAsyncScript(string script, params object[] args) /// The JavaScript code to execute. /// The arguments to the script. /// The value returned by the script. - public object ExecuteScript(string script, params object[] args) + public object? ExecuteScript(string script, params object?[]? args) { return this.ExecuteScriptCommand(script, DriverCommand.ExecuteScript, args); } @@ -257,7 +256,7 @@ public object ExecuteScript(string script, params object[] args) /// The arguments to the script. /// The value returned by the script. /// If is . - public object ExecuteScript(PinnedScript script, params object[] args) + public object? ExecuteScript(PinnedScript script, params object?[]? args) { if (script == null) { @@ -267,6 +266,8 @@ public object ExecuteScript(PinnedScript script, params object[] args) return this.ExecuteScript(script.MakeExecutionScript(), args); } +#nullable restore + /// /// Finds the first element in the page that matches the object /// @@ -344,6 +345,8 @@ public virtual ReadOnlyCollection FindElements(string mechanism, st return this.GetElementsFromResponse(commandResponse); } +#nullable enable + /// /// Gets a object representing the image of the page on the screen. /// @@ -352,7 +355,7 @@ public Screenshot GetScreenshot() { Response screenshotResponse = this.Execute(DriverCommand.Screenshot, null); - string base64 = screenshotResponse.Value.ToString(); + string base64 = screenshotResponse.Value?.ToString() ?? throw new WebDriverException("Screenshot command returned successfully, but response was empty"); return new Screenshot(base64); } @@ -371,7 +374,7 @@ public PrintDocument Print(PrintOptions printOptions) Response commandResponse = this.Execute(DriverCommand.Print, printOptions.ToDictionary()); - string base64 = commandResponse.Value.ToString(); + string base64 = commandResponse.Value?.ToString() ?? throw new WebDriverException("Print command returned successfully, but response was empty"); return new PrintDocument(base64); } @@ -392,14 +395,12 @@ public void PerformActions(IList actionSequenceList) objectList.Add(sequence.ToDictionary()); } - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters["actions"] = objectList; this.Execute(DriverCommand.Actions, parameters); } -#nullable enable - /// /// Resets the input state of the action executor. /// @@ -458,7 +459,7 @@ public INavigation Navigate() /// A containing the names and values of the parameters of the command. /// A containing information about the success or failure of the command and any data returned by the command. /// The command returned an exceptional value. - public object? ExecuteCustomDriverCommand(string driverCommandToExecute, Dictionary parameters) + public object? ExecuteCustomDriverCommand(string driverCommandToExecute, Dictionary? parameters) { if (this.registeredCommands.Contains(driverCommandToExecute)) { @@ -526,7 +527,7 @@ internal bool RegisterDriverCommand(string commandName, [NotNullWhen(true)] Comm throw new NoSuchElementException(); } - if (response.Value is Dictionary elementDictionary) + if (response.Value is Dictionary elementDictionary) { return this.elementFactory.CreateElement(elementDictionary); } @@ -546,7 +547,7 @@ internal ReadOnlyCollection GetElementsFromResponse(Response respon { foreach (object? elementObject in elements) { - if (elementObject is Dictionary elementDictionary) + if (elementObject is Dictionary elementDictionary) { WebElement element = this.elementFactory.CreateElement(elementDictionary); toReturn.Add(element); @@ -557,15 +558,13 @@ internal ReadOnlyCollection GetElementsFromResponse(Response respon return toReturn.AsReadOnly(); } -#nullable restore - /// /// Executes commands with the driver /// /// Command that needs executing /// Parameters needed for the command /// WebDriver Response - internal Response InternalExecute(string driverCommandToExecute, Dictionary parameters) + internal Response InternalExecute(string driverCommandToExecute, Dictionary? parameters) { return Task.Run(() => this.InternalExecuteAsync(driverCommandToExecute, parameters)).GetAwaiter().GetResult(); } @@ -577,7 +576,7 @@ internal Response InternalExecute(string driverCommandToExecute, DictionaryParameters needed for the command /// A task object representing the asynchronous operation internal Task InternalExecuteAsync(string driverCommandToExecute, - Dictionary parameters) + Dictionary? parameters) { return this.ExecuteAsync(driverCommandToExecute, parameters); } @@ -589,7 +588,7 @@ internal Task InternalExecuteAsync(string driverCommandToExecute, /// A containing the names and values of the parameters of the command. /// A containing information about the success or failure of the command and any data returned by the command. protected virtual Response Execute(string driverCommandToExecute, - Dictionary parameters) + Dictionary? parameters) { return Task.Run(() => this.ExecuteAsync(driverCommandToExecute, parameters)).GetAwaiter().GetResult(); } @@ -600,7 +599,7 @@ protected virtual Response Execute(string driverCommandToExecute, /// A value representing the command to execute. /// A containing the names and values of the parameters of the command. /// A containing information about the success or failure of the command and any data returned by the command. - protected virtual async Task ExecuteAsync(string driverCommandToExecute, Dictionary parameters) + protected virtual async Task ExecuteAsync(string driverCommandToExecute, Dictionary? parameters) { Command commandToExecute = new Command(SessionId, driverCommandToExecute, parameters); @@ -614,6 +613,8 @@ protected virtual async Task ExecuteAsync(string driverCommandToExecut return commandResponse; } +#nullable restore + /// /// Starts a session with the driver /// @@ -861,8 +862,6 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command } } -#nullable restore - /// /// Executes JavaScript in the context of the currently selected frame or window using a specific command. /// @@ -870,11 +869,11 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command /// The name of the command to execute. /// The arguments to the script. /// The value returned by the script. - protected object ExecuteScriptCommand(string script, string commandName, params object[] args) + protected object? ExecuteScriptCommand(string script, string commandName, params object?[]? args) { - object[] convertedArgs = ConvertArgumentsToJavaScriptObjects(args); + object?[] convertedArgs = ConvertArgumentsToJavaScriptObjects(args); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("script", script); if (convertedArgs != null && convertedArgs.Length > 0) @@ -890,16 +889,16 @@ protected object ExecuteScriptCommand(string script, string commandName, params return this.ParseJavaScriptReturnValue(commandResponse.Value); } - private static object ConvertObjectToJavaScriptObject(object arg) + private static object? ConvertObjectToJavaScriptObject(object? arg) { - IWebDriverObjectReference argAsObjectReference = arg as IWebDriverObjectReference; + IWebDriverObjectReference? argAsObjectReference = arg as IWebDriverObjectReference; if (argAsObjectReference == null && arg is IWrapsElement argAsWrapsElement) { argAsObjectReference = argAsWrapsElement.WrappedElement as IWebDriverObjectReference; } - object converted; + object? converted; if (arg is string || arg is float || arg is double || arg is int || arg is long || arg is bool || arg == null) { @@ -916,18 +915,18 @@ private static object ConvertObjectToJavaScriptObject(object arg) // checking for IEnumerable, since dictionaries also implement IEnumerable. // Additionally, JavaScript objects have property names as strings, so all // keys will be converted to strings. - Dictionary dictionary = new Dictionary(); - foreach (var key in argAsDictionary.Keys) + Dictionary dictionary = new Dictionary(); + foreach (DictionaryEntry argEntry in argAsDictionary) { - dictionary.Add(key.ToString(), ConvertObjectToJavaScriptObject(argAsDictionary[key])); + dictionary.Add(argEntry.Key.ToString()!, ConvertObjectToJavaScriptObject(argEntry.Value)); } converted = dictionary; } else if (arg is IEnumerable argAsEnumerable) { - List objectList = new List(); - foreach (object item in argAsEnumerable) + List objectList = new List(); + foreach (object? item in argAsEnumerable) { objectList.Add(ConvertObjectToJavaScriptObject(item)); } @@ -947,11 +946,11 @@ private static object ConvertObjectToJavaScriptObject(object arg) /// /// The arguments. /// The list of the arguments converted to JavaScript objects. - private static object[] ConvertArgumentsToJavaScriptObjects(object[] args) + private static object?[] ConvertArgumentsToJavaScriptObjects(object?[]? args) { if (args == null) { - return new object[] { null }; + return new object?[] { null }; } for (int i = 0; i < args.Length; i++) @@ -962,17 +961,17 @@ private static object[] ConvertArgumentsToJavaScriptObjects(object[] args) return args; } - private object ParseJavaScriptReturnValue(object responseValue) + private object? ParseJavaScriptReturnValue(object? responseValue) { - object returnValue; + object? returnValue; - if (responseValue is Dictionary resultAsDictionary) + if (responseValue is Dictionary resultAsDictionary) { if (this.elementFactory.ContainsElementReference(resultAsDictionary)) { returnValue = this.elementFactory.CreateElement(resultAsDictionary); } - else if (ShadowRoot.TryCreate(this, resultAsDictionary, out ShadowRoot shadowRoot)) + else if (ShadowRoot.TryCreate(this, resultAsDictionary, out ShadowRoot? shadowRoot)) { returnValue = shadowRoot; } @@ -989,13 +988,13 @@ private object ParseJavaScriptReturnValue(object responseValue) returnValue = resultAsDictionary; } } - else if (responseValue is object[] resultAsArray) + else if (responseValue is object?[] resultAsArray) { bool allElementsAreWebElements = true; - List toReturn = new List(); - foreach (object item in resultAsArray) + List toReturn = new List(); + foreach (object? item in resultAsArray) { - object parsedItem = this.ParseJavaScriptReturnValue(item); + object? parsedItem = this.ParseJavaScriptReturnValue(item); if (parsedItem is not IWebElement parsedItemAsElement) { allElementsAreWebElements = false; @@ -1007,10 +1006,9 @@ private object ParseJavaScriptReturnValue(object responseValue) if (toReturn.Count > 0 && allElementsAreWebElements) { List elementList = new List(); - foreach (object listItem in toReturn) + foreach (object? listItem in toReturn) { - IWebElement itemAsElement = listItem as IWebElement; - elementList.Add(itemAsElement); + elementList.Add((IWebElement)listItem!); } returnValue = elementList.AsReadOnly(); @@ -1028,8 +1026,6 @@ private object ParseJavaScriptReturnValue(object responseValue) return returnValue; } -#nullable enable - /// /// Creates a Virtual Authenticator. /// @@ -1061,7 +1057,7 @@ public void RemoveVirtualAuthenticator(string authenticatorId) throw new ArgumentNullException(nameof(authenticatorId)); } - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); this.Execute(DriverCommand.RemoveVirtualAuthenticator, parameters); @@ -1088,7 +1084,7 @@ public void AddCredential(Credential credential) string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(credential.ToDictionary()); + Dictionary parameters = new Dictionary(credential.ToDictionary()); parameters.Add("authenticatorId", authenticatorId); this.Execute(driverCommandToExecute: DriverCommand.AddCredential, parameters); @@ -1103,7 +1099,7 @@ public List GetCredentials() { string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); Response getCredentialsResponse = this.Execute(driverCommandToExecute: DriverCommand.GetCredentials, parameters); @@ -1149,7 +1145,7 @@ public void RemoveCredential(string credentialId) string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); parameters.Add("credentialId", credentialId); @@ -1164,7 +1160,7 @@ public void RemoveAllCredentials() { string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); this.Execute(driverCommandToExecute: DriverCommand.RemoveAllCredentials, parameters); @@ -1178,7 +1174,7 @@ public void SetUserVerified(bool verified) { string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); parameters.Add("isUserVerified", verified); From 4060d7c964a301d580c540756e2cb28d1f7f0f8e Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 4 Feb 2025 01:54:37 -0500 Subject: [PATCH 05/12] fix nullability of adjacent types --- dotnet/src/webdriver/Command.cs | 10 +++++----- dotnet/src/webdriver/ICustomDriverCommandExecutor.cs | 2 +- dotnet/src/webdriver/VirtualAuth/Credential.cs | 4 ++-- .../VirtualAuth/VirtualAuthenticatorOptions.cs | 4 ++-- dotnet/src/webdriver/WebElementFactory.cs | 10 +++++----- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dotnet/src/webdriver/Command.cs b/dotnet/src/webdriver/Command.cs index 1559fe9690f5a..adb5950fbb318 100644 --- a/dotnet/src/webdriver/Command.cs +++ b/dotnet/src/webdriver/Command.cs @@ -55,10 +55,10 @@ public Command(string name, string jsonParameters) /// Session ID the driver is using /// Name of the command /// Parameters for that command - public Command(SessionId? sessionId, string name, Dictionary? parameters) + public Command(SessionId? sessionId, string name, Dictionary? parameters) { this.SessionId = sessionId; - this.Parameters = parameters ?? new Dictionary(); + this.Parameters = parameters ?? new Dictionary(); this.Name = name; } @@ -78,7 +78,7 @@ public Command(SessionId? sessionId, string name, Dictionary? pa /// Gets the parameters of the command /// [JsonPropertyName("parameters")] - public Dictionary Parameters { get; } + public Dictionary Parameters { get; } /// /// Gets the parameters of the command as a JSON-encoded string. @@ -117,9 +117,9 @@ public override string ToString() /// A with a string keys, and an object value. /// If is not a JSON object. /// If is . - private static Dictionary? ConvertParametersFromJson(string value) + private static Dictionary? ConvertParametersFromJson(string value) { - Dictionary? parameters = JsonSerializer.Deserialize>(value, s_jsonSerializerOptions); + Dictionary? parameters = JsonSerializer.Deserialize>(value, s_jsonSerializerOptions); return parameters; } } diff --git a/dotnet/src/webdriver/ICustomDriverCommandExecutor.cs b/dotnet/src/webdriver/ICustomDriverCommandExecutor.cs index 145bb8c66013d..6b849674107ca 100644 --- a/dotnet/src/webdriver/ICustomDriverCommandExecutor.cs +++ b/dotnet/src/webdriver/ICustomDriverCommandExecutor.cs @@ -36,7 +36,7 @@ public interface ICustomDriverCommandExecutor /// A containing the names and values of the parameters of the command. /// An object that contains the value returned by the command, if any. /// The command returned an exceptional value. - object? ExecuteCustomDriverCommand(string driverCommandToExecute, Dictionary parameters); + object? ExecuteCustomDriverCommand(string driverCommandToExecute, Dictionary? parameters); /// /// Registers a set of commands to be executed with this driver instance. diff --git a/dotnet/src/webdriver/VirtualAuth/Credential.cs b/dotnet/src/webdriver/VirtualAuth/Credential.cs index af3e09cc94e41..357f2a4ec6413 100644 --- a/dotnet/src/webdriver/VirtualAuth/Credential.cs +++ b/dotnet/src/webdriver/VirtualAuth/Credential.cs @@ -124,9 +124,9 @@ public static Credential FromDictionary(Dictionary dictionary) /// Serializes this Credential instance to a dictionary. /// /// The dictionary containing the values for this Credential. - public Dictionary ToDictionary() + public Dictionary ToDictionary() { - Dictionary toReturn = new Dictionary(); + Dictionary toReturn = new Dictionary(); toReturn["credentialId"] = Base64UrlEncoder.Encode(this.id); toReturn["isResidentCredential"] = this.IsResidentCredential; diff --git a/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs b/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs index 502d1368f9d0f..80807f240009e 100644 --- a/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs +++ b/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs @@ -172,9 +172,9 @@ public VirtualAuthenticatorOptions SetIsUserVerified(bool isUserVerified) /// Serializes this set of options into a dictionary of key-value pairs. /// /// The dictionary containing the values of this set of options. - public Dictionary ToDictionary() + public Dictionary ToDictionary() { - Dictionary toReturn = new Dictionary(); + Dictionary toReturn = new Dictionary(); toReturn["protocol"] = this.protocol; toReturn["transport"] = this.transport; diff --git a/dotnet/src/webdriver/WebElementFactory.cs b/dotnet/src/webdriver/WebElementFactory.cs index eb6428354e121..80ff907ebdc2f 100644 --- a/dotnet/src/webdriver/WebElementFactory.cs +++ b/dotnet/src/webdriver/WebElementFactory.cs @@ -49,7 +49,7 @@ public WebElementFactory(WebDriver parentDriver) /// /// The dictionary containing the element reference. /// A containing the information from the specified dictionary. - public virtual WebElement CreateElement(Dictionary elementDictionary) + public virtual WebElement CreateElement(Dictionary elementDictionary) { string elementId = this.GetElementId(elementDictionary); return new WebElement(this.ParentDriver, elementId); @@ -60,7 +60,7 @@ public virtual WebElement CreateElement(Dictionary elementDictio /// /// The dictionary to check. /// if the dictionary contains an element reference; otherwise, . - public bool ContainsElementReference(Dictionary elementDictionary) + public bool ContainsElementReference(Dictionary elementDictionary) { if (elementDictionary == null) { @@ -78,7 +78,7 @@ public bool ContainsElementReference(Dictionary elementDictionar /// If is . /// If the dictionary does not contain the element reference property name. /// If the element property is or . - public string GetElementId(Dictionary elementDictionary) + public string GetElementId(Dictionary elementDictionary) { if (elementDictionary == null) { @@ -90,13 +90,13 @@ public string GetElementId(Dictionary elementDictionary) throw new ArgumentException("elementDictionary", "The specified dictionary does not contain an element reference"); } - string? elementId = elementIdObj.ToString(); + string? elementId = elementIdObj?.ToString(); if (string.IsNullOrEmpty(elementId)) { throw new InvalidOperationException("The specified element ID is either null or the empty string."); } - return elementId; + return elementId!; } } } From 46cea73eaadd3b5eea235b1512f5fa10ccf41d3a Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 4 Feb 2025 02:23:51 -0500 Subject: [PATCH 06/12] remove changes to Execute --- dotnet/src/webdriver/Command.cs | 10 +++---- .../webdriver/ICustomDriverCommandExecutor.cs | 2 +- .../src/webdriver/VirtualAuth/Credential.cs | 4 +-- .../VirtualAuthenticatorOptions.cs | 4 +-- dotnet/src/webdriver/WebDriver.cs | 26 +++++++++---------- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/dotnet/src/webdriver/Command.cs b/dotnet/src/webdriver/Command.cs index adb5950fbb318..1559fe9690f5a 100644 --- a/dotnet/src/webdriver/Command.cs +++ b/dotnet/src/webdriver/Command.cs @@ -55,10 +55,10 @@ public Command(string name, string jsonParameters) /// Session ID the driver is using /// Name of the command /// Parameters for that command - public Command(SessionId? sessionId, string name, Dictionary? parameters) + public Command(SessionId? sessionId, string name, Dictionary? parameters) { this.SessionId = sessionId; - this.Parameters = parameters ?? new Dictionary(); + this.Parameters = parameters ?? new Dictionary(); this.Name = name; } @@ -78,7 +78,7 @@ public Command(SessionId? sessionId, string name, Dictionary? p /// Gets the parameters of the command /// [JsonPropertyName("parameters")] - public Dictionary Parameters { get; } + public Dictionary Parameters { get; } /// /// Gets the parameters of the command as a JSON-encoded string. @@ -117,9 +117,9 @@ public override string ToString() /// A with a string keys, and an object value. /// If is not a JSON object. /// If is . - private static Dictionary? ConvertParametersFromJson(string value) + private static Dictionary? ConvertParametersFromJson(string value) { - Dictionary? parameters = JsonSerializer.Deserialize>(value, s_jsonSerializerOptions); + Dictionary? parameters = JsonSerializer.Deserialize>(value, s_jsonSerializerOptions); return parameters; } } diff --git a/dotnet/src/webdriver/ICustomDriverCommandExecutor.cs b/dotnet/src/webdriver/ICustomDriverCommandExecutor.cs index 6b849674107ca..145bb8c66013d 100644 --- a/dotnet/src/webdriver/ICustomDriverCommandExecutor.cs +++ b/dotnet/src/webdriver/ICustomDriverCommandExecutor.cs @@ -36,7 +36,7 @@ public interface ICustomDriverCommandExecutor /// A containing the names and values of the parameters of the command. /// An object that contains the value returned by the command, if any. /// The command returned an exceptional value. - object? ExecuteCustomDriverCommand(string driverCommandToExecute, Dictionary? parameters); + object? ExecuteCustomDriverCommand(string driverCommandToExecute, Dictionary parameters); /// /// Registers a set of commands to be executed with this driver instance. diff --git a/dotnet/src/webdriver/VirtualAuth/Credential.cs b/dotnet/src/webdriver/VirtualAuth/Credential.cs index 357f2a4ec6413..af3e09cc94e41 100644 --- a/dotnet/src/webdriver/VirtualAuth/Credential.cs +++ b/dotnet/src/webdriver/VirtualAuth/Credential.cs @@ -124,9 +124,9 @@ public static Credential FromDictionary(Dictionary dictionary) /// Serializes this Credential instance to a dictionary. /// /// The dictionary containing the values for this Credential. - public Dictionary ToDictionary() + public Dictionary ToDictionary() { - Dictionary toReturn = new Dictionary(); + Dictionary toReturn = new Dictionary(); toReturn["credentialId"] = Base64UrlEncoder.Encode(this.id); toReturn["isResidentCredential"] = this.IsResidentCredential; diff --git a/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs b/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs index 80807f240009e..502d1368f9d0f 100644 --- a/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs +++ b/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs @@ -172,9 +172,9 @@ public VirtualAuthenticatorOptions SetIsUserVerified(bool isUserVerified) /// Serializes this set of options into a dictionary of key-value pairs. /// /// The dictionary containing the values of this set of options. - public Dictionary ToDictionary() + public Dictionary ToDictionary() { - Dictionary toReturn = new Dictionary(); + Dictionary toReturn = new Dictionary(); toReturn["protocol"] = this.protocol; toReturn["transport"] = this.transport; diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 1d5cc325badd7..2304bcd98f2bc 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -558,13 +558,15 @@ internal ReadOnlyCollection GetElementsFromResponse(Response respon return toReturn.AsReadOnly(); } +#nullable restore + /// /// Executes commands with the driver /// /// Command that needs executing /// Parameters needed for the command /// WebDriver Response - internal Response InternalExecute(string driverCommandToExecute, Dictionary? parameters) + internal Response InternalExecute(string driverCommandToExecute, Dictionary parameters) { return Task.Run(() => this.InternalExecuteAsync(driverCommandToExecute, parameters)).GetAwaiter().GetResult(); } @@ -576,7 +578,7 @@ internal Response InternalExecute(string driverCommandToExecute, DictionaryParameters needed for the command /// A task object representing the asynchronous operation internal Task InternalExecuteAsync(string driverCommandToExecute, - Dictionary? parameters) + Dictionary parameters) { return this.ExecuteAsync(driverCommandToExecute, parameters); } @@ -588,7 +590,7 @@ internal Task InternalExecuteAsync(string driverCommandToExecute, /// A containing the names and values of the parameters of the command. /// A containing information about the success or failure of the command and any data returned by the command. protected virtual Response Execute(string driverCommandToExecute, - Dictionary? parameters) + Dictionary parameters) { return Task.Run(() => this.ExecuteAsync(driverCommandToExecute, parameters)).GetAwaiter().GetResult(); } @@ -599,7 +601,7 @@ protected virtual Response Execute(string driverCommandToExecute, /// A value representing the command to execute. /// A containing the names and values of the parameters of the command. /// A containing information about the success or failure of the command and any data returned by the command. - protected virtual async Task ExecuteAsync(string driverCommandToExecute, Dictionary? parameters) + protected virtual async Task ExecuteAsync(string driverCommandToExecute, Dictionary parameters) { Command commandToExecute = new Command(SessionId, driverCommandToExecute, parameters); @@ -613,8 +615,6 @@ protected virtual async Task ExecuteAsync(string driverCommandToExecut return commandResponse; } -#nullable restore - /// /// Starts a session with the driver /// @@ -873,7 +873,7 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command { object?[] convertedArgs = ConvertArgumentsToJavaScriptObjects(args); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("script", script); if (convertedArgs != null && convertedArgs.Length > 0) @@ -1057,7 +1057,7 @@ public void RemoveVirtualAuthenticator(string authenticatorId) throw new ArgumentNullException(nameof(authenticatorId)); } - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); this.Execute(DriverCommand.RemoveVirtualAuthenticator, parameters); @@ -1084,7 +1084,7 @@ public void AddCredential(Credential credential) string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(credential.ToDictionary()); + Dictionary parameters = new Dictionary(credential.ToDictionary()); parameters.Add("authenticatorId", authenticatorId); this.Execute(driverCommandToExecute: DriverCommand.AddCredential, parameters); @@ -1099,7 +1099,7 @@ public List GetCredentials() { string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); Response getCredentialsResponse = this.Execute(driverCommandToExecute: DriverCommand.GetCredentials, parameters); @@ -1145,7 +1145,7 @@ public void RemoveCredential(string credentialId) string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); parameters.Add("credentialId", credentialId); @@ -1160,7 +1160,7 @@ public void RemoveAllCredentials() { string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); this.Execute(driverCommandToExecute: DriverCommand.RemoveAllCredentials, parameters); @@ -1174,7 +1174,7 @@ public void SetUserVerified(bool verified) { string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters.Add("authenticatorId", authenticatorId); parameters.Add("isUserVerified", verified); From d460905f8c327f181e345b77fc22db8b66b64ed8 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 4 Feb 2025 02:25:31 -0500 Subject: [PATCH 07/12] remove more --- dotnet/src/webdriver/WebDriver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 2304bcd98f2bc..039430a4263e8 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -459,7 +459,7 @@ public INavigation Navigate() /// A containing the names and values of the parameters of the command. /// A containing information about the success or failure of the command and any data returned by the command. /// The command returned an exceptional value. - public object? ExecuteCustomDriverCommand(string driverCommandToExecute, Dictionary? parameters) + public object? ExecuteCustomDriverCommand(string driverCommandToExecute, Dictionary parameters) { if (this.registeredCommands.Contains(driverCommandToExecute)) { From 02262243e3ee978d0ea786d231e04e7979e4af88 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 4 Feb 2025 02:27:27 -0500 Subject: [PATCH 08/12] revert final change about Execute --- dotnet/src/webdriver/WebDriver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 039430a4263e8..9194e728ffc70 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -395,7 +395,7 @@ public void PerformActions(IList actionSequenceList) objectList.Add(sequence.ToDictionary()); } - Dictionary parameters = new Dictionary(); + Dictionary parameters = new Dictionary(); parameters["actions"] = objectList; this.Execute(DriverCommand.Actions, parameters); From 4c1f3be91a868c4a00d15d8ad87ab77f380812ba Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 4 Feb 2025 13:30:48 -0500 Subject: [PATCH 09/12] Executing null command name throws, document this --- dotnet/src/webdriver/Command.cs | 3 ++- dotnet/src/webdriver/CommandInfoRepository.cs | 1 + dotnet/src/webdriver/WebDriver.cs | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/Command.cs b/dotnet/src/webdriver/Command.cs index 1559fe9690f5a..3a44422a00f84 100644 --- a/dotnet/src/webdriver/Command.cs +++ b/dotnet/src/webdriver/Command.cs @@ -55,11 +55,12 @@ public Command(string name, string jsonParameters) /// Session ID the driver is using /// Name of the command /// Parameters for that command + /// If is . public Command(SessionId? sessionId, string name, Dictionary? parameters) { this.SessionId = sessionId; this.Parameters = parameters ?? new Dictionary(); - this.Name = name; + this.Name = name ?? throw new ArgumentNullException(nameof(name)); } /// diff --git a/dotnet/src/webdriver/CommandInfoRepository.cs b/dotnet/src/webdriver/CommandInfoRepository.cs index fa184c60bda5c..36b19d6ea3b6d 100644 --- a/dotnet/src/webdriver/CommandInfoRepository.cs +++ b/dotnet/src/webdriver/CommandInfoRepository.cs @@ -87,6 +87,7 @@ public bool IsCommandNameDefined(string commandName) /// /// The for which to get the information. /// The for the specified command, or if not found or value is not . + /// If is . public T? GetCommandInfo(string commandName) where T : CommandInfo { T? toReturn = default; diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 9194e728ffc70..ce79d6e25b731 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -566,6 +566,7 @@ internal ReadOnlyCollection GetElementsFromResponse(Response respon /// Command that needs executing /// Parameters needed for the command /// WebDriver Response + /// If is . internal Response InternalExecute(string driverCommandToExecute, Dictionary parameters) { return Task.Run(() => this.InternalExecuteAsync(driverCommandToExecute, parameters)).GetAwaiter().GetResult(); @@ -577,6 +578,7 @@ internal Response InternalExecute(string driverCommandToExecute, DictionaryCommand that needs executing /// Parameters needed for the command /// A task object representing the asynchronous operation + /// If is . internal Task InternalExecuteAsync(string driverCommandToExecute, Dictionary parameters) { @@ -589,6 +591,7 @@ internal Task InternalExecuteAsync(string driverCommandToExecute, /// A value representing the command to execute. /// A containing the names and values of the parameters of the command. /// A containing information about the success or failure of the command and any data returned by the command. + /// If is . protected virtual Response Execute(string driverCommandToExecute, Dictionary parameters) { @@ -601,6 +604,7 @@ protected virtual Response Execute(string driverCommandToExecute, /// A value representing the command to execute. /// A containing the names and values of the parameters of the command. /// A containing information about the success or failure of the command and any data returned by the command. + /// If is . protected virtual async Task ExecuteAsync(string driverCommandToExecute, Dictionary parameters) { Command commandToExecute = new Command(SessionId, driverCommandToExecute, parameters); From b9561da7c243dbc8a6f3b8f20a02349cc7246abf Mon Sep 17 00:00:00 2001 From: Michael Render Date: Wed, 5 Feb 2025 21:52:50 -0500 Subject: [PATCH 10/12] Use new `EnsureValueIsNotNull` helper --- dotnet/src/webdriver/WebDriver.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index ce79d6e25b731..c4c9c48bd1f36 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -106,6 +106,8 @@ public string Url get { Response commandResponse = this.Execute(DriverCommand.GetCurrentUrl, null); + + commandResponse.EnsureValueIsNotNull(); return commandResponse.Value.ToString(); } @@ -136,6 +138,7 @@ public string PageSource { Response commandResponse = this.Execute(DriverCommand.GetPageSource, null); + commandResponse.EnsureValueIsNotNull(); return commandResponse.Value.ToString(); } } @@ -150,6 +153,7 @@ public string CurrentWindowHandle { Response commandResponse = this.Execute(DriverCommand.GetCurrentWindowHandle, null); + commandResponse.EnsureValueIsNotNull(); return commandResponse.Value.ToString(); } } @@ -162,6 +166,8 @@ public ReadOnlyCollection WindowHandles get { Response commandResponse = this.Execute(DriverCommand.GetWindowHandles, null); + + commandResponse.EnsureValueIsNotNull(); object[] handles = (object[])commandResponse.Value; List handleList = new List(handles.Length); foreach (object handle in handles) @@ -355,7 +361,8 @@ public Screenshot GetScreenshot() { Response screenshotResponse = this.Execute(DriverCommand.Screenshot, null); - string base64 = screenshotResponse.Value?.ToString() ?? throw new WebDriverException("Screenshot command returned successfully, but response was empty"); + screenshotResponse.EnsureValueIsNotNull(); + string base64 = screenshotResponse.Value.ToString()!; return new Screenshot(base64); } @@ -374,7 +381,8 @@ public PrintDocument Print(PrintOptions printOptions) Response commandResponse = this.Execute(DriverCommand.Print, printOptions.ToDictionary()); - string base64 = commandResponse.Value?.ToString() ?? throw new WebDriverException("Print command returned successfully, but response was empty"); + commandResponse.EnsureValueIsNotNull(); + string base64 = commandResponse.Value.ToString()!; return new PrintDocument(base64); } @@ -653,6 +661,7 @@ protected void StartSession(ICapabilities capabilities) Response response = this.Execute(DriverCommand.NewSession, parameters); + response.EnsureValueIsNotNull(); if (response.Value is not Dictionary rawCapabilities) { string errorMessage = string.Format(CultureInfo.InvariantCulture, "The new session command returned a value ('{0}') that is not a valid JSON object.", response.Value); @@ -1044,7 +1053,9 @@ public string AddVirtualAuthenticator(VirtualAuthenticatorOptions options) } Response commandResponse = this.Execute(DriverCommand.AddVirtualAuthenticator, options.ToDictionary()); - string id = (string)commandResponse.Value!; + + commandResponse.EnsureValueIsNotNull(); + string id = (string)commandResponse.Value; this.AuthenticatorId = id; return id; } @@ -1108,6 +1119,7 @@ public List GetCredentials() Response getCredentialsResponse = this.Execute(driverCommandToExecute: DriverCommand.GetCredentials, parameters); + getCredentialsResponse.EnsureValueIsNotNull(); if (getCredentialsResponse.Value is not object?[] credentialsList) { throw new WebDriverException($"Get credentials call succeeded, but the response was not a list of credentials: {getCredentialsResponse.Value}"); From eb3dd0ff4d097b6bae2dc29f4926ae135b7744d8 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Thu, 6 Feb 2025 00:04:35 -0500 Subject: [PATCH 11/12] cleanup --- dotnet/src/webdriver/WebDriver.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index c4c9c48bd1f36..c7338a6085131 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -1004,11 +1004,11 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command else if (responseValue is object?[] resultAsArray) { bool allElementsAreWebElements = true; - List toReturn = new List(); + List toReturn = new List(resultAsArray.Length); foreach (object? item in resultAsArray) { object? parsedItem = this.ParseJavaScriptReturnValue(item); - if (parsedItem is not IWebElement parsedItemAsElement) + if (parsedItem is not IWebElement) { allElementsAreWebElements = false; } @@ -1018,7 +1018,7 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command if (toReturn.Count > 0 && allElementsAreWebElements) { - List elementList = new List(); + List elementList = new List(resultAsArray.Length); foreach (object? listItem in toReturn) { elementList.Add((IWebElement)listItem!); From 4f3c8c50ed156c173fdf8fadf834d096e7e79397 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Mon, 10 Feb 2025 13:38:09 -0500 Subject: [PATCH 12/12] `Execute` cannot return `null` --- dotnet/src/webdriver/WebDriver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index c7338a6085131..a0be02f770ea0 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -122,7 +122,7 @@ public string Title get { Response commandResponse = this.Execute(DriverCommand.GetTitle, null); - object returnedTitle = commandResponse?.Value ?? string.Empty; + object returnedTitle = commandResponse.Value ?? string.Empty; return returnedTitle.ToString(); }