Skip to content

Commit

Permalink
Update to use Selenium 4.24.0 (#261) +semver:feature
Browse files Browse the repository at this point in the history
* Update to use Selenium 4.24.0 +semver:feature
Use System.Text.Json instead of Newtonsoft.Json for DevToolsHandlong
Update tests, use --disable-search-engine-choice-screen in tests
Add Clear method to ITextBox interface
Use new FindElements logic from Aquality.Selenium.Core to avoid possible StaleElementReference while iterating WebElements list to fix #260
  • Loading branch information
mialeska authored Sep 2, 2024
1 parent 3dce554 commit f9669bb
Show file tree
Hide file tree
Showing 17 changed files with 104 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Aquality.Selenium.Core" Version="3.0.12" />
<PackageReference Include="Aquality.Selenium.Core" Version="3.1.1" />
<PackageReference Include="OpenCvSharp4.runtime.osx_arm64" Version="4.8.1-rc" />
<PackageReference Include="WebDriverManager" Version="2.17.4" />
<PackageReference Include="OpenCvSharp4" Version="4.10.0.20240616" />
Expand Down
25 changes: 18 additions & 7 deletions Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using Aquality.Selenium.Core.Localization;
using Aquality.Selenium.Logging;
using Newtonsoft.Json.Linq;
using OpenQA.Selenium;
using OpenQA.Selenium.Chromium;
using OpenQA.Selenium.DevTools;
using OpenQA.Selenium.Firefox;
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;

Expand All @@ -31,7 +32,7 @@ public DevToolsHandling(IDevTools devToolsProvider)
wasDevToolsSessionClosed = false;
}

private ILocalizedLogger Logger => AqualityServices.LocalizedLogger;
private static ILocalizedLogger Logger => AqualityServices.LocalizedLogger;

/// <summary>
/// Gets a value indicating whether a DevTools session is active.
Expand Down Expand Up @@ -114,9 +115,9 @@ public object ExecuteCdpCommand(string commandName, Dictionary<string, object> 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;
}
Expand All @@ -130,17 +131,17 @@ public object ExecuteCdpCommand(string commandName, Dictionary<string, object> c
/// Sends the specified command and returns the associated command response.
/// </summary>
/// <param name="commandName">The name of the command to send.</param>
/// <param name="commandParameters">The parameters of the command as a JToken object.</param>
/// <param name="commandParameters">The parameters of the command as a JsonNode object.</param>
/// <param name="cancellationToken">A CancellationToken object to allow for cancellation of the command.</param>
/// <param name="millisecondsTimeout">The execution timeout of the command in milliseconds.</param>
/// <param name="throwExceptionIfResponseNotReceived"><see langword="true"/> to throw an exception if a response is not received; otherwise, <see langword="false"/>.</param>
/// <param name="loggingOptions">Logging preferences.</param>
/// <returns>A JToken based on a command created with the specified command name and parameters.</returns>
public async Task<JToken> SendCommand(string commandName, JToken commandParameters = null,
/// <returns>A JsonNode based on a command created with the specified command name and parameters.</returns>
public async Task<JsonNode> 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);
Expand All @@ -156,23 +157,23 @@ public async Task<JToken> SendCommand(string commandName, JToken commandParamete
/// <param name="millisecondsTimeout">The execution timeout of the command in milliseconds.</param>
/// <param name="throwExceptionIfResponseNotReceived"><see langword="true"/> to throw an exception if a response is not received; otherwise, <see langword="false"/>.</param>
/// <param name="loggingOptions">Logging preferences.</param>
/// <returns>A JToken based on a command created with the specified command name and parameters.</returns>
public async Task<JToken> SendCommand(ICommand commandWithParameters,
/// <returns>A JsonNode based on a command created with the specified command name and parameters.</returns>
public async Task<JsonNode> 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());
}
Expand All @@ -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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -18,7 +18,7 @@ public static class DevToolsPerformanceExtensions
/// </summary>
/// <param name="devTools">Current instance of <see cref="DevToolsHandling"/>.</param>
/// <returns>A task for asynchronous command.</returns>
public static async Task DisablePerfomanceMonitoring(this DevToolsHandling devTools)
public static async Task DisablePerformanceMonitoring(this DevToolsHandling devTools)
{
await devTools.SendCommand(new DisableCommandSettings());
}
Expand All @@ -30,7 +30,7 @@ public static async Task DisablePerfomanceMonitoring(this DevToolsHandling devTo
/// <param name="timeDomain">Time domain to use for collecting and reporting duration metrics.
/// Allowed Values: timeTicks, threadTicks. </param>
/// <returns>A task for asynchronous command.</returns>
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 });
}
Expand All @@ -42,8 +42,8 @@ public static async Task EnablePerfomanceMonitoring(this DevToolsHandling devToo
/// <returns>A task for asynchronous command with current values for run-time metrics as result.</returns>
public static async Task<IDictionary<string, double>> 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));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public JavaScriptHandling(IWebDriver driver)
javaScriptEngine = new JavaScriptEngine(driver);
}

private ILocalizedLogger Logger => AqualityServices.LocalizedLogger;
private static ILocalizedLogger Logger => AqualityServices.LocalizedLogger;

/// <summary>
/// Gets the read-only list of initialization scripts added for this JavaScript engine.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public NetworkHandling(IWebDriver driver)
network = driver.Manage().Network;
}

private ILocalizedLogger Logger => AqualityServices.LocalizedLogger;
private static ILocalizedLogger Logger => AqualityServices.LocalizedLogger;

/// <summary>
/// A network request sent event.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ protected void SetOptionsByPropertyNames(DriverOptions options)
}
}

private void SetOptionByPropertyName(DriverOptions options, KeyValuePair<string, object> option, Exception exception)
private static void SetOptionByPropertyName(DriverOptions options, KeyValuePair<string, object> option, Exception exception)
{
var optionProperty = options
.GetType()
Expand All @@ -215,14 +215,14 @@ private void SetOptionByPropertyName(DriverOptions options, KeyValuePair<string,
optionProperty.SetValue(options, valueToSet);
}

private object ParseEnumValue(Type propertyType, object optionValue)
private static object ParseEnumValue(Type propertyType, object optionValue)
{
return optionValue is string
? Enum.Parse(propertyType, optionValue.ToString(), ignoreCase: true)
: Enum.ToObject(propertyType, Convert.ChangeType(optionValue, Enum.GetUnderlyingType(propertyType)));
}

private bool IsEnumValue(Type propertyType, object optionValue)
private static bool IsEnumValue(Type propertyType, object optionValue)
{
var valueAsString = optionValue.ToString();
if (!propertyType.IsEnum || string.IsNullOrEmpty(valueAsString))
Expand All @@ -237,15 +237,15 @@ private bool IsEnumValue(Type propertyType, object optionValue)
&& propertyType.IsEnumDefined(Convert.ChangeType(optionValue, Enum.GetUnderlyingType(propertyType))));
}

private bool IsValueOfIntegralNumericType(object value)
private static bool IsValueOfIntegralNumericType(object value)
{
return value is byte || value is sbyte
|| value is ushort || value is short
|| value is uint || value is int
|| value is ulong || value is long;
}

private bool IsPropertyNameMatchOption(string propertyName, string optionKey)
private static bool IsPropertyNameMatchOption(string propertyName, string optionKey)
{
return propertyName.Equals(optionKey, StringComparison.InvariantCultureIgnoreCase)
|| optionKey.ToLowerInvariant().Contains(propertyName.ToLowerInvariant());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public JsActions(IElement element, string elementType, ILocalizedLogger logger,
Logger = logger;
}

private Browser Browser => AqualityServices.Browser;
private static Browser Browser => AqualityServices.Browser;

private IElementActionRetrier ActionRetrier => AqualityServices.Get<IElementActionRetrier>();
private static IElementActionRetrier ActionRetrier => AqualityServices.Get<IElementActionRetrier>();

protected ILocalizedLogger Logger { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<IBrowserProfile>();
protected virtual IBrowserProfile BrowserProfile => AqualityServices.Get<IBrowserProfile>();

public JsActions JsActions => new JsActions(this, ElementType, LocalizedLogger, BrowserProfile);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ public interface ITextBox : IElement
/// <value>String representation of element's value</value>
string Value { get; }

/// <summary>
/// Clear element text.
/// </summary>
void Clear();

/// <summary>
/// Type text in an element.
/// </summary>
Expand Down
Loading

0 comments on commit f9669bb

Please sign in to comment.