Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dotnet] Annotate nullability on more of WebElement #15230

Open
wants to merge 11 commits into
base: trunk
Choose a base branch
from
79 changes: 56 additions & 23 deletions dotnet/src/webdriver/WebElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public class WebElement : IWebElement, IFindsElement, IWrapsDriver, ILocatable,
/// </summary>
public const string ElementReferencePropertyName = "element-6066-11e4-a52e-4f735466cecf";

#nullable enable

private readonly WebDriver driver;

/// <summary>
Expand Down Expand Up @@ -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()!;
}
}

Expand All @@ -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()!;
}
}

Expand Down Expand Up @@ -151,7 +155,11 @@ public virtual Point Location

Response commandResponse = this.Execute(DriverCommand.GetElementRect, parameters);

Dictionary<string, object> rawPoint = (Dictionary<string, object>)commandResponse.Value;
if (commandResponse.Value is not Dictionary<string, object?> 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);
Expand All @@ -171,7 +179,11 @@ public virtual Size Size

Response commandResponse = this.Execute(DriverCommand.GetElementRect, parameters);

Dictionary<string, object> rawSize = (Dictionary<string, object>)commandResponse.Value;
if (commandResponse.Value is not Dictionary<string, object?> 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);
Expand Down Expand Up @@ -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<string, object> rawLocation = (Dictionary<string, object>)scriptResponse;

Expand All @@ -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()!;
}
}

Expand All @@ -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<string, object> parameters = new Dictionary<string, object>();
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
}
}

Expand Down Expand Up @@ -313,11 +328,14 @@ public virtual void Click()
this.Execute(DriverCommand.ClickElement, parameters);
}

#nullable restore

/// <summary>
/// Finds the first <see cref="IWebElement"/> using the given method.
/// </summary>
/// <param name="by">The locating mechanism to use.</param>
/// <returns>The first matching <see cref="IWebElement"/> on the current context.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="by"/> is <see langword="null"/>.</exception>
/// <exception cref="NoSuchElementException">If no element matches the criteria.</exception>
public virtual IWebElement FindElement(By by)
{
Expand All @@ -329,6 +347,8 @@ public virtual IWebElement FindElement(By by)
return by.FindElement(this);
}

#nullable enable

/// <summary>
/// Finds a child element matching the given mechanism and value.
/// </summary>
Expand All @@ -347,6 +367,8 @@ public virtual IWebElement FindElement(string mechanism, string value)
return this.driver.GetElementFromResponse(commandResponse);
}

#nullable restore

/// <summary>
/// Finds all <see cref="IWebElement">IWebElements</see> within the current context
/// using the given mechanism.
Expand All @@ -364,6 +386,8 @@ public virtual ReadOnlyCollection<IWebElement> FindElements(By by)
return by.FindElements(this);
}

#nullable enable

/// <summary>
/// Finds all child elements matching the given mechanism and value.
/// </summary>
Expand Down Expand Up @@ -419,15 +443,14 @@ public virtual ReadOnlyCollection<IWebElement> FindElements(string mechanism, st
/// via JavaScript.
/// </remarks>
/// <exception cref="StaleElementReferenceException">Thrown when the target element is no longer valid in the document DOM.</exception>
public virtual string GetAttribute(string attributeName)
public virtual string? GetAttribute(string attributeName)
{
Response commandResponse = null;
string attributeValue = string.Empty;
Dictionary<string, object> parameters = new Dictionary<string, object>();
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.
Expand All @@ -452,7 +475,7 @@ public virtual string GetAttribute(string attributeName)
/// of an IDL property of the element, either use the <see cref="GetAttribute(string)"/>
/// method or the <see cref="GetDomProperty(string)"/> method.
/// </remarks>
public virtual string GetDomAttribute(string attributeName)
public virtual string? GetDomAttribute(string attributeName)
{
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("id", this.Id);
Expand All @@ -470,7 +493,7 @@ public virtual string GetDomAttribute(string attributeName)
/// <returns>The JavaScript property's current value. Returns a <see langword="null"/> if the
/// value is not set or the property does not exist.</returns>
/// <exception cref="StaleElementReferenceException">Thrown when the target element is no longer valid in the document DOM.</exception>
public virtual string GetDomProperty(string propertyName)
public virtual string? GetDomProperty(string propertyName)
{
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("id", this.Id);
Expand All @@ -493,12 +516,12 @@ public virtual ISearchContext GetShadowRoot()
parameters.Add("id", this.Id);

Response commandResponse = this.Execute(DriverCommand.GetElementShadowRoot, parameters);
if (commandResponse.Value is not Dictionary<string, object> shadowRootDictionary)
if (commandResponse.Value is not Dictionary<string, object?> 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.");
}
Expand All @@ -524,7 +547,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()!;
}

/// <summary>
Expand All @@ -538,7 +563,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);
Expand Down Expand Up @@ -597,7 +624,7 @@ public virtual void SendKeys(string text)
/// <exception cref="StaleElementReferenceException">Thrown when the target element is no longer valid in the document DOM.</exception>
public virtual void Submit()
{
string elementType = this.GetAttribute("type");
string? elementType = this.GetAttribute("type");
if (elementType != null && elementType == "submit")
{
this.Click();
Expand Down Expand Up @@ -641,7 +668,7 @@ public override int GetHashCode()
/// </summary>
/// <param name="obj">Object to compare against</param>
/// <returns>A boolean if it is equal or not</returns>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj is not IWebElement other)
{
Expand Down Expand Up @@ -676,6 +703,8 @@ Dictionary<string, object> IWebDriverObjectReference.ToDictionary()
return elementDictionary;
}

#nullable restore

/// <summary>
/// Executes a command on this element using the specified parameters.
/// </summary>
Expand All @@ -687,6 +716,8 @@ protected virtual Response Execute(string commandToExecute, Dictionary<string, o
return this.driver.InternalExecute(commandToExecute, parameters);
}

#nullable enable

private static string GetAtom(string atomResourceName)
{
string atom = string.Empty;
Expand Down Expand Up @@ -721,7 +752,9 @@ private string UploadFile(string localFile)
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("file", base64zip);
Response response = this.Execute(DriverCommand.UploadFile, parameters);
return response.Value.ToString();

response.EnsureValueIsNotNull();
return response.Value.ToString()!;
}
catch (IOException e)
{
Expand Down
Loading