diff --git a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.csproj b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.csproj index e2885d9..8ae7a48 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.csproj +++ b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.csproj @@ -86,7 +86,7 @@ - + diff --git a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml index ef1caaa..68584f4 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml +++ b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml @@ -349,6 +349,12 @@ Navigates back. + + + Move back a single entry in the browser's history as an asynchronous task. + + A task object representing the asynchronous operation. + Navigates forward. @@ -376,7 +382,7 @@ Navigate to a url as an asynchronous task. - Uri object of where you want the browser to go. + String representation of where you want the browser to go. A task object representing the asynchronous operation. @@ -636,17 +642,17 @@ Logging preferences. An object representing the result of the command, if applicable. - + Sends the specified command and returns the associated command response. The name of the command to send. - The parameters of the command as a JToken object. + The parameters of the command as a JsonNode object. A CancellationToken object to allow for cancellation of the command. The execution timeout of the command in milliseconds. to throw an exception if a response is not received; otherwise, . Logging preferences. - A JToken based on a command created with the specified command name and parameters. + A JsonNode based on a command created with the specified command name and parameters. @@ -657,7 +663,7 @@ The execution timeout of the command in milliseconds. to throw an exception if a response is not received; otherwise, . Logging preferences. - A JToken based on a command created with the specified command name and parameters. + A JsonNode based on a command created with the specified command name and parameters. @@ -665,14 +671,14 @@ For more information, see . - + Disable collecting and reporting metrics. Current instance of . A task for asynchronous command. - + Enable collecting and reporting metrics. @@ -2361,6 +2367,11 @@ String representation of element's value + + + Clear element text. + + Type text in an element. diff --git a/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsHandling.cs b/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsHandling.cs index f8e2958..1ef5948 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsHandling.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsHandling.cs @@ -1,6 +1,5 @@ using Aquality.Selenium.Core.Localization; using Aquality.Selenium.Logging; -using Newtonsoft.Json.Linq; using OpenQA.Selenium; using OpenQA.Selenium.Chromium; using OpenQA.Selenium.DevTools; @@ -8,6 +7,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; @@ -31,7 +32,7 @@ public DevToolsHandling(IDevTools devToolsProvider) wasDevToolsSessionClosed = false; } - private ILocalizedLogger Logger => AqualityServices.LocalizedLogger; + private static ILocalizedLogger Logger => AqualityServices.LocalizedLogger; /// /// Gets a value indicating whether a DevTools session is active. @@ -114,9 +115,9 @@ public object ExecuteCdpCommand(string commandName, Dictionary c { if (devToolsProvider is ChromiumDriver driver) { - LogCommand(commandName, JToken.FromObject(commandParameters), loggingOptions); + LogCommand(commandName, JsonSerializer.SerializeToNode(commandParameters), loggingOptions); var result = driver.ExecuteCdpCommand(commandName, commandParameters); - var formattedResult = JToken.FromObject(result); + var formattedResult = JsonSerializer.SerializeToNode(result); LogCommandResult(formattedResult, loggingOptions); return result; } @@ -130,17 +131,17 @@ public object ExecuteCdpCommand(string commandName, Dictionary c /// Sends the specified command and returns the associated command response. /// /// The name of the command to send. - /// The parameters of the command as a JToken object. + /// The parameters of the command as a JsonNode object. /// A CancellationToken object to allow for cancellation of the command. /// The execution timeout of the command in milliseconds. /// to throw an exception if a response is not received; otherwise, . /// Logging preferences. - /// A JToken based on a command created with the specified command name and parameters. - public async Task SendCommand(string commandName, JToken commandParameters = null, + /// A JsonNode based on a command created with the specified command name and parameters. + public async Task SendCommand(string commandName, JsonNode commandParameters = null, CancellationToken cancellationToken = default, int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true, DevToolsCommandLoggingOptions loggingOptions = null) { - var parameters = commandParameters ?? new JObject(); + var parameters = commandParameters ?? new JsonObject(); LogCommand(commandName, parameters, loggingOptions); var result = await devToolsProvider.GetDevToolsSession() .SendCommand(commandName, parameters, cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived); @@ -156,23 +157,23 @@ public async Task SendCommand(string commandName, JToken commandParamete /// The execution timeout of the command in milliseconds. /// to throw an exception if a response is not received; otherwise, . /// Logging preferences. - /// A JToken based on a command created with the specified command name and parameters. - public async Task SendCommand(ICommand commandWithParameters, + /// A JsonNode based on a command created with the specified command name and parameters. + public async Task SendCommand(ICommand commandWithParameters, CancellationToken cancellationToken = default, int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true, DevToolsCommandLoggingOptions loggingOptions = null) { - return await SendCommand(commandWithParameters.CommandName, JToken.FromObject(commandWithParameters), + return await SendCommand(commandWithParameters.CommandName, JsonSerializer.SerializeToNode(commandWithParameters, commandWithParameters.GetType()), cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived, loggingOptions); } - private void LogCommand(string commandName, JToken commandParameters, DevToolsCommandLoggingOptions loggingOptions = null) + protected virtual void LogCommand(string commandName, JsonNode commandParameters, DevToolsCommandLoggingOptions loggingOptions = null) { var logging = (loggingOptions ?? new DevToolsCommandLoggingOptions()).Command; if (!logging.Enabled) { return; } - if (commandParameters.Any()) + if (IsNotEmpty(commandParameters)) { Logger.LogByLevel(logging.LogLevel, "loc.browser.devtools.command.execute.withparams", commandName, commandParameters.ToString()); } @@ -182,13 +183,18 @@ private void LogCommand(string commandName, JToken commandParameters, DevToolsCo } } - private void LogCommandResult(JToken result, DevToolsCommandLoggingOptions loggingOptions = null) + protected virtual void LogCommandResult(JsonNode result, DevToolsCommandLoggingOptions loggingOptions = null) { var logging = (loggingOptions ?? new DevToolsCommandLoggingOptions()).Result; - if (result.Any() && logging.Enabled) + if (IsNotEmpty(result) && logging.Enabled) { Logger.LogByLevel(logging.LogLevel, "loc.browser.devtools.command.execute.result", result.ToString()); } } + + private static bool IsNotEmpty(JsonNode jsonNode) + { + return jsonNode is JsonArray array ? array.Any() : (jsonNode as JsonObject).Any(); + } } } diff --git a/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsPerformanceExtensions.cs b/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsPerformanceExtensions.cs index d926a2b..8a806ff 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsPerformanceExtensions.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsPerformanceExtensions.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json.Linq; -using OpenQA.Selenium.DevTools.V85.Performance; +using OpenQA.Selenium.DevTools.V85.Performance; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text.Json.Nodes; using System.Threading.Tasks; namespace Aquality.Selenium.Browsers @@ -18,7 +18,7 @@ public static class DevToolsPerformanceExtensions /// /// Current instance of . /// A task for asynchronous command. - public static async Task DisablePerfomanceMonitoring(this DevToolsHandling devTools) + public static async Task DisablePerformanceMonitoring(this DevToolsHandling devTools) { await devTools.SendCommand(new DisableCommandSettings()); } @@ -30,7 +30,7 @@ public static async Task DisablePerfomanceMonitoring(this DevToolsHandling devTo /// Time domain to use for collecting and reporting duration metrics. /// Allowed Values: timeTicks, threadTicks. /// A task for asynchronous command. - public static async Task EnablePerfomanceMonitoring(this DevToolsHandling devTools, string timeDomain = null) + public static async Task EnablePerformanceMonitoring(this DevToolsHandling devTools, string timeDomain = null) { await devTools.SendCommand(new EnableCommandSettings { TimeDomain = timeDomain }); } @@ -42,8 +42,8 @@ public static async Task EnablePerfomanceMonitoring(this DevToolsHandling devToo /// A task for asynchronous command with current values for run-time metrics as result. public static async Task> GetPerformanceMetrics(this DevToolsHandling devTools) { - JToken result = await devTools.SendCommand(new GetMetricsCommandSettings()); - return (result["metrics"] as JArray) + JsonNode result = await devTools.SendCommand(new GetMetricsCommandSettings()); + return (result["metrics"].AsArray()) .ToDictionary(item => item["name"].ToString(), item => double.Parse(item["value"].ToString(), CultureInfo.InvariantCulture)); } } diff --git a/Aquality.Selenium/src/Aquality.Selenium/Browsers/JavaScriptHandling.cs b/Aquality.Selenium/src/Aquality.Selenium/Browsers/JavaScriptHandling.cs index 8e1512d..b362bb7 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Browsers/JavaScriptHandling.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Browsers/JavaScriptHandling.cs @@ -23,7 +23,7 @@ public JavaScriptHandling(IWebDriver driver) javaScriptEngine = new JavaScriptEngine(driver); } - private ILocalizedLogger Logger => AqualityServices.LocalizedLogger; + private static ILocalizedLogger Logger => AqualityServices.LocalizedLogger; /// /// Gets the read-only list of initialization scripts added for this JavaScript engine. diff --git a/Aquality.Selenium/src/Aquality.Selenium/Browsers/NetworkHandling.cs b/Aquality.Selenium/src/Aquality.Selenium/Browsers/NetworkHandling.cs index 98840f3..cbe726d 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Browsers/NetworkHandling.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Browsers/NetworkHandling.cs @@ -21,7 +21,7 @@ public NetworkHandling(IWebDriver driver) network = driver.Manage().Network; } - private ILocalizedLogger Logger => AqualityServices.LocalizedLogger; + private static ILocalizedLogger Logger => AqualityServices.LocalizedLogger; /// /// A network request sent event. diff --git a/Aquality.Selenium/src/Aquality.Selenium/Configurations/WebDriverSettings/DriverSettings.cs b/Aquality.Selenium/src/Aquality.Selenium/Configurations/WebDriverSettings/DriverSettings.cs index 420f948..67743ba 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Configurations/WebDriverSettings/DriverSettings.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Configurations/WebDriverSettings/DriverSettings.cs @@ -201,7 +201,7 @@ protected void SetOptionsByPropertyNames(DriverOptions options) } } - private void SetOptionByPropertyName(DriverOptions options, KeyValuePair option, Exception exception) + private static void SetOptionByPropertyName(DriverOptions options, KeyValuePair option, Exception exception) { var optionProperty = options .GetType() @@ -215,14 +215,14 @@ private void SetOptionByPropertyName(DriverOptions options, KeyValuePair AqualityServices.Browser; + private static Browser Browser => AqualityServices.Browser; - private IElementActionRetrier ActionRetrier => AqualityServices.Get(); + private static IElementActionRetrier ActionRetrier => AqualityServices.Get(); protected ILocalizedLogger Logger { get; } diff --git a/Aquality.Selenium/src/Aquality.Selenium/Elements/Actions/MouseActions.cs b/Aquality.Selenium/src/Aquality.Selenium/Elements/Actions/MouseActions.cs index 75f739c..3229dee 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Elements/Actions/MouseActions.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Elements/Actions/MouseActions.cs @@ -113,7 +113,7 @@ public void MoveMouseFromElement() .MoveToElement(element, -element.Size.Width / 2, -element.Size.Height / 2))); } - private SeleniumActions MoveToElement(IWebElement element) + private static SeleniumActions MoveToElement(IWebElement element) { return new SeleniumActions(AqualityServices.Browser.Driver).MoveToElement(element); } diff --git a/Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs b/Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs index 4cd8e08..1715fb7 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs @@ -30,7 +30,7 @@ protected Element(By locator, string name, ElementState state) : base(locator, n public override ICoreElementStateProvider State => new ElementStateProvider(Locator, ConditionalWait, Finder, LogElementState); - protected IBrowserProfile BrowserProfile => AqualityServices.Get(); + protected virtual IBrowserProfile BrowserProfile => AqualityServices.Get(); public JsActions JsActions => new JsActions(this, ElementType, LocalizedLogger, BrowserProfile); diff --git a/Aquality.Selenium/src/Aquality.Selenium/Elements/Interfaces/ITextBox.cs b/Aquality.Selenium/src/Aquality.Selenium/Elements/Interfaces/ITextBox.cs index 89597e7..1c8b72a 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Elements/Interfaces/ITextBox.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Elements/Interfaces/ITextBox.cs @@ -11,6 +11,11 @@ public interface ITextBox : IElement /// String representation of element's value string Value { get; } + /// + /// Clear element text. + /// + void Clear(); + /// /// Type text in an element. /// diff --git a/Aquality.Selenium/src/Aquality.Selenium/Elements/TextBox.cs b/Aquality.Selenium/src/Aquality.Selenium/Elements/TextBox.cs index 3d23e05..a2c81a0 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Elements/TextBox.cs +++ b/Aquality.Selenium/src/Aquality.Selenium/Elements/TextBox.cs @@ -19,6 +19,13 @@ protected internal TextBox(By locator, string name, ElementState state) : base(l public string Value => GetAttribute(Attributes.Value); + public void Clear() + { + LogElementAction("loc.text.clearing"); + JsActions.HighlightElement(); + DoWithRetry(() => GetElement().Clear()); + } + public void Type(string value, bool secret = false) { LogElementAction("loc.text.typing", secret ? SecretMask : value); diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Aquality.Selenium.Tests.csproj b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Aquality.Selenium.Tests.csproj index 3dc4b11..ecd0b4c 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Aquality.Selenium.Tests.csproj +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Aquality.Selenium.Tests.csproj @@ -29,12 +29,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsEmulationTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsEmulationTests.cs index 0aaf740..fee2c29 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsEmulationTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsEmulationTests.cs @@ -59,11 +59,11 @@ public void Should_BePossibleTo_SetAndClearDeviceMetricsOverride_WithVersionSpec { void setAction(long width, long height, bool isMobile, double scaleFactor) { - var parameters = new OpenQA.Selenium.DevTools.V127.Emulation.SetDeviceMetricsOverrideCommandSettings + var parameters = new OpenQA.Selenium.DevTools.V128.Emulation.SetDeviceMetricsOverrideCommandSettings { - DisplayFeature = new OpenQA.Selenium.DevTools.V127.Emulation.DisplayFeature + DisplayFeature = new OpenQA.Selenium.DevTools.V128.Emulation.DisplayFeature { - Orientation = OpenQA.Selenium.DevTools.V127.Emulation.DisplayFeatureOrientationValues.Horizontal + Orientation = OpenQA.Selenium.DevTools.V128.Emulation.DisplayFeatureOrientationValues.Horizontal }, Width = width, Height = height, diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsPerformanceTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsPerformanceTests.cs index 2137542..25a61ea 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsPerformanceTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsPerformanceTests.cs @@ -11,7 +11,7 @@ internal class DevToolsPerformanceTests : UITest [Test] public void Should_BePossibleTo_CollectPerformanceMetrics() { - Assert.DoesNotThrowAsync(async () => await DevTools.EnablePerfomanceMonitoring(), "Should be possible to enable performance monitoring"); + Assert.DoesNotThrowAsync(async () => await DevTools.EnablePerformanceMonitoring(), "Should be possible to enable performance monitoring"); AqualityServices.Browser.GoTo("http://www.google.com"); IDictionary metrics = null; @@ -22,7 +22,7 @@ public void Should_BePossibleTo_CollectPerformanceMetrics() IDictionary otherMetrics = DevTools.GetPerformanceMetrics().GetAwaiter().GetResult(); Assert.That(otherMetrics, Is.Not.EqualTo(metrics), "Some additional metrics should have been collected"); - Assert.DoesNotThrowAsync(async () => await DevTools.DisablePerfomanceMonitoring(), "Should be possible to disable performance monitoring"); + Assert.DoesNotThrowAsync(async () => await DevTools.DisablePerformanceMonitoring(), "Should be possible to disable performance monitoring"); AqualityServices.Browser.Refresh(); metrics = DevTools.GetPerformanceMetrics().GetAwaiter().GetResult(); Assert.That(metrics, Is.Empty, "Metrics should have not been collected after performance monitoring have been disabled"); diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Elements/TextBoxTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Elements/TextBoxTests.cs index 8f1a5ef..104aaea 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Elements/TextBoxTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/Elements/TextBoxTests.cs @@ -27,6 +27,33 @@ public void Should_BePossibleTo_FocusAndType() Assert.That(usernameTxb.Value, Is.EqualTo(text)); } + [Test] + public void Should_BePossibleTo_Clear_WhenWasEmpty() + { + var usernameTxb = authForm.UserNameTextBox; + usernameTxb.Clear(); + Assert.That(usernameTxb.Value, Is.Empty); + } + + [Test] + public void Should_BePossibleTo_Clear_WhenWasFilled() + { + var initialText = "initial value"; + var usernameTxb = authForm.UserNameTextBox; + usernameTxb.Type(initialText); + usernameTxb.Clear(); + Assert.That(usernameTxb.Value, Is.Empty); + } + + [Test] + public void Should_BePossibleTo_Clear_Twice() + { + var usernameTxb = authForm.UserNameTextBox; + usernameTxb.Clear(); + usernameTxb.Clear(); + Assert.That(usernameTxb.Value, Is.Empty); + } + [Test] public void Should_BePossibleTo_ClearAndType() { diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.json b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.json index 053ae45..794da47 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.json +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Resources/settings.json @@ -25,7 +25,7 @@ "Performance": "All" }, "excludedArguments": [ "enable-automation" ], - "startArguments": [], + "startArguments": [ "--disable-search-engine-choice-screen" ], "pageLoadStrategy": "Normal" }, "firefox": {