diff --git a/dotnet/src/webdriver/WebElement.cs b/dotnet/src/webdriver/WebElement.cs index 62a85580329d1..8b7c17c8b4b3e 100644 --- a/dotnet/src/webdriver/WebElement.cs +++ b/dotnet/src/webdriver/WebElement.cs @@ -40,6 +40,8 @@ public class WebElement : IWebElement, IFindsElement, IWrapsDriver, ILocatable, /// public const string ElementReferencePropertyName = "element-6066-11e4-a52e-4f735466cecf"; +#nullable enable + private readonly WebDriver driver; /// @@ -77,7 +79,8 @@ public virtual string TagName Response commandResponse = this.Execute(DriverCommand.GetElementTagName, parameters); - return commandResponse.Value.ToString(); + commandResponse.EnsureValueIsNotNull(); + return commandResponse.Value.ToString()!; } } @@ -95,7 +98,8 @@ public virtual string Text Response commandResponse = this.Execute(DriverCommand.GetElementText, parameters); - return commandResponse.Value.ToString(); + commandResponse.EnsureValueIsNotNull(); + return commandResponse.Value.ToString()!; } } @@ -151,7 +155,11 @@ public virtual Point Location Response commandResponse = this.Execute(DriverCommand.GetElementRect, parameters); - Dictionary rawPoint = (Dictionary)commandResponse.Value; + if (commandResponse.Value is not Dictionary rawPoint) + { + throw new WebDriverException($"GetElementRect command was successful, but response was not an object: {commandResponse.Value}"); + } + int x = Convert.ToInt32(rawPoint["x"], CultureInfo.InvariantCulture); int y = Convert.ToInt32(rawPoint["y"], CultureInfo.InvariantCulture); return new Point(x, y); @@ -171,7 +179,11 @@ public virtual Size Size Response commandResponse = this.Execute(DriverCommand.GetElementRect, parameters); - Dictionary rawSize = (Dictionary)commandResponse.Value; + if (commandResponse.Value is not Dictionary rawSize) + { + throw new WebDriverException($"GetElementRect command was successful, but response was not an object: {commandResponse.Value}"); + } + int width = Convert.ToInt32(rawSize["width"], CultureInfo.InvariantCulture); int height = Convert.ToInt32(rawSize["height"], CultureInfo.InvariantCulture); return new Size(width, height); @@ -207,7 +219,7 @@ public virtual Point LocationOnScreenOnceScrolledIntoView { get { - object scriptResponse = this.driver.ExecuteScript("var rect = arguments[0].getBoundingClientRect(); return {'x': rect.left, 'y': rect.top};", this); + object scriptResponse = this.driver.ExecuteScript("var rect = arguments[0].getBoundingClientRect(); return {'x': rect.left, 'y': rect.top};", this)!; Dictionary rawLocation = (Dictionary)scriptResponse; @@ -229,7 +241,8 @@ public virtual string ComputedAccessibleLabel Response commandResponse = this.Execute(DriverCommand.GetComputedAccessibleLabel, parameters); - return commandResponse.Value.ToString(); + commandResponse.EnsureValueIsNotNull(); + return commandResponse.Value.ToString()!; } } @@ -240,16 +253,18 @@ public virtual string ComputedAccessibleRole { get { - // TODO: Returning this as a string is incorrect. The W3C WebDriver Specification - // needs to be updated to more thoroughly document the structure of what is returned - // by this command. Once that is done, a type-safe class will be created, and will - // be returned by this property. Dictionary parameters = new Dictionary(); parameters.Add("id", this.Id); Response commandResponse = this.Execute(DriverCommand.GetComputedAccessibleRole, parameters); +#nullable disable + // TODO: Returning this as a string is incorrect. The W3C WebDriver Specification + // needs to be updated to more thoroughly document the structure of what is returned + // by this command. Once that is done, a type-safe class will be created, and will + // be returned by this property. return commandResponse.Value.ToString(); +#nullable enable } } @@ -312,11 +327,14 @@ public virtual void Click() this.Execute(DriverCommand.ClickElement, parameters); } +#nullable restore + /// /// Finds the first using the given method. /// /// The locating mechanism to use. /// The first matching on the current context. + /// If is . /// If no element matches the criteria. public virtual IWebElement FindElement(By by) { @@ -328,6 +346,8 @@ public virtual IWebElement FindElement(By by) return by.FindElement(this); } +#nullable enable + /// /// Finds a child element matching the given mechanism and value. /// @@ -346,6 +366,8 @@ public virtual IWebElement FindElement(string mechanism, string value) return this.driver.GetElementFromResponse(commandResponse); } +#nullable restore + /// /// Finds all IWebElements within the current context /// using the given mechanism. @@ -363,6 +385,8 @@ public virtual ReadOnlyCollection FindElements(By by) return by.FindElements(this); } +#nullable enable + /// /// Finds all child elements matching the given mechanism and value. /// @@ -418,15 +442,14 @@ public virtual ReadOnlyCollection FindElements(string mechanism, st /// via JavaScript. /// /// Thrown when the target element is no longer valid in the document DOM. - public virtual string GetAttribute(string attributeName) + public virtual string? GetAttribute(string attributeName) { - Response commandResponse = null; - string attributeValue = string.Empty; Dictionary parameters = new Dictionary(); string atom = GetAtom("get-attribute.js"); parameters.Add("script", atom); parameters.Add("args", new object[] { ((IWebDriverObjectReference)this).ToDictionary(), attributeName }); - commandResponse = this.Execute(DriverCommand.ExecuteScript, parameters); + + Response commandResponse = Execute(DriverCommand.ExecuteScript, parameters); // Normalize string values of boolean results as lowercase. @@ -451,7 +474,7 @@ public virtual string GetAttribute(string attributeName) /// of an IDL property of the element, either use the /// method or the method. /// - public virtual string GetDomAttribute(string attributeName) + public virtual string? GetDomAttribute(string attributeName) { Dictionary parameters = new Dictionary(); parameters.Add("id", this.Id); @@ -469,7 +492,7 @@ public virtual string GetDomAttribute(string attributeName) /// The JavaScript property's current value. Returns a if the /// value is not set or the property does not exist. /// Thrown when the target element is no longer valid in the document DOM. - public virtual string GetDomProperty(string propertyName) + public virtual string? GetDomProperty(string propertyName) { Dictionary parameters = new Dictionary(); parameters.Add("id", this.Id); @@ -492,12 +515,12 @@ public virtual ISearchContext GetShadowRoot() parameters.Add("id", this.Id); Response commandResponse = this.Execute(DriverCommand.GetElementShadowRoot, parameters); - if (commandResponse.Value is not Dictionary shadowRootDictionary) + if (commandResponse.Value is not Dictionary shadowRootDictionary) { throw new WebDriverException("Get shadow root command succeeded, but response value does not represent a shadow root."); } - if (!ShadowRoot.TryCreate(this.driver, shadowRootDictionary, out ShadowRoot shadowRoot)) + if (!ShadowRoot.TryCreate(this.driver, shadowRootDictionary, out ShadowRoot? shadowRoot)) { throw new WebDriverException("Get shadow root command succeeded, but response value does not have a shadow root key value."); } @@ -523,7 +546,9 @@ public virtual string GetCssValue(string propertyName) parameters.Add("name", propertyName); Response commandResponse = this.Execute(DriverCommand.GetElementValueOfCssProperty, parameters); - return commandResponse.Value.ToString(); + + commandResponse.EnsureValueIsNotNull(); + return commandResponse.Value.ToString()!; } /// @@ -537,7 +562,9 @@ public virtual Screenshot GetScreenshot() // Get the screenshot as base64. Response screenshotResponse = this.Execute(DriverCommand.ElementScreenshot, parameters); - string base64 = screenshotResponse.Value.ToString(); + + screenshotResponse.EnsureValueIsNotNull(); + string base64 = screenshotResponse.Value.ToString()!; // ... and convert it. return new Screenshot(base64); @@ -595,7 +622,7 @@ public virtual void SendKeys(string text) /// Thrown when the target element is no longer valid in the document DOM. public virtual void Submit() { - string elementType = this.GetAttribute("type"); + string? elementType = this.GetAttribute("type"); if (elementType != null && elementType == "submit") { this.Click(); @@ -639,7 +666,7 @@ public override int GetHashCode() /// /// Object to compare against /// A boolean if it is equal or not - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is not IWebElement other) { @@ -674,6 +701,8 @@ Dictionary IWebDriverObjectReference.ToDictionary() return elementDictionary; } +#nullable restore + /// /// Executes a command on this element using the specified parameters. /// @@ -685,6 +714,8 @@ protected virtual Response Execute(string commandToExecute, Dictionary parameters = new Dictionary(); parameters.Add("file", base64zip); Response response = this.Execute(DriverCommand.UploadFile, parameters); - return response.Value.ToString(); + + response.EnsureValueIsNotNull(); + return response.Value.ToString()!; } catch (IOException e) {