diff --git a/dotnet/src/support/BUILD.bazel b/dotnet/src/support/BUILD.bazel index abf65ed58a889..4f76ce3da5695 100644 --- a/dotnet/src/support/BUILD.bazel +++ b/dotnet/src/support/BUILD.bazel @@ -35,6 +35,8 @@ csharp_library( "UI/*.cs", ]) + [":assembly-info"], out = "WebDriver.Support", + langversion = "12.0", + nullable = "annotations", target_frameworks = [ "netstandard2.0", ], @@ -74,6 +76,8 @@ csharp_library( ]) + [":assembly-info"], out = "WebDriver.Support.StrongNamed", keyfile = "//dotnet:WebDriver.snk", + langversion = "12.0", + nullable = "annotations", target_frameworks = [ "netstandard2.0", ], diff --git a/dotnet/src/support/Events/FindElementEventArgs.cs b/dotnet/src/support/Events/FindElementEventArgs.cs index b618082295b9e..b89e4779acffe 100644 --- a/dotnet/src/support/Events/FindElementEventArgs.cs +++ b/dotnet/src/support/Events/FindElementEventArgs.cs @@ -26,15 +26,12 @@ namespace OpenQA.Selenium.Support.Events /// public class FindElementEventArgs : EventArgs { - private IWebDriver driver; - private IWebElement element; - private By method; - /// /// Initializes a new instance of the class. /// /// The WebDriver instance used in finding elements. - /// The object containing the method used to find elements + /// The object containing the method used to find elements. + /// If or are . public FindElementEventArgs(IWebDriver driver, By method) : this(driver, null, method) { @@ -44,37 +41,29 @@ public FindElementEventArgs(IWebDriver driver, By method) /// Initializes a new instance of the class. /// /// The WebDriver instance used in finding elements. - /// The parent element used as the context for the search. + /// The parent element used as the context for the search, or if none exists. /// The object containing the method used to find elements. - public FindElementEventArgs(IWebDriver driver, IWebElement element, By method) + /// If or are . + public FindElementEventArgs(IWebDriver driver, IWebElement? element, By method) { - this.driver = driver; - this.element = element; - this.method = method; + this.Driver = driver ?? throw new ArgumentNullException(nameof(driver)); + this.Element = element; + this.FindMethod = method ?? throw new ArgumentNullException(nameof(method)); } /// /// Gets the WebDriver instance used in finding elements. /// - public IWebDriver Driver - { - get { return this.driver; } - } + public IWebDriver Driver { get; } /// - /// Gets the parent element used as the context for the search. + /// Gets the parent element used as the context for the search, or if no element is associated. /// - public IWebElement Element - { - get { return this.element; } - } + public IWebElement? Element { get; } /// /// Gets the object containing the method used to find elements. /// - public By FindMethod - { - get { return this.method; } - } + public By FindMethod { get; } } } diff --git a/dotnet/src/support/Events/GetShadowRootEventArgs.cs b/dotnet/src/support/Events/GetShadowRootEventArgs.cs index 9d177ebd82eb9..95c989ef0f7f2 100644 --- a/dotnet/src/support/Events/GetShadowRootEventArgs.cs +++ b/dotnet/src/support/Events/GetShadowRootEventArgs.cs @@ -26,34 +26,26 @@ namespace OpenQA.Selenium.Support.Events /// public class GetShadowRootEventArgs : EventArgs { - private IWebDriver driver; - private ISearchContext searchContext; - /// /// Initializes a new instance of the class. /// /// The WebDriver instance used in the current context. /// The parent searc context used as the context for getting shadow root. + /// If or are . public GetShadowRootEventArgs(IWebDriver driver, ISearchContext searchContext) { - this.driver = driver; - this.searchContext = searchContext; + this.Driver = driver ?? throw new ArgumentNullException(nameof(driver)); + this.SearchContext = searchContext ?? throw new ArgumentNullException(nameof(searchContext)); } /// /// Gets the WebDriver instance used in the current context. /// - public IWebDriver Driver - { - get { return this.driver; } - } + public IWebDriver Driver { get; } /// /// Gets the parent search context used as the context for getting shadow root. /// - public ISearchContext SearchContext - { - get { return this.searchContext; } - } + public ISearchContext SearchContext { get; } } } diff --git a/dotnet/src/support/Events/WebDriverExceptionEventArgs.cs b/dotnet/src/support/Events/WebDriverExceptionEventArgs.cs index 3bebb9a5b5d6e..75aa790caeaf5 100644 --- a/dotnet/src/support/Events/WebDriverExceptionEventArgs.cs +++ b/dotnet/src/support/Events/WebDriverExceptionEventArgs.cs @@ -26,34 +26,26 @@ namespace OpenQA.Selenium.Support.Events /// public class WebDriverExceptionEventArgs : EventArgs { - private Exception thrownException; - private IWebDriver driver; - /// /// Initializes a new instance of the class. /// /// The WebDriver instance throwing the exception. /// The exception thrown by the driver. + /// If or are . public WebDriverExceptionEventArgs(IWebDriver driver, Exception thrownException) { - this.driver = driver; - this.thrownException = thrownException; + this.Driver = driver ?? throw new ArgumentNullException(nameof(driver)); + this.ThrownException = thrownException ?? throw new ArgumentNullException(nameof(thrownException)); } /// /// Gets the exception thrown by the driver. /// - public Exception ThrownException - { - get { return this.thrownException; } - } + public Exception ThrownException { get; } /// - /// Gets the WebDriver instance . + /// Gets the WebDriver instance. /// - public IWebDriver Driver - { - get { return this.driver; } - } + public IWebDriver Driver { get; } } } diff --git a/dotnet/src/support/Events/WebDriverNavigationEventArgs.cs b/dotnet/src/support/Events/WebDriverNavigationEventArgs.cs index 8e7058f58cfab..ce6af33399f2b 100644 --- a/dotnet/src/support/Events/WebDriverNavigationEventArgs.cs +++ b/dotnet/src/support/Events/WebDriverNavigationEventArgs.cs @@ -26,13 +26,11 @@ namespace OpenQA.Selenium.Support.Events /// public class WebDriverNavigationEventArgs : EventArgs { - private string url; - private IWebDriver driver; - /// /// Initializes a new instance of the class. /// /// The WebDriver instance used in navigation. + /// If is . public WebDriverNavigationEventArgs(IWebDriver driver) : this(driver, null) { @@ -42,27 +40,22 @@ public WebDriverNavigationEventArgs(IWebDriver driver) /// Initializes a new instance of the class. /// /// The WebDriver instance used in navigation. - /// The URL navigated to by the driver. - public WebDriverNavigationEventArgs(IWebDriver driver, string url) + /// The URL navigated to by the driver, or if none exists. + /// If is . + public WebDriverNavigationEventArgs(IWebDriver driver, string? url) { - this.url = url; - this.driver = driver; + this.Url = url; + this.Driver = driver ?? throw new ArgumentNullException(nameof(driver)); } /// - /// Gets the URL navigated to by the driver. + /// Gets the URL navigated to by the driver, or if no URL could be determined. /// - public string Url - { - get { return this.url; } - } + public string? Url { get; } /// /// Gets the WebDriver instance used in navigation. /// - public IWebDriver Driver - { - get { return this.driver; } - } + public IWebDriver Driver { get; } } } diff --git a/dotnet/src/support/Events/WebDriverScriptEventArgs.cs b/dotnet/src/support/Events/WebDriverScriptEventArgs.cs index 82f6c3f985a32..2251376293da3 100644 --- a/dotnet/src/support/Events/WebDriverScriptEventArgs.cs +++ b/dotnet/src/support/Events/WebDriverScriptEventArgs.cs @@ -26,34 +26,26 @@ namespace OpenQA.Selenium.Support.Events /// public class WebDriverScriptEventArgs : EventArgs { - private IWebDriver driver; - private string script; - /// /// Initializes a new instance of the class. /// /// The WebDriver instance used to execute the script. /// The script executed by the driver. + /// If or are . public WebDriverScriptEventArgs(IWebDriver driver, string script) { - this.driver = driver; - this.script = script; + this.Driver = driver ?? throw new ArgumentNullException(nameof(driver)); + this.Script = script ?? throw new ArgumentNullException(nameof(script)); } /// /// Gets the WebDriver instance used to execute the script. /// - public IWebDriver Driver - { - get { return this.driver; } - } + public IWebDriver Driver { get; } /// /// Gets the script executed by the driver. /// - public string Script - { - get { return this.script; } - } + public string Script { get; } } } diff --git a/dotnet/src/support/Events/WebElementEventArgs.cs b/dotnet/src/support/Events/WebElementEventArgs.cs index 2dbe482f5b21a..383b3f593f5f3 100644 --- a/dotnet/src/support/Events/WebElementEventArgs.cs +++ b/dotnet/src/support/Events/WebElementEventArgs.cs @@ -26,34 +26,26 @@ namespace OpenQA.Selenium.Support.Events /// public class WebElementEventArgs : EventArgs { - private IWebDriver driver; - private IWebElement element; - /// /// Initializes a new instance of the class. /// /// The WebDriver instance used for the action. /// The element used for the action. + /// If or are . public WebElementEventArgs(IWebDriver driver, IWebElement element) { - this.driver = driver; - this.element = element; + this.Driver = driver ?? throw new ArgumentNullException(nameof(driver)); + this.Element = element ?? throw new ArgumentNullException(nameof(element)); } /// /// Gets the WebDriver instance used for the action. /// - public IWebDriver Driver - { - get { return this.driver; } - } + public IWebDriver Driver { get; } /// /// Gets the element used for the action. /// - public IWebElement Element - { - get { return this.element; } - } + public IWebElement Element { get; } } } diff --git a/dotnet/src/support/Events/WebElementValueEventArgs.cs b/dotnet/src/support/Events/WebElementValueEventArgs.cs index abd45cd90d510..76ef60e0f72d9 100644 --- a/dotnet/src/support/Events/WebElementValueEventArgs.cs +++ b/dotnet/src/support/Events/WebElementValueEventArgs.cs @@ -17,6 +17,8 @@ // under the License. // +using System; + namespace OpenQA.Selenium.Support.Events { /// @@ -30,15 +32,16 @@ public class WebElementValueEventArgs : WebElementEventArgs /// The WebDriver instance used for the action. /// The element used for the action. /// The new value for the element. - public WebElementValueEventArgs(IWebDriver driver, IWebElement element, string value) + /// If or are . + public WebElementValueEventArgs(IWebDriver driver, IWebElement element, string? value) : base(driver, element) { this.Value = value; } /// - /// Gets the Value that is written to the element + /// Gets the Value that is written to the element. /// - public string Value { get; private set; } + public string? Value { get; } } } diff --git a/dotnet/src/support/Extensions/WebDriverExtensions.cs b/dotnet/src/support/Extensions/WebDriverExtensions.cs index 10c0e25ea243c..ab0862b383aab 100644 --- a/dotnet/src/support/Extensions/WebDriverExtensions.cs +++ b/dotnet/src/support/Extensions/WebDriverExtensions.cs @@ -37,25 +37,23 @@ public static class WebDriverExtensions /// indicate that it cannot take screenshots. public static Screenshot TakeScreenshot(this IWebDriver driver) { - ITakesScreenshot screenshotDriver = GetDriverAs(driver); - if (screenshotDriver == null) + ITakesScreenshot? screenshotDriver = GetDriverAs(driver); + if (screenshotDriver is null) { - IHasCapabilities capabilitiesDriver = driver as IHasCapabilities; - if (capabilitiesDriver == null) - { - throw new WebDriverException("Driver does not implement ITakesScreenshot or IHasCapabilities"); - } + IHasCapabilities capabilitiesDriver = driver as IHasCapabilities + ?? throw new WebDriverException("Driver does not implement ITakesScreenshot or IHasCapabilities"); - if (!capabilitiesDriver.Capabilities.HasCapability(CapabilityType.TakesScreenshot) || !(bool)capabilitiesDriver.Capabilities.GetCapability(CapabilityType.TakesScreenshot)) + if (capabilitiesDriver.Capabilities.GetCapability(CapabilityType.TakesScreenshot) is not true) { throw new WebDriverException("Driver capabilities do not support taking screenshots"); } - MethodInfo executeMethod = driver.GetType().GetMethod("Execute", BindingFlags.Instance | BindingFlags.NonPublic); - Response screenshotResponse = executeMethod.Invoke(driver, new object[] { DriverCommand.Screenshot, null }) as Response; - if (screenshotResponse == null) + MethodInfo executeMethod = driver.GetType().GetMethod("Execute", BindingFlags.Instance | BindingFlags.NonPublic)!; + + object? responseObject = executeMethod.Invoke(driver, new object[] { DriverCommand.Screenshot, null }); + if (responseObject is not Response screenshotResponse) { - throw new WebDriverException("Unexpected failure getting screenshot; response was not in the proper format."); + throw new WebDriverException($"Unexpected failure getting screenshot; response was not in the proper format: {responseObject}"); } string screenshotResult = screenshotResponse.Value.ToString(); @@ -73,7 +71,7 @@ public static Screenshot TakeScreenshot(this IWebDriver driver) /// The arguments to the script. /// Thrown if this instance /// does not implement - public static void ExecuteJavaScript(this IWebDriver driver, string script, params object[] args) + public static void ExecuteJavaScript(this IWebDriver driver, string script, params object?[] args) { ExecuteJavaScriptInternal(driver, script, args); } @@ -89,58 +87,52 @@ public static void ExecuteJavaScript(this IWebDriver driver, string script, para /// Thrown if this instance /// does not implement , or if the actual return type /// of the JavaScript execution does not match the expected type. - public static T ExecuteJavaScript(this IWebDriver driver, string script, params object[] args) + public static T? ExecuteJavaScript(this IWebDriver driver, string script, params object?[] args) { var value = ExecuteJavaScriptInternal(driver, script, args); - var result = default(T); - Type type = typeof(T); if (value == null) { - if (type.IsValueType && (Nullable.GetUnderlyingType(type) == null)) + if (default(T) != null) { - throw new WebDriverException("Script returned null, but desired type is a value type"); + throw new WebDriverException("Script returned null, but desired type is a non-nullable value type"); } + + return default; } - else if (type.IsInstanceOfType(value)) + + if (value is T t) { - result = (T)value; + return t; } - else + + try { - try - { - result = (T)Convert.ChangeType(value, type); - } - catch (Exception exp) - { - throw new WebDriverException("Script returned a value, but the result could not be cast to the desired type", exp); - } + return (T)Convert.ChangeType(value, typeof(T)); + } + catch (Exception exp) + { + throw new WebDriverException("Script returned a value, but the result could not be cast to the desired type", exp); } - - return result; } - private static object ExecuteJavaScriptInternal(IWebDriver driver, string script, object[] args) + private static object ExecuteJavaScriptInternal(IWebDriver driver, string script, object?[] args) { - IJavaScriptExecutor executor = GetDriverAs(driver); - if (executor == null) - { - throw new WebDriverException("Driver does not implement IJavaScriptExecutor"); - } + IJavaScriptExecutor? executor = GetDriverAs(driver) + ?? throw new WebDriverException("Driver does not implement IJavaScriptExecutor"); return executor.ExecuteScript(script, args); } - private static T GetDriverAs(IWebDriver driver) where T : class + private static T? GetDriverAs(IWebDriver driver) where T : class { - T convertedDriver = driver as T; + T? convertedDriver = driver as T; if (convertedDriver == null) { // If the driver doesn't directly implement the desired interface, but does // implement IWrapsDriver, walk up the hierarchy of wrapped drivers until // either we find a class that does implement the desired interface, or is // no longer wrapping a driver. - IWrapsDriver driverWrapper = driver as IWrapsDriver; + IWrapsDriver? driverWrapper = driver as IWrapsDriver; while (convertedDriver == null && driverWrapper != null) { convertedDriver = driverWrapper.WrappedDriver as T; diff --git a/dotnet/src/support/UI/LoadableComponentException.cs b/dotnet/src/support/UI/LoadableComponentException.cs index 9d7b3e3284dc1..82bcef512a345 100644 --- a/dotnet/src/support/UI/LoadableComponentException.cs +++ b/dotnet/src/support/UI/LoadableComponentException.cs @@ -18,7 +18,6 @@ // using System; -using System.Runtime.Serialization; namespace OpenQA.Selenium.Support.UI { @@ -41,7 +40,7 @@ public LoadableComponentException() /// a specified error message. /// /// The message of the exception - public LoadableComponentException(string message) + public LoadableComponentException(string? message) : base(message) { } @@ -54,7 +53,7 @@ public LoadableComponentException(string message) /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception, /// or if no inner exception is specified. - public LoadableComponentException(string message, Exception innerException) + public LoadableComponentException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/support/UI/LoadableComponent{T}.cs b/dotnet/src/support/UI/LoadableComponent{T}.cs index 173906f86db67..14e66fc8b4293 100644 --- a/dotnet/src/support/UI/LoadableComponent{T}.cs +++ b/dotnet/src/support/UI/LoadableComponent{T}.cs @@ -20,22 +20,19 @@ namespace OpenQA.Selenium.Support.UI { /// - /// Represents any abstraction of something that can be loaded. This may be an entire web page, or - /// simply a component within that page (such as a login box or menu) or even a service. - /// - /// The type to be returned (normally the subclass' type) - /// - /// The expected usage is: + /// Represents any abstraction of something that can be loaded. + /// This may be an entire web page, or simply a component within that page (such as a login box or menu) or even a service. /// /// - /// new HypotheticalComponent().Load(); + /// // Example usage: + /// new MyComponent().Load(); /// /// - /// + /// + /// The type to be returned (normally the subclass' type) /// - /// After the method is called, the component will be loaded and - /// ready for use. Overload the protected Load and IsLoaded members to both load a component and determine - /// if the component is already loaded. + /// After the method is called, the component will be loaded and ready for use. + /// Overload the protected Load and IsLoaded members to both load a component and determine if the component is already loaded. /// public abstract class LoadableComponent : ILoadableComponent where T : LoadableComponent @@ -43,11 +40,7 @@ public abstract class LoadableComponent : ILoadableComponent /// /// Gets or sets the message for the exception thrown when a component cannot be loaded /// - public virtual string UnableToLoadMessage - { - get; - set; - } + public virtual string? UnableToLoadMessage { get; set; } /// /// Gets a value indicating whether the component is fully loaded. @@ -60,17 +53,14 @@ protected bool IsLoaded { get { - bool isLoaded = false; try { - isLoaded = this.EvaluateLoadedStatus(); + return this.EvaluateLoadedStatus(); } catch (WebDriverException) { return false; } - - return isLoaded; } } diff --git a/dotnet/src/support/UI/PopupWindowFinder.cs b/dotnet/src/support/UI/PopupWindowFinder.cs index 7b0484049b67f..732f711d0a1fa 100644 --- a/dotnet/src/support/UI/PopupWindowFinder.cs +++ b/dotnet/src/support/UI/PopupWindowFinder.cs @@ -50,6 +50,7 @@ public class PopupWindowFinder /// to manipulate the popup window. /// When using this constructor overload, the timeout will be 5 seconds, /// and the check for a new window will be performed every 250 milliseconds. + /// If is . public PopupWindowFinder(IWebDriver driver) : this(driver, DefaultTimeout, DefaultSleepInterval) { @@ -65,6 +66,7 @@ public PopupWindowFinder(IWebDriver driver) /// time to wait for the popup window to appear. /// When using this constructor overload, the check for a new window /// will be performed every 250 milliseconds. + /// If is . public PopupWindowFinder(IWebDriver driver, TimeSpan timeout) : this(driver, timeout, DefaultSleepInterval) { @@ -81,22 +83,17 @@ public PopupWindowFinder(IWebDriver driver, TimeSpan timeout) /// time to wait for the popup window to appear. /// The representing the /// amount of time to wait between checks of the available window handles. + /// If is . public PopupWindowFinder(IWebDriver driver, TimeSpan timeout, TimeSpan sleepInterval) { - this.driver = driver; + this.driver = driver ?? throw new ArgumentNullException(nameof(driver)); this.timeout = timeout; this.sleepInterval = sleepInterval; } - private static TimeSpan DefaultTimeout - { - get { return TimeSpan.FromSeconds(5); } - } + private static TimeSpan DefaultTimeout => TimeSpan.FromSeconds(5); - private static TimeSpan DefaultSleepInterval - { - get { return TimeSpan.FromMilliseconds(250); } - } + private static TimeSpan DefaultSleepInterval => TimeSpan.FromMilliseconds(250); /// /// Clicks on an element that is expected to trigger a popup browser window. @@ -108,12 +105,12 @@ private static TimeSpan DefaultSleepInterval /// Thrown if the element to click is . public string Click(IWebElement element) { - if (element == null) + if (element is null) { throw new ArgumentNullException(nameof(element), "element cannot be null"); } - return this.Invoke(() => { element.Click(); }); + return this.Invoke(element.Click); } /// @@ -126,7 +123,7 @@ public string Click(IWebElement element) /// Thrown if the action to invoke is . public string Invoke(Action popupMethod) { - if (popupMethod == null) + if (popupMethod is null) { throw new ArgumentNullException(nameof(popupMethod), "popupMethod cannot be null"); } @@ -136,7 +133,7 @@ public string Invoke(Action popupMethod) WebDriverWait wait = new WebDriverWait(new SystemClock(), this.driver, this.timeout, this.sleepInterval); string popupHandle = wait.Until((d) => { - string foundHandle = null; + string? foundHandle = null; IList differentHandles = GetDifference(existingHandles, this.driver.WindowHandles); if (differentHandles.Count > 0) { diff --git a/dotnet/src/support/UI/SelectElement.cs b/dotnet/src/support/UI/SelectElement.cs index 71b06a229245d..0508b642eaebd 100644 --- a/dotnet/src/support/UI/SelectElement.cs +++ b/dotnet/src/support/UI/SelectElement.cs @@ -39,14 +39,14 @@ public class SelectElement : IWrapsElement /// Thrown when the element wrapped is not a <select> element. public SelectElement(IWebElement element) { - if (element == null) + if (element is null) { throw new ArgumentNullException(nameof(element), "element cannot be null"); } string tagName = element.TagName; - if (string.IsNullOrEmpty(tagName) || string.Compare(tagName, "select", StringComparison.OrdinalIgnoreCase) != 0) + if (string.IsNullOrEmpty(tagName) || !string.Equals(tagName, "select", StringComparison.OrdinalIgnoreCase)) { throw new UnexpectedTagNameException("select", tagName); } @@ -55,7 +55,7 @@ public SelectElement(IWebElement element) // let check if it's a multiple string attribute = element.GetAttribute("multiple"); - this.IsMultiple = attribute != null && attribute.ToLowerInvariant() != "false"; + this.IsMultiple = attribute != null && !attribute.Equals("false", StringComparison.OrdinalIgnoreCase); } /// @@ -69,18 +69,12 @@ public IWebElement WrappedElement /// /// Gets a value indicating whether the parent element supports multiple selections. /// - public bool IsMultiple { get; private set; } + public bool IsMultiple { get; } /// /// Gets the list of options for the select element. /// - public IList Options - { - get - { - return this.element.FindElements(By.TagName("option")); - } - } + public IList Options => this.element.FindElements(By.TagName("option")); /// /// Gets the selected item within the select element. @@ -133,10 +127,11 @@ public IList AllSelectedOptions /// <option value="foo">Bar</option> /// /// + /// If is . /// Thrown if there is no element with the given text present. public void SelectByText(string text, bool partialMatch = false) { - if (text == null) + if (text is null) { throw new ArgumentNullException(nameof(text), "text must not be null"); } @@ -432,8 +427,7 @@ private static string EscapeQuotes(string toEscape) private static string GetLongestSubstringWithoutSpace(string s) { string result = string.Empty; - string[] substrings = s.Split(' '); - foreach (string substring in substrings) + foreach (string substring in s.Split(' ')) { if (substring.Length > result.Length) { diff --git a/dotnet/src/support/UI/SlowLoadableComponent{T}.cs b/dotnet/src/support/UI/SlowLoadableComponent{T}.cs index dd1dfce89476d..ad5448c1a3a25 100644 --- a/dotnet/src/support/UI/SlowLoadableComponent{T}.cs +++ b/dotnet/src/support/UI/SlowLoadableComponent{T}.cs @@ -24,23 +24,20 @@ namespace OpenQA.Selenium.Support.UI { /// - /// A which might not have finished loading when Load() returns. After a - /// call to Load(), the IsLoaded property should continue to return false until the component has fully - /// loaded. Use the HandleErrors() method to check for error conditions which caused the Load() to fail. + /// A which might not have finished loading when Load() returns. + /// After a call to Load(), the IsLoaded property should continue to return false until the component has fully loaded. /// - ///
-    /// new SlowHypotheticalComponent().Load();
-    /// 
+ /// + /// // Example usage: + /// new MySlowComponent().Load(); + /// ///
///
+ /// Override the HandleErrors() method to check for error conditions which caused to fail. /// The type to be returned (normally the subclass' type) public abstract class SlowLoadableComponent : LoadableComponent where T : SlowLoadableComponent { - private readonly IClock clock; - private readonly TimeSpan timeout; - private TimeSpan sleepInterval = TimeSpan.FromMilliseconds(200); - /// /// Initializes a new instance of the class. /// @@ -55,36 +52,27 @@ protected SlowLoadableComponent(TimeSpan timeout) ///
/// The within which the component should be loaded. /// The to use when measuring the timeout. + /// If is . protected SlowLoadableComponent(TimeSpan timeout, IClock clock) { - this.clock = clock; - this.timeout = timeout; + this.Clock = clock ?? throw new ArgumentNullException(nameof(clock)); + this.Timeout = timeout; } /// /// Gets or sets the time to sleep between each check of the load status of the component. /// - public TimeSpan SleepInterval - { - get { return this.sleepInterval; } - set { this.sleepInterval = value; } - } + public TimeSpan SleepInterval { get; set; } = TimeSpan.FromMilliseconds(200); /// /// Gets the timeout interval before which this component must be considered loaded. /// - protected TimeSpan Timeout - { - get { return this.timeout; } - } + protected TimeSpan Timeout { get; } /// /// Gets the clock object providing timing for monitoring the load status of this component. /// - protected IClock Clock - { - get { return this.clock; } - } + protected IClock Clock { get; } /// /// Ensures that the component is currently loaded. @@ -102,9 +90,9 @@ public override T Load() this.TryLoad(); } - DateTime end = this.clock.LaterBy(this.timeout); + DateTime end = this.Clock.LaterBy(this.Timeout); - while (this.clock.IsNowBefore(end)) + while (this.Clock.IsNowBefore(end)) { if (this.IsLoaded) { @@ -123,7 +111,7 @@ public override T Load() { if (string.IsNullOrEmpty(UnableToLoadMessage)) { - this.UnableToLoadMessage = string.Format(CultureInfo.InvariantCulture, "Timed out after {0} seconds.", this.timeout.TotalSeconds); + this.UnableToLoadMessage = string.Format(CultureInfo.InvariantCulture, "Timed out after {0} seconds.", this.Timeout.TotalSeconds); } throw new WebDriverTimeoutException(this.UnableToLoadMessage); @@ -147,7 +135,7 @@ protected virtual void HandleErrors() /// protected virtual void Wait() { - Thread.Sleep(this.sleepInterval); + Thread.Sleep(this.SleepInterval); } } } diff --git a/dotnet/src/support/UI/UnexpectedTagNameException.cs b/dotnet/src/support/UI/UnexpectedTagNameException.cs index 299c5694eef29..b9df3207fc4bc 100644 --- a/dotnet/src/support/UI/UnexpectedTagNameException.cs +++ b/dotnet/src/support/UI/UnexpectedTagNameException.cs @@ -19,7 +19,6 @@ using System; using System.Globalization; -using System.Runtime.Serialization; namespace OpenQA.Selenium.Support.UI { @@ -53,7 +52,7 @@ public UnexpectedTagNameException() /// a specified error message. ///
/// The message of the exception - public UnexpectedTagNameException(string message) + public UnexpectedTagNameException(string? message) : base(message) { } @@ -66,7 +65,7 @@ public UnexpectedTagNameException(string message) /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception, /// or if no inner exception is specified. - public UnexpectedTagNameException(string message, Exception innerException) + public UnexpectedTagNameException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/support/WebDriver.Support.csproj b/dotnet/src/support/WebDriver.Support.csproj index 6a4541cb6b4fa..2eebe493287c2 100644 --- a/dotnet/src/support/WebDriver.Support.csproj +++ b/dotnet/src/support/WebDriver.Support.csproj @@ -5,6 +5,8 @@ WebDriver.Support OpenQA.Selenium.Support visual-studio + 12.0 + annotations diff --git a/dotnet/src/webdriver/Support/DefaultWait{T}.cs b/dotnet/src/webdriver/Support/DefaultWait{T}.cs index 1f06731ef2fef..cd70f1d1ca384 100644 --- a/dotnet/src/webdriver/Support/DefaultWait{T}.cs +++ b/dotnet/src/webdriver/Support/DefaultWait{T}.cs @@ -19,10 +19,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Threading; +#nullable enable + namespace OpenQA.Selenium.Support.UI { /// @@ -32,14 +35,9 @@ namespace OpenQA.Selenium.Support.UI /// The type of object on which the wait it to be applied. public class DefaultWait : IWait { - private T input; - private IClock clock; - - private TimeSpan timeout = DefaultSleepTimeout; - private TimeSpan sleepInterval = DefaultSleepTimeout; - private string message = string.Empty; - - private List ignoredExceptions = new List(); + private readonly T input; + private readonly IClock clock; + private readonly List ignoredExceptions = new List(); /// /// Initializes a new instance of the class. @@ -55,53 +53,29 @@ public DefaultWait(T input) /// /// The input value to pass to the evaluated conditions. /// The clock to use when measuring the timeout. + /// If or are . public DefaultWait(T input, IClock clock) { - if (input == null) - { - throw new ArgumentNullException(nameof(input), "input cannot be null"); - } - - if (clock == null) - { - throw new ArgumentNullException(nameof(clock), "clock cannot be null"); - } - - this.input = input; - this.clock = clock; + this.input = input ?? throw new ArgumentNullException(nameof(input), "input cannot be null"); ; + this.clock = clock ?? throw new ArgumentNullException(nameof(clock), "clock cannot be null"); ; } /// /// Gets or sets how long to wait for the evaluated condition to be true. The default timeout is 500 milliseconds. /// - public TimeSpan Timeout - { - get { return this.timeout; } - set { this.timeout = value; } - } + public TimeSpan Timeout { get; set; } = DefaultSleepTimeout; /// /// Gets or sets how often the condition should be evaluated. The default timeout is 500 milliseconds. /// - public TimeSpan PollingInterval - { - get { return this.sleepInterval; } - set { this.sleepInterval = value; } - } + public TimeSpan PollingInterval { get; set; } = DefaultSleepTimeout; /// /// Gets or sets the message to be displayed when time expires. /// - public string Message - { - get { return this.message; } - set { this.message = value; } - } + public string Message { get; set; } = string.Empty; - private static TimeSpan DefaultSleepTimeout - { - get { return TimeSpan.FromMilliseconds(500); } - } + private static TimeSpan DefaultSleepTimeout => TimeSpan.FromMilliseconds(500); /// /// Configures this instance to ignore specific types of exceptions while waiting for a condition. @@ -140,7 +114,8 @@ public void IgnoreExceptionTypes(params Type[] exceptionTypes) /// The delegate's expected return type. /// A delegate taking an object of type T as its parameter, and returning a TResult. /// The delegate's return value. - public virtual TResult Until(Func condition) + [return: NotNull] + public virtual TResult Until(Func condition) { return Until(condition, CancellationToken.None); } @@ -160,7 +135,8 @@ public virtual TResult Until(Func condition) /// A delegate taking an object of type T as its parameter, and returning a TResult. /// A cancellation token that can be used to cancel the wait. /// The delegate's return value. - public virtual TResult Until(Func condition, CancellationToken token) + [return: NotNull] + public virtual TResult Until(Func condition, CancellationToken token) { if (condition == null) { @@ -170,11 +146,11 @@ public virtual TResult Until(Func condition, CancellationTo var resultType = typeof(TResult); if ((resultType.IsValueType && resultType != typeof(bool)) || !typeof(object).IsAssignableFrom(resultType)) { - throw new ArgumentException("Can only wait on an object or boolean response, tried to use type: " + resultType.ToString(), nameof(condition)); + throw new ArgumentException($"Can only wait on an object or boolean response, tried to use type: {resultType}", nameof(condition)); } - Exception lastException = null; - var endTime = this.clock.LaterBy(this.timeout); + Exception? lastException = null; + var endTime = this.clock.LaterBy(this.Timeout); while (true) { token.ThrowIfCancellationRequested(); @@ -184,8 +160,7 @@ public virtual TResult Until(Func condition, CancellationTo var result = condition(this.input); if (resultType == typeof(bool)) { - var boolResult = result as bool?; - if (boolResult.HasValue && boolResult.Value) + if (result is true) { return result; } @@ -212,16 +187,16 @@ public virtual TResult Until(Func condition, CancellationTo // with a zero timeout can succeed. if (!this.clock.IsNowBefore(endTime)) { - string timeoutMessage = string.Format(CultureInfo.InvariantCulture, "Timed out after {0} seconds", this.timeout.TotalSeconds); - if (!string.IsNullOrEmpty(this.message)) + string timeoutMessage = string.Format(CultureInfo.InvariantCulture, "Timed out after {0} seconds", this.Timeout.TotalSeconds); + if (!string.IsNullOrEmpty(this.Message)) { - timeoutMessage += ": " + this.message; + timeoutMessage += ": " + this.Message; } this.ThrowTimeoutException(timeoutMessage, lastException); } - Thread.Sleep(this.sleepInterval); + Thread.Sleep(this.PollingInterval); } } @@ -232,7 +207,7 @@ public virtual TResult Until(Func condition, CancellationTo /// The last exception thrown by the condition. /// This method may be overridden to throw an exception that is /// idiomatic for a particular test infrastructure. - protected virtual void ThrowTimeoutException(string exceptionMessage, Exception lastException) + protected virtual void ThrowTimeoutException(string exceptionMessage, Exception? lastException) { throw new WebDriverTimeoutException(exceptionMessage, lastException); } diff --git a/dotnet/src/webdriver/Support/IClock.cs b/dotnet/src/webdriver/Support/IClock.cs index ceb2dab588f04..92661d7bba013 100644 --- a/dotnet/src/webdriver/Support/IClock.cs +++ b/dotnet/src/webdriver/Support/IClock.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Support.UI { /// diff --git a/dotnet/src/webdriver/Support/IWait{T}.cs b/dotnet/src/webdriver/Support/IWait{T}.cs index 4943de86271a6..b5c8f18a4ee7b 100644 --- a/dotnet/src/webdriver/Support/IWait{T}.cs +++ b/dotnet/src/webdriver/Support/IWait{T}.cs @@ -18,6 +18,9 @@ // using System; +using System.Diagnostics.CodeAnalysis; + +#nullable enable namespace OpenQA.Selenium.Support.UI { @@ -57,6 +60,7 @@ public interface IWait /// If TResult is a boolean, the method returns when the condition is true, and otherwise. /// If TResult is an object, the method returns the object when the condition evaluates to a value other than . /// Thrown when TResult is not boolean or an object type. - TResult Until(Func condition); + [return: NotNull] + TResult Until(Func condition); } } diff --git a/dotnet/src/webdriver/Support/SystemClock.cs b/dotnet/src/webdriver/Support/SystemClock.cs index 49616b76c8c01..5b8afc1105cd6 100644 --- a/dotnet/src/webdriver/Support/SystemClock.cs +++ b/dotnet/src/webdriver/Support/SystemClock.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Support.UI { /// @@ -29,29 +31,20 @@ public class SystemClock : IClock /// /// Gets the current date and time values. /// - public DateTime Now - { - get { return DateTime.Now; } - } + public DateTime Now => DateTime.Now; /// /// Calculates the date and time values after a specific delay. /// /// The delay after to calculate. /// The future date and time values. - public DateTime LaterBy(TimeSpan delay) - { - return DateTime.Now.Add(delay); - } + public DateTime LaterBy(TimeSpan delay) => DateTime.Now.Add(delay); /// /// Gets a value indicating whether the current date and time is before the specified date and time. /// /// The date and time values to compare the current date and time values to. /// if the current date and time is before the specified date and time; otherwise, . - public bool IsNowBefore(DateTime otherDateTime) - { - return DateTime.Now < otherDateTime; - } + public bool IsNowBefore(DateTime otherDateTime) => DateTime.Now < otherDateTime; } } diff --git a/dotnet/src/webdriver/Support/WebDriverWait.cs b/dotnet/src/webdriver/Support/WebDriverWait.cs index c0f710b03a377..e5acc8e75ddc9 100644 --- a/dotnet/src/webdriver/Support/WebDriverWait.cs +++ b/dotnet/src/webdriver/Support/WebDriverWait.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Support.UI { /// @@ -49,6 +51,7 @@ public WebDriverWait(IWebDriver driver, TimeSpan timeout) /// The WebDriver instance used to wait. /// The timeout value indicating how long to wait for the condition. /// A value indicating how often to check for the condition to be true. + /// If or are . public WebDriverWait(IClock clock, IWebDriver driver, TimeSpan timeout, TimeSpan sleepInterval) : base(driver, clock) { @@ -57,9 +60,6 @@ public WebDriverWait(IClock clock, IWebDriver driver, TimeSpan timeout, TimeSpan this.IgnoreExceptionTypes(typeof(NotFoundException)); } - private static TimeSpan DefaultSleepTimeout - { - get { return TimeSpan.FromMilliseconds(500); } - } + private static TimeSpan DefaultSleepTimeout => TimeSpan.FromMilliseconds(500); } } diff --git a/dotnet/test/support/Events/EventFiringWebDriverTest.cs b/dotnet/test/support/Events/EventFiringWebDriverTest.cs index bf2d95aec33f3..303ff09a837a9 100644 --- a/dotnet/test/support/Events/EventFiringWebDriverTest.cs +++ b/dotnet/test/support/Events/EventFiringWebDriverTest.cs @@ -40,8 +40,14 @@ public class EventFiringWebDriverTest public void Setup() { mockDriver = new Mock(); - mockElement = new Mock(); - mockShadowRoot = new Mock(); + mockElement = new Mock() + { + DefaultValue = DefaultValue.Mock + }; + mockShadowRoot = new Mock() + { + DefaultValue = DefaultValue.Mock + }; mockNavigation = new Mock(); log = new StringBuilder(); }