Skip to content

Commit f9669bb

Browse files
authored
Update to use Selenium 4.24.0 (#261) +semver:feature
* 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
1 parent 3dce554 commit f9669bb

File tree

17 files changed

+104
-48
lines changed

17 files changed

+104
-48
lines changed

Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
</ItemGroup>
8787

8888
<ItemGroup>
89-
<PackageReference Include="Aquality.Selenium.Core" Version="3.0.12" />
89+
<PackageReference Include="Aquality.Selenium.Core" Version="3.1.1" />
9090
<PackageReference Include="OpenCvSharp4.runtime.osx_arm64" Version="4.8.1-rc" />
9191
<PackageReference Include="WebDriverManager" Version="2.17.4" />
9292
<PackageReference Include="OpenCvSharp4" Version="4.10.0.20240616" />

Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml

Lines changed: 18 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsHandling.cs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
using Aquality.Selenium.Core.Localization;
22
using Aquality.Selenium.Logging;
3-
using Newtonsoft.Json.Linq;
43
using OpenQA.Selenium;
54
using OpenQA.Selenium.Chromium;
65
using OpenQA.Selenium.DevTools;
76
using OpenQA.Selenium.Firefox;
87
using System;
98
using System.Collections.Generic;
109
using System.Linq;
10+
using System.Text.Json;
11+
using System.Text.Json.Nodes;
1112
using System.Threading;
1213
using System.Threading.Tasks;
1314

@@ -31,7 +32,7 @@ public DevToolsHandling(IDevTools devToolsProvider)
3132
wasDevToolsSessionClosed = false;
3233
}
3334

34-
private ILocalizedLogger Logger => AqualityServices.LocalizedLogger;
35+
private static ILocalizedLogger Logger => AqualityServices.LocalizedLogger;
3536

3637
/// <summary>
3738
/// Gets a value indicating whether a DevTools session is active.
@@ -114,9 +115,9 @@ public object ExecuteCdpCommand(string commandName, Dictionary<string, object> c
114115
{
115116
if (devToolsProvider is ChromiumDriver driver)
116117
{
117-
LogCommand(commandName, JToken.FromObject(commandParameters), loggingOptions);
118+
LogCommand(commandName, JsonSerializer.SerializeToNode(commandParameters), loggingOptions);
118119
var result = driver.ExecuteCdpCommand(commandName, commandParameters);
119-
var formattedResult = JToken.FromObject(result);
120+
var formattedResult = JsonSerializer.SerializeToNode(result);
120121
LogCommandResult(formattedResult, loggingOptions);
121122
return result;
122123
}
@@ -130,17 +131,17 @@ public object ExecuteCdpCommand(string commandName, Dictionary<string, object> c
130131
/// Sends the specified command and returns the associated command response.
131132
/// </summary>
132133
/// <param name="commandName">The name of the command to send.</param>
133-
/// <param name="commandParameters">The parameters of the command as a JToken object.</param>
134+
/// <param name="commandParameters">The parameters of the command as a JsonNode object.</param>
134135
/// <param name="cancellationToken">A CancellationToken object to allow for cancellation of the command.</param>
135136
/// <param name="millisecondsTimeout">The execution timeout of the command in milliseconds.</param>
136137
/// <param name="throwExceptionIfResponseNotReceived"><see langword="true"/> to throw an exception if a response is not received; otherwise, <see langword="false"/>.</param>
137138
/// <param name="loggingOptions">Logging preferences.</param>
138-
/// <returns>A JToken based on a command created with the specified command name and parameters.</returns>
139-
public async Task<JToken> SendCommand(string commandName, JToken commandParameters = null,
139+
/// <returns>A JsonNode based on a command created with the specified command name and parameters.</returns>
140+
public async Task<JsonNode> SendCommand(string commandName, JsonNode commandParameters = null,
140141
CancellationToken cancellationToken = default, int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true,
141142
DevToolsCommandLoggingOptions loggingOptions = null)
142143
{
143-
var parameters = commandParameters ?? new JObject();
144+
var parameters = commandParameters ?? new JsonObject();
144145
LogCommand(commandName, parameters, loggingOptions);
145146
var result = await devToolsProvider.GetDevToolsSession()
146147
.SendCommand(commandName, parameters, cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived);
@@ -156,23 +157,23 @@ public async Task<JToken> SendCommand(string commandName, JToken commandParamete
156157
/// <param name="millisecondsTimeout">The execution timeout of the command in milliseconds.</param>
157158
/// <param name="throwExceptionIfResponseNotReceived"><see langword="true"/> to throw an exception if a response is not received; otherwise, <see langword="false"/>.</param>
158159
/// <param name="loggingOptions">Logging preferences.</param>
159-
/// <returns>A JToken based on a command created with the specified command name and parameters.</returns>
160-
public async Task<JToken> SendCommand(ICommand commandWithParameters,
160+
/// <returns>A JsonNode based on a command created with the specified command name and parameters.</returns>
161+
public async Task<JsonNode> SendCommand(ICommand commandWithParameters,
161162
CancellationToken cancellationToken = default, int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true,
162163
DevToolsCommandLoggingOptions loggingOptions = null)
163164
{
164-
return await SendCommand(commandWithParameters.CommandName, JToken.FromObject(commandWithParameters),
165+
return await SendCommand(commandWithParameters.CommandName, JsonSerializer.SerializeToNode(commandWithParameters, commandWithParameters.GetType()),
165166
cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived, loggingOptions);
166167
}
167168

168-
private void LogCommand(string commandName, JToken commandParameters, DevToolsCommandLoggingOptions loggingOptions = null)
169+
protected virtual void LogCommand(string commandName, JsonNode commandParameters, DevToolsCommandLoggingOptions loggingOptions = null)
169170
{
170171
var logging = (loggingOptions ?? new DevToolsCommandLoggingOptions()).Command;
171172
if (!logging.Enabled)
172173
{
173174
return;
174175
}
175-
if (commandParameters.Any())
176+
if (IsNotEmpty(commandParameters))
176177
{
177178
Logger.LogByLevel(logging.LogLevel, "loc.browser.devtools.command.execute.withparams", commandName, commandParameters.ToString());
178179
}
@@ -182,13 +183,18 @@ private void LogCommand(string commandName, JToken commandParameters, DevToolsCo
182183
}
183184
}
184185

185-
private void LogCommandResult(JToken result, DevToolsCommandLoggingOptions loggingOptions = null)
186+
protected virtual void LogCommandResult(JsonNode result, DevToolsCommandLoggingOptions loggingOptions = null)
186187
{
187188
var logging = (loggingOptions ?? new DevToolsCommandLoggingOptions()).Result;
188-
if (result.Any() && logging.Enabled)
189+
if (IsNotEmpty(result) && logging.Enabled)
189190
{
190191
Logger.LogByLevel(logging.LogLevel, "loc.browser.devtools.command.execute.result", result.ToString());
191192
}
192193
}
194+
195+
private static bool IsNotEmpty(JsonNode jsonNode)
196+
{
197+
return jsonNode is JsonArray array ? array.Any() : (jsonNode as JsonObject).Any();
198+
}
193199
}
194200
}

Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsPerformanceExtensions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
using Newtonsoft.Json.Linq;
2-
using OpenQA.Selenium.DevTools.V85.Performance;
1+
using OpenQA.Selenium.DevTools.V85.Performance;
32
using System.Collections.Generic;
43
using System.Globalization;
54
using System.Linq;
5+
using System.Text.Json.Nodes;
66
using System.Threading.Tasks;
77

88
namespace Aquality.Selenium.Browsers
@@ -18,7 +18,7 @@ public static class DevToolsPerformanceExtensions
1818
/// </summary>
1919
/// <param name="devTools">Current instance of <see cref="DevToolsHandling"/>.</param>
2020
/// <returns>A task for asynchronous command.</returns>
21-
public static async Task DisablePerfomanceMonitoring(this DevToolsHandling devTools)
21+
public static async Task DisablePerformanceMonitoring(this DevToolsHandling devTools)
2222
{
2323
await devTools.SendCommand(new DisableCommandSettings());
2424
}
@@ -30,7 +30,7 @@ public static async Task DisablePerfomanceMonitoring(this DevToolsHandling devTo
3030
/// <param name="timeDomain">Time domain to use for collecting and reporting duration metrics.
3131
/// Allowed Values: timeTicks, threadTicks. </param>
3232
/// <returns>A task for asynchronous command.</returns>
33-
public static async Task EnablePerfomanceMonitoring(this DevToolsHandling devTools, string timeDomain = null)
33+
public static async Task EnablePerformanceMonitoring(this DevToolsHandling devTools, string timeDomain = null)
3434
{
3535
await devTools.SendCommand(new EnableCommandSettings { TimeDomain = timeDomain });
3636
}
@@ -42,8 +42,8 @@ public static async Task EnablePerfomanceMonitoring(this DevToolsHandling devToo
4242
/// <returns>A task for asynchronous command with current values for run-time metrics as result.</returns>
4343
public static async Task<IDictionary<string, double>> GetPerformanceMetrics(this DevToolsHandling devTools)
4444
{
45-
JToken result = await devTools.SendCommand(new GetMetricsCommandSettings());
46-
return (result["metrics"] as JArray)
45+
JsonNode result = await devTools.SendCommand(new GetMetricsCommandSettings());
46+
return (result["metrics"].AsArray())
4747
.ToDictionary(item => item["name"].ToString(), item => double.Parse(item["value"].ToString(), CultureInfo.InvariantCulture));
4848
}
4949
}

Aquality.Selenium/src/Aquality.Selenium/Browsers/JavaScriptHandling.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public JavaScriptHandling(IWebDriver driver)
2323
javaScriptEngine = new JavaScriptEngine(driver);
2424
}
2525

26-
private ILocalizedLogger Logger => AqualityServices.LocalizedLogger;
26+
private static ILocalizedLogger Logger => AqualityServices.LocalizedLogger;
2727

2828
/// <summary>
2929
/// Gets the read-only list of initialization scripts added for this JavaScript engine.

Aquality.Selenium/src/Aquality.Selenium/Browsers/NetworkHandling.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public NetworkHandling(IWebDriver driver)
2121
network = driver.Manage().Network;
2222
}
2323

24-
private ILocalizedLogger Logger => AqualityServices.LocalizedLogger;
24+
private static ILocalizedLogger Logger => AqualityServices.LocalizedLogger;
2525

2626
/// <summary>
2727
/// A network request sent event.

Aquality.Selenium/src/Aquality.Selenium/Configurations/WebDriverSettings/DriverSettings.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ protected void SetOptionsByPropertyNames(DriverOptions options)
201201
}
202202
}
203203

204-
private void SetOptionByPropertyName(DriverOptions options, KeyValuePair<string, object> option, Exception exception)
204+
private static void SetOptionByPropertyName(DriverOptions options, KeyValuePair<string, object> option, Exception exception)
205205
{
206206
var optionProperty = options
207207
.GetType()
@@ -215,14 +215,14 @@ private void SetOptionByPropertyName(DriverOptions options, KeyValuePair<string,
215215
optionProperty.SetValue(options, valueToSet);
216216
}
217217

218-
private object ParseEnumValue(Type propertyType, object optionValue)
218+
private static object ParseEnumValue(Type propertyType, object optionValue)
219219
{
220220
return optionValue is string
221221
? Enum.Parse(propertyType, optionValue.ToString(), ignoreCase: true)
222222
: Enum.ToObject(propertyType, Convert.ChangeType(optionValue, Enum.GetUnderlyingType(propertyType)));
223223
}
224224

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

240-
private bool IsValueOfIntegralNumericType(object value)
240+
private static bool IsValueOfIntegralNumericType(object value)
241241
{
242242
return value is byte || value is sbyte
243243
|| value is ushort || value is short
244244
|| value is uint || value is int
245245
|| value is ulong || value is long;
246246
}
247247

248-
private bool IsPropertyNameMatchOption(string propertyName, string optionKey)
248+
private static bool IsPropertyNameMatchOption(string propertyName, string optionKey)
249249
{
250250
return propertyName.Equals(optionKey, StringComparison.InvariantCultureIgnoreCase)
251251
|| optionKey.ToLowerInvariant().Contains(propertyName.ToLowerInvariant());

Aquality.Selenium/src/Aquality.Selenium/Elements/Actions/JsActions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ public JsActions(IElement element, string elementType, ILocalizedLogger logger,
2929
Logger = logger;
3030
}
3131

32-
private Browser Browser => AqualityServices.Browser;
32+
private static Browser Browser => AqualityServices.Browser;
3333

34-
private IElementActionRetrier ActionRetrier => AqualityServices.Get<IElementActionRetrier>();
34+
private static IElementActionRetrier ActionRetrier => AqualityServices.Get<IElementActionRetrier>();
3535

3636
protected ILocalizedLogger Logger { get; }
3737

Aquality.Selenium/src/Aquality.Selenium/Elements/Actions/MouseActions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public void MoveMouseFromElement()
113113
.MoveToElement(element, -element.Size.Width / 2, -element.Size.Height / 2)));
114114
}
115115

116-
private SeleniumActions MoveToElement(IWebElement element)
116+
private static SeleniumActions MoveToElement(IWebElement element)
117117
{
118118
return new SeleniumActions(AqualityServices.Browser.Driver).MoveToElement(element);
119119
}

Aquality.Selenium/src/Aquality.Selenium/Elements/Element.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ protected Element(By locator, string name, ElementState state) : base(locator, n
3030

3131
public override ICoreElementStateProvider State => new ElementStateProvider(Locator, ConditionalWait, Finder, LogElementState);
3232

33-
protected IBrowserProfile BrowserProfile => AqualityServices.Get<IBrowserProfile>();
33+
protected virtual IBrowserProfile BrowserProfile => AqualityServices.Get<IBrowserProfile>();
3434

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

Aquality.Selenium/src/Aquality.Selenium/Elements/Interfaces/ITextBox.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ public interface ITextBox : IElement
1111
/// <value>String representation of element's value</value>
1212
string Value { get; }
1313

14+
/// <summary>
15+
/// Clear element text.
16+
/// </summary>
17+
void Clear();
18+
1419
/// <summary>
1520
/// Type text in an element.
1621
/// </summary>

0 commit comments

Comments
 (0)