diff --git a/dotnet/src/webdriver/DomMutatedEventArgs.cs b/dotnet/src/webdriver/DomMutatedEventArgs.cs index fc2178f930f79..3ee853a0c36a4 100644 --- a/dotnet/src/webdriver/DomMutatedEventArgs.cs +++ b/dotnet/src/webdriver/DomMutatedEventArgs.cs @@ -26,15 +26,14 @@ namespace OpenQA.Selenium /// public class DomMutatedEventArgs : EventArgs { - private DomMutationData attributeData; + internal DomMutatedEventArgs(DomMutationData attributeData) + { + AttributeData = attributeData; + } /// /// Gets the data about the attribute being changed. /// - public DomMutationData AttributeData - { - get { return this.attributeData; } - internal set { this.attributeData = value; } - } + public DomMutationData AttributeData { get; } } } diff --git a/dotnet/src/webdriver/DomMutationData.cs b/dotnet/src/webdriver/DomMutationData.cs index da64568637b87..0664918af6338 100644 --- a/dotnet/src/webdriver/DomMutationData.cs +++ b/dotnet/src/webdriver/DomMutationData.cs @@ -26,58 +26,38 @@ namespace OpenQA.Selenium /// public class DomMutationData { - private string targetId; - private string attributeName; - private string attributeValue; - private string attributeOriginalValue; - /// /// Gets the ID of the element whose value is changing. /// [JsonPropertyName("target")] [JsonInclude] - public string TargetId - { - get { return this.targetId; } - internal set { this.targetId = value; } - } + public string TargetId { get; internal set; } /// /// Gets the name of the attribute that is changing. /// [JsonPropertyName("name")] [JsonInclude] - public string AttributeName - { - get { return this.attributeName; } - internal set { this.attributeName = value; } - } + public string AttributeName { get; internal set; } /// /// Gets the value to which the attribute is being changed. /// [JsonPropertyName("value")] [JsonInclude] - public string AttributeValue - { - get { return this.attributeValue; } - internal set { this.attributeValue = value; } - } + public string AttributeValue { get; internal set; } /// /// Gets the value from which the attribute has been changed. /// [JsonPropertyName("oldValue")] [JsonInclude] - public string AttributeOriginalValue - { - get { return this.attributeOriginalValue; } - internal set { this.attributeOriginalValue = value; } - } + public string AttributeOriginalValue { get; internal set; } /// /// Stores the element associated with the target ID /// + [JsonIgnore] public IWebElement Element { get; internal set; } /// @@ -86,7 +66,7 @@ public string AttributeOriginalValue /// A string that represents the current object. public override string ToString() { - return string.Format("target: {0}, name: {1}, value: {2}, originalValue: {3}", this.targetId, this.attributeName, this.attributeValue, this.attributeOriginalValue); + return string.Format("target: {0}, name: {1}, value: {2}, originalValue: {3}", this.TargetId, this.AttributeName, this.AttributeValue, this.AttributeOriginalValue); } } } diff --git a/dotnet/src/webdriver/IJavaScriptEngine.cs b/dotnet/src/webdriver/IJavaScriptEngine.cs index 3445c59753d60..27a6b172d190c 100644 --- a/dotnet/src/webdriver/IJavaScriptEngine.cs +++ b/dotnet/src/webdriver/IJavaScriptEngine.cs @@ -21,6 +21,8 @@ using System.Collections.Generic; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium { /// @@ -31,22 +33,22 @@ public interface IJavaScriptEngine : IDisposable /// /// Occurs when a JavaScript callback with a named binding is executed. /// - event EventHandler JavaScriptCallbackExecuted; + event EventHandler? JavaScriptCallbackExecuted; /// - /// Occurs when an exeception is thrown by JavaScript being executed in the browser. + /// Occurs when an exception is thrown by JavaScript being executed in the browser. /// - event EventHandler JavaScriptExceptionThrown; + event EventHandler? JavaScriptExceptionThrown; /// /// Occurs when methods on the JavaScript console are called. /// - event EventHandler JavaScriptConsoleApiCalled; + event EventHandler? JavaScriptConsoleApiCalled; /// /// Occurs when a value of an attribute in an element is being changed. /// - event EventHandler DomMutated; + event EventHandler? DomMutated; /// /// Gets the read-only list of initialization scripts added for this JavaScript engine. @@ -87,7 +89,7 @@ public interface IJavaScriptEngine : IDisposable /// The friendly name by which to refer to this initialization script. /// The JavaScript to be loaded on every page. /// A task containing an object representing the script to be loaded on each page. - /// If is . + /// If or are . Task AddInitializationScript(string scriptName, string script); /// @@ -99,7 +101,7 @@ public interface IJavaScriptEngine : IDisposable Task RemoveInitializationScript(string scriptName); /// - /// Asynchronously removes all intialization scripts from being + /// Asynchronously removes all initialization scripts from being /// loaded on every document load. /// /// A task that represents the asynchronous operation. @@ -129,6 +131,8 @@ public interface IJavaScriptEngine : IDisposable /// /// The name of the callback that will trigger events when called by JavaScript executing in the browser. /// A task that represents the asynchronous operation. + /// If is . + /// If A binding with the specified name already exists. Task AddScriptCallbackBinding(string bindingName); /// @@ -136,6 +140,7 @@ public interface IJavaScriptEngine : IDisposable /// /// The name of the callback to be removed. /// A task that represents the asynchronous operation. + /// If is . Task RemoveScriptCallbackBinding(string bindingName); /// diff --git a/dotnet/src/webdriver/InitializationScript.cs b/dotnet/src/webdriver/InitializationScript.cs index eaf29bb9438c0..940996a875abc 100644 --- a/dotnet/src/webdriver/InitializationScript.cs +++ b/dotnet/src/webdriver/InitializationScript.cs @@ -17,8 +17,11 @@ // under the License. // +using System; using System.Globalization; +#nullable enable + namespace OpenQA.Selenium { /// @@ -26,27 +29,34 @@ namespace OpenQA.Selenium /// public class InitializationScript { + internal InitializationScript(string scriptId, string scriptName, string scriptSource) + { + this.ScriptId = scriptId ?? throw new ArgumentNullException(nameof(scriptId)); + this.ScriptName = scriptName ?? throw new ArgumentNullException(nameof(scriptName)); + this.ScriptSource = scriptSource ?? throw new ArgumentNullException(nameof(scriptSource)); + } + /// /// Gets the internal ID of the initialization script. /// - public string ScriptId { get; internal set; } + public string ScriptId { get; } /// /// Gets the friendly name of the initialization script. /// - public string ScriptName { get; internal set; } + public string ScriptName { get; } /// /// Gets the JavaScript source of the initialization script. /// - public string ScriptSource { get; internal set; } + public string ScriptSource { get; } /// /// Indicates whether the current is equal to another of the same type. /// - /// An to compare with this . + /// An to compare with this . /// if the current is equal to the other parameter; otherwise, . - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is InitializationScript other && this.ScriptId == other.ScriptId && this.ScriptName == other.ScriptName && this.ScriptSource == other.ScriptSource; } diff --git a/dotnet/src/webdriver/JavaScriptCallbackExecutedEventArgs.cs b/dotnet/src/webdriver/JavaScriptCallbackExecutedEventArgs.cs index da2c5f652351e..aabf783d23540 100644 --- a/dotnet/src/webdriver/JavaScriptCallbackExecutedEventArgs.cs +++ b/dotnet/src/webdriver/JavaScriptCallbackExecutedEventArgs.cs @@ -26,17 +26,25 @@ namespace OpenQA.Selenium /// public class JavaScriptCallbackExecutedEventArgs : EventArgs { - private string bindingName; - private string payload; - /// - /// Gets or sets the binding name of the JavaScript callback that was execute. + /// Initializes a new instance of the type. /// - public string BindingName { get => bindingName; set => bindingName = value; } + /// The payload sent from the JavaScript callback. + /// The binding name of the JavaScript callback that was execute. + public JavaScriptCallbackExecutedEventArgs(string scriptPayload, string bindingName) + { + this.ScriptPayload = scriptPayload; + this.BindingName = bindingName; + } /// /// Gets or sets the payload sent from the JavaScript callback. /// - public string ScriptPayload { get => payload; set => payload = value; } + public string ScriptPayload { get; set; } + + /// + /// Gets or sets the binding name of the JavaScript callback that was execute. + /// + public string BindingName { get; set; } } } diff --git a/dotnet/src/webdriver/JavaScriptConsoleApiCalledEventArgs.cs b/dotnet/src/webdriver/JavaScriptConsoleApiCalledEventArgs.cs index 23909b755aca0..391a4cbca7b70 100644 --- a/dotnet/src/webdriver/JavaScriptConsoleApiCalledEventArgs.cs +++ b/dotnet/src/webdriver/JavaScriptConsoleApiCalledEventArgs.cs @@ -26,23 +26,32 @@ namespace OpenQA.Selenium /// public class JavaScriptConsoleApiCalledEventArgs : EventArgs { - private string messageContent; - private DateTime messageTimeStamp; - private string messageType; + /// + /// Initializes a new instance of the type. + /// + /// The content of the message written to the JavaScript console. + /// The time stamp of the message written to the JavaScript console. + /// The type of message written to the JavaScript console. + public JavaScriptConsoleApiCalledEventArgs(string messageContent, DateTime messageTimeStamp, string messageType) + { + this.MessageContent = messageContent; + this.MessageTimeStamp = messageTimeStamp; + this.MessageType = messageType; + } /// - /// Gets or sets the content of the message written to the JavaScript console + /// Gets or sets the content of the message written to the JavaScript console. /// - public string MessageContent { get => messageContent; set => messageContent = value; } + public string MessageContent { get; set; } /// /// Gets or sets the time stamp of the message written to the JavaScript console. /// - public DateTime MessageTimeStamp { get => messageTimeStamp; set => messageTimeStamp = value; } + public DateTime MessageTimeStamp { get; set; } /// /// Gets or sets the type of message written to the JavaScript console. /// - public string MessageType { get => messageType; set => messageType = value; } + public string MessageType { get; set; } } } diff --git a/dotnet/src/webdriver/JavaScriptEngine.cs b/dotnet/src/webdriver/JavaScriptEngine.cs index 8ea7018530294..b1a573490b9f4 100644 --- a/dotnet/src/webdriver/JavaScriptEngine.cs +++ b/dotnet/src/webdriver/JavaScriptEngine.cs @@ -27,6 +27,8 @@ using System.Text.Json; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium { /// @@ -34,13 +36,13 @@ namespace OpenQA.Selenium /// public class JavaScriptEngine : IJavaScriptEngine { - private readonly string MonitorBindingName = "__webdriver_attribute"; + private const string MonitorBindingName = "__webdriver_attribute"; - private IWebDriver driver; - private Lazy session; - private Dictionary initializationScripts = new Dictionary(); - private Dictionary pinnedScripts = new Dictionary(); - private HashSet bindings = new HashSet(); + private readonly IWebDriver driver; + private readonly Lazy session; + private readonly Dictionary initializationScripts = new Dictionary(); + private readonly Dictionary pinnedScripts = new Dictionary(); + private readonly HashSet bindings = new HashSet(); private bool isEnabled = false; private bool isDisposed = false; @@ -56,8 +58,7 @@ public JavaScriptEngine(IWebDriver driver) this.driver = driver; this.session = new Lazy(() => { - IDevTools devToolsDriver = driver as IDevTools; - if (devToolsDriver == null) + if (driver is not IDevTools devToolsDriver) { throw new WebDriverException("Driver must implement IDevTools to use these features"); } @@ -69,22 +70,22 @@ public JavaScriptEngine(IWebDriver driver) /// /// Occurs when a JavaScript callback with a named binding is executed. /// - public event EventHandler JavaScriptCallbackExecuted; + public event EventHandler? JavaScriptCallbackExecuted; /// - /// Occurs when an exeception is thrown by JavaScript being executed in the browser. + /// Occurs when an exception is thrown by JavaScript being executed in the browser. /// - public event EventHandler JavaScriptExceptionThrown; + public event EventHandler? JavaScriptExceptionThrown; /// /// Occurs when methods on the JavaScript console are called. /// - public event EventHandler JavaScriptConsoleApiCalled; + public event EventHandler? JavaScriptConsoleApiCalled; /// /// Occurs when a value of an attribute in an element is being changed. /// - public event EventHandler DomMutated; + public event EventHandler? DomMutated; /// /// Gets the read-only list of initialization scripts added for this JavaScript engine. @@ -162,23 +163,29 @@ public async Task DisableDomMutationMonitoring() /// The friendly name by which to refer to this initialization script. /// The JavaScript to be loaded on every page. /// A task containing an object representing the script to be loaded on each page. + /// If or are . public async Task AddInitializationScript(string scriptName, string script) { - if (this.initializationScripts.ContainsKey(scriptName)) + if (scriptName is null) + { + throw new ArgumentNullException(nameof(scriptName)); + } + + if (script is null) + { + throw new ArgumentNullException(nameof(script)); + } + + if (this.initializationScripts.TryGetValue(scriptName, out InitializationScript? existingScript)) { - return this.initializationScripts[scriptName]; + return existingScript; } await this.EnableDomains().ConfigureAwait(false); string scriptId = await this.session.Value.Domains.JavaScript.AddScriptToEvaluateOnNewDocument(script).ConfigureAwait(false); - InitializationScript initializationScript = new InitializationScript() - { - ScriptId = scriptId, - ScriptName = scriptName, - ScriptSource = script - }; + InitializationScript initializationScript = new InitializationScript(scriptId, scriptName, script); this.initializationScripts[scriptName] = initializationScript; return initializationScript; } @@ -188,18 +195,24 @@ public async Task AddInitializationScript(string scriptNam /// /// The friendly name of the initialization script to be removed. /// A task that represents the asynchronous operation. + /// If is . public async Task RemoveInitializationScript(string scriptName) { - if (this.initializationScripts.ContainsKey(scriptName)) + if (scriptName is null) { - string scriptId = this.initializationScripts[scriptName].ScriptId; + throw new ArgumentNullException(nameof(scriptName)); + } + + if (this.initializationScripts.TryGetValue(scriptName, out InitializationScript? script)) + { + string scriptId = script.ScriptId; await this.session.Value.Domains.JavaScript.RemoveScriptToEvaluateOnNewDocument(scriptId).ConfigureAwait(false); this.initializationScripts.Remove(scriptName); } } /// - /// Asynchronously removes all intialization scripts from being loaded on every document load. + /// Asynchronously removes all initialization scripts from being loaded on every document load. /// /// A task that represents the asynchronous operation. public async Task ClearInitializationScripts() @@ -269,8 +282,15 @@ public async Task UnpinScript(PinnedScript script) /// /// The name of the callback that will trigger events when called by JavaScript executing in the browser. /// A task that represents the asynchronous operation. + /// If is . + /// If A binding with the specified name already exists. public async Task AddScriptCallbackBinding(string bindingName) { + if (bindingName is null) + { + throw new ArgumentNullException(nameof(bindingName)); + } + if (!this.bindings.Add(bindingName)) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "A binding named {0} has already been added", bindingName)); @@ -285,8 +305,14 @@ public async Task AddScriptCallbackBinding(string bindingName) /// /// The name of the callback to be removed. /// A task that represents the asynchronous operation. + /// If is . public async Task RemoveScriptCallbackBinding(string bindingName) { + if (bindingName is null) + { + throw new ArgumentNullException(nameof(bindingName)); + } + await this.session.Value.Domains.JavaScript.RemoveBinding(bindingName).ConfigureAwait(false); _ = this.bindings.Remove(bindingName); } @@ -337,6 +363,7 @@ public async Task Reset() public void Dispose() { this.Dispose(true); + GC.SuppressFinalize(this); } /// @@ -380,7 +407,7 @@ private async Task EnableDomains() } } - private string GetMutationListenerScript() + private static string GetMutationListenerScript() { string listenerScript = string.Empty; using (Stream resourceStream = ResourceUtilities.GetResourceStream("mutation-listener.js", "mutation-listener.js")) @@ -394,57 +421,42 @@ private string GetMutationListenerScript() return listenerScript; } - private void OnScriptBindingCalled(object sender, BindingCalledEventArgs e) + private void OnScriptBindingCalled(object? sender, BindingCalledEventArgs e) { if (e.Name == MonitorBindingName) { - DomMutationData valueChangeData = JsonSerializer.Deserialize(e.Payload); + DomMutationData valueChangeData = JsonSerializer.Deserialize(e.Payload) ?? throw new JsonException("DomMutationData returned null"); var locator = By.CssSelector($"*[data-__webdriver_id='{valueChangeData.TargetId}']"); valueChangeData.Element = driver.FindElements(locator).FirstOrDefault(); - if (this.DomMutated != null) - { - this.DomMutated(this, new DomMutatedEventArgs() - { - AttributeData = valueChangeData - }); - } + this.DomMutated?.Invoke(this, new DomMutatedEventArgs(valueChangeData)); } - if (this.JavaScriptCallbackExecuted != null) - { - this.JavaScriptCallbackExecuted(this, new JavaScriptCallbackExecutedEventArgs() - { - ScriptPayload = e.Payload, - BindingName = e.Name - }); - } + this.JavaScriptCallbackExecuted?.Invoke(this, new JavaScriptCallbackExecutedEventArgs + ( + scriptPayload: e.Payload, + bindingName: e.Name + )); } - private void OnJavaScriptExceptionThrown(object sender, ExceptionThrownEventArgs e) + private void OnJavaScriptExceptionThrown(object? sender, ExceptionThrownEventArgs e) { - if (this.JavaScriptExceptionThrown != null) - { - this.JavaScriptExceptionThrown(this, new JavaScriptExceptionThrownEventArgs() - { - Message = e.Message - }); - } + this.JavaScriptExceptionThrown?.Invoke(this, new JavaScriptExceptionThrownEventArgs(e.Message)); } - private void OnConsoleApiCalled(object sender, ConsoleApiCalledEventArgs e) + private void OnConsoleApiCalled(object? sender, ConsoleApiCalledEventArgs e) { if (this.JavaScriptConsoleApiCalled != null) { for (int i = 0; i < e.Arguments.Count; i++) { - this.JavaScriptConsoleApiCalled(this, new JavaScriptConsoleApiCalledEventArgs() - { - MessageContent = e.Arguments[i].Value, - MessageTimeStamp = e.Timestamp, - MessageType = e.Type - }); + this.JavaScriptConsoleApiCalled(this, new JavaScriptConsoleApiCalledEventArgs + ( + messageContent: e.Arguments[i].Value, + messageTimeStamp: e.Timestamp, + messageType: e.Type + )); } } } diff --git a/dotnet/src/webdriver/JavaScriptExceptionThrownEventArgs.cs b/dotnet/src/webdriver/JavaScriptExceptionThrownEventArgs.cs index cfd79daae0726..bf0e1da43fa26 100644 --- a/dotnet/src/webdriver/JavaScriptExceptionThrownEventArgs.cs +++ b/dotnet/src/webdriver/JavaScriptExceptionThrownEventArgs.cs @@ -26,11 +26,18 @@ namespace OpenQA.Selenium /// public class JavaScriptExceptionThrownEventArgs : EventArgs { - private string message; + /// + /// Initializes a new instance of the type. + /// + /// The message of the exception thrown by JavaScript executing in the browser. + public JavaScriptExceptionThrownEventArgs(string message) + { + Message = message; + } /// /// Gets or sets the message of the exception thrown by JavaScript executing in the browser. /// - public string Message { get => message; set => message = value; } + public string Message { get; set; } } }