From 7f4d4bfd2153a272e1bfc0be34187a847fb9ea32 Mon Sep 17 00:00:00 2001 From: "Jose D. Gomez R." <1josegomezr@gmail.com> Date: Fri, 15 Nov 2024 22:33:03 +0100 Subject: [PATCH 01/58] [rb] Handle graceful webdriver shutdown (#14430) When shutting down `Selenium::WebDriver::ServiceManager#stop_server` issues a `/shutdown` request against the webdriver server and the server exits cleanly, however the mechanism to assert if the child process is up or not cannot distinguish between busy or not found. `Selenium::WebDriver::ChildProcess#exited?` returns `false` when the process is still alive because `Selenium::WebDriver::ChildProcess#waitpid2` returns `nil`. However, by catching `Errno::ECHILD` and `Errno::ESRCH` and returning `nil` `#waitpid2` masks a not running pid as "running" delaying the shutdown procedure when the server was already gone. This patch moves the exception handling away from the `Process` wrappers so its closer to the decision points in `Selenium::WebDriver::ChildProcess#exited?` and `Selenium::WebDriver::ChildProcess#stop`. Addresses a similar inconsistency in #14032 --- .../webdriver/common/child_process.rb | 34 +++++++++++-------- .../webdriver/common/service_manager.rb | 1 + 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/rb/lib/selenium/webdriver/common/child_process.rb b/rb/lib/selenium/webdriver/common/child_process.rb index c63b8fa3b7c02..41fd206616da6 100644 --- a/rb/lib/selenium/webdriver/common/child_process.rb +++ b/rb/lib/selenium/webdriver/common/child_process.rb @@ -64,16 +64,10 @@ def stop(timeout = 3) return unless @pid return if exited? - WebDriver.logger.debug("Sending TERM to process: #{@pid}", id: :process) - terminate(@pid) - poll_for_exit(timeout) - - WebDriver.logger.debug(" -> stopped #{@pid}", id: :process) - rescue TimeoutError, Errno::EINVAL - WebDriver.logger.debug(" -> sending KILL to process: #{@pid}", id: :process) - kill(@pid) - wait - WebDriver.logger.debug(" -> killed #{@pid}", id: :process) + terminate_and_wait_else_kill(timeout) + rescue Errno::ECHILD, Errno::ESRCH => e + # Process exited earlier than terminate/kill could catch + WebDriver.logger.debug(" -> process: #{@pid} does not exist (#{e.class.name})", id: :process) end def alive? @@ -91,6 +85,9 @@ def exited? WebDriver.logger.debug(" -> exit code is #{exit_code.inspect}", id: :process) !!exit_code + rescue Errno::ECHILD, Errno::ESRCH + WebDriver.logger.debug(" -> process: #{@pid} already finished", id: :process) + true end def poll_for_exit(timeout) @@ -110,20 +107,29 @@ def wait private + def terminate_and_wait_else_kill(timeout) + WebDriver.logger.debug("Sending TERM to process: #{@pid}", id: :process) + terminate(@pid) + poll_for_exit(timeout) + + WebDriver.logger.debug(" -> stopped #{@pid}", id: :process) + rescue TimeoutError, Errno::EINVAL + WebDriver.logger.debug(" -> sending KILL to process: #{@pid}", id: :process) + kill(@pid) + wait + WebDriver.logger.debug(" -> killed #{@pid}", id: :process) + end + def terminate(pid) Process.kill(SIGTERM, pid) end def kill(pid) Process.kill(SIGKILL, pid) - rescue Errno::ECHILD, Errno::ESRCH - # already dead end def waitpid2(pid, flags = 0) Process.waitpid2(pid, flags) - rescue Errno::ECHILD - # already dead end end # ChildProcess end # WebDriver diff --git a/rb/lib/selenium/webdriver/common/service_manager.rb b/rb/lib/selenium/webdriver/common/service_manager.rb index f3e623f7b9532..c93e2d688c03e 100644 --- a/rb/lib/selenium/webdriver/common/service_manager.rb +++ b/rb/lib/selenium/webdriver/common/service_manager.rb @@ -113,6 +113,7 @@ def stop_process def stop_server connect_to_server do |http| headers = WebDriver::Remote::Http::Common::DEFAULT_HEADERS.dup + WebDriver.logger.debug('Sending shutdown request to server', id: :driver_service) http.get('/shutdown', headers) end end From bee157189360078440c21c64f03a78712b81e6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sautter?= Date: Sat, 16 Nov 2024 15:40:51 +0100 Subject: [PATCH 02/58] [java] consume the input of the connection --- .../org/openqa/selenium/net/UrlChecker.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/java/src/org/openqa/selenium/net/UrlChecker.java b/java/src/org/openqa/selenium/net/UrlChecker.java index 6c9a6157bf1a6..0d282ad735f10 100644 --- a/java/src/org/openqa/selenium/net/UrlChecker.java +++ b/java/src/org/openqa/selenium/net/UrlChecker.java @@ -20,6 +20,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.io.IOException; +import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Arrays; @@ -75,6 +76,7 @@ public void waitUntilAvailable(long timeout, TimeUnit unit, final URL... urls) // Ok, try again. } finally { if (connection != null) { + consume(connection); connection.disconnect(); } } @@ -127,6 +129,7 @@ public void waitUntilUnavailable(long timeout, TimeUnit unit, final URL url) return null; } finally { if (connection != null) { + consume(connection); connection.disconnect(); } } @@ -154,6 +157,27 @@ public void waitUntilUnavailable(long timeout, TimeUnit unit, final URL url) } } + /** + * Read and closes the ErrorStream / InputStream of the HttpURLConnection to allow Java reusing + * the open socket. + * + * @param connection the connection to consume the input + */ + private static void consume(HttpURLConnection connection) { + try { + InputStream data = connection.getErrorStream(); + if (data == null) { + data = connection.getInputStream(); + } + if (data != null) { + data.readAllBytes(); + data.close(); + } + } catch (IOException e) { + // swallow + } + } + private HttpURLConnection connectToUrl(URL url) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(CONNECT_TIMEOUT_MS); From 83d52f8ba2f32662d028db7ee0373ec048a44e8f Mon Sep 17 00:00:00 2001 From: Michael Render Date: Sat, 16 Nov 2024 12:16:43 -0500 Subject: [PATCH 03/58] [dotnet] Make FirefoxProfile AOT-safe (#14742) --- .../src/webdriver/Firefox/FirefoxProfile.cs | 22 +--- dotnet/src/webdriver/Firefox/Preferences.cs | 112 ++++++++++-------- 2 files changed, 68 insertions(+), 66 deletions(-) diff --git a/dotnet/src/webdriver/Firefox/FirefoxProfile.cs b/dotnet/src/webdriver/Firefox/FirefoxProfile.cs index 2e0036a8f2819..cf340826db916 100644 --- a/dotnet/src/webdriver/Firefox/FirefoxProfile.cs +++ b/dotnet/src/webdriver/Firefox/FirefoxProfile.cs @@ -296,24 +296,14 @@ private void UpdateUserPreferences() private void ReadDefaultPreferences() { - var jsonSerializerOptions = new JsonSerializerOptions - { - Converters = - { - new ResponseValueJsonConverter() - } - }; - using (Stream defaultPrefsStream = ResourceUtilities.GetResourceStream("webdriver_prefs.json", "webdriver_prefs.json")) { - using (StreamReader reader = new StreamReader(defaultPrefsStream)) - { - string defaultPreferences = reader.ReadToEnd(); - Dictionary deserializedPreferences = JsonSerializer.Deserialize>(defaultPreferences, jsonSerializerOptions); - Dictionary immutableDefaultPreferences = deserializedPreferences["frozen"] as Dictionary; - Dictionary editableDefaultPreferences = deserializedPreferences["mutable"] as Dictionary; - this.profilePreferences = new Preferences(immutableDefaultPreferences, editableDefaultPreferences); - } + using JsonDocument defaultPreferences = JsonDocument.Parse(defaultPrefsStream); + + JsonElement immutableDefaultPreferences = defaultPreferences.RootElement.GetProperty("frozen"); + JsonElement editableDefaultPreferences = defaultPreferences.RootElement.GetProperty("mutable"); + + this.profilePreferences = new Preferences(immutableDefaultPreferences, editableDefaultPreferences); } } diff --git a/dotnet/src/webdriver/Firefox/Preferences.cs b/dotnet/src/webdriver/Firefox/Preferences.cs index fa767ca5a3589..708d3a201c045 100644 --- a/dotnet/src/webdriver/Firefox/Preferences.cs +++ b/dotnet/src/webdriver/Firefox/Preferences.cs @@ -21,6 +21,9 @@ using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Text.Json; + +#nullable enable namespace OpenQA.Selenium.Firefox { @@ -29,31 +32,27 @@ namespace OpenQA.Selenium.Firefox /// internal class Preferences { - private Dictionary preferences = new Dictionary(); - private Dictionary immutablePreferences = new Dictionary(); + private readonly Dictionary preferences = new Dictionary(); + private readonly HashSet immutablePreferences = new HashSet(); /// /// Initializes a new instance of the class. /// /// A set of preferences that cannot be modified once set. /// A set of default preferences. - public Preferences(Dictionary defaultImmutablePreferences, Dictionary defaultPreferences) + public Preferences(JsonElement defaultImmutablePreferences, JsonElement defaultPreferences) { - if (defaultImmutablePreferences != null) + foreach (JsonProperty pref in defaultImmutablePreferences.EnumerateObject()) { - foreach (KeyValuePair pref in defaultImmutablePreferences) - { - this.SetPreferenceValue(pref.Key, pref.Value); - this.immutablePreferences.Add(pref.Key, pref.Value.ToString()); - } + this.ThrowIfPreferenceIsImmutable(pref.Name, pref.Value); + this.preferences[pref.Name] = pref.Value.GetRawText(); + this.immutablePreferences.Add(pref.Name); } - if (defaultPreferences != null) + foreach (JsonProperty pref in defaultPreferences.EnumerateObject()) { - foreach (KeyValuePair pref in defaultPreferences) - { - this.SetPreferenceValue(pref.Key, pref.Value); - } + this.ThrowIfPreferenceIsImmutable(pref.Name, pref.Value); + this.preferences[pref.Name] = pref.Value.GetRawText(); } } @@ -64,9 +63,31 @@ public Preferences(Dictionary defaultImmutablePreferences, Dicti /// A value give the preference. /// If the preference already exists in the currently-set list of preferences, /// the value will be updated. + /// If or are . + /// + /// If is wrapped with double-quotes. + /// -or- + /// If the specified preference is immutable. + /// internal void SetPreference(string key, string value) { - this.SetPreferenceValue(key, value); + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (IsWrappedAsString(value)) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Preference values must be plain strings: {0}: {1}", key, value)); + } + + this.ThrowIfPreferenceIsImmutable(key, value); + this.preferences[key] = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", value); } /// @@ -76,9 +97,17 @@ internal void SetPreference(string key, string value) /// A value give the preference. /// If the preference already exists in the currently-set list of preferences, /// the value will be updated. + /// If is . + /// If the specified preference is immutable. internal void SetPreference(string key, int value) { - this.SetPreferenceValue(key, value); + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + + this.ThrowIfPreferenceIsImmutable(key, value); + this.preferences[key] = value.ToString(CultureInfo.InvariantCulture); } /// @@ -88,9 +117,17 @@ internal void SetPreference(string key, int value) /// A value give the preference. /// If the preference already exists in the currently-set list of preferences, /// the value will be updated. + /// If is . + /// If the specified preference is immutable. internal void SetPreference(string key, bool value) { - this.SetPreferenceValue(key, value); + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + + this.ThrowIfPreferenceIsImmutable(key, value); + this.preferences[key] = value ? "true" : "false"; } /// @@ -98,6 +135,7 @@ internal void SetPreference(string key, bool value) /// /// The name of the preference to retrieve. /// The value of the preference, or an empty string if the preference is not set. + /// If is . internal string GetPreference(string preferenceName) { if (this.preferences.ContainsKey(preferenceName)) @@ -151,44 +189,18 @@ private static bool IsWrappedAsString(string value) return value.StartsWith("\"", StringComparison.OrdinalIgnoreCase) && value.EndsWith("\"", StringComparison.OrdinalIgnoreCase); } - private bool IsSettablePreference(string preferenceName) + private void ThrowIfPreferenceIsImmutable(string preferenceName, TValue value) { - return !this.immutablePreferences.ContainsKey(preferenceName); - } - - private void SetPreferenceValue(string key, object value) - { - if (!this.IsSettablePreference(key)) + if (this.immutablePreferences.Contains(preferenceName)) { - string message = string.Format(CultureInfo.InvariantCulture, "Preference {0} may not be overridden: frozen value={1}, requested value={2}", key, this.immutablePreferences[key], value.ToString()); + string message = string.Format(CultureInfo.InvariantCulture, "Preference {0} may not be overridden: frozen value={1}, requested value={2}", preferenceName, this.preferences[preferenceName], value?.ToString()); throw new ArgumentException(message); } + } - string stringValue = value as string; - if (stringValue != null) - { - if (IsWrappedAsString(stringValue)) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Preference values must be plain strings: {0}: {1}", key, value)); - } - - this.preferences[key] = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", value); - return; - } - - if (value is bool) - { - this.preferences[key] = Convert.ToBoolean(value, CultureInfo.InvariantCulture).ToString().ToLowerInvariant(); - return; - } - - if (value is int || value is long) - { - this.preferences[key] = Convert.ToInt32(value, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture); - return; - } - - throw new WebDriverException("Value must be string, int or boolean"); + private bool IsSettablePreference(string preferenceName) + { + return !this.immutablePreferences.Contains(preferenceName); } } } From e4ab299ea4d16943c18e8c31e9db1f7738ed9493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sautter?= Date: Sun, 17 Nov 2024 21:58:29 +0100 Subject: [PATCH 04/58] [grid] retry creating a session in a distributed grid --- .../selenium/grid/node/remote/RemoteNode.java | 12 +++++++++++- .../sessionqueue/local/LocalNewSessionQueue.java | 13 ++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/java/src/org/openqa/selenium/grid/node/remote/RemoteNode.java b/java/src/org/openqa/selenium/grid/node/remote/RemoteNode.java index 5df5da5969c42..d83d7bbbdd9ca 100644 --- a/java/src/org/openqa/selenium/grid/node/remote/RemoteNode.java +++ b/java/src/org/openqa/selenium/grid/node/remote/RemoteNode.java @@ -46,6 +46,7 @@ import org.openqa.selenium.NoSuchSessionException; import org.openqa.selenium.RetrySessionRequestException; import org.openqa.selenium.SessionNotCreatedException; +import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.grid.data.CreateSessionRequest; import org.openqa.selenium.grid.data.CreateSessionResponse; @@ -132,7 +133,16 @@ public Either newSession( HttpTracing.inject(tracer, tracer.getCurrentContext(), req); req.setContent(asJson(sessionRequest)); - HttpResponse httpResponse = client.with(addSecret).execute(req); + HttpResponse httpResponse; + try { + httpResponse = client.with(addSecret).execute(req); + } catch (TimeoutException e) { + // When using a short session timeout the node might not be able to start the session in time. + // The client timeout might be higher so, it makes sense to retry. In case the client does + // timeout, the SessionRequest is marked as canceled and the session is either not added to + // the queue or disposed as soon as the node started it. + return Either.left(new RetrySessionRequestException("Timeout while starting the session", e)); + } Optional> maybeResponse = Optional.ofNullable(Values.get(httpResponse, Map.class)); diff --git a/java/src/org/openqa/selenium/grid/sessionqueue/local/LocalNewSessionQueue.java b/java/src/org/openqa/selenium/grid/sessionqueue/local/LocalNewSessionQueue.java index 66df209de1d58..d5192aba28ac1 100644 --- a/java/src/org/openqa/selenium/grid/sessionqueue/local/LocalNewSessionQueue.java +++ b/java/src/org/openqa/selenium/grid/sessionqueue/local/LocalNewSessionQueue.java @@ -293,11 +293,18 @@ public boolean retryAddToQueue(SessionRequest request) { if (!requests.containsKey(request.getRequestId())) { return false; } - if (isTimedOut(Instant.now(), requests.get(request.getRequestId()))) { + Data data = requests.get(request.getRequestId()); + if (isTimedOut(Instant.now(), data)) { // as we try to re-add a session request that has already expired, force session timeout failDueToTimeout(request.getRequestId()); // return true to avoid handleNewSessionRequest to call 'complete' an other time return true; + } else if (data.isCanceled()) { + complete( + request.getRequestId(), + Either.left(new SessionNotCreatedException("Client has gone away"))); + // return true to avoid handleNewSessionRequest to call 'complete' an other time + return true; } if (queue.contains(request)) { @@ -472,6 +479,10 @@ public synchronized void cancel() { canceled = true; } + public synchronized boolean isCanceled() { + return canceled; + } + public synchronized boolean setResult( Either result) { if (complete || canceled) { From 9054e892ccabfb470243e2bad585f0474901dd31 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Sun, 17 Nov 2024 16:49:05 -0500 Subject: [PATCH 05/58] [dotnet] Enable NRT on exceptional types (#14672) --- dotnet/src/webdriver/DefaultFileDetector.cs | 6 +- .../webdriver/DetachedShadowRootException.cs | 7 +- .../DevTools/CommandResponseException.cs | 6 +- .../DriverServiceNotFoundException.cs | 9 +- .../ElementClickInterceptedException.cs | 7 +- .../ElementNotInteractableException.cs | 9 +- .../ElementNotSelectableException.cs | 9 +- .../webdriver/ElementNotVisibleException.cs | 7 +- dotnet/src/webdriver/ErrorResponse.cs | 82 +++------ dotnet/src/webdriver/Firefox/FirefoxDriver.cs | 12 ++ dotnet/src/webdriver/IFileDetector.cs | 6 +- .../webdriver/InsecureCertificateException.cs | 9 +- .../webdriver/Internal/NullableAttributes.cs | 168 ++++++++++++++++++ .../webdriver/InvalidCookieDomainException.cs | 7 +- .../webdriver/InvalidElementStateException.cs | 7 +- .../src/webdriver/InvalidSelectorException.cs | 13 +- dotnet/src/webdriver/JavaScriptException.cs | 7 +- .../MoveTargetOutOfBoundsException.cs | 7 +- .../src/webdriver/NoAlertPresentException.cs | 7 +- dotnet/src/webdriver/NoSuchDriverException.cs | 11 +- .../src/webdriver/NoSuchElementException.cs | 11 +- dotnet/src/webdriver/NoSuchFrameException.cs | 7 +- .../webdriver/NoSuchShadowRootException.cs | 9 +- dotnet/src/webdriver/NoSuchWindowException.cs | 7 +- dotnet/src/webdriver/NotFoundException.cs | 7 +- .../src/webdriver/Remote/LocalFileDetector.cs | 5 +- dotnet/src/webdriver/StackTraceElement.cs | 33 ++-- .../StaleElementReferenceException.cs | 11 +- .../webdriver/UnableToSetCookieException.cs | 7 +- .../src/webdriver/UnhandledAlertException.cs | 18 +- .../webdriver/WebDriverArgumentException.cs | 7 +- dotnet/src/webdriver/WebDriverException.cs | 7 +- .../webdriver/WebDriverTimeoutException.cs | 7 +- dotnet/src/webdriver/XPathLookupException.cs | 7 +- 34 files changed, 367 insertions(+), 172 deletions(-) create mode 100644 dotnet/src/webdriver/Internal/NullableAttributes.cs diff --git a/dotnet/src/webdriver/DefaultFileDetector.cs b/dotnet/src/webdriver/DefaultFileDetector.cs index 927d7ada27e6c..4f21649d1311e 100644 --- a/dotnet/src/webdriver/DefaultFileDetector.cs +++ b/dotnet/src/webdriver/DefaultFileDetector.cs @@ -17,6 +17,10 @@ // under the License. // +using System.Diagnostics.CodeAnalysis; + +#nullable enable + namespace OpenQA.Selenium { /// @@ -31,7 +35,7 @@ public class DefaultFileDetector : IFileDetector /// /// The sequence to test for file existence. /// This method always returns in this implementation. - public bool IsFile(string keySequence) + public bool IsFile([NotNullWhen(true)] string? keySequence) { return false; } diff --git a/dotnet/src/webdriver/DetachedShadowRootException.cs b/dotnet/src/webdriver/DetachedShadowRootException.cs index 0c2a8bfd3fd9d..ae45207be9c2a 100644 --- a/dotnet/src/webdriver/DetachedShadowRootException.cs +++ b/dotnet/src/webdriver/DetachedShadowRootException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public DetachedShadowRootException() /// a specified error message. /// /// The message that describes the error. - public DetachedShadowRootException(string message) + public DetachedShadowRootException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public DetachedShadowRootException(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 DetachedShadowRootException(string message, Exception innerException) + public DetachedShadowRootException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/DevTools/CommandResponseException.cs b/dotnet/src/webdriver/DevTools/CommandResponseException.cs index 580a70bbe8b41..9a292804b885f 100644 --- a/dotnet/src/webdriver/DevTools/CommandResponseException.cs +++ b/dotnet/src/webdriver/DevTools/CommandResponseException.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium.DevTools { /// @@ -39,7 +41,7 @@ public CommandResponseException() /// Initializes a new instance of the class with the specified message. /// /// The message of the exception. - public CommandResponseException(string message) + public CommandResponseException(string? message) : base(message) { } @@ -49,7 +51,7 @@ public CommandResponseException(string message) /// /// The message of the exception. /// The inner exception for this exception. - public CommandResponseException(string message, Exception innerException) + public CommandResponseException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/DriverServiceNotFoundException.cs b/dotnet/src/webdriver/DriverServiceNotFoundException.cs index 0941959d50d6b..2afe507aa99d0 100644 --- a/dotnet/src/webdriver/DriverServiceNotFoundException.cs +++ b/dotnet/src/webdriver/DriverServiceNotFoundException.cs @@ -18,12 +18,13 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { /// - /// The exception that is thrown when an element is not visible. + /// The exception that is thrown when the driver service is not available. /// [Serializable] public class DriverServiceNotFoundException : WebDriverException @@ -41,7 +42,7 @@ public DriverServiceNotFoundException() /// a specified error message. /// /// The message that describes the error. - public DriverServiceNotFoundException(string message) + public DriverServiceNotFoundException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public DriverServiceNotFoundException(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 DriverServiceNotFoundException(string message, Exception innerException) + public DriverServiceNotFoundException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/ElementClickInterceptedException.cs b/dotnet/src/webdriver/ElementClickInterceptedException.cs index 445abd0d1a5e6..5f76374650a01 100644 --- a/dotnet/src/webdriver/ElementClickInterceptedException.cs +++ b/dotnet/src/webdriver/ElementClickInterceptedException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public ElementClickInterceptedException() /// a specified error message. /// /// The message that describes the error. - public ElementClickInterceptedException(string message) + public ElementClickInterceptedException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public ElementClickInterceptedException(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 ElementClickInterceptedException(string message, Exception innerException) + public ElementClickInterceptedException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/ElementNotInteractableException.cs b/dotnet/src/webdriver/ElementNotInteractableException.cs index 86a304f7ff5fc..ec458b4233c85 100644 --- a/dotnet/src/webdriver/ElementNotInteractableException.cs +++ b/dotnet/src/webdriver/ElementNotInteractableException.cs @@ -18,12 +18,13 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { /// - /// The exception that is thrown when an element is not visible. + /// The exception that is thrown when an element is not interactable. /// [Serializable] public class ElementNotInteractableException : InvalidElementStateException @@ -41,7 +42,7 @@ public ElementNotInteractableException() /// a specified error message. /// /// The message that describes the error. - public ElementNotInteractableException(string message) + public ElementNotInteractableException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public ElementNotInteractableException(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 ElementNotInteractableException(string message, Exception innerException) + public ElementNotInteractableException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/ElementNotSelectableException.cs b/dotnet/src/webdriver/ElementNotSelectableException.cs index 37a5c91dcb702..7734e883bb222 100644 --- a/dotnet/src/webdriver/ElementNotSelectableException.cs +++ b/dotnet/src/webdriver/ElementNotSelectableException.cs @@ -18,12 +18,13 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { /// - /// The exception that is thrown when an element is not visible. + /// The exception that is thrown when an element is not selectable. /// [Serializable] public class ElementNotSelectableException : InvalidElementStateException @@ -41,7 +42,7 @@ public ElementNotSelectableException() /// a specified error message. /// /// The message that describes the error. - public ElementNotSelectableException(string message) + public ElementNotSelectableException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public ElementNotSelectableException(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 ElementNotSelectableException(string message, Exception innerException) + public ElementNotSelectableException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/ElementNotVisibleException.cs b/dotnet/src/webdriver/ElementNotVisibleException.cs index 6db344ed92828..f05ad905afe37 100644 --- a/dotnet/src/webdriver/ElementNotVisibleException.cs +++ b/dotnet/src/webdriver/ElementNotVisibleException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public ElementNotVisibleException() /// a specified error message. /// /// The message that describes the error. - public ElementNotVisibleException(string message) + public ElementNotVisibleException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public ElementNotVisibleException(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 ElementNotVisibleException(string message, Exception innerException) + public ElementNotVisibleException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/ErrorResponse.cs b/dotnet/src/webdriver/ErrorResponse.cs index e8143e8a956ab..2d56cfe04ce99 100644 --- a/dotnet/src/webdriver/ErrorResponse.cs +++ b/dotnet/src/webdriver/ErrorResponse.cs @@ -19,6 +19,8 @@ using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium { /// @@ -26,11 +28,6 @@ namespace OpenQA.Selenium /// public class ErrorResponse { - private StackTraceElement[] stackTrace; - private string message = string.Empty; - private string className = string.Empty; - private string screenshot = string.Empty; - /// /// Initializes a new instance of the class. /// @@ -43,58 +40,45 @@ public ErrorResponse() /// /// A containing names and values of /// the properties of this . - public ErrorResponse(Dictionary responseValue) + public ErrorResponse(Dictionary? responseValue) { if (responseValue != null) { - if (responseValue.ContainsKey("message")) + if (responseValue.TryGetValue("message", out object? messageObj) + && messageObj?.ToString() is string message) { - if (responseValue["message"] != null) - { - this.message = responseValue["message"].ToString(); - } - else - { - this.message = "The error did not contain a message."; - } + this.Message = message; } - - if (responseValue.ContainsKey("screen") && responseValue["screen"] != null) + else { - this.screenshot = responseValue["screen"].ToString(); + this.Message = "The error did not contain a message."; } - if (responseValue.ContainsKey("class") && responseValue["class"] != null) + if (responseValue.TryGetValue("screen", out object? screenObj)) { - this.className = responseValue["class"].ToString(); + this.Screenshot = screenObj?.ToString(); } - if (responseValue.ContainsKey("stackTrace") || responseValue.ContainsKey("stacktrace")) + if (responseValue.TryGetValue("class", out object? classObj)) { - object[] stackTraceArray = null; - - if (responseValue.ContainsKey("stackTrace")) - { - stackTraceArray = responseValue["stackTrace"] as object[]; - } - else if (responseValue.ContainsKey("stacktrace")) - { - stackTraceArray = responseValue["stacktrace"] as object[]; - } + this.ClassName = classObj?.ToString(); + } - if (stackTraceArray != null) + if (responseValue.TryGetValue("stackTrace", out object? stackTraceObj) + || responseValue.TryGetValue("stacktrace", out stackTraceObj)) + { + if (stackTraceObj is object?[] stackTraceArray) { List stackTraceList = new List(); - foreach (object rawStackTraceElement in stackTraceArray) + foreach (object? rawStackTraceElement in stackTraceArray) { - Dictionary elementAsDictionary = rawStackTraceElement as Dictionary; - if (elementAsDictionary != null) + if (rawStackTraceElement is Dictionary elementAsDictionary) { stackTraceList.Add(new StackTraceElement(elementAsDictionary)); } } - this.stackTrace = stackTraceList.ToArray(); + this.StackTrace = stackTraceList.ToArray(); } } } @@ -103,38 +87,22 @@ public ErrorResponse(Dictionary responseValue) /// /// Gets or sets the message from the response /// - public string Message - { - get { return this.message; } - set { this.message = value; } - } + public string Message { get; } = string.Empty; /// /// Gets or sets the class name that threw the error /// - public string ClassName - { - get { return this.className; } - set { this.className = value; } - } + public string? ClassName { get; } + // TODO: (JimEvans) Change this to return an Image. /// /// Gets or sets the screenshot of the error /// - public string Screenshot - { - // TODO: (JimEvans) Change this to return an Image. - get { return this.screenshot; } - set { this.screenshot = value; } - } + public string? Screenshot { get; } /// /// Gets or sets the stack trace of the error /// - public StackTraceElement[] StackTrace - { - get { return this.stackTrace; } - set { this.stackTrace = value; } - } + public StackTraceElement[]? StackTrace { get; } } } diff --git a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs index 3d573dc47a91d..da3061c897d8b 100644 --- a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs +++ b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs @@ -288,6 +288,9 @@ public void SetContext(FirefoxCommandContext context) /// /// Full path of the directory of the add-on to install. /// Whether the add-on is temporary; required for unsigned add-ons. + /// The unique identifier of the installed add-on. + /// If is null or empty. + /// If the directory at does not exist. public string InstallAddOnFromDirectory(string addOnDirectoryToInstall, bool temporary = false) { if (string.IsNullOrEmpty(addOnDirectoryToInstall)) @@ -311,6 +314,12 @@ public string InstallAddOnFromDirectory(string addOnDirectoryToInstall, bool tem /// /// Full path and file name of the add-on to install. /// Whether the add-on is temporary; required for unsigned add-ons. + /// The unique identifier of the installed add-on. + /// + /// If is null or empty. + /// or + /// If the file at does not exist. + /// public string InstallAddOnFromFile(string addOnFileToInstall, bool temporary = false) { if (string.IsNullOrEmpty(addOnFileToInstall)) @@ -334,6 +343,8 @@ public string InstallAddOnFromFile(string addOnFileToInstall, bool temporary = f /// /// The base64-encoded string representation of the add-on binary. /// Whether the add-on is temporary; required for unsigned add-ons. + /// The unique identifier of the installed add-on. + /// If is null or empty. public string InstallAddOn(string base64EncodedAddOn, bool temporary = false) { if (string.IsNullOrEmpty(base64EncodedAddOn)) @@ -354,6 +365,7 @@ public string InstallAddOn(string base64EncodedAddOn, bool temporary = false) /// Uninstalls a Firefox add-on. /// /// The ID of the add-on to uninstall. + /// If is null or empty. public void UninstallAddOn(string addOnId) { if (string.IsNullOrEmpty(addOnId)) diff --git a/dotnet/src/webdriver/IFileDetector.cs b/dotnet/src/webdriver/IFileDetector.cs index 49e6a0387a447..2d48f6c722487 100644 --- a/dotnet/src/webdriver/IFileDetector.cs +++ b/dotnet/src/webdriver/IFileDetector.cs @@ -17,6 +17,10 @@ // under the License. // +using System.Diagnostics.CodeAnalysis; + +#nullable enable + namespace OpenQA.Selenium { /// @@ -31,6 +35,6 @@ public interface IFileDetector /// /// The sequence to test for file existence. /// if the key sequence represents a file; otherwise, . - bool IsFile(string keySequence); + bool IsFile([NotNullWhen(true)] string? keySequence); } } diff --git a/dotnet/src/webdriver/InsecureCertificateException.cs b/dotnet/src/webdriver/InsecureCertificateException.cs index 52644886135af..a232f6b511294 100644 --- a/dotnet/src/webdriver/InsecureCertificateException.cs +++ b/dotnet/src/webdriver/InsecureCertificateException.cs @@ -18,12 +18,13 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { /// - /// The exception that is thrown when a frame is not found. + /// The exception that is thrown when an insecure certificate is used. /// [Serializable] public class InsecureCertificateException : WebDriverException @@ -41,7 +42,7 @@ public InsecureCertificateException() /// a specified error message. /// /// The message that describes the error. - public InsecureCertificateException(string message) + public InsecureCertificateException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public InsecureCertificateException(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 InsecureCertificateException(string message, Exception innerException) + public InsecureCertificateException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/Internal/NullableAttributes.cs b/dotnet/src/webdriver/Internal/NullableAttributes.cs new file mode 100644 index 0000000000000..bbb123a0a86e2 --- /dev/null +++ b/dotnet/src/webdriver/Internal/NullableAttributes.cs @@ -0,0 +1,168 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + + +#if !NET8_0_OR_GREATER + +// Following polyfill guidance explained here https://devblogs.microsoft.com/dotnet/creating-aot-compatible-libraries/#targetframeworks +// Original code in https://github.com/dotnet/runtime/blob/419e949d258ecee4c40a460fb09c66d974229623/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs + +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class AllowNullAttribute : Attribute + { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class DisallowNullAttribute : Attribute + { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class MaybeNullAttribute : Attribute + { } + + /// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class NotNullAttribute : Attribute + { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] + internal sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + internal sealed class DoesNotReturnAttribute : Attribute + { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] + internal sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute(string member) => Members = new[] { member }; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] + internal sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated field or property member will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new[] { member }; + } + + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated field and property members will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } + } +} + +#endif diff --git a/dotnet/src/webdriver/InvalidCookieDomainException.cs b/dotnet/src/webdriver/InvalidCookieDomainException.cs index d77b16a9877ad..e5ab10dbc7b93 100644 --- a/dotnet/src/webdriver/InvalidCookieDomainException.cs +++ b/dotnet/src/webdriver/InvalidCookieDomainException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public InvalidCookieDomainException() /// a specified error message. /// /// The message that describes the error. - public InvalidCookieDomainException(string message) + public InvalidCookieDomainException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public InvalidCookieDomainException(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 InvalidCookieDomainException(string message, Exception innerException) + public InvalidCookieDomainException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/InvalidElementStateException.cs b/dotnet/src/webdriver/InvalidElementStateException.cs index 2ef4f4529f8be..2f4c9d039e7ea 100644 --- a/dotnet/src/webdriver/InvalidElementStateException.cs +++ b/dotnet/src/webdriver/InvalidElementStateException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public InvalidElementStateException() /// a specified error message. /// /// The message that describes the error. - public InvalidElementStateException(string message) + public InvalidElementStateException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public InvalidElementStateException(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 InvalidElementStateException(string message, Exception innerException) + public InvalidElementStateException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/InvalidSelectorException.cs b/dotnet/src/webdriver/InvalidSelectorException.cs index 8afe6301dad93..6d15bfb1af118 100644 --- a/dotnet/src/webdriver/InvalidSelectorException.cs +++ b/dotnet/src/webdriver/InvalidSelectorException.cs @@ -18,12 +18,13 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { /// - /// The exception that is thrown when an element is not visible. + /// The exception that is thrown when an invalid selector is used. /// [Serializable] public class InvalidSelectorException : WebDriverException @@ -46,7 +47,7 @@ public InvalidSelectorException() /// a specified error message. /// /// The message that describes the error. - public InvalidSelectorException(string message) + public InvalidSelectorException(string? message) : base(GetMessage(message)) { } @@ -59,7 +60,7 @@ public InvalidSelectorException(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 InvalidSelectorException(string message, Exception innerException) + public InvalidSelectorException(string? message, Exception? innerException) : base(GetMessage(message), innerException) { } @@ -69,9 +70,9 @@ public InvalidSelectorException(string message, Exception innerException) /// /// The original message for exception /// The final message for exception - protected static string GetMessage(string message) + protected static string GetMessage(string? message) { - return message + "; " + supportMsg + supportUrl; + return $"{message}; {supportMsg}{supportUrl}"; } } } diff --git a/dotnet/src/webdriver/JavaScriptException.cs b/dotnet/src/webdriver/JavaScriptException.cs index 1fd58e1543c29..d3dcc0b743b30 100644 --- a/dotnet/src/webdriver/JavaScriptException.cs +++ b/dotnet/src/webdriver/JavaScriptException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public JavaScriptException() /// a specified error message. /// /// The message that describes the error. - public JavaScriptException(string message) + public JavaScriptException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public JavaScriptException(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 JavaScriptException(string message, Exception innerException) + public JavaScriptException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/MoveTargetOutOfBoundsException.cs b/dotnet/src/webdriver/MoveTargetOutOfBoundsException.cs index 945858e904238..154d1218f804c 100644 --- a/dotnet/src/webdriver/MoveTargetOutOfBoundsException.cs +++ b/dotnet/src/webdriver/MoveTargetOutOfBoundsException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -42,7 +43,7 @@ public MoveTargetOutOfBoundsException() /// a specified error message. /// /// The message that describes the error. - public MoveTargetOutOfBoundsException(string message) + public MoveTargetOutOfBoundsException(string? message) : base(message) { } @@ -55,7 +56,7 @@ public MoveTargetOutOfBoundsException(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 MoveTargetOutOfBoundsException(string message, Exception innerException) + public MoveTargetOutOfBoundsException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/NoAlertPresentException.cs b/dotnet/src/webdriver/NoAlertPresentException.cs index d4e0e3c534c83..f7c3c2b31de95 100644 --- a/dotnet/src/webdriver/NoAlertPresentException.cs +++ b/dotnet/src/webdriver/NoAlertPresentException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public NoAlertPresentException() /// a specified error message. /// /// The message that describes the error. - public NoAlertPresentException(string message) + public NoAlertPresentException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public NoAlertPresentException(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 NoAlertPresentException(string message, Exception innerException) + public NoAlertPresentException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/NoSuchDriverException.cs b/dotnet/src/webdriver/NoSuchDriverException.cs index 4a411844d5a79..5964267e7d2e6 100644 --- a/dotnet/src/webdriver/NoSuchDriverException.cs +++ b/dotnet/src/webdriver/NoSuchDriverException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -47,7 +48,7 @@ public NoSuchDriverException() /// a specified error message. /// /// The message that describes the error. - public NoSuchDriverException(string message) + public NoSuchDriverException(string? message) : base(GetMessage(message)) { } @@ -60,7 +61,7 @@ public NoSuchDriverException(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 NoSuchDriverException(string message, Exception innerException) + public NoSuchDriverException(string? message, Exception? innerException) : base(GetMessage(message), innerException) { } @@ -70,9 +71,9 @@ public NoSuchDriverException(string message, Exception innerException) /// /// The original message for exception /// The final message for exception - protected static string GetMessage(string message) + protected static string GetMessage(string? message) { - return message + "; " + supportMsg + supportUrl; + return $"{message}; {supportMsg}{supportUrl}"; } } } diff --git a/dotnet/src/webdriver/NoSuchElementException.cs b/dotnet/src/webdriver/NoSuchElementException.cs index 83a1f9780fcf7..a6aa6416c0853 100644 --- a/dotnet/src/webdriver/NoSuchElementException.cs +++ b/dotnet/src/webdriver/NoSuchElementException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -47,7 +48,7 @@ public NoSuchElementException() /// a specified error message. /// /// The message that describes the error. - public NoSuchElementException(string message) + public NoSuchElementException(string? message) : base(GetMessage(message)) { } @@ -60,7 +61,7 @@ public NoSuchElementException(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 NoSuchElementException(string message, Exception innerException) + public NoSuchElementException(string? message, Exception? innerException) : base(GetMessage(message), innerException) { } @@ -70,9 +71,9 @@ public NoSuchElementException(string message, Exception innerException) /// /// The original message for exception /// The final message for exception - protected static string GetMessage(string message) + protected static string GetMessage(string? message) { - return message + "; " + supportMsg + supportUrl; + return $"{message}; {supportMsg}{supportUrl}"; } } } diff --git a/dotnet/src/webdriver/NoSuchFrameException.cs b/dotnet/src/webdriver/NoSuchFrameException.cs index 29592622f6b0e..517d4dda1e719 100644 --- a/dotnet/src/webdriver/NoSuchFrameException.cs +++ b/dotnet/src/webdriver/NoSuchFrameException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public NoSuchFrameException() /// a specified error message. /// /// The message that describes the error. - public NoSuchFrameException(string message) + public NoSuchFrameException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public NoSuchFrameException(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 NoSuchFrameException(string message, Exception innerException) + public NoSuchFrameException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/NoSuchShadowRootException.cs b/dotnet/src/webdriver/NoSuchShadowRootException.cs index 751c2f2fb50bb..22909b1b3c979 100644 --- a/dotnet/src/webdriver/NoSuchShadowRootException.cs +++ b/dotnet/src/webdriver/NoSuchShadowRootException.cs @@ -18,12 +18,13 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { /// - /// The exception that is thrown when a frame is not found. + /// The exception that is thrown when a shadow root is not found. /// [Serializable] public class NoSuchShadowRootException : NotFoundException @@ -41,7 +42,7 @@ public NoSuchShadowRootException() /// a specified error message. /// /// The message that describes the error. - public NoSuchShadowRootException(string message) + public NoSuchShadowRootException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public NoSuchShadowRootException(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 NoSuchShadowRootException(string message, Exception innerException) + public NoSuchShadowRootException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/NoSuchWindowException.cs b/dotnet/src/webdriver/NoSuchWindowException.cs index 5fd9cbfa1c1af..7f1ba8bd6e198 100644 --- a/dotnet/src/webdriver/NoSuchWindowException.cs +++ b/dotnet/src/webdriver/NoSuchWindowException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public NoSuchWindowException() /// a specified error message. /// /// The message that describes the error. - public NoSuchWindowException(string message) + public NoSuchWindowException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public NoSuchWindowException(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 NoSuchWindowException(string message, Exception innerException) + public NoSuchWindowException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/NotFoundException.cs b/dotnet/src/webdriver/NotFoundException.cs index a215ba31f48f3..acb2ac1fe79c4 100644 --- a/dotnet/src/webdriver/NotFoundException.cs +++ b/dotnet/src/webdriver/NotFoundException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public NotFoundException() /// a specified error message. /// /// The message that describes the error. - public NotFoundException(string message) + public NotFoundException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public NotFoundException(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 NotFoundException(string message, Exception innerException) + public NotFoundException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/Remote/LocalFileDetector.cs b/dotnet/src/webdriver/Remote/LocalFileDetector.cs index 7e23d0676ed7d..ab1539b6aaeed 100644 --- a/dotnet/src/webdriver/Remote/LocalFileDetector.cs +++ b/dotnet/src/webdriver/Remote/LocalFileDetector.cs @@ -17,8 +17,11 @@ // under the License. // +using System.Diagnostics.CodeAnalysis; using System.IO; +#nullable enable + namespace OpenQA.Selenium.Remote { /// @@ -33,7 +36,7 @@ public class LocalFileDetector : IFileDetector /// /// The sequence to test for file existence. /// if the key sequence represents a file; otherwise, . - public bool IsFile(string keySequence) + public bool IsFile([NotNullWhen(true)] string? keySequence) { return File.Exists(keySequence); } diff --git a/dotnet/src/webdriver/StackTraceElement.cs b/dotnet/src/webdriver/StackTraceElement.cs index e16c896764330..457ee0d5a0c99 100644 --- a/dotnet/src/webdriver/StackTraceElement.cs +++ b/dotnet/src/webdriver/StackTraceElement.cs @@ -21,6 +21,8 @@ using System.Globalization; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium { /// @@ -44,32 +46,43 @@ public StackTraceElement() /// Initializes a new instance of the class using the given property values. /// /// A containing the names and values for the properties of this . - public StackTraceElement(Dictionary elementAttributes) + public StackTraceElement(Dictionary? elementAttributes) { if (elementAttributes != null) { - if (elementAttributes.ContainsKey("className") && elementAttributes["className"] != null) + if (elementAttributes.TryGetValue("className", out object? classNameObj)) { - this.className = elementAttributes["className"].ToString(); + string? className = classNameObj?.ToString(); + if (className is not null) + { + this.className = className; + } } - if (elementAttributes.ContainsKey("methodName") && elementAttributes["methodName"] != null) + if (elementAttributes.TryGetValue("methodName", out object? methodNameObj)) { - this.methodName = elementAttributes["methodName"].ToString(); + string? methodName = methodNameObj?.ToString(); + if (methodName is not null) + { + this.methodName = methodName; + } } - if (elementAttributes.ContainsKey("lineNumber")) + if (elementAttributes.TryGetValue("lineNumber", out object? lineNumberObj)) { - int line = 0; - if (int.TryParse(elementAttributes["lineNumber"].ToString(), out line)) + if (int.TryParse(lineNumberObj?.ToString(), out int line)) { this.lineNumber = line; } } - if (elementAttributes.ContainsKey("fileName") && elementAttributes["fileName"] != null) + if (elementAttributes.TryGetValue("fileName", out object? fileNameObj)) { - this.fileName = elementAttributes["fileName"].ToString(); + string? fileName = fileNameObj?.ToString(); + if (fileName is not null) + { + this.fileName = fileName; + } } } } diff --git a/dotnet/src/webdriver/StaleElementReferenceException.cs b/dotnet/src/webdriver/StaleElementReferenceException.cs index 23672a63a33f4..38957f83708b2 100644 --- a/dotnet/src/webdriver/StaleElementReferenceException.cs +++ b/dotnet/src/webdriver/StaleElementReferenceException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -46,7 +47,7 @@ public StaleElementReferenceException() /// a specified error message. /// /// The message that describes the error. - public StaleElementReferenceException(string message) + public StaleElementReferenceException(string? message) : base(GetMessage(message)) { } @@ -59,7 +60,7 @@ public StaleElementReferenceException(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 StaleElementReferenceException(string message, Exception innerException) + public StaleElementReferenceException(string? message, Exception? innerException) : base(GetMessage(message), innerException) { } @@ -69,9 +70,9 @@ public StaleElementReferenceException(string message, Exception innerException) /// /// The original message for exception /// The final message for exception - protected static string GetMessage(string message) + protected static string GetMessage(string? message) { - return message + "; " + supportMsg + supportUrl; + return $"{message}; {supportMsg}{supportUrl}"; } } } diff --git a/dotnet/src/webdriver/UnableToSetCookieException.cs b/dotnet/src/webdriver/UnableToSetCookieException.cs index 07463efb2a225..453bab307dc4b 100644 --- a/dotnet/src/webdriver/UnableToSetCookieException.cs +++ b/dotnet/src/webdriver/UnableToSetCookieException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public UnableToSetCookieException() /// a specified error message. /// /// The message that describes the error. - public UnableToSetCookieException(string message) + public UnableToSetCookieException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public UnableToSetCookieException(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 UnableToSetCookieException(string message, Exception innerException) + public UnableToSetCookieException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/UnhandledAlertException.cs b/dotnet/src/webdriver/UnhandledAlertException.cs index 78d1c99435b31..bb9fa8c2278f6 100644 --- a/dotnet/src/webdriver/UnhandledAlertException.cs +++ b/dotnet/src/webdriver/UnhandledAlertException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -28,7 +29,10 @@ namespace OpenQA.Selenium [Serializable] public class UnhandledAlertException : WebDriverException { - private string alertText; + /// + /// Gets the text of the unhandled alert. + /// + public string AlertText { get; } = string.Empty; /// /// Initializes a new instance of the class. @@ -57,7 +61,7 @@ public UnhandledAlertException(string message) public UnhandledAlertException(string message, string alertText) : base(message) { - this.alertText = alertText; + this.AlertText = alertText; } /// @@ -72,13 +76,5 @@ public UnhandledAlertException(string message, Exception innerException) : base(message, innerException) { } - - /// - /// Gets the text of the unhandled alert. - /// - public string AlertText - { - get { return this.alertText; } - } } } diff --git a/dotnet/src/webdriver/WebDriverArgumentException.cs b/dotnet/src/webdriver/WebDriverArgumentException.cs index 586fdd991cc18..0832624372495 100644 --- a/dotnet/src/webdriver/WebDriverArgumentException.cs +++ b/dotnet/src/webdriver/WebDriverArgumentException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public WebDriverArgumentException() /// a specified error message. /// /// The message that describes the error. - public WebDriverArgumentException(string message) + public WebDriverArgumentException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public WebDriverArgumentException(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 WebDriverArgumentException(string message, Exception innerException) + public WebDriverArgumentException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/WebDriverException.cs b/dotnet/src/webdriver/WebDriverException.cs index 25daccb516076..456c6d6c94206 100644 --- a/dotnet/src/webdriver/WebDriverException.cs +++ b/dotnet/src/webdriver/WebDriverException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -51,7 +52,7 @@ public WebDriverException() /// a specified error message. /// /// The message that describes the error. - public WebDriverException(string message) + public WebDriverException(string? message) : base(message) { } @@ -64,7 +65,7 @@ public WebDriverException(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 WebDriverException(string message, Exception innerException) + public WebDriverException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/WebDriverTimeoutException.cs b/dotnet/src/webdriver/WebDriverTimeoutException.cs index 513277beaf436..b7dedbbf0f39f 100644 --- a/dotnet/src/webdriver/WebDriverTimeoutException.cs +++ b/dotnet/src/webdriver/WebDriverTimeoutException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public WebDriverTimeoutException() /// a specified error message. /// /// The message that describes the error. - public WebDriverTimeoutException(string message) + public WebDriverTimeoutException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public WebDriverTimeoutException(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 WebDriverTimeoutException(string message, Exception innerException) + public WebDriverTimeoutException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/dotnet/src/webdriver/XPathLookupException.cs b/dotnet/src/webdriver/XPathLookupException.cs index 6e706c6837b28..f8e633cd1ad43 100644 --- a/dotnet/src/webdriver/XPathLookupException.cs +++ b/dotnet/src/webdriver/XPathLookupException.cs @@ -18,7 +18,8 @@ // using System; -using System.Runtime.Serialization; + +#nullable enable namespace OpenQA.Selenium { @@ -41,7 +42,7 @@ public XPathLookupException() /// a specified error message. /// /// The message that describes the error. - public XPathLookupException(string message) + public XPathLookupException(string? message) : base(message) { } @@ -54,7 +55,7 @@ public XPathLookupException(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 XPathLookupException(string message, Exception innerException) + public XPathLookupException(string? message, Exception? innerException) : base(message, innerException) { } From 0d2dda17b4c4aba6ab0537f9d28910527c45a38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boni=20Garc=C3=ADa?= Date: Mon, 18 Nov 2024 16:51:19 +0100 Subject: [PATCH 06/58] [rust] Use endpoint for stable versions first to manage Firefox (#14536) (#14613) --- rust/src/firefox.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rust/src/firefox.rs b/rust/src/firefox.rs index c0ee53fc4ddc8..d071dd741b316 100644 --- a/rust/src/firefox.rs +++ b/rust/src/firefox.rs @@ -478,9 +478,10 @@ impl SeleniumManager for FirefoxManager { } let mut firefox_versions = - self.request_versions_from_online(FIREFOX_HISTORY_MAJOR_ENDPOINT)?; + self.request_versions_from_online(FIREFOX_HISTORY_ENDPOINT)?; if firefox_versions.is_empty() { - firefox_versions = self.request_versions_from_online(FIREFOX_HISTORY_ENDPOINT)?; + firefox_versions = + self.request_versions_from_online(FIREFOX_HISTORY_MAJOR_ENDPOINT)?; if firefox_versions.is_empty() { firefox_versions = self.request_versions_from_online(FIREFOX_HISTORY_DEV_ENDPOINT)?; From fe5b1985e570bae90bf757c23439d461ef0dda9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boni=20Garc=C3=ADa?= Date: Mon, 18 Nov 2024 17:04:32 +0100 Subject: [PATCH 07/58] [rust] Selenium Manager honors full browser version (#13419) (#14619) * [rust] Selenium Manager honors full browser version (#13419) * [rust] Minor change related to variable name --- rust/src/chrome.rs | 22 ++++---- rust/src/lib.rs | 82 ++++++++++++++++------------ rust/tests/browser_download_tests.rs | 3 + 3 files changed, 61 insertions(+), 46 deletions(-) diff --git a/rust/src/chrome.rs b/rust/src/chrome.rs index f65dc46e2efc9..fb2506439ef63 100644 --- a/rust/src/chrome.rs +++ b/rust/src/chrome.rs @@ -521,18 +521,18 @@ impl SeleniumManager for ChromeManager { let good_versions_url = self.create_cft_url_for_browsers(GOOD_VERSIONS_ENDPOINT); let all_versions = self.request_versions_from_online::(&good_versions_url)?; - let filtered_versions: Vec = all_versions - .versions - .into_iter() - .filter(|r| r.version.starts_with(major_browser_version.as_str())) - .collect(); + let iter_versions = all_versions.versions.into_iter(); + let filtered_versions: Vec = if self.is_browser_version_specific() { + iter_versions + .filter(|r| r.version.eq(browser_version.as_str())) + .collect() + } else { + iter_versions + .filter(|r| r.version.starts_with(major_browser_version.as_str())) + .collect() + }; if filtered_versions.is_empty() { - return Err(anyhow!(format_three_args( - UNAVAILABLE_DOWNLOAD_WITH_MIN_VERSION_ERR_MSG, - browser_name, - &major_browser_version, - &MIN_CHROME_VERSION_CFT.to_string(), - ))); + return self.unavailable_download(); } let last_browser = filtered_versions.last().unwrap(); let platform_url: Vec<&PlatformUrl> = last_browser diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 751f092029e6d..3df601e79bd2c 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -237,43 +237,47 @@ pub trait SeleniumManager { ))); } - // Browser version is checked in the local metadata - match get_browser_version_from_metadata( - &metadata.browsers, - self.get_browser_name(), - &major_browser_version, - ) { - Some(version) => { - self.get_logger().trace(format!( - "Browser with valid TTL. Getting {} version from metadata", - self.get_browser_name() - )); - browser_version = version; - self.set_browser_version(browser_version.clone()); - } - _ => { - // If not in metadata, discover version using online metadata - if self.is_browser_version_stable() || self.is_browser_version_empty() { - browser_version = - self.request_latest_browser_version_from_online(original_browser_version)?; - } else { - browser_version = - self.request_fixed_browser_version_from_online(original_browser_version)?; + if self.is_version_specific(original_browser_version) { + browser_version = original_browser_version.to_string(); + } else { + // Browser version is checked in the local metadata + match get_browser_version_from_metadata( + &metadata.browsers, + self.get_browser_name(), + &major_browser_version, + ) { + Some(version) => { + self.get_logger().trace(format!( + "Browser with valid TTL. Getting {} version from metadata", + self.get_browser_name() + )); + browser_version = version; + self.set_browser_version(browser_version.clone()); } - self.set_browser_version(browser_version.clone()); + _ => { + // If not in metadata, discover version using online metadata + if self.is_browser_version_stable() || self.is_browser_version_empty() { + browser_version = self + .request_latest_browser_version_from_online(original_browser_version)?; + } else { + browser_version = self + .request_fixed_browser_version_from_online(original_browser_version)?; + } + self.set_browser_version(browser_version.clone()); - let browser_ttl = self.get_ttl(); - if browser_ttl > 0 - && !self.is_browser_version_empty() - && !self.is_browser_version_stable() - { - metadata.browsers.push(create_browser_metadata( - self.get_browser_name(), - &major_browser_version, - &browser_version, - browser_ttl, - )); - write_metadata(&metadata, self.get_logger(), cache_path); + let browser_ttl = self.get_ttl(); + if browser_ttl > 0 + && !self.is_browser_version_empty() + && !self.is_browser_version_stable() + { + metadata.browsers.push(create_browser_metadata( + self.get_browser_name(), + &major_browser_version, + &browser_version, + browser_ttl, + )); + write_metadata(&metadata, self.get_logger(), cache_path); + } } } } @@ -715,6 +719,14 @@ pub trait SeleniumManager { self.is_stable(self.get_browser_version()) } + fn is_version_specific(&self, version: &str) -> bool { + version.contains(".") + } + + fn is_browser_version_specific(&self) -> bool { + self.is_version_specific(self.get_browser_version()) + } + fn setup(&mut self) -> Result { let mut driver_in_path = None; let mut driver_in_path_version = None; diff --git a/rust/tests/browser_download_tests.rs b/rust/tests/browser_download_tests.rs index 0c3329131725c..1259f2e4893bf 100644 --- a/rust/tests/browser_download_tests.rs +++ b/rust/tests/browser_download_tests.rs @@ -48,10 +48,13 @@ fn browser_latest_download_test(#[case] browser: String) { #[rstest] #[case("chrome", "113")] +#[case("chrome", "131.0.6725.0")] #[case("chrome", "beta")] #[case("firefox", "116")] +#[case("firefox", "121.0.1")] #[case("firefox", "beta")] #[case("firefox", "esr")] +#[case("edge", "129.0.2792.79")] #[case("edge", "beta")] fn browser_version_download_test(#[case] browser: String, #[case] browser_version: String) { if OS.eq("windows") && browser.eq("edge") { From 0eb839371479062896d97611cfff4bdbf6b43de5 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Mon, 18 Nov 2024 16:48:39 -0500 Subject: [PATCH 08/58] [dotnet] Propagate async throughout test setup and teardown (#14775) --- dotnet/test/chrome/ChromeSpecificTests.cs | 5 +++-- dotnet/test/common/AssemblyFixture.cs | 13 +++++++------ .../test/common/Environment/EnvironmentManager.cs | 4 ++-- .../test/common/Environment/RemoteSeleniumServer.cs | 9 +++++---- dotnet/test/common/Environment/TestWebServer.cs | 9 +++++---- dotnet/test/edge/AssemblyTeardown.cs | 9 +++++---- dotnet/test/firefox/AssemblyTeardown.cs | 9 +++++---- dotnet/test/ie/AssemblyTeardown.cs | 9 +++++---- dotnet/test/remote/AssemblyTeardown.cs | 13 +++++++------ dotnet/test/support/UI/PopupWindowFinderTest.cs | 9 +++++---- dotnet/test/support/UI/SelectBrowserTests.cs | 9 +++++---- 11 files changed, 54 insertions(+), 44 deletions(-) diff --git a/dotnet/test/chrome/ChromeSpecificTests.cs b/dotnet/test/chrome/ChromeSpecificTests.cs index 40b4faeff3811..a0cc07f28ea04 100644 --- a/dotnet/test/chrome/ChromeSpecificTests.cs +++ b/dotnet/test/chrome/ChromeSpecificTests.cs @@ -19,6 +19,7 @@ using NUnit.Framework; using OpenQA.Selenium.Environment; +using System.Threading.Tasks; namespace OpenQA.Selenium.Chrome { @@ -26,10 +27,10 @@ namespace OpenQA.Selenium.Chrome public class ChromeSpecificTests : DriverTestFixture { [OneTimeTearDown] - public void RunAfterAnyTests() + public async Task RunAfterAnyTestsAsync() { EnvironmentManager.Instance.CloseCurrentDriver(); - EnvironmentManager.Instance.WebServer.Stop(); + await EnvironmentManager.Instance.WebServer.StopAsync(); } } } diff --git a/dotnet/test/common/AssemblyFixture.cs b/dotnet/test/common/AssemblyFixture.cs index fda821c9ea304..aacc1b2a7d573 100644 --- a/dotnet/test/common/AssemblyFixture.cs +++ b/dotnet/test/common/AssemblyFixture.cs @@ -19,6 +19,7 @@ using NUnit.Framework; using OpenQA.Selenium.Environment; +using System.Threading.Tasks; namespace OpenQA.Selenium { @@ -31,25 +32,25 @@ public AssemblyFixture() } [OneTimeSetUp] - public void RunBeforeAnyTest() + public async Task RunBeforeAnyTestAsync() { Internal.Logging.Log.SetLevel(Internal.Logging.LogEventLevel.Trace); - EnvironmentManager.Instance.WebServer.Start(); + await EnvironmentManager.Instance.WebServer.StartAsync(); if (EnvironmentManager.Instance.Browser == Browser.Remote) { - EnvironmentManager.Instance.RemoteServer.Start(); + await EnvironmentManager.Instance.RemoteServer.StartAsync(); } } [OneTimeTearDown] - public void RunAfterAnyTests() + public async Task RunAfterAnyTestsAsync() { EnvironmentManager.Instance.CloseCurrentDriver(); - EnvironmentManager.Instance.WebServer.Stop(); + await EnvironmentManager.Instance.WebServer.StopAsync(); if (EnvironmentManager.Instance.Browser == Browser.Remote) { - EnvironmentManager.Instance.RemoteServer.Stop(); + await EnvironmentManager.Instance.RemoteServer.StopAsync(); } } } diff --git a/dotnet/test/common/Environment/EnvironmentManager.cs b/dotnet/test/common/Environment/EnvironmentManager.cs index 20653378c27e8..9c0b53b90c56c 100644 --- a/dotnet/test/common/Environment/EnvironmentManager.cs +++ b/dotnet/test/common/Environment/EnvironmentManager.cs @@ -199,11 +199,11 @@ private EnvironmentManager() { if (remoteServer != null) { - remoteServer.Stop(); + remoteServer.StopAsync().Wait(); } if (webServer != null) { - webServer.Stop(); + webServer.StopAsync().Wait(); } CloseCurrentDriver(); } diff --git a/dotnet/test/common/Environment/RemoteSeleniumServer.cs b/dotnet/test/common/Environment/RemoteSeleniumServer.cs index 80d3c27e5e0bc..388bc6b1e3083 100644 --- a/dotnet/test/common/Environment/RemoteSeleniumServer.cs +++ b/dotnet/test/common/Environment/RemoteSeleniumServer.cs @@ -22,6 +22,7 @@ using System.IO; using System.Net; using System.Net.Http; +using System.Threading.Tasks; namespace OpenQA.Selenium.Environment { @@ -38,7 +39,7 @@ public RemoteSeleniumServer(string projectRoot, bool autoStartServer) autoStart = autoStartServer; } - public void Start() + public async Task StartAsync() { if (autoStart && (webserverProcess == null || webserverProcess.HasExited)) { @@ -67,7 +68,7 @@ public void Start() { try { - using var response = httpClient.GetAsync("http://localhost:6000/wd/hub/status").GetAwaiter().GetResult(); + using var response = await httpClient.GetAsync("http://localhost:6000/wd/hub/status"); if (response.StatusCode == HttpStatusCode.OK) { @@ -86,7 +87,7 @@ public void Start() } } - public void Stop() + public async Task StopAsync() { if (autoStart && webserverProcess != null && !webserverProcess.HasExited) { @@ -94,7 +95,7 @@ public void Stop() try { - using var response = httpClient.GetAsync("http://localhost:6000/selenium-server/driver?cmd=shutDownSeleniumServer").GetAwaiter().GetResult(); + using var response = await httpClient.GetAsync("http://localhost:6000/selenium-server/driver?cmd=shutDownSeleniumServer"); } catch (Exception ex) when (ex is HttpRequestException || ex is TimeoutException) { diff --git a/dotnet/test/common/Environment/TestWebServer.cs b/dotnet/test/common/Environment/TestWebServer.cs index b47585cd3c312..f5fcd0f4ff0c6 100644 --- a/dotnet/test/common/Environment/TestWebServer.cs +++ b/dotnet/test/common/Environment/TestWebServer.cs @@ -25,6 +25,7 @@ using System.Net.Http; using System.Runtime.InteropServices; using System.Text; +using System.Threading.Tasks; namespace OpenQA.Selenium.Environment { @@ -50,7 +51,7 @@ public TestWebServer(string projectRoot, TestWebServerConfig config) this.port = config.Port; } - public void Start() + public async Task StartAsync() { if (webserverProcess == null || webserverProcess.HasExited) { @@ -146,7 +147,7 @@ public void Start() { try { - using var response = httpClient.GetAsync(EnvironmentManager.Instance.UrlBuilder.LocalWhereIs("simpleTest.html")).GetAwaiter().GetResult(); + using var response = await httpClient.GetAsync(EnvironmentManager.Instance.UrlBuilder.LocalWhereIs("simpleTest.html")); if (response.StatusCode == HttpStatusCode.OK) { @@ -174,7 +175,7 @@ public void Start() } } - public void Stop() + public async Task StopAsync() { if (webserverProcess != null) { @@ -182,7 +183,7 @@ public void Stop() { try { - using (httpClient.GetAsync(EnvironmentManager.Instance.UrlBuilder.LocalWhereIs("quitquitquit")).GetAwaiter().GetResult()) + using (await httpClient.GetAsync(EnvironmentManager.Instance.UrlBuilder.LocalWhereIs("quitquitquit"))) { } diff --git a/dotnet/test/edge/AssemblyTeardown.cs b/dotnet/test/edge/AssemblyTeardown.cs index 6b8c737e61bbe..ff9875f8f9c00 100644 --- a/dotnet/test/edge/AssemblyTeardown.cs +++ b/dotnet/test/edge/AssemblyTeardown.cs @@ -19,6 +19,7 @@ using NUnit.Framework; using OpenQA.Selenium.Environment; +using System.Threading.Tasks; namespace OpenQA.Selenium.Edge { @@ -27,16 +28,16 @@ namespace OpenQA.Selenium.Edge public class MySetUpClass { [OneTimeSetUp] - public void RunBeforeAnyTest() + public async Task RunBeforeAnyTestAsync() { - EnvironmentManager.Instance.WebServer.Start(); + await EnvironmentManager.Instance.WebServer.StartAsync(); } [OneTimeTearDown] - public void RunAfterAnyTests() + public async Task RunAfterAnyTestsAsync() { EnvironmentManager.Instance.CloseCurrentDriver(); - EnvironmentManager.Instance.WebServer.Stop(); + await EnvironmentManager.Instance.WebServer.StopAsync(); } } } diff --git a/dotnet/test/firefox/AssemblyTeardown.cs b/dotnet/test/firefox/AssemblyTeardown.cs index 4e0438f44aca7..a0423752a63f5 100644 --- a/dotnet/test/firefox/AssemblyTeardown.cs +++ b/dotnet/test/firefox/AssemblyTeardown.cs @@ -19,6 +19,7 @@ using NUnit.Framework; using OpenQA.Selenium.Environment; +using System.Threading.Tasks; namespace OpenQA.Selenium.Firefox { @@ -27,16 +28,16 @@ namespace OpenQA.Selenium.Firefox public class MySetUpClass { [OneTimeSetUp] - public void RunBeforeAnyTest() + public async Task RunBeforeAnyTestAsync() { - EnvironmentManager.Instance.WebServer.Start(); + await EnvironmentManager.Instance.WebServer.StartAsync(); } [OneTimeTearDown] - public void RunAfterAnyTests() + public async Task RunAfterAnyTestsAsync() { EnvironmentManager.Instance.CloseCurrentDriver(); - EnvironmentManager.Instance.WebServer.Stop(); + await EnvironmentManager.Instance.WebServer.StopAsync(); } } } diff --git a/dotnet/test/ie/AssemblyTeardown.cs b/dotnet/test/ie/AssemblyTeardown.cs index d2780925484f3..d720502b6e112 100644 --- a/dotnet/test/ie/AssemblyTeardown.cs +++ b/dotnet/test/ie/AssemblyTeardown.cs @@ -19,6 +19,7 @@ using NUnit.Framework; using OpenQA.Selenium.Environment; +using System.Threading.Tasks; namespace OpenQA.Selenium.IE { @@ -27,16 +28,16 @@ namespace OpenQA.Selenium.IE public class MySetUpClass { [OneTimeSetUp] - public void RunBeforeAnyTest() + public async Task RunBeforeAnyTestAsync() { - EnvironmentManager.Instance.WebServer.Start(); + await EnvironmentManager.Instance.WebServer.StartAsync(); } [OneTimeTearDown] - public void RunAfterAnyTests() + public async Task RunAfterAnyTestsAsync() { EnvironmentManager.Instance.CloseCurrentDriver(); - EnvironmentManager.Instance.WebServer.Stop(); + await EnvironmentManager.Instance.WebServer.StopAsync(); } } } diff --git a/dotnet/test/remote/AssemblyTeardown.cs b/dotnet/test/remote/AssemblyTeardown.cs index a9fc17ea13a2d..aca281e6ee801 100644 --- a/dotnet/test/remote/AssemblyTeardown.cs +++ b/dotnet/test/remote/AssemblyTeardown.cs @@ -19,6 +19,7 @@ using NUnit.Framework; using OpenQA.Selenium.Environment; +using System.Threading.Tasks; namespace OpenQA.Selenium.Remote { @@ -27,23 +28,23 @@ namespace OpenQA.Selenium.Remote public class MySetUpClass { [OneTimeSetUp] - public void RunBeforeAnyTest() + public async Task RunBeforeAnyTestAsync() { - EnvironmentManager.Instance.WebServer.Start(); + await EnvironmentManager.Instance.WebServer.StartAsync(); if (EnvironmentManager.Instance.Browser == Browser.Remote) { - EnvironmentManager.Instance.RemoteServer.Start(); + await EnvironmentManager.Instance.RemoteServer.StartAsync(); } } [OneTimeTearDown] - public void RunAfterAnyTests() + public async Task RunAfterAnyTestsAsync() { EnvironmentManager.Instance.CloseCurrentDriver(); - EnvironmentManager.Instance.WebServer.Stop(); + await EnvironmentManager.Instance.WebServer.StopAsync(); if (EnvironmentManager.Instance.Browser == Browser.Remote) { - EnvironmentManager.Instance.RemoteServer.Stop(); + await EnvironmentManager.Instance.RemoteServer.StopAsync(); } } } diff --git a/dotnet/test/support/UI/PopupWindowFinderTest.cs b/dotnet/test/support/UI/PopupWindowFinderTest.cs index bbbf910d15969..692fa8d19e1bb 100644 --- a/dotnet/test/support/UI/PopupWindowFinderTest.cs +++ b/dotnet/test/support/UI/PopupWindowFinderTest.cs @@ -19,6 +19,7 @@ using NUnit.Framework; using OpenQA.Selenium.Environment; +using System.Threading.Tasks; namespace OpenQA.Selenium.Support.UI { @@ -27,16 +28,16 @@ public class PopupWindowFinderTest : DriverTestFixture { //TODO: Move these to a standalone class when more tests rely on the server being up [OneTimeSetUp] - public void RunBeforeAnyTest() + public async Task RunBeforeAnyTestAsync() { - EnvironmentManager.Instance.WebServer.Start(); + await EnvironmentManager.Instance.WebServer.StartAsync(); } [OneTimeTearDown] - public void RunAfterAnyTests() + public async Task RunAfterAnyTestsAsync() { EnvironmentManager.Instance.CloseCurrentDriver(); - EnvironmentManager.Instance.WebServer.Stop(); + await EnvironmentManager.Instance.WebServer.StopAsync(); } [Test] diff --git a/dotnet/test/support/UI/SelectBrowserTests.cs b/dotnet/test/support/UI/SelectBrowserTests.cs index 38c1a9d29f933..fc835d96a4596 100644 --- a/dotnet/test/support/UI/SelectBrowserTests.cs +++ b/dotnet/test/support/UI/SelectBrowserTests.cs @@ -21,6 +21,7 @@ using OpenQA.Selenium.Environment; using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace OpenQA.Selenium.Support.UI { @@ -28,16 +29,16 @@ namespace OpenQA.Selenium.Support.UI public class SelectBrowserTests : DriverTestFixture { [OneTimeSetUp] - public void RunBeforeAnyTest() + public async Task RunBeforeAnyTestAsync() { - EnvironmentManager.Instance.WebServer.Start(); + await EnvironmentManager.Instance.WebServer.StartAsync(); } [OneTimeTearDown] - public void RunAfterAnyTests() + public async Task RunAfterAnyTestsAsync() { EnvironmentManager.Instance.CloseCurrentDriver(); - EnvironmentManager.Instance.WebServer.Stop(); + await EnvironmentManager.Instance.WebServer.StopAsync(); } [SetUp] From a169e1abe064e1ec1f5348721a20c6a90ab1fb0b Mon Sep 17 00:00:00 2001 From: Selenium CI Bot Date: Tue, 19 Nov 2024 05:37:13 +0100 Subject: [PATCH 09/58] [dotnet][rb][java][js][py] Automated Browser Version Update (#14747) Update pinned browser versions Co-authored-by: Selenium CI Bot --- common/repositories.bzl | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/common/repositories.bzl b/common/repositories.bzl index cdbdd4d13140a..08eacbcf17615 100644 --- a/common/repositories.bzl +++ b/common/repositories.bzl @@ -11,8 +11,8 @@ def pin_browsers(): http_archive( name = "linux_firefox", - url = "https://ftp.mozilla.org/pub/firefox/releases/132.0.1/linux-x86_64/en-US/firefox-132.0.1.tar.bz2", - sha256 = "ecdcb4787263cacd31aa3a1b62c14f1d3b69af44a0b40f9eb040852f401097c1", + url = "https://ftp.mozilla.org/pub/firefox/releases/132.0.2/linux-x86_64/en-US/firefox-132.0.2.tar.bz2", + sha256 = "777d47f8b8710ab450582dc0dc0cdf8f43c2291249b3eaf740ee28ee34cda139", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -33,8 +33,8 @@ js_library( dmg_archive( name = "mac_firefox", - url = "https://ftp.mozilla.org/pub/firefox/releases/132.0.1/mac/en-US/Firefox%20132.0.1.dmg", - sha256 = "409c0bdb4e434c1191b71504626f8165b01e2582e561a870591940186614be2e", + url = "https://ftp.mozilla.org/pub/firefox/releases/132.0.2/mac/en-US/Firefox%20132.0.2.dmg", + sha256 = "233251c46eb4964868d815a9233cab855ac6160736310771a67af93a9b78224d", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -50,8 +50,8 @@ js_library( http_archive( name = "linux_beta_firefox", - url = "https://ftp.mozilla.org/pub/firefox/releases/133.0b6/linux-x86_64/en-US/firefox-133.0b6.tar.bz2", - sha256 = "0f600dd3225ca6824004d28449e94d3768012f49eaea5506c618a199f234486e", + url = "https://ftp.mozilla.org/pub/firefox/releases/133.0b9/linux-x86_64/en-US/firefox-133.0b9.tar.bz2", + sha256 = "5c9f79912bfbf892d2b676973a26ffc078ee9b8fd9b791bfa856db030e657750", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -72,8 +72,8 @@ js_library( dmg_archive( name = "mac_beta_firefox", - url = "https://ftp.mozilla.org/pub/firefox/releases/133.0b6/mac/en-US/Firefox%20133.0b6.dmg", - sha256 = "a6be00e4471d07eefc149a73e564232f2051fa8a39c1e12385550c8822f128b5", + url = "https://ftp.mozilla.org/pub/firefox/releases/133.0b9/mac/en-US/Firefox%20133.0b9.dmg", + sha256 = "0eb0fabe9216dc80c2ca403dd2eba935d71f2bdc1dea1d1cc37f03666ef094d1", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -123,10 +123,10 @@ js_library( pkg_archive( name = "mac_edge", - url = "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/1225faee-37ac-4c03-8f2b-153353d900c6/MicrosoftEdge-130.0.2849.80.pkg", - sha256 = "a0f3353555a7057158fd0335ecc783a45e1ed5bf38da9975396b63008591af80", + url = "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/08b226c9-fbe8-43c0-94fe-ed9c3eeb8f59/MicrosoftEdge-131.0.2903.51.pkg", + sha256 = "5bc1eab86bb315aa9f2cd2b7d9afe072df35280f6e6d1a9ca9c108d95bda8acd", move = { - "MicrosoftEdge-130.0.2849.80.pkg/Payload/Microsoft Edge.app": "Edge.app", + "MicrosoftEdge-131.0.2903.51.pkg/Payload/Microsoft Edge.app": "Edge.app", }, build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") @@ -143,8 +143,8 @@ js_library( deb_archive( name = "linux_edge", - url = "https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-stable/microsoft-edge-stable_130.0.2849.80-1_amd64.deb", - sha256 = "1b6f5743703e6da81c65c28dbcfd949d605466e226acc7cde9efbd4beabfa05d", + url = "https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-stable/microsoft-edge-stable_131.0.2903.51-1_amd64.deb", + sha256 = "8aad12c97bcae417ff9cc4251b75211eeda7f1513312dc57b2f744e824e028c0", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -165,8 +165,8 @@ js_library( http_archive( name = "linux_edgedriver", - url = "https://msedgedriver.azureedge.net/130.0.2849.78/edgedriver_linux64.zip", - sha256 = "aec868f31bd714a5c12405f6fd6e0e7bfb3d0d06ae79690ecffde4af73da2075", + url = "https://msedgedriver.azureedge.net/131.0.2903.52/edgedriver_linux64.zip", + sha256 = "ddbeda7cec5ed16b96c3cf0f6759de30e4f3726da9da31bfba1371ccd8fcfd14", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -182,8 +182,8 @@ js_library( http_archive( name = "mac_edgedriver", - url = "https://msedgedriver.azureedge.net/130.0.2849.81/edgedriver_mac64.zip", - sha256 = "da719a1170c2e93a88186dd9dabe485dda816280539522af03535d6c02eb1943", + url = "https://msedgedriver.azureedge.net/131.0.2903.52/edgedriver_mac64.zip", + sha256 = "719f54eb9376df5963e80da727c8ab8bacf6a1f57b785602a53a22fe330bb160", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -199,8 +199,8 @@ js_library( http_archive( name = "linux_chrome", - url = "https://storage.googleapis.com/chrome-for-testing-public/130.0.6723.116/linux64/chrome-linux64.zip", - sha256 = "3e71b99204dc191a8692048526a4ad41803b8b9035ea4ef14eb9b1d37331e1f1", + url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.69/linux64/chrome-linux64.zip", + sha256 = "3e33f61511e5e9dabac0d7a57b4bb975555ed1d4dababa7898205c030f82e4e3", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -221,8 +221,8 @@ js_library( http_archive( name = "mac_chrome", - url = "https://storage.googleapis.com/chrome-for-testing-public/130.0.6723.116/mac-x64/chrome-mac-x64.zip", - sha256 = "2f535efa4d92c9aa3c7a1fd896ae4088d6a306150649bb7c1e6ef20f7d536476", + url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.69/mac-x64/chrome-mac-x64.zip", + sha256 = "72a52967c80f9f145856d08d91052eaa27f6b951f9a4d8ab279f192b98784e41", strip_prefix = "chrome-mac-x64", patch_cmds = [ "mv 'Google Chrome for Testing.app' Chrome.app", @@ -243,8 +243,8 @@ js_library( http_archive( name = "linux_chromedriver", - url = "https://storage.googleapis.com/chrome-for-testing-public/130.0.6723.116/linux64/chromedriver-linux64.zip", - sha256 = "35b6751942cb589e8bde4733cf6dc7a1484693a56004e5dc8d994beede19e847", + url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.69/linux64/chromedriver-linux64.zip", + sha256 = "afc7b41aa0e1606e8cc177c776287d836635690964e39eab1ed94d63a0c96be2", strip_prefix = "chromedriver-linux64", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") @@ -261,8 +261,8 @@ js_library( http_archive( name = "mac_chromedriver", - url = "https://storage.googleapis.com/chrome-for-testing-public/130.0.6723.116/mac-x64/chromedriver-mac-x64.zip", - sha256 = "f8f71dfbed7dfe7255b2a1abda3cf28cc4d661f6f653dc1282735c703c86b865", + url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.69/mac-x64/chromedriver-mac-x64.zip", + sha256 = "92583e52f601951d3e0849891239bb2f6ff00dd8f8fd6c908473cc21c0533dd2", strip_prefix = "chromedriver-mac-x64", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") From b164d854ce08ef72aed3bce142cfdff8d7b8b3ce Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Tue, 19 Nov 2024 15:38:50 +0000 Subject: [PATCH 10/58] [rb][js] Add funding information to package.json and gemspec files (#14774) --- javascript/node/selenium-webdriver/package.json | 12 +++++++++++- rb/selenium-devtools.gemspec | 3 ++- rb/selenium-webdriver.gemspec | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/javascript/node/selenium-webdriver/package.json b/javascript/node/selenium-webdriver/package.json index e06d9132c886a..aaa10a9f2a682 100644 --- a/javascript/node/selenium-webdriver/package.json +++ b/javascript/node/selenium-webdriver/package.json @@ -61,5 +61,15 @@ }, "publishConfig": { "registry": "https://registry.npmjs.org/" - } + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/SeleniumHQ" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/selenium" + } + ] } diff --git a/rb/selenium-devtools.gemspec b/rb/selenium-devtools.gemspec index 709efc6bcdb2c..ce776dc765631 100644 --- a/rb/selenium-devtools.gemspec +++ b/rb/selenium-devtools.gemspec @@ -23,7 +23,8 @@ Gem::Specification.new do |s| 'changelog_uri' => 'https://github.com/SeleniumHQ/selenium/blob/trunk/rb/CHANGES', 'github_repo' => 'ssh://github.com/SeleniumHQ/selenium', 'source_code_uri' => 'https://github.com/SeleniumHQ/selenium/tree/trunk/rb', - 'rubygems_mfa_required' => 'true' + 'rubygems_mfa_required' => 'true', + 'funding_uri' => 'https://github.com/sponsors/SeleniumHQ' } s.required_rubygems_version = Gem::Requirement.new('> 1.3.1') if s.respond_to? :required_rubygems_version= diff --git a/rb/selenium-webdriver.gemspec b/rb/selenium-webdriver.gemspec index b6c09f273c326..183981a1ba634 100644 --- a/rb/selenium-webdriver.gemspec +++ b/rb/selenium-webdriver.gemspec @@ -24,7 +24,8 @@ Gem::Specification.new do |s| 'changelog_uri' => 'https://github.com/SeleniumHQ/selenium/blob/trunk/rb/CHANGES', 'github_repo' => 'ssh://github.com/SeleniumHQ/selenium', 'source_code_uri' => 'https://github.com/SeleniumHQ/selenium/tree/trunk/rb', - 'rubygems_mfa_required' => 'true' + 'rubygems_mfa_required' => 'true', + 'funding_uri' => 'https://github.com/sponsors/SeleniumHQ' } s.required_rubygems_version = Gem::Requirement.new('> 1.3.1') if s.respond_to? :required_rubygems_version= From 751bacb6bc934436ec9dec2416a022d8d577e30a Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Tue, 19 Nov 2024 20:01:52 +0100 Subject: [PATCH 11/58] [rb] Resolve `uri` gem deprecation warning (#14770) > /home/user/.rbenv/versions/3.3.6/lib/ruby/gems/3.3.0/gems/selenium-webdriver-4.26.0/lib/selenium/webdriver/remote/bridge.rb:679: warning: URI::RFC3986_PARSER.escape is obsoleted. Use URI::RFC2396_PARSER.escape explicitly. Ruby switches the default parser from RFC2396 to RFC3986. This parser contains all methods from the old parser but delegates to RFC2396 for a few and warns. Namely `extract`, `make_regexp`, `escape`, and `unescape`. selenium currently supports Ruby >= 3.1, so the current old compatibility code is unnecessary. `RFC2396_PARSER` is a somewhat new addition, so some kind of check is still needed. It is available in Ruby 3.1 but early patch versions are missing it. --- rb/lib/selenium/webdriver/remote/bridge.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rb/lib/selenium/webdriver/remote/bridge.rb b/rb/lib/selenium/webdriver/remote/bridge.rb index 1678065010108..2c26285a780e0 100644 --- a/rb/lib/selenium/webdriver/remote/bridge.rb +++ b/rb/lib/selenium/webdriver/remote/bridge.rb @@ -686,7 +686,7 @@ def execute(command, opts = {}, command_hash = nil) end def escaper - @escaper ||= defined?(URI::Parser) ? URI::DEFAULT_PARSER : URI + @escaper ||= defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER end def commands(command) From d9149acc097531d336e611bd92d897381a0316c6 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Tue, 19 Nov 2024 14:12:56 -0500 Subject: [PATCH 12/58] [dotnet] Solidify nullability of `PinnedScript` (#14708) --- .../support/Events/EventFiringWebDriver.cs | 6 +++ dotnet/src/webdriver/IJavaScriptEngine.cs | 4 ++ dotnet/src/webdriver/IJavascriptExecutor.cs | 2 + dotnet/src/webdriver/ISearchContext.cs | 2 + dotnet/src/webdriver/JavaScriptEngine.cs | 25 ++++++++-- dotnet/src/webdriver/PinnedScript.cs | 49 +++++++------------ dotnet/src/webdriver/WebDriver.cs | 9 +++- dotnet/test/common/ExecutingJavascriptTest.cs | 28 +++++++++++ 8 files changed, 89 insertions(+), 36 deletions(-) diff --git a/dotnet/src/support/Events/EventFiringWebDriver.cs b/dotnet/src/support/Events/EventFiringWebDriver.cs index 46661f9225838..e68b261e387c3 100644 --- a/dotnet/src/support/Events/EventFiringWebDriver.cs +++ b/dotnet/src/support/Events/EventFiringWebDriver.cs @@ -478,6 +478,7 @@ public object ExecuteScript(string script, params object[] args) /// A object containing the code to execute. /// The arguments to the script. /// The value returned by the script. + /// If is . /// /// /// The ExecuteScript method executes JavaScript in the context of @@ -509,6 +510,11 @@ public object ExecuteScript(string script, params object[] args) /// public object ExecuteScript(PinnedScript script, params object[] args) { + if (script == null) + { + throw new ArgumentNullException(nameof(script)); + } + IJavaScriptExecutor javascriptDriver = this.driver as IJavaScriptExecutor; if (javascriptDriver == null) { diff --git a/dotnet/src/webdriver/IJavaScriptEngine.cs b/dotnet/src/webdriver/IJavaScriptEngine.cs index 0c4481d970b85..3445c59753d60 100644 --- a/dotnet/src/webdriver/IJavaScriptEngine.cs +++ b/dotnet/src/webdriver/IJavaScriptEngine.cs @@ -87,6 +87,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 . Task AddInitializationScript(string scriptName, string script); /// @@ -94,6 +95,7 @@ public interface IJavaScriptEngine : IDisposable /// /// The friendly name of the initialization script to be removed. /// A task that represents the asynchronous operation. + /// If is . Task RemoveInitializationScript(string scriptName); /// @@ -109,6 +111,7 @@ public interface IJavaScriptEngine : IDisposable /// /// The JavaScript to pin /// A task containing a object to use to execute the script. + /// If is . Task PinScript(string script); /// @@ -116,6 +119,7 @@ public interface IJavaScriptEngine : IDisposable /// /// The object to unpin. /// A task that represents the asynchronous operation. + /// If is . Task UnpinScript(PinnedScript script); /// diff --git a/dotnet/src/webdriver/IJavascriptExecutor.cs b/dotnet/src/webdriver/IJavascriptExecutor.cs index c8680a0c14c6c..fcbf9080efd2c 100644 --- a/dotnet/src/webdriver/IJavascriptExecutor.cs +++ b/dotnet/src/webdriver/IJavascriptExecutor.cs @@ -17,6 +17,7 @@ // under the License. // +using System; using System.Collections.Generic; namespace OpenQA.Selenium @@ -98,6 +99,7 @@ public interface IJavaScriptExecutor /// variable, as if the function were called via "Function.apply" /// /// + /// If is . object ExecuteScript(PinnedScript script, params object[] args); /// diff --git a/dotnet/src/webdriver/ISearchContext.cs b/dotnet/src/webdriver/ISearchContext.cs index 6f88562e296c8..53c5f33ae36da 100644 --- a/dotnet/src/webdriver/ISearchContext.cs +++ b/dotnet/src/webdriver/ISearchContext.cs @@ -17,6 +17,7 @@ // under the License. // +using System; using System.Collections.ObjectModel; namespace OpenQA.Selenium @@ -31,6 +32,7 @@ public interface ISearchContext /// /// The locating mechanism to use. /// The first matching on the current context. + /// If is . /// If no element matches the criteria. IWebElement FindElement(By by); diff --git a/dotnet/src/webdriver/JavaScriptEngine.cs b/dotnet/src/webdriver/JavaScriptEngine.cs index 35dc6764aac54..4bd4fe4676eb4 100644 --- a/dotnet/src/webdriver/JavaScriptEngine.cs +++ b/dotnet/src/webdriver/JavaScriptEngine.cs @@ -219,14 +219,25 @@ public async Task ClearInitializationScripts() /// /// The JavaScript to pin /// A task containing a object to use to execute the script. + /// If is . public async Task PinScript(string script) { + if (script == null) + { + throw new ArgumentNullException(nameof(script)); + } + + string newScriptHandle = Guid.NewGuid().ToString("N"); + // We do an "Evaluate" first so as to immediately create the script on the loaded // page, then will add it to the initialization of future pages. - PinnedScript pinnedScript = new PinnedScript(script); await this.EnableDomains().ConfigureAwait(false); - await this.session.Value.Domains.JavaScript.Evaluate(pinnedScript.CreationScript).ConfigureAwait(false); - pinnedScript.ScriptId = await this.session.Value.Domains.JavaScript.AddScriptToEvaluateOnNewDocument(pinnedScript.CreationScript).ConfigureAwait(false); + + string creationScript = PinnedScript.MakeCreationScript(newScriptHandle, script); + await this.session.Value.Domains.JavaScript.Evaluate(creationScript).ConfigureAwait(false); + string scriptId = await this.session.Value.Domains.JavaScript.AddScriptToEvaluateOnNewDocument(creationScript).ConfigureAwait(false); + + PinnedScript pinnedScript = new PinnedScript(script, newScriptHandle, scriptId); this.pinnedScripts[pinnedScript.Handle] = pinnedScript; return pinnedScript; } @@ -236,11 +247,17 @@ public async Task PinScript(string script) /// /// The object to unpin. /// A task that represents the asynchronous operation. + /// If is . public async Task UnpinScript(PinnedScript script) { + if (script == null) + { + throw new ArgumentNullException(nameof(script)); + } + if (this.pinnedScripts.ContainsKey(script.Handle)) { - await this.session.Value.Domains.JavaScript.Evaluate(script.RemovalScript).ConfigureAwait(false); + await this.session.Value.Domains.JavaScript.Evaluate(script.MakeRemovalScript()).ConfigureAwait(false); await this.session.Value.Domains.JavaScript.RemoveScriptToEvaluateOnNewDocument(script.ScriptId).ConfigureAwait(false); this.pinnedScripts.Remove(script.Handle); } diff --git a/dotnet/src/webdriver/PinnedScript.cs b/dotnet/src/webdriver/PinnedScript.cs index bf01e982385b6..629c1bd7212f3 100644 --- a/dotnet/src/webdriver/PinnedScript.cs +++ b/dotnet/src/webdriver/PinnedScript.cs @@ -17,83 +17,70 @@ // under the License. // -using System; using System.Globalization; +#nullable enable + namespace OpenQA.Selenium { /// /// A class representing a pinned JavaScript function that can be repeatedly called /// without sending the entire script across the wire for every execution. /// - public class PinnedScript + public sealed class PinnedScript { - private string scriptSource; - private string scriptHandle; - private string scriptId; - /// /// Initializes a new instance of the class. /// /// The body of the JavaScript function to pin. + /// The unique handle for this pinned script. + /// The internal ID of this script. /// /// This constructor is explicitly internal. Creation of pinned script objects /// is strictly the perview of Selenium, and should not be required by external /// libraries. /// - internal PinnedScript(string script) + internal PinnedScript(string script, string stringHandle, string scriptId) { - this.scriptSource = script; - this.scriptHandle = Guid.NewGuid().ToString("N"); + this.Source = script; + this.Handle = stringHandle; + this.ScriptId = scriptId; } /// /// Gets the unique handle for this pinned script. /// - public string Handle - { - get { return this.scriptHandle; } - } + public string Handle { get; } /// /// Gets the source representing the body of the function in the pinned script. /// - public string Source - { - get { return this.scriptSource; } - } + public string Source { get; } - /// - /// Gets the script to create the pinned script in the browser. - /// - internal string CreationScript + internal static string MakeCreationScript(string scriptHandle, string scriptSource) { - get { return string.Format(CultureInfo.InvariantCulture, "function __webdriver_{0}(arguments) {{ {1} }}", this.scriptHandle, this.scriptSource); } + return string.Format(CultureInfo.InvariantCulture, "function __webdriver_{0}(arguments) {{ {1} }}", scriptHandle, scriptSource); } /// /// Gets the script used to execute the pinned script in the browser. /// - internal string ExecutionScript + internal string MakeExecutionScript() { - get { return string.Format(CultureInfo.InvariantCulture, "return __webdriver_{0}(arguments)", this.scriptHandle); } + return string.Format(CultureInfo.InvariantCulture, "return __webdriver_{0}(arguments)", this.Handle); } /// /// Gets the script used to remove the pinned script from the browser. /// - internal string RemovalScript + internal string MakeRemovalScript() { - get { return string.Format(CultureInfo.InvariantCulture, "__webdriver_{0} = undefined", this.scriptHandle); } + return string.Format(CultureInfo.InvariantCulture, "__webdriver_{0} = undefined", this.Handle); } /// /// Gets or sets the ID of this script. /// - internal string ScriptId - { - get { return this.scriptId; } - set { this.scriptId = value; } - } + internal string ScriptId { get; } } } diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 1106fb0da8bbd..e29ce29a12c79 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -280,9 +280,15 @@ public object ExecuteScript(string script, params object[] args) /// A object containing the JavaScript code to execute. /// The arguments to the script. /// The value returned by the script. + /// If is . public object ExecuteScript(PinnedScript script, params object[] args) { - return this.ExecuteScript(script.ExecutionScript, args); + if (script == null) + { + throw new ArgumentNullException(nameof(script)); + } + + return this.ExecuteScript(script.MakeExecutionScript(), args); } /// @@ -290,6 +296,7 @@ public object ExecuteScript(PinnedScript script, params object[] args) /// /// By mechanism to find the object /// IWebElement object so that you can interact with that object + /// If is . /// /// /// IWebDriver driver = new InternetExplorerDriver(); diff --git a/dotnet/test/common/ExecutingJavascriptTest.cs b/dotnet/test/common/ExecutingJavascriptTest.cs index 463f82a4c434f..048b712d3178d 100644 --- a/dotnet/test/common/ExecutingJavascriptTest.cs +++ b/dotnet/test/common/ExecutingJavascriptTest.cs @@ -21,6 +21,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Threading.Tasks; namespace OpenQA.Selenium { @@ -468,6 +469,33 @@ public void ShouldBeAbleToExecuteABigChunkOfJavascriptCode() } } + [Test] + [IgnoreBrowser(Selenium.Browser.IE, "IE does not support Chrome DevTools Protocol")] + [IgnoreBrowser(Selenium.Browser.Firefox, "Firefox does not support Chrome DevTools Protocol")] + [IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Chrome DevTools Protocol")] + public async Task ShouldBeAbleToPinJavascriptCodeAndExecuteRepeatedly() + { + IJavaScriptEngine jsEngine = new JavaScriptEngine(driver); + + driver.Url = xhtmlTestPage; + + PinnedScript script = await jsEngine.PinScript("return document.title;"); + for (int i = 0; i < 5; i++) + { + object result = ((IJavaScriptExecutor)driver).ExecuteScript(script); + + Assert.That(result, Is.InstanceOf()); + Assert.That(result, Is.EqualTo("XHTML Test Page")); + } + + await jsEngine.UnpinScript(script); + + Assert.That(() => + { + _ = ((IJavaScriptExecutor)driver).ExecuteScript(script); + }, Throws.TypeOf()); + } + [Test] public void ShouldBeAbleToExecuteScriptAndReturnElementsList() { From 673d2c78be76f1ccbb2e1017e5240d52f428b400 Mon Sep 17 00:00:00 2001 From: Sandeep Suryaprasad <26169602+sandeepsuryaprasad@users.noreply.github.com> Date: Wed, 20 Nov 2024 05:33:17 +0530 Subject: [PATCH 13/58] [py] moved project metadata from `setup.py` to `pyproject.toml` (#14311) --- py/pyproject.toml | 44 +++++++++++++++++++++++++++++++++- py/setup.py | 60 +---------------------------------------------- 2 files changed, 44 insertions(+), 60 deletions(-) diff --git a/py/pyproject.toml b/py/pyproject.toml index eecffc1f3c3c8..7ee15417a32f1 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -2,12 +2,54 @@ requires = ["setuptools", "setuptools-rust"] build-backend = "setuptools.build_meta" +[project] +name = "selenium" +version = "4.27.0.dev202410311942" +license = "Apache 2.0" +description = "Official Python bindings for Selenium WebDriver." +readme = "README.rst" +requires-python = "~=3.8" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: POSIX", + "Operating System :: Microsoft :: Windows", + "Operating System :: MacOS :: MacOS X", + "Topic :: Software Development :: Testing", + "Topic :: Software Development :: Libraries", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + ] +dependencies = [ + "urllib3[socks]>=1.26,<3", + "trio~=0.17", + "trio-websocket~=0.9", + "certifi>=2021.10.8", + "typing_extensions~=4.9", + "websocket-client~=1.8", + ] + +[tool.setuptools] +zip-safe = false + [tool.setuptools.packages.find] include = ["selenium*"] exclude = ["test*"] -namespaces = false +namespace = false # include-package-data is `true` by default in pyproject.toml +[project.urls] +Repository = "https://github.com/SeleniumHQ/selenium/" +BugTracker = "https://github.com/SeleniumHQ/selenium/issues" +Changelog = "https://github.com/SeleniumHQ/selenium/blob/trunk/py/CHANGES" +Documentation = "https://www.selenium.dev/documentation/overview/" +SourceCode = "https://github.com/SeleniumHQ/selenium/tree/trunk/py" + [tool.setuptools.package-data] selenium_package = [ "*.py", diff --git a/py/setup.py b/py/setup.py index cd6b84b8e2c14..3014b5321e307 100755 --- a/py/setup.py +++ b/py/setup.py @@ -27,70 +27,12 @@ setup_args = { 'cmdclass': {'install': install}, - 'name': 'selenium', - 'version': "4.27.0.dev202410311942", - 'license': 'Apache 2.0', - 'description': 'Official Python bindings for Selenium WebDriver.', - 'long_description': open(join(abspath(dirname(__file__)), "README.rst")).read(), - 'url': 'https://github.com/SeleniumHQ/selenium/', - 'project_urls': { - 'Bug Tracker': 'https://github.com/SeleniumHQ/selenium/issues', - 'Changes': 'https://github.com/SeleniumHQ/selenium/blob/trunk/py/CHANGES', - 'Documentation': 'https://www.selenium.dev/documentation/overview/', - 'Source Code': 'https://github.com/SeleniumHQ/selenium/tree/trunk/py', - }, - 'python_requires': '~=3.8', - 'classifiers': ['Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: POSIX', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: MacOS :: MacOS X', - 'Topic :: Software Development :: Testing', - 'Topic :: Software Development :: Libraries', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - ], - 'package_dir': { - 'selenium': 'selenium', - 'selenium.common': 'selenium/common', - 'selenium.webdriver': 'selenium/webdriver', - }, - 'packages': ['selenium', - 'selenium.common', - 'selenium.webdriver', - 'selenium.webdriver.chrome', - 'selenium.webdriver.chromium', - 'selenium.webdriver.common', - 'selenium.webdriver.edge', - 'selenium.webdriver.firefox', - 'selenium.webdriver.ie', - 'selenium.webdriver.remote', - 'selenium.webdriver.safari', - 'selenium.webdriver.support', - 'selenium.webdriver.webkitgtk', - 'selenium.webdriver.wpewebkit', - ], - 'include_package_data': True, - 'install_requires': [ - "urllib3[socks]>=1.26,<3", - "trio~=0.17", - "trio-websocket~=0.9", - "certifi>=2021.10.8", - "typing_extensions~=4.9", - "websocket-client~=1.8", - ], 'rust_extensions': [ RustExtension( {"selenium-manager": "selenium.webdriver.common.selenium-manager"}, binding=Binding.Exec ) ], - 'zip_safe': False } -setup(**setup_args) +setup(**setup_args) \ No newline at end of file From 8f725b3a80c3f3d621821e94a87db346ea91a8b1 Mon Sep 17 00:00:00 2001 From: Puja Jagani Date: Wed, 20 Nov 2024 09:54:27 +0530 Subject: [PATCH 14/58] [dotnet] Add CDP deprecation warning for Firefox (#14759) Co-authored-by: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> --- dotnet/src/webdriver/Firefox/FirefoxDriver.cs | 1 + dotnet/src/webdriver/Remote/RemoteWebDriver.cs | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs index da3061c897d8b..99f9cb3ea68c6 100644 --- a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs +++ b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs @@ -413,6 +413,7 @@ public DevToolsSession GetDevToolsSession(int devToolsProtocolVersion) /// Creates a session to communicate with a browser using a Developer Tools debugging protocol. /// /// The active session to use to communicate with the Developer Tools debugging protocol. + [Obsolete("CDP support for Firefox is deprecated and will be removed in future versions. Please switch to WebDriver BiDi.")] public DevToolsSession GetDevToolsSession(DevToolsOptions options) { if (this.devToolsSession == null) diff --git a/dotnet/src/webdriver/Remote/RemoteWebDriver.cs b/dotnet/src/webdriver/Remote/RemoteWebDriver.cs index 35a32af124d78..8483eb2fbc3ec 100644 --- a/dotnet/src/webdriver/Remote/RemoteWebDriver.cs +++ b/dotnet/src/webdriver/Remote/RemoteWebDriver.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.Internal.Logging; using OpenQA.Selenium.DevTools; using System; using System.Collections.Generic; @@ -63,6 +64,8 @@ namespace OpenQA.Selenium.Remote /// public class RemoteWebDriver : WebDriver, IDevTools, IHasDownloads { + private static readonly ILogger _logger = OpenQA.Selenium.Internal.Logging.Log.GetLogger(typeof(RemoteWebDriver)); + /// /// The name of the Selenium grid remote DevTools end point capability. /// @@ -425,6 +428,14 @@ public ReadOnlyCollection FindElementsByCssSelector(string cssSelec /// The active session to use to communicate with the Developer Tools debugging protocol. public DevToolsSession GetDevToolsSession() { + if (this.Capabilities.GetCapability(CapabilityType.BrowserName) == "firefox") + { + if (_logger.IsEnabled(LogEventLevel.Warn)) + { + _logger.Warn("CDP support for Firefox is deprecated and will be removed in future versions. Please switch to WebDriver BiDi."); + } + } + return GetDevToolsSession(new DevToolsOptions() { ProtocolVersion = DevToolsSession.AutoDetectDevToolsProtocolVersion }); } From 789e8d42de31a507ff78958025e395bebd2dab46 Mon Sep 17 00:00:00 2001 From: Viet Nguyen Duc Date: Wed, 20 Nov 2024 17:46:34 +0700 Subject: [PATCH 15/58] [ci][py] Update latest index for new Nightly upload (#14739) Signed-off-by: Viet Nguyen Duc --- Rakefile | 5 +++-- py/BUILD.bazel | 2 +- py/docs/source/conf.py | 2 +- py/pyproject.toml | 10 +++++----- py/selenium/__init__.py | 2 +- py/selenium/webdriver/__init__.py | 2 +- py/setup.py | 2 +- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Rakefile b/Rakefile index 24f41e429f1cd..454096c176366 100644 --- a/Rakefile +++ b/Rakefile @@ -582,10 +582,11 @@ namespace :py do desc 'Update Python version' task :version, [:version] do |_task, arguments| old_version = python_version - nightly = ".dev#{Time.now.strftime('%Y%m%d%H%M')}" + nightly = ".#{Time.now.strftime('%Y%m%d%H%M')}" new_version = updated_version(old_version, arguments[:version], nightly) ['py/setup.py', + 'py/pyproject.toml', 'py/BUILD.bazel', 'py/selenium/__init__.py', 'py/selenium/webdriver/__init__.py', @@ -1138,7 +1139,7 @@ def updated_version(current, desired = nil, nightly = nil) desired.split('.').tap { |v| v << 0 while v.size < 3 }.join('.') elsif current.split(/\.|-/).size > 3 # if current version is already nightly, just need to bump it; this will be noop for some languages - pattern = /-?\.?(nightly|SNAPSHOT|dev)\d*$/ + pattern = /-?\.?(nightly|SNAPSHOT|dev|\d{12})\d*$/ current.gsub(pattern, nightly) elsif current.split(/\.|-/).size == 3 # if current version is not nightly, need to bump the version and make nightly diff --git a/py/BUILD.bazel b/py/BUILD.bazel index beba3d5684c7c..0e955f052f4d8 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -62,7 +62,7 @@ compile_pip_requirements( ], ) -SE_VERSION = "4.27.0.dev202410311942" +SE_VERSION = "4.27.0.202410311942" BROWSER_VERSIONS = [ "v85", diff --git a/py/docs/source/conf.py b/py/docs/source/conf.py index 1d5148a0508fa..41a620b368248 100644 --- a/py/docs/source/conf.py +++ b/py/docs/source/conf.py @@ -58,7 +58,7 @@ # The short X.Y version. version = '4.27' # The full version, including alpha/beta/rc tags. -release = '4.27.0.dev202410311942' +release = '4.27.0.202410311942' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/py/pyproject.toml b/py/pyproject.toml index 7ee15417a32f1..6488cda070f56 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "selenium" -version = "4.27.0.dev202410311942" +version = "4.27.0.202410311942" license = "Apache 2.0" description = "Official Python bindings for Selenium WebDriver." readme = "README.rst" @@ -52,15 +52,15 @@ SourceCode = "https://github.com/SeleniumHQ/selenium/tree/trunk/py" [tool.setuptools.package-data] selenium_package = [ - "*.py", + "*.py", "*.rst", - "*.json", - "*.xpi", + "*.json", + "*.xpi", "*.js", "py.typed", "prune*", "selenium.egg-info*", - "selenium-manager", + "selenium-manager", "selenium-manager.exe", "CHANGES", "LICENSE" diff --git a/py/selenium/__init__.py b/py/selenium/__init__.py index e7ab5cc0b075e..8fa1fd3219d4d 100644 --- a/py/selenium/__init__.py +++ b/py/selenium/__init__.py @@ -16,4 +16,4 @@ # under the License. -__version__ = "4.27.0.dev202410311942" +__version__ = "4.27.0.202410311942" diff --git a/py/selenium/webdriver/__init__.py b/py/selenium/webdriver/__init__.py index b64471644e380..c57217aefb69f 100644 --- a/py/selenium/webdriver/__init__.py +++ b/py/selenium/webdriver/__init__.py @@ -44,7 +44,7 @@ from .wpewebkit.service import Service as WPEWebKitService # noqa from .wpewebkit.webdriver import WebDriver as WPEWebKit # noqa -__version__ = "4.27.0.dev202410311942" +__version__ = "4.27.0.202410311942" # We need an explicit __all__ because the above won't otherwise be exported. __all__ = [ diff --git a/py/setup.py b/py/setup.py index 3014b5321e307..0f93e33f0ecae 100755 --- a/py/setup.py +++ b/py/setup.py @@ -35,4 +35,4 @@ ], } -setup(**setup_args) \ No newline at end of file +setup(**setup_args) From fefdba1ccc258720e6d79b0dd85f8e962c7e2e00 Mon Sep 17 00:00:00 2001 From: Titus Fortner Date: Wed, 20 Nov 2024 10:16:38 -0800 Subject: [PATCH 16/58] [rb] implement navigation commands with BiDi (#14094) * [rb] create context manager and implement navigation with BiDi * replace BrowsingContext class instead of creating new context manager * Fix formatting issues --------- Co-authored-by: Augustin Gottlieb <33221555+aguspe@users.noreply.github.com> Co-authored-by: aguspe --- .../webdriver/bidi/browsing_context.rb | 110 ++++++++++-------- .../webdriver/bidi/browsing_context_info.rb | 35 ------ .../webdriver/bidi/navigate_result.rb | 33 ------ .../selenium/webdriver/remote/bidi_bridge.rb | 22 ++++ .../webdriver/bidi/browsing_context.rbs | 20 ++-- .../selenium/webdriver/remote/bidi_bridge.rbs | 24 +++- .../webdriver/bidi/browsing_context_spec.rb | 99 ++++++---------- .../selenium/webdriver/navigation_spec.rb | 63 +++++----- 8 files changed, 176 insertions(+), 230 deletions(-) delete mode 100644 rb/lib/selenium/webdriver/bidi/browsing_context_info.rb delete mode 100644 rb/lib/selenium/webdriver/bidi/navigate_result.rb diff --git a/rb/lib/selenium/webdriver/bidi/browsing_context.rb b/rb/lib/selenium/webdriver/bidi/browsing_context.rb index 8e4eaa1434e0b..b8f33227ce8a6 100644 --- a/rb/lib/selenium/webdriver/bidi/browsing_context.rb +++ b/rb/lib/selenium/webdriver/bidi/browsing_context.rb @@ -17,72 +17,84 @@ # specific language governing permissions and limitations # under the License. -require_relative 'navigate_result' -require_relative 'browsing_context_info' - module Selenium module WebDriver class BiDi + # Implements the browsingContext Module of the WebDriver-BiDi specification + # + # @api private + # class BrowsingContext - attr_accessor :id - READINESS_STATE = { - none: 'none', - interactive: 'interactive', - complete: 'complete' + 'none' => 'none', + 'eager' => 'interactive', + 'normal' => 'complete' }.freeze - def initialize(driver:, browsing_context_id: nil, type: nil, reference_context: nil) - unless driver.capabilities.web_socket_url - raise Error::WebDriverError, - 'WebDriver instance must support BiDi protocol' - end - - unless type.nil? || %i[window tab].include?(type) - raise ArgumentError, - "Valid types are :window & :tab. Received: #{type.inspect}" - end - - @bidi = driver.bidi - @id = browsing_context_id.nil? ? create(type, reference_context)['context'] : browsing_context_id + # TODO: store current window handle in bridge object instead of always calling it + def initialize(bridge) + @bridge = bridge + @bidi = @bridge.bidi + page_load_strategy = bridge.capabilities[:page_load_strategy] + @readiness = READINESS_STATE[page_load_strategy] end - def navigate(url:, readiness_state: nil) - unless readiness_state.nil? || READINESS_STATE.key?(readiness_state) - raise ArgumentError, - "Valid readiness states are :none, :interactive & :complete. Received: #{readiness_state.inspect}" - end - - navigate_result = @bidi.send_cmd('browsingContext.navigate', context: @id, url: url, - wait: READINESS_STATE[readiness_state]) - - NavigateResult.new( - url: navigate_result['url'], - navigation_id: navigate_result['navigation'] - ) + # Navigates to the specified URL in the given browsing context. + # + # @param url [String] The URL to navigate to. + # @param context_id [String, NilClass] The ID of the browsing context to navigate in. + # Defaults to the window handle of the current context. + def navigate(url, context_id: nil) + context_id ||= @bridge.window_handle + @bidi.send_cmd('browsingContext.navigate', context: context_id, url: url, wait: @readiness) end - def get_tree(max_depth: nil) - result = @bidi.send_cmd('browsingContext.getTree', root: @id, maxDepth: max_depth).dig('contexts', 0) - - BrowsingContextInfo.new( - id: result['context'], - url: result['url'], - children: result['children'], - parent_context: result['parent'] - ) + # Traverses the browsing context history by a given delta. + # + # @param delta [Integer] The number of steps to traverse. + # Positive values go forwards, negative values go backwards. + # @param context_id [String, NilClass] The ID of the context to traverse. + # Defaults to the window handle of the current context. + def traverse_history(delta, context_id: nil) + context_id ||= @bridge.window_handle + @bidi.send_cmd('browsingContext.traverseHistory', context: context_id, delta: delta) end - def close - @bidi.send_cmd('browsingContext.close', context: @id) + # Reloads the browsing context. + # @param [String, NilClass] context_id The ID of the context to reload. + # Defaults to the window handle of the current context. + # @param [Boolean] ignore_cache Whether to bypass the cache when reloading. + # Defaults to false. + def reload(context_id: nil, ignore_cache: false) + context_id ||= @bridge.window_handle + params = {context: context_id, ignore_cache: ignore_cache, wait: @readiness} + @bidi.send_cmd('browsingContext.reload', **params) end - private + # Closes the browsing context. + # + # @param [String] context_id The ID of the context to close. + # Defaults to the window handle of the current context. + def close(context_id: nil) + context_id ||= @bridge.window_handle + @bidi.send_cmd('browsingContext.close', context: context_id) + end - def create(type, reference_context) - @bidi.send_cmd('browsingContext.create', type: type.to_s, referenceContext: reference_context) + # Create a new browsing context. + # + # @param [Symbol] type The type of browsing context to create. + # Valid options are :tab and :window with :window being the default + # @param [String] context_id The reference context for the new browsing context. + # Defaults to the current window handle. + # + # @return [String] The context ID of the created browsing context. + def create(type: nil, context_id: nil) + type ||= :window + context_id ||= @bridge.window_handle + result = @bidi.send_cmd('browsingContext.create', type: type.to_s, referenceContext: context_id) + result['context'] end - end # BrowsingContext + end end # BiDi end # WebDriver end # Selenium diff --git a/rb/lib/selenium/webdriver/bidi/browsing_context_info.rb b/rb/lib/selenium/webdriver/bidi/browsing_context_info.rb deleted file mode 100644 index 8a4435c0cd67a..0000000000000 --- a/rb/lib/selenium/webdriver/bidi/browsing_context_info.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -# Licensed to the Software Freedom Conservancy (SFC) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The SFC licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -module Selenium - module WebDriver - class BiDi - class BrowsingContextInfo - attr_accessor :id, :url, :children, :parent_browsing_context - - def initialize(id:, url:, children:, parent_context:) - @id = id - @url = url - @children = children - @parent_browsing_context = parent_context - end - end # BrowsingContextInfo - end # BiDi - end # WebDriver -end # Selenium diff --git a/rb/lib/selenium/webdriver/bidi/navigate_result.rb b/rb/lib/selenium/webdriver/bidi/navigate_result.rb deleted file mode 100644 index ad32c28ea952b..0000000000000 --- a/rb/lib/selenium/webdriver/bidi/navigate_result.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -# Licensed to the Software Freedom Conservancy (SFC) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The SFC licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -module Selenium - module WebDriver - class BiDi - class NavigateResult - attr_accessor :url, :navigation_id - - def initialize(url:, navigation_id:) - @url = url - @navigation_id = navigation_id - end - end # NavigateResult - end # BiDi - end # WebDriver -end # Selenium diff --git a/rb/lib/selenium/webdriver/remote/bidi_bridge.rb b/rb/lib/selenium/webdriver/remote/bidi_bridge.rb index 935fdff5b2954..c95ddec538f85 100644 --- a/rb/lib/selenium/webdriver/remote/bidi_bridge.rb +++ b/rb/lib/selenium/webdriver/remote/bidi_bridge.rb @@ -29,6 +29,22 @@ def create_session(capabilities) @bidi = Selenium::WebDriver::BiDi.new(url: socket_url) end + def get(url) + browsing_context.navigate(url) + end + + def go_back + browsing_context.traverse_history(-1) + end + + def go_forward + browsing_context.traverse_history(1) + end + + def refresh + browsing_context.reload + end + def quit super ensure @@ -38,6 +54,12 @@ def quit def close execute(:close_window).tap { |handles| bidi.close if handles.empty? } end + + private + + def browsing_context + @browsing_context ||= WebDriver::BiDi::BrowsingContext.new(self) + end end # BiDiBridge end # Remote end # WebDriver diff --git a/rb/sig/lib/selenium/webdriver/bidi/browsing_context.rbs b/rb/sig/lib/selenium/webdriver/bidi/browsing_context.rbs index a690a38221634..1577c22073561 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/browsing_context.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/browsing_context.rbs @@ -2,25 +2,21 @@ module Selenium module WebDriver class BiDi class BrowsingContext - @bidi: untyped + @bidi: BiDi - @id: untyped + READINESS_STATE: Hash[String, String] - attr_accessor id: untyped + def initialize: (Remote::Bridge bridge) -> void - READINESS_STATE: Hash[Symbol, String] + def navigate: (String url, String? context_id) -> void - def initialize: (driver: untyped, ?browsing_context_id: untyped?, ?type: untyped?, ?reference_context: untyped?) -> void + def traverse_history: (Integer delta, String? context_id) -> void - def navigate: (url: untyped, ?readiness_state: untyped?) -> untyped + def reload: (String? context_id, ?ignore_cache: bool) -> void - def get_tree: (?max_depth: untyped?) -> untyped + def close: (String? context_id) -> void - def close: () -> untyped - - private - - def create: (untyped type, untyped reference_context) -> untyped + def create: (?type: Symbol | String | nil, ?context_id: String | nil) -> String end end end diff --git a/rb/sig/lib/selenium/webdriver/remote/bidi_bridge.rbs b/rb/sig/lib/selenium/webdriver/remote/bidi_bridge.rbs index bb0c77cc36863..aeec5854d18cf 100644 --- a/rb/sig/lib/selenium/webdriver/remote/bidi_bridge.rbs +++ b/rb/sig/lib/selenium/webdriver/remote/bidi_bridge.rbs @@ -1,16 +1,28 @@ module Selenium module WebDriver module Remote - class BiDiBridge < Bridge - @bidi: untyped + class BiDiBridge + @browsing_context: BiDi::BrowsingContext - attr_reader bidi: untyped + attr_reader bidi: BiDi - def create_session: (Hash[Symbol, String] capabilities) -> BiDi + def create_session: (untyped capabilities) -> void - def quit: () -> nil + def get: (String url) -> void - def close: () -> untyped + def go_back: () -> void + + def go_forward: () -> void + + def refresh: () -> void + + def quit: () -> void + + def close: () -> void + + private + + def browsing_context: () -> BiDi::BrowsingContext end end end diff --git a/rb/spec/integration/selenium/webdriver/bidi/browsing_context_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/browsing_context_spec.rb index 902a289441652..353847a4c0bd7 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/browsing_context_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/browsing_context_spec.rb @@ -26,85 +26,54 @@ class BiDi only: {browser: %i[chrome edge firefox]} do after { |example| reset_driver!(example: example) } - it 'can create a browsing context for given id' do - id = driver.window_handle - browsing_context = described_class.new(driver: driver, browsing_context_id: id) - expect(browsing_context.id).to eq(id) - end + let(:bridge) { driver.instance_variable_get(:@bridge) } - it 'can create a window' do - browsing_context = described_class.new(driver: driver, type: :window) - expect(browsing_context.id).not_to be_nil - end + describe '#create' do + it 'without arguments' do + id = described_class.new(bridge).create - it 'can create a window with a reference context' do - browsing_context = described_class.new(driver: driver, type: :window, - reference_context: driver.window_handle) - expect(browsing_context.id).not_to be_nil - end + expect(driver.window_handles).to include(id) + end - it 'can create a tab without a reference context' do - browsing_context = described_class.new(driver: driver, type: :tab) - expect(browsing_context.id).not_to be_nil - end + it 'accepts a tab type' do + id = described_class.new(bridge).create(type: :tab) - it 'can create a tab with a reference context' do - browsing_context = described_class.new(driver: driver, type: :tab, reference_context: driver.window_handle) - expect(browsing_context.id).not_to be_nil - end - - it 'can navigate to a url' do - browsing_context = described_class.new(driver: driver, type: :tab) + expect(driver.window_handles).to include(id) + end - info = browsing_context.navigate url: url_for('/bidi/logEntryAdded.html') + it 'accepts a window type' do + id = described_class.new(bridge).create(type: :window) - expect(browsing_context.id).not_to be_nil - expect(info.url).to include('/bidi/logEntryAdded.html') - end + expect(driver.window_handles).to include(id) + end - it 'can navigate to a url with readiness state' do - browsing_context = described_class.new(driver: driver, type: :tab) - - info = browsing_context.navigate url: url_for('/bidi/logEntryAdded.html'), - readiness_state: :complete - - expect(browsing_context.id).not_to be_nil - expect(info.url).to include('/bidi/logEntryAdded.html') - end - - it 'can get tree with a child' do - browsing_context_id = driver.window_handle - parent_window = described_class.new(driver: driver, browsing_context_id: browsing_context_id) - parent_window.navigate(url: url_for('iframes.html'), - readiness_state: :complete) - - context_info = parent_window.get_tree - expect(context_info.children.size).to eq(1) - expect(context_info.id).to eq(browsing_context_id) - expect(context_info.children[0]['url']).to include('formPage.html') - end + it 'errors on unknown type' do + msg = /invalid argument: Invalid enum value. Expected 'tab' | 'window', received 'unknown'/ + expect { + described_class.new(bridge).create(type: :unknown) + }.to raise_error(Error::WebDriverError, msg) + end - it 'can get tree with depth' do - browsing_context_id = driver.window_handle - parent_window = described_class.new(driver: driver, browsing_context_id: browsing_context_id) - parent_window.navigate(url: url_for('iframes.html'), - readiness_state: :complete) + it 'accepts a reference context' do + id = driver.window_handle + result = described_class.new(bridge).create(context_id: id) - context_info = parent_window.get_tree(max_depth: 0) - expect(context_info.children).to be_nil - expect(context_info.id).to eq(browsing_context_id) + expect(driver.window_handles).to include(id, result) + end end - it 'can close a window' do - window1 = described_class.new(driver: driver, type: :window) - window2 = described_class.new(driver: driver, type: :window) + it 'closes a window' do + browsing_context = described_class.new(bridge) + window1 = browsing_context.create + window2 = browsing_context.create - window2.close + browsing_context.close(context_id: window2) - expect { window1.get_tree }.not_to raise_error - expect { window2.get_tree }.to raise_error(Error::WebDriverError) + handles = driver.window_handles + expect(handles).to include(window1) + expect(handles).not_to include(window2) end - end # BrowsingContext + end end # BiDi end # WebDriver end # Selenium diff --git a/rb/spec/integration/selenium/webdriver/navigation_spec.rb b/rb/spec/integration/selenium/webdriver/navigation_spec.rb index b7586bc1bb9d8..1f7f5506c4b4b 100644 --- a/rb/spec/integration/selenium/webdriver/navigation_spec.rb +++ b/rb/spec/integration/selenium/webdriver/navigation_spec.rb @@ -18,43 +18,46 @@ # under the License. require_relative 'spec_helper' +module Selenium + module WebDriver + describe Navigation do + it 'navigates back and forward' do + form_title = 'We Leave From Here' + result_title = 'We Arrive Here' + form_url = url_for 'formPage.html' + result_url = url_for 'resultPage.html' -describe 'Navigation', exclusive: {bidi: false, reason: 'Not yet implemented with BiDi'} do - it 'navigates back and forward' do - form_title = 'We Leave From Here' - result_title = 'We Arrive Here' - form_url = url_for 'formPage.html' - result_url = url_for 'resultPage.html' + driver.navigate.to form_url + expect(driver.title).to eq(form_title) - driver.navigate.to form_url - expect(driver.title).to eq(form_title) + driver.find_element(id: 'imageButton').click + wait.until { driver.title != form_title } - driver.find_element(id: 'imageButton').click - wait.until { driver.title != form_title } + expect(driver.current_url).to include(result_url) + expect(driver.title).to eq(result_title) - expect(driver.current_url).to include(result_url) - expect(driver.title).to eq(result_title) + driver.navigate.back - driver.navigate.back + expect(driver.current_url).to include(form_url) + expect(driver.title).to eq(form_title) - expect(driver.current_url).to include(form_url) - expect(driver.title).to eq(form_title) + driver.navigate.forward + expect(driver.current_url).to include(result_url) + expect(driver.title).to eq(result_title) + end - driver.navigate.forward - expect(driver.current_url).to include(result_url) - expect(driver.title).to eq(result_title) - end + it 'refreshes the page' do + changed_title = 'Changed' - it 'refreshes the page' do - changed_title = 'Changed' + driver.navigate.to url_for('javascriptPage.html') + driver.find_element(link_text: 'Change the page title!').click + expect(driver.title).to eq(changed_title) - driver.navigate.to url_for('javascriptPage.html') - driver.find_element(link_text: 'Change the page title!').click - expect(driver.title).to eq(changed_title) + driver.navigate.refresh + wait.until { driver.title != changed_title } - driver.navigate.refresh - wait.until { driver.title != changed_title } - - expect(driver.title).to eq('Testing Javascript') - end -end + expect(driver.title).to eq('Testing Javascript') + end + end + end # WebDriver +end # Selenium From 192b2d5bf657b10e98821b1883302142bd414c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sautter?= Date: Wed, 20 Nov 2024 21:49:08 +0100 Subject: [PATCH 17/58] [grid] avoid starting a session which will be disposed after start --- .../local/LocalNewSessionQueue.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/java/src/org/openqa/selenium/grid/sessionqueue/local/LocalNewSessionQueue.java b/java/src/org/openqa/selenium/grid/sessionqueue/local/LocalNewSessionQueue.java index d5192aba28ac1..5dc3a4e947da7 100644 --- a/java/src/org/openqa/selenium/grid/sessionqueue/local/LocalNewSessionQueue.java +++ b/java/src/org/openqa/selenium/grid/sessionqueue/local/LocalNewSessionQueue.java @@ -300,9 +300,7 @@ public boolean retryAddToQueue(SessionRequest request) { // return true to avoid handleNewSessionRequest to call 'complete' an other time return true; } else if (data.isCanceled()) { - complete( - request.getRequestId(), - Either.left(new SessionNotCreatedException("Client has gone away"))); + failDueToCanceled(request.getRequestId()); // return true to avoid handleNewSessionRequest to call 'complete' an other time return true; } @@ -370,7 +368,18 @@ public List getNextAvailable(Map stereotypes .limit(batchSize) .collect(Collectors.toList()); - availableRequests.forEach(req -> this.remove(req.getRequestId())); + availableRequests.removeIf( + (req) -> { + Data data = this.requests.get(req.getRequestId()); + + if (data.isCanceled()) { + failDueToCanceled(req.getRequestId()); + return true; + } + + this.remove(req.getRequestId()); + return false; + }); return availableRequests; } finally { @@ -458,6 +467,11 @@ private void failDueToTimeout(RequestId reqId) { complete(reqId, Either.left(new SessionNotCreatedException("Timed out creating session"))); } + private void failDueToCanceled(RequestId reqId) { + // this error should never reach the client, as this is a client initiated state + complete(reqId, Either.left(new SessionNotCreatedException("Client has gone away"))); + } + private class Data { public final Instant endTime; From 60e31710765cdf3ac48a97217b84b41960922ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sautter?= Date: Wed, 20 Nov 2024 21:55:55 +0100 Subject: [PATCH 18/58] [java] close the running Server in unittests if a retry is needed --- .../environment/webserver/NettyAppServer.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/java/test/org/openqa/selenium/environment/webserver/NettyAppServer.java b/java/test/org/openqa/selenium/environment/webserver/NettyAppServer.java index 04316b0e451d8..2ff06b6dfcd12 100644 --- a/java/test/org/openqa/selenium/environment/webserver/NettyAppServer.java +++ b/java/test/org/openqa/selenium/environment/webserver/NettyAppServer.java @@ -149,7 +149,16 @@ public void start() { () -> { server.start(); if (secure != null) { - secure.start(); + try { + secure.start(); + } catch (Exception e) { + try { + server.stop(); + } catch (Exception ex) { + e.addSuppressed(ex); + throw e; + } + } } }); } From 0954ccac4c86e4ba81db65d255f1d04d8edd7b29 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Wed, 20 Nov 2024 19:02:33 -0500 Subject: [PATCH 19/58] [dotnet] Modernize exception handling in tests via assert that throws (#14776) --- dotnet/src/webdriver/WebDriver.cs | 2 +- dotnet/test/common/AlertsTest.cs | 95 ++++++++-------- dotnet/test/common/CorrectEventFiringTest.cs | 16 +-- dotnet/test/common/ElementAttributeTest.cs | 23 ++-- .../Environment/RemoteSeleniumServer.cs | 15 +-- dotnet/test/common/ExecutingJavascriptTest.cs | 102 ++++++++++++++---- dotnet/test/common/FrameSwitchingTest.cs | 51 ++++----- dotnet/test/common/TargetLocatorTest.cs | 72 ++++++------- dotnet/test/common/WindowSwitchingTest.cs | 76 ++++--------- .../Extensions/ExecuteJavaScriptTest.cs | 36 +++++-- 10 files changed, 248 insertions(+), 240 deletions(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index e29ce29a12c79..6bd964136c928 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -935,7 +935,7 @@ private static object ConvertObjectToJavaScriptObject(object arg) } else { - throw new ArgumentException("Argument is of an illegal type" + arg.ToString(), nameof(arg)); + throw new ArgumentException("Argument is of an illegal type: " + arg.ToString(), nameof(arg)); } return converted; diff --git a/dotnet/test/common/AlertsTest.cs b/dotnet/test/common/AlertsTest.cs index a99706724838b..84a05f4a6a78c 100644 --- a/dotnet/test/common/AlertsTest.cs +++ b/dotnet/test/common/AlertsTest.cs @@ -60,7 +60,9 @@ public void ShouldThrowArgumentNullExceptionWhenKeysNull() IAlert alert = WaitFor(AlertToBePresent, "No alert found"); try { - Assert.That(() => alert.SendKeys(null), Throws.ArgumentNullException); + Assert.That( + () => alert.SendKeys(null), + Throws.ArgumentNullException); } finally { @@ -147,13 +149,12 @@ public void SettingTheValueOfAnAlertThrows() driver.FindElement(By.Id("alert")).Click(); IAlert alert = WaitFor(AlertToBePresent, "No alert found"); + try { - alert.SendKeys("cheese"); - Assert.Fail("Expected exception"); - } - catch (ElementNotInteractableException) - { + Assert.That( + () => alert.SendKeys("cheese"), + Throws.TypeOf()); } finally { @@ -198,8 +199,10 @@ public void AlertShouldNotAllowAdditionalCommandsIfDismissed() IAlert alert = WaitFor(AlertToBePresent, "No alert found"); alert.Dismiss(); - string text; - Assert.That(() => text = alert.Text, Throws.InstanceOf()); + + Assert.That( + () => alert.Text, + Throws.TypeOf()); } [Test] @@ -249,7 +252,9 @@ public void SwitchingToMissingAlertThrows() { driver.Url = CreateAlertPage("cheese"); - Assert.That(() => AlertToBePresent(), Throws.InstanceOf()); + Assert.That( + () => AlertToBePresent(), + Throws.TypeOf()); } [Test] @@ -270,15 +275,9 @@ public void SwitchingToMissingAlertInAClosedWindowThrows() driver.Close(); WaitFor(WindowHandleCountToBe(1), "Window count was not 1"); - try - { - AlertToBePresent().Accept(); - Assert.Fail("Expected exception"); - } - catch (NoSuchWindowException) - { - // Expected - } + Assert.That( + () => AlertToBePresent().Accept(), + Throws.TypeOf()); } finally @@ -321,17 +320,22 @@ public void HandlesTwoAlertsFromOneInteraction() { driver.Url = EnvironmentManager.Instance.UrlBuilder.CreateInlinePage(new InlinePage() .WithScripts( - "function setInnerText(id, value) {", - " document.getElementById(id).innerHTML = '

' + value + '

';", - "}", - "function displayTwoPrompts() {", - " setInnerText('text1', prompt('First'));", - " setInnerText('text2', prompt('Second'));", - "}") + """ + function setInnerText(id, value) { + document.getElementById(id).innerHTML = '

' + value + '

'; + } + + function displayTwoPrompts() { + setInnerText('text1', prompt('First')); + setInnerText('text2', prompt('Second')); + } + """) .WithBody( - "click me", - "
", - "
")); + """ + click me +
+
+ """)); driver.FindElement(By.Id("double-prompt")).Click(); @@ -355,7 +359,7 @@ public void HandlesTwoAlertsFromOneInteraction() public void ShouldHandleAlertOnPageLoad() { string pageWithOnLoad = EnvironmentManager.Instance.UrlBuilder.CreateInlinePage(new InlinePage() - .WithOnLoad("javascript:alert(\"onload\")") + .WithOnLoad("""javascript:alert("onload")""") .WithBody("

Page with onload event handler

")); driver.Url = EnvironmentManager.Instance.UrlBuilder.CreateInlinePage(new InlinePage() .WithBody(string.Format("open new page", pageWithOnLoad))); @@ -411,17 +415,12 @@ public void ShouldNotHandleAlertInAnotherWindow() Assert.AreEqual(1, allWindows.Count); onloadWindow = allWindows[0]; - try + Assert.That(() => { IWebElement el = driver.FindElement(By.Id("open-new-window")); WaitFor(AlertToBePresent, TimeSpan.FromSeconds(5), "No alert found"); - Assert.Fail("Expected exception"); - } - catch (WebDriverException) - { - // An operation timed out exception is expected, - // since we're using WaitFor. - } + }, + Throws.TypeOf()); } finally @@ -442,15 +441,10 @@ public void IncludesAlertTextInUnhandledAlertException() driver.FindElement(By.Id("alert")).Click(); WaitFor(AlertToBePresent, "No alert found"); - try - { - string title = driver.Title; - Assert.Fail("Expected UnhandledAlertException"); - } - catch (UnhandledAlertException e) - { - Assert.AreEqual("cheese", e.AlertText); - } + + Assert.That( + () => driver.Title, + Throws.TypeOf().With.Property(nameof(UnhandledAlertException.AlertText)).EqualTo("cheese")); } [Test] @@ -522,16 +516,14 @@ private Func ElementToBePresent(By locator) { return () => { - IWebElement foundElement = null; try { - foundElement = driver.FindElement(By.Id("open-page-with-onunload-alert")); + return driver.FindElement(By.Id("open-page-with-onunload-alert")); } catch (NoSuchElementException) { + return null; } - - return foundElement; }; } @@ -554,9 +546,8 @@ private Func WindowWithName(string name) } catch (NoSuchWindowException) { + return false; } - - return false; }; } diff --git a/dotnet/test/common/CorrectEventFiringTest.cs b/dotnet/test/common/CorrectEventFiringTest.cs index e358197100d08..d30e205b485fd 100644 --- a/dotnet/test/common/CorrectEventFiringTest.cs +++ b/dotnet/test/common/CorrectEventFiringTest.cs @@ -348,20 +348,12 @@ public void SendingKeysToAFocusedElementShouldNotBlurThatElement() focused = true; break; } - try - { - System.Threading.Thread.Sleep(200); - } - catch (Exception) - { - throw; - } - } - if (!focused) - { - Assert.Fail("Clicking on element didn't focus it in time - can't proceed so failing"); + + System.Threading.Thread.Sleep(200); } + Assert.That(focused, Is.True, "Clicking on element didn't focus it in time - can't proceed so failing"); + element.SendKeys("a"); AssertEventNotFired("blur"); } diff --git a/dotnet/test/common/ElementAttributeTest.cs b/dotnet/test/common/ElementAttributeTest.cs index 21ed7305a1801..43a1be4a063a9 100644 --- a/dotnet/test/common/ElementAttributeTest.cs +++ b/dotnet/test/common/ElementAttributeTest.cs @@ -127,28 +127,19 @@ public void ShouldThrowExceptionIfSendingKeysToElementDisabledUsingRandomDisable { driver.Url = formsPage; IWebElement disabledTextElement1 = driver.FindElement(By.Id("disabledTextElement1")); - try + + Assert.That(() => { disabledTextElement1.SendKeys("foo"); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidElementStateException) - { - //Expected - } + }, Throws.TypeOf()); Assert.AreEqual(string.Empty, disabledTextElement1.Text); IWebElement disabledTextElement2 = driver.FindElement(By.Id("disabledTextElement2")); - try - { - disabledTextElement2.SendKeys("bar"); - Assert.Fail("Should have thrown exception"); - } - catch (InvalidElementStateException) - { - //Expected - } + + Assert.That( + () => disabledTextElement2.SendKeys("bar"), + Throws.TypeOf()); Assert.AreEqual(string.Empty, disabledTextElement2.Text); } diff --git a/dotnet/test/common/Environment/RemoteSeleniumServer.cs b/dotnet/test/common/Environment/RemoteSeleniumServer.cs index 388bc6b1e3083..8c12943c928f3 100644 --- a/dotnet/test/common/Environment/RemoteSeleniumServer.cs +++ b/dotnet/test/common/Environment/RemoteSeleniumServer.cs @@ -91,14 +91,15 @@ public async Task StopAsync() { if (autoStart && webserverProcess != null && !webserverProcess.HasExited) { - using var httpClient = new HttpClient(); - - try - { - using var response = await httpClient.GetAsync("http://localhost:6000/selenium-server/driver?cmd=shutDownSeleniumServer"); - } - catch (Exception ex) when (ex is HttpRequestException || ex is TimeoutException) + using (var httpClient = new HttpClient()) { + try + { + using var response = await httpClient.GetAsync("http://localhost:6000/selenium-server/driver?cmd=shutDownSeleniumServer"); + } + catch (Exception ex) when (ex is HttpRequestException || ex is TimeoutException) + { + } } webserverProcess.WaitForExit(10000); diff --git a/dotnet/test/common/ExecutingJavascriptTest.cs b/dotnet/test/common/ExecutingJavascriptTest.cs index 048b712d3178d..34a567a7a92c2 100644 --- a/dotnet/test/common/ExecutingJavascriptTest.cs +++ b/dotnet/test/common/ExecutingJavascriptTest.cs @@ -391,14 +391,17 @@ public void ShouldBeAbleToPassACollectionAsArgument() Assert.AreEqual(collection.Count, length); } - + [Test] public void ShouldThrowAnExceptionIfAnArgumentIsNotValid() { if (!(driver is IJavaScriptExecutor)) return; driver.Url = javascriptPage; - Assert.That(() => ExecuteScript("return arguments[0];", driver), Throws.InstanceOf()); + + Assert.That( + () => ExecuteScript("return arguments[0];", driver), + Throws.ArgumentException.With.Message.StartsWith("Argument is of an illegal type: ")); } [Test] @@ -490,10 +493,9 @@ public async Task ShouldBeAbleToPinJavascriptCodeAndExecuteRepeatedly() await jsEngine.UnpinScript(script); - Assert.That(() => - { - _ = ((IJavaScriptExecutor)driver).ExecuteScript(script); - }, Throws.TypeOf()); + Assert.That( + () => ((IJavaScriptExecutor)driver).ExecuteScript(script), + Throws.TypeOf()); } [Test] @@ -566,7 +568,9 @@ public void ShouldThrowAnExceptionWhenArgumentsWithStaleElementPassed() Dictionary args = new Dictionary(); args["key"] = new object[] { "a", new object[] { "zero", 1, true, 3.14159, false, el }, "c" }; - Assert.That(() => executor.ExecuteScript("return undefined;", args), Throws.InstanceOf()); + Assert.That( + () => executor.ExecuteScript("return undefined;", args), + Throws.TypeOf()); } [Test] @@ -611,7 +615,17 @@ public void ShouldHandleRecursiveStructures() { driver.Url = simpleTestPage; - Assert.That(() => ExecuteScript("var obj1 = {}; var obj2 = {}; obj1['obj2'] = obj2; obj2['obj1'] = obj1; return obj1"), Throws.InstanceOf()); + Assert.That( + () => ExecuteScript( + """ + var obj1 = {}; + var obj2 = {}; + obj1['obj2'] = obj2; + obj2['obj1'] = obj1; + return obj1 + """ + ), + Throws.TypeOf()); } //------------------------------------------------------------------ @@ -622,26 +636,68 @@ public void ShouldHandleRecursiveStructures() [Ignore("Reason for ignore: Failure indicates hang condition, which would break the test suite. Really needs a timeout set.")] public void ShouldThrowExceptionIfExecutingOnNoPage() { - bool exceptionCaught = false; - try - { - ((IJavaScriptExecutor)driver).ExecuteScript("return 1;"); - } - catch (WebDriverException) - { - exceptionCaught = true; - } - - if (!exceptionCaught) - { - Assert.Fail("Expected an exception to be caught"); - } + Assert.That( + () => ((IJavaScriptExecutor)driver).ExecuteScript("return 1;"), + Throws.InstanceOf()); } [Test] public void ExecutingLargeJavaScript() { - string script = "// stolen from injectableSelenium.js in WebDriver\nvar browserbot = {\n\n triggerEvent: function(element, eventType, canBubble, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown) {\n canBubble = (typeof(canBubble) == undefined) ? true: canBubble;\n if (element.fireEvent && element.ownerDocument && element.ownerDocument.createEventObject) {\n // IE\n var evt = this.createEventObject(element, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown);\n element.fireEvent('on' + eventType,evt);\n } else {\n var evt = document.createEvent('HTMLEvents');\n\n try {\n evt.shiftKey = shiftKeyDown;\n evt.metaKey = metaKeyDown;\n evt.altKey = altKeyDown;\n evt.ctrlKey = controlKeyDown;\n } catch(e) {\n // Nothing sane to do\n }\n\n evt.initEvent(eventType, canBubble, true);\n return element.dispatchEvent(evt);\n }\n },\n\n getVisibleText: function() {\n var selection = getSelection();\n var range = document.createRange();\n range.selectNodeContents(document.documentElement);\n selection.addRange(range);\nvar string = selection.toString();\n selection.removeAllRanges();\n\n return string;\n },\n\n getOuterHTML: function(element) {\n if(element.outerHTML) {\n return element.outerHTML;\n } else if(typeof(XMLSerializer) != undefined) {\n return new XMLSerializer().serializeToString(element);\n } else {\n throw \"can't get outerHTML in this browser\";\n }\n }\n\n\n};return browserbot.getOuterHTML.apply(browserbot, arguments);"; + string script = """ + // stolen from injectableSelenium.js in WebDriver + var browserbot = { + + triggerEvent: function(element, eventType, canBubble, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown) { + canBubble = (typeof(canBubble) == undefined) ? true : canBubble; + + if (element.fireEvent && element.ownerDocument && element.ownerDocument.createEventObject) { + // IE + var evt = this.createEventObject(element, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown); + element.fireEvent('on' + eventType,evt); + } else { + var evt = document.createEvent('HTMLEvents'); + + try { + evt.shiftKey = shiftKeyDown; + evt.metaKey = metaKeyDown; + evt.altKey = altKeyDown; + evt.ctrlKey = controlKeyDown; + } catch(e) { + // Nothing sane to do + } + + evt.initEvent(eventType, canBubble, true); + return element.dispatchEvent(evt); + } + }, + + getVisibleText: function() { + var selection = getSelection(); + var range = document.createRange(); + range.selectNodeContents(document.documentElement); + selection.addRange(range); + + var string = selection.toString(); + selection.removeAllRanges(); + + return string; + }, + + getOuterHTML: function(element) { + if(element.outerHTML) { + return element.outerHTML; + } else if(typeof(XMLSerializer) != undefined) { + return new XMLSerializer().serializeToString(element); + } else { + throw "can't get outerHTML in this browser"; + } + } + }; + + return browserbot.getOuterHTML.apply(browserbot, arguments); + """; + driver.Url = javascriptPage; IWebElement element = driver.FindElement(By.TagName("body")); object x = ExecuteScript(script, element); diff --git a/dotnet/test/common/FrameSwitchingTest.cs b/dotnet/test/common/FrameSwitchingTest.cs index c669ab8fca519..a5e9777e2f48a 100644 --- a/dotnet/test/common/FrameSwitchingTest.cs +++ b/dotnet/test/common/FrameSwitchingTest.cs @@ -175,28 +175,16 @@ public void FrameSearchesShouldBeRelativeToTheCurrentlySelectedFrame() driver.SwitchTo().Frame(frameElement); Assert.AreEqual("2", driver.FindElement(By.Id("pageNumber")).Text); - try - { - driver.SwitchTo().Frame("third"); - Assert.Fail(); - } - catch (NoSuchFrameException) - { - // Do nothing - } + Assert.That( + () => driver.SwitchTo().Frame("third"), + Throws.TypeOf()); driver.SwitchTo().DefaultContent(); driver.SwitchTo().Frame("third"); - try - { - driver.SwitchTo().Frame("second"); - Assert.Fail(); - } - catch (NoSuchFrameException) - { - // Do nothing - } + Assert.That( + () => driver.SwitchTo().Frame("second"), + Throws.TypeOf()); driver.SwitchTo().DefaultContent(); driver.SwitchTo().Frame("second"); @@ -216,7 +204,9 @@ public void ShouldThrowFrameNotFoundExceptionLookingUpSubFramesWithSuperFrameNam { driver.Url = framesetPage; driver.SwitchTo().Frame("fourth"); - Assert.That(() => driver.SwitchTo().Frame("second"), Throws.InstanceOf()); + Assert.That( + () => driver.SwitchTo().Frame("second"), + Throws.TypeOf()); } @@ -224,14 +214,20 @@ public void ShouldThrowFrameNotFoundExceptionLookingUpSubFramesWithSuperFrameNam public void ShouldThrowAnExceptionWhenAFrameCannotBeFound() { driver.Url = xhtmlTestPage; - Assert.That(() => driver.SwitchTo().Frame("Nothing here"), Throws.InstanceOf()); + + Assert.That( + () => driver.SwitchTo().Frame("Nothing here"), + Throws.TypeOf()); } [Test] public void ShouldThrowAnExceptionWhenAFrameCannotBeFoundByIndex() { driver.Url = xhtmlTestPage; - Assert.That(() => driver.SwitchTo().Frame(27), Throws.InstanceOf()); + + Assert.That( + () => driver.SwitchTo().Frame(27), + Throws.TypeOf()); } [Test] @@ -470,7 +466,9 @@ public void ShouldNotBeAbleToDoAnythingTheFrameIsDeletedFromUnderUs() IWebElement killIframe = driver.FindElement(By.Id("killIframe")); killIframe.Click(); - Assert.That(() => driver.FindElement(By.Id("killIframe")), Throws.InstanceOf()); + Assert.That( + () => driver.FindElement(By.Id("killIframe")), + Throws.TypeOf()); } [Test] @@ -615,9 +613,8 @@ private bool FrameExistsAndSwitchedTo(string locator) } catch (NoSuchFrameException) { + return false; } - - return false; } private bool FrameExistsAndSwitchedTo(int index) @@ -629,9 +626,8 @@ private bool FrameExistsAndSwitchedTo(int index) } catch (NoSuchFrameException) { + return false; } - - return false; } private bool FrameExistsAndSwitchedTo(IWebElement frameElement) @@ -643,9 +639,8 @@ private bool FrameExistsAndSwitchedTo(IWebElement frameElement) } catch (NoSuchFrameException) { + return false; } - - return false; } } } diff --git a/dotnet/test/common/TargetLocatorTest.cs b/dotnet/test/common/TargetLocatorTest.cs index 7985431a68a1c..19a23cb1dd086 100644 --- a/dotnet/test/common/TargetLocatorTest.cs +++ b/dotnet/test/common/TargetLocatorTest.cs @@ -30,14 +30,20 @@ public class TargetLocatorTest : DriverTestFixture public void ShouldThrowExceptionAfterSwitchingToNonExistingFrameIndex() { driver.Url = framesPage; - Assert.That(() => driver.SwitchTo().Frame(10), Throws.InstanceOf()); + + Assert.That( + () => driver.SwitchTo().Frame(10), + Throws.TypeOf()); } [Test] public void ShouldThrowExceptionAfterSwitchingToNonExistingFrameName() { driver.Url = framesPage; - Assert.That(() => driver.SwitchTo().Frame("æ©ñµøöíúüþ®éåä²doesnotexist"), Throws.InstanceOf()); + + Assert.That( + () => driver.SwitchTo().Frame("æ©ñµøöíúüþ®éåä²doesnotexist"), + Throws.TypeOf()); } [Test] @@ -45,7 +51,10 @@ public void ShouldThrowExceptionAfterSwitchingToNullFrameName() { string frameName = null; driver.Url = framesPage; - Assert.That(() => driver.SwitchTo().Frame(frameName), Throws.InstanceOf()); + + Assert.That( + () => driver.SwitchTo().Frame(frameName), + Throws.TypeOf()); } [Test] @@ -83,29 +92,21 @@ public void ShouldSwitchToFrameByNameAndBackToDefaultContent() Assert.AreEqual(driver.FindElement(By.Id("pageNumber")).Text, "1"); driver.SwitchTo().DefaultContent(); - try - { - // DefaultContent should not have the element in it. - Assert.AreEqual(driver.FindElement(By.Id("pageNumber")).Text, "1"); - Assert.Fail("Should not be able to get element in frame from DefaultContent"); - } - catch (NoSuchElementException) - { - } + + // DefaultContent should not have the element in it. + Assert.That( + () => driver.FindElement(By.Id("pageNumber")), + Throws.TypeOf()); driver.SwitchTo().Frame("second"); Assert.AreEqual(driver.FindElement(By.Id("pageNumber")).Text, "2"); driver.SwitchTo().DefaultContent(); - try - { - // DefaultContent should not have the element in it. - Assert.AreEqual(driver.FindElement(By.Id("pageNumber")).Text, "1"); - Assert.Fail("Should not be able to get element in frame from DefaultContent"); - } - catch (NoSuchElementException) - { - } + + // DefaultContent should not have the element in it. + Assert.That( + () => driver.FindElement(By.Id("pageNumber")), + Throws.TypeOf()); } [Test] @@ -117,29 +118,22 @@ public void ShouldSwitchToFrameByIndexAndBackToDefaultContent() Assert.AreEqual(driver.FindElement(By.Id("pageNumber")).Text, "1"); driver.SwitchTo().DefaultContent(); - try - { - // DefaultContent should not have the element in it. - Assert.AreEqual(driver.FindElement(By.Id("pageNumber")).Text, "1"); - Assert.Fail("Should not be able to get element in frame from DefaultContent"); - } - catch (NoSuchElementException) - { - } + + // DefaultContent should not have the element in it. + Assert.That( + () => driver.FindElement(By.Id("pageNumber")), + Throws.TypeOf()); + driver.SwitchTo().Frame(1); Assert.AreEqual(driver.FindElement(By.Id("pageNumber")).Text, "2"); driver.SwitchTo().DefaultContent(); - try - { - // DefaultContent should not have the element in it. - Assert.AreEqual(driver.FindElement(By.Id("pageNumber")).Text, "1"); - Assert.Fail("Should not be able to get element in frame from DefaultContent"); - } - catch (NoSuchElementException) - { - } + + // DefaultContent should not have the element in it. + Assert.That( + () => driver.FindElement(By.Id("pageNumber")).Text, + Throws.TypeOf()); } } diff --git a/dotnet/test/common/WindowSwitchingTest.cs b/dotnet/test/common/WindowSwitchingTest.cs index b268200710f92..ab153b8377a50 100644 --- a/dotnet/test/common/WindowSwitchingTest.cs +++ b/dotnet/test/common/WindowSwitchingTest.cs @@ -60,14 +60,10 @@ public void ShouldThrowNoSuchWindowException() { driver.Url = xhtmlTestPage; String current = driver.CurrentWindowHandle; - try - { - driver.SwitchTo().Window("invalid name"); - } - catch (NoSuchWindowException) - { - // This is expected. - } + + Assert.That( + () => driver.SwitchTo().Window("invalid name"), + Throws.TypeOf()); driver.SwitchTo().Window(current); } @@ -91,12 +87,9 @@ public void ShouldThrowNoSuchWindowExceptionOnAnAttemptToGetItsHandle() try { - string currentHandle = driver.CurrentWindowHandle; - Assert.Fail("NoSuchWindowException expected"); - } - catch (NoSuchWindowException) - { - // Expected. + Assert.That( + () => driver.CurrentWindowHandle, + Throws.TypeOf()); } finally { @@ -123,25 +116,13 @@ public void ShouldThrowNoSuchWindowExceptionOnAnyOperationIfAWindowIsClosed() try { - try - { - string title = driver.Title; - Assert.Fail("NoSuchWindowException expected"); - } - catch (NoSuchWindowException) - { - // Expected. - } + Assert.That( + () => driver.Title, + Throws.TypeOf()); - try - { - driver.FindElement(By.TagName("body")); - Assert.Fail("NoSuchWindowException expected"); - } - catch (NoSuchWindowException) - { - // Expected. - } + Assert.That( + () => driver.FindElement(By.TagName("body")), + Throws.TypeOf()); } finally { @@ -169,12 +150,9 @@ public void ShouldThrowNoSuchWindowExceptionOnAnyElementOperationIfAWindowIsClos try { - string bodyText = body.Text; - Assert.Fail("NoSuchWindowException expected"); - } - catch (NoSuchWindowException) - { - // Expected. + Assert.That( + () => body.Text, + Throws.TypeOf()); } finally { @@ -280,15 +258,10 @@ public void FailingToSwitchToAWindowLeavesTheCurrentWindowAsIs() driver.Url = xhtmlTestPage; String current = driver.CurrentWindowHandle; - try - { - driver.SwitchTo().Window("i will never exist"); - Assert.Fail("Should not be ablt to change to a non-existant window"); - } - catch (NoSuchWindowException) - { - // expected - } + Assert.That( + () => driver.SwitchTo().Window("i will never exist"), + Throws.TypeOf(), + "Should not be able to change to a non-existant window"); String newHandle = driver.CurrentWindowHandle; @@ -488,9 +461,8 @@ private Func WindowWithName(string name) } catch (NoSuchWindowException) { + return false; } - - return false; }; } @@ -498,16 +470,14 @@ private Func AlertToBePresent() { return () => { - IAlert alert = null; try { - alert = driver.SwitchTo().Alert(); + return driver.SwitchTo().Alert(); } catch (NoAlertPresentException) { + return null; } - - return alert; }; } } diff --git a/dotnet/test/support/Extensions/ExecuteJavaScriptTest.cs b/dotnet/test/support/Extensions/ExecuteJavaScriptTest.cs index 88f99381f539d..15ad94527c7aa 100644 --- a/dotnet/test/support/Extensions/ExecuteJavaScriptTest.cs +++ b/dotnet/test/support/Extensions/ExecuteJavaScriptTest.cs @@ -57,7 +57,9 @@ public void ShouldConvertToIEnumerable() driver.Setup(_ => _.ExecuteScript(It.IsAny(), It.IsAny())).Returns(expected); - Assert.That(() => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), Throws.Nothing); + Assert.That( + () => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), + Throws.Nothing); } [Test] @@ -67,7 +69,9 @@ public void ShouldConvertToIEnumerableOfObject() driver.Setup(_ => _.ExecuteScript(It.IsAny(), It.IsAny())).Returns(expected); - Assert.That(() => driver.Object.ExecuteJavaScript>(JavaScript, JavaScriptParameters), Throws.Nothing); + Assert.That( + () => driver.Object.ExecuteJavaScript>(JavaScript, JavaScriptParameters), + Throws.Nothing); } [Test] @@ -77,7 +81,9 @@ public void ShouldNotConvertToIEnumerableOfInteger() driver.Setup(_ => _.ExecuteScript(It.IsAny(), It.IsAny())).Returns(expected); - Assert.That(() => driver.Object.ExecuteJavaScript>(JavaScript, JavaScriptParameters), Throws.InstanceOf()); + Assert.That( + () => driver.Object.ExecuteJavaScript>(JavaScript, JavaScriptParameters), + Throws.TypeOf()); } [Test] @@ -87,7 +93,9 @@ public void ShouldConvertToReadOnlyCollectionOfObject() driver.Setup(_ => _.ExecuteScript(It.IsAny(), It.IsAny())).Returns(expected); - Assert.That(() => driver.Object.ExecuteJavaScript>(JavaScript, JavaScriptParameters), Throws.Nothing); + Assert.That( + () => driver.Object.ExecuteJavaScript>(JavaScript, JavaScriptParameters), + Throws.Nothing); } [Test] @@ -97,7 +105,9 @@ public void ShouldNotConvertToSubClassOfReadOnlyCollectionOfObject() driver.Setup(_ => _.ExecuteScript(It.IsAny(), It.IsAny())).Returns(expected); - Assert.That(() => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), Throws.InstanceOf()); + Assert.That( + () => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), + Throws.TypeOf()); } [Test] @@ -105,7 +115,9 @@ public void ShouldNotThrowWhenNullIsReturned() { driver.Setup(_ => _.ExecuteScript(It.IsAny(), It.IsAny())).Returns(null); - Assert.That(() => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), Throws.Nothing); + Assert.That( + () => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), + Throws.Nothing); } [Test] @@ -113,7 +125,9 @@ public void ShouldNotThrowWhenNullIsReturnedForNullableValueType() { driver.Setup(_ => _.ExecuteScript(It.IsAny(), It.IsAny())).Returns(null); - Assert.That(() => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), Throws.Nothing); + Assert.That( + () => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), + Throws.Nothing); } [Test] @@ -121,7 +135,9 @@ public void ShouldThrowWhenNullIsReturnedForValueType() { driver.Setup(_ => _.ExecuteScript(It.IsAny(), It.IsAny())).Returns(null); - Assert.That(() => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), Throws.InstanceOf()); + Assert.That( + () => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), + Throws.TypeOf()); } [Test] @@ -129,7 +145,9 @@ public void ShouldAllowExecutingJavaScriptWithoutReturningResult() { driver.Setup(_ => _.ExecuteScript(It.IsAny(), It.IsAny())).Returns(null); - Assert.That(() => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), Throws.Nothing); + Assert.That( + () => driver.Object.ExecuteJavaScript(JavaScript, JavaScriptParameters), + Throws.Nothing); } } } From e2b33c6015bc9a2a6bcbb7db4f8219fc69897de8 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Thu, 21 Nov 2024 05:38:04 -0500 Subject: [PATCH 20/58] [dotnet] Address warnings for Firefox devtool depreciations (#14786) --- dotnet/src/webdriver/Firefox/FirefoxDriver.cs | 1 + dotnet/src/webdriver/Remote/RemoteWebDriver.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs index 99f9cb3ea68c6..123f0eb6dc545 100644 --- a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs +++ b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs @@ -393,6 +393,7 @@ public Screenshot GetFullPageScreenshot() /// Creates a session to communicate with a browser using the Chromium Developer Tools debugging protocol. /// /// The active session to use to communicate with the Chromium Developer Tools debugging protocol. + [Obsolete("CDP support for Firefox is deprecated and will be removed in future versions. Please switch to WebDriver BiDi.")] public DevToolsSession GetDevToolsSession() { return GetDevToolsSession(new DevToolsOptions() { ProtocolVersion = FirefoxDevToolsProtocolVersion }); diff --git a/dotnet/src/webdriver/Remote/RemoteWebDriver.cs b/dotnet/src/webdriver/Remote/RemoteWebDriver.cs index 8483eb2fbc3ec..0950c84949ff9 100644 --- a/dotnet/src/webdriver/Remote/RemoteWebDriver.cs +++ b/dotnet/src/webdriver/Remote/RemoteWebDriver.cs @@ -428,7 +428,7 @@ public ReadOnlyCollection FindElementsByCssSelector(string cssSelec /// The active session to use to communicate with the Developer Tools debugging protocol. public DevToolsSession GetDevToolsSession() { - if (this.Capabilities.GetCapability(CapabilityType.BrowserName) == "firefox") + if (this.Capabilities.GetCapability(CapabilityType.BrowserName) is "firefox") { if (_logger.IsEnabled(LogEventLevel.Warn)) { From b1828bf1087d7d4acfd437d83ef6168617286191 Mon Sep 17 00:00:00 2001 From: Navin Chandra <98466550+navin772@users.noreply.github.com> Date: Thu, 21 Nov 2024 18:33:18 +0530 Subject: [PATCH 21/58] [py]: replace dead battery imghdr with filetype (#14771) --- py/BUILD.bazel | 1 + py/requirements.txt | 1 + py/requirements_lock.txt | 131 +++++++++--------- .../common/takes_screenshots_tests.py | 11 +- .../ff_takes_full_page_screenshots_tests.py | 9 +- .../remote/remote_connection_tests.py | 6 +- 6 files changed, 83 insertions(+), 76 deletions(-) diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 0e955f052f4d8..25c084a6f745d 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -74,6 +74,7 @@ BROWSER_VERSIONS = [ TEST_DEPS = [ requirement("attrs"), requirement("debugpy"), + requirement("filetype"), requirement("idna"), requirement("iniconfig"), requirement("importlib_metadata"), diff --git a/py/requirements.txt b/py/requirements.txt index 38085a1181db8..5f4dc4d646d0b 100644 --- a/py/requirements.txt +++ b/py/requirements.txt @@ -4,6 +4,7 @@ certifi==2023.11.17 cffi==1.16.0 cryptography==42.0.8 debugpy==1.8.7 +filetype==1.2.0 h11==0.14.0 idna==3.7 importlib-metadata==6.8.0 diff --git a/py/requirements_lock.txt b/py/requirements_lock.txt index fc5cb15044fdb..2da2d212d25cf 100644 --- a/py/requirements_lock.txt +++ b/py/requirements_lock.txt @@ -172,66 +172,69 @@ charset-normalizer==3.3.2 \ --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 # via requests -cryptography==42.0.7 \ - --hash=sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55 \ - --hash=sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785 \ - --hash=sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b \ - --hash=sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886 \ - --hash=sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82 \ - --hash=sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1 \ - --hash=sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda \ - --hash=sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f \ - --hash=sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68 \ - --hash=sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60 \ - --hash=sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7 \ - --hash=sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd \ - --hash=sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582 \ - --hash=sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc \ - --hash=sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858 \ - --hash=sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b \ - --hash=sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2 \ - --hash=sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678 \ - --hash=sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13 \ - --hash=sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4 \ - --hash=sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8 \ - --hash=sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604 \ - --hash=sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477 \ - --hash=sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e \ - --hash=sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a \ - --hash=sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9 \ - --hash=sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14 \ - --hash=sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda \ - --hash=sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da \ - --hash=sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562 \ - --hash=sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2 \ - --hash=sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9 +cryptography==42.0.8 \ + --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ + --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ + --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ + --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ + --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ + --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ + --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ + --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ + --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ + --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ + --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ + --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ + --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ + --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ + --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ + --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ + --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ + --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ + --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ + --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ + --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ + --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ + --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ + --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ + --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ + --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ + --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ + --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ + --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ + --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ + --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ + --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e # via # -r py/requirements.txt # pyopenssl - # secretstorage -debugpy==1.8.1 \ - --hash=sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb \ - --hash=sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146 \ - --hash=sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8 \ - --hash=sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242 \ - --hash=sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0 \ - --hash=sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741 \ - --hash=sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539 \ - --hash=sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23 \ - --hash=sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3 \ - --hash=sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39 \ - --hash=sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd \ - --hash=sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9 \ - --hash=sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace \ - --hash=sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42 \ - --hash=sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0 \ - --hash=sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7 \ - --hash=sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e \ - --hash=sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234 \ - --hash=sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98 \ - --hash=sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703 \ - --hash=sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42 \ - --hash=sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099 +debugpy==1.8.7 \ + --hash=sha256:11ad72eb9ddb436afb8337891a986302e14944f0f755fd94e90d0d71e9100bba \ + --hash=sha256:171899588bcd412151e593bd40d9907133a7622cd6ecdbdb75f89d1551df13c2 \ + --hash=sha256:18b8f731ed3e2e1df8e9cdaa23fb1fc9c24e570cd0081625308ec51c82efe42e \ + --hash=sha256:29e1571c276d643757ea126d014abda081eb5ea4c851628b33de0c2b6245b037 \ + --hash=sha256:2efb84d6789352d7950b03d7f866e6d180284bc02c7e12cb37b489b7083d81aa \ + --hash=sha256:2f729228430ef191c1e4df72a75ac94e9bf77413ce5f3f900018712c9da0aaca \ + --hash=sha256:45c30aaefb3e1975e8a0258f5bbd26cd40cde9bfe71e9e5a7ac82e79bad64e39 \ + --hash=sha256:4b908291a1d051ef3331484de8e959ef3e66f12b5e610c203b5b75d2725613a7 \ + --hash=sha256:4d27d842311353ede0ad572600c62e4bcd74f458ee01ab0dd3a1a4457e7e3706 \ + --hash=sha256:57b00de1c8d2c84a61b90880f7e5b6deaf4c312ecbde3a0e8912f2a56c4ac9ae \ + --hash=sha256:628a11f4b295ffb4141d8242a9bb52b77ad4a63a2ad19217a93be0f77f2c28c9 \ + --hash=sha256:6a9d9d6d31846d8e34f52987ee0f1a904c7baa4912bf4843ab39dadf9b8f3e0d \ + --hash=sha256:6e1c4ffb0c79f66e89dfd97944f335880f0d50ad29525dc792785384923e2211 \ + --hash=sha256:703c1fd62ae0356e194f3e7b7a92acd931f71fe81c4b3be2c17a7b8a4b546ec2 \ + --hash=sha256:85ce9c1d0eebf622f86cc68618ad64bf66c4fc3197d88f74bb695a416837dd55 \ + --hash=sha256:90d93e4f2db442f8222dec5ec55ccfc8005821028982f1968ebf551d32b28907 \ + --hash=sha256:93176e7672551cb5281577cdb62c63aadc87ec036f0c6a486f0ded337c504596 \ + --hash=sha256:95fe04a573b8b22896c404365e03f4eda0ce0ba135b7667a1e57bd079793b96b \ + --hash=sha256:a6cf2510740e0c0b4a40330640e4b454f928c7b99b0c9dbf48b11efba08a8cda \ + --hash=sha256:b12515e04720e9e5c2216cc7086d0edadf25d7ab7e3564ec8b4521cf111b4f8c \ + --hash=sha256:b6db2a370e2700557a976eaadb16243ec9c91bd46f1b3bb15376d7aaa7632c81 \ + --hash=sha256:caf528ff9e7308b74a1749c183d6808ffbedbb9fb6af78b033c28974d9b8831f \ + --hash=sha256:cba1d078cf2e1e0b8402e6bda528bf8fda7ccd158c3dba6c012b7897747c41a0 \ + --hash=sha256:d050a1ec7e925f514f0f6594a1e522580317da31fbda1af71d1530d6ea1f2b40 \ + --hash=sha256:da8df5b89a41f1fd31503b179d0a84a5fdb752dddd5b5388dbd1ae23cda31ce9 \ + --hash=sha256:f2f4349a28e3228a42958f8ddaa6333d6f8282d5edaea456070e48609c5983b7 # via -r py/requirements.txt docutils==0.20.1 \ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \ @@ -243,6 +246,10 @@ exceptiongroup==1.1.1 \ # via # pytest # trio +filetype==1.2.0 \ + --hash=sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb \ + --hash=sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25 + # via -r py/requirements.txt h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -281,12 +288,6 @@ jaraco-classes==3.3.0 \ --hash=sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb \ --hash=sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621 # via keyring -jeepney==0.8.0 \ - --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ - --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 - # via - # keyring - # secretstorage keyring==24.3.0 \ --hash=sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836 \ --hash=sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25 @@ -511,10 +512,6 @@ rich==13.7.0 \ --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \ --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235 # via twine -secretstorage==3.3.3 \ - --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ - --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 - # via keyring sniffio==1.3.1 \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc diff --git a/py/test/selenium/webdriver/common/takes_screenshots_tests.py b/py/test/selenium/webdriver/common/takes_screenshots_tests.py index a889503491d8b..4e0eddee0b3df 100644 --- a/py/test/selenium/webdriver/common/takes_screenshots_tests.py +++ b/py/test/selenium/webdriver/common/takes_screenshots_tests.py @@ -16,8 +16,8 @@ # under the License. import base64 -import imghdr +import filetype import pytest from selenium.webdriver.common.by import By @@ -26,13 +26,15 @@ def test_get_screenshot_as_base64(driver, pages): pages.load("simpleTest.html") result = base64.b64decode(driver.get_screenshot_as_base64()) - assert imghdr.what("", result) == "png" + kind = filetype.guess(result) + assert kind is not None and kind.mime == "image/png" def test_get_screenshot_as_png(driver, pages): pages.load("simpleTest.html") result = driver.get_screenshot_as_png() - assert imghdr.what("", result) == "png" + kind = filetype.guess(result) + assert kind is not None and kind.mime == "image/png" @pytest.mark.xfail_firefox @@ -41,4 +43,5 @@ def test_get_element_screenshot(driver, pages): pages.load("simpleTest.html") element = driver.find_element(By.ID, "multiline") result = base64.b64decode(element.screenshot_as_base64) - assert imghdr.what("", result) == "png" + kind = filetype.guess(result) + assert kind is not None and kind.mime == "image/png" diff --git a/py/test/selenium/webdriver/firefox/ff_takes_full_page_screenshots_tests.py b/py/test/selenium/webdriver/firefox/ff_takes_full_page_screenshots_tests.py index 03ecd0d3cb562..e1274bf6e5116 100644 --- a/py/test/selenium/webdriver/firefox/ff_takes_full_page_screenshots_tests.py +++ b/py/test/selenium/webdriver/firefox/ff_takes_full_page_screenshots_tests.py @@ -16,16 +16,19 @@ # under the License. import base64 -import imghdr + +import filetype def test_get_full_page_screenshot_as_base64(driver, pages): pages.load("simpleTest.html") result = base64.b64decode(driver.get_full_page_screenshot_as_base64()) - assert imghdr.what("", result) == "png" + kind = filetype.guess(result) + assert kind is not None and kind.mime == "image/png" def test_get_full_page_screenshot_as_png(driver, pages): pages.load("simpleTest.html") result = driver.get_full_page_screenshot_as_png() - assert imghdr.what("", result) == "png" + kind = filetype.guess(result) + assert kind is not None and kind.mime == "image/png" diff --git a/py/test/selenium/webdriver/remote/remote_connection_tests.py b/py/test/selenium/webdriver/remote/remote_connection_tests.py index db27ba0570015..e4046aff719a4 100644 --- a/py/test/selenium/webdriver/remote/remote_connection_tests.py +++ b/py/test/selenium/webdriver/remote/remote_connection_tests.py @@ -15,11 +15,13 @@ # specific language governing permissions and limitations # under the License. import base64 -import imghdr + +import filetype def test_browser_specific_method(driver, pages): pages.load("simpleTest.html") screenshot = driver.execute("FULL_PAGE_SCREENSHOT")["value"] result = base64.b64decode(screenshot) - assert imghdr.what("", result) == "png" + kind = filetype.guess(result) + assert kind is not None and kind.mime == "image/png" From e9c09a200e374bba63acb0ef605175abb125e82e Mon Sep 17 00:00:00 2001 From: Augustin Gottlieb <33221555+aguspe@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:30:35 +0100 Subject: [PATCH 22/58] [rb] Deprecate CDP methods on Firefox (#14763) * Deprecate CDP for firefox * Make the deprecation message less generic --- .../webdriver/common/driver_extensions/has_log_events.rb | 7 +++++++ .../common/driver_extensions/has_network_interception.rb | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/rb/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb b/rb/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb index 1965466633f08..8acadbe0b8519 100644 --- a/rb/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +++ b/rb/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb @@ -57,6 +57,13 @@ module HasLogEvents # def on_log_event(kind, &block) + if browser == :firefox + WebDriver.logger.deprecate( + 'Driver#on_log_event on Firefox', + 'the script.add_console_message_handler or the script.add_javascript_error_handler methods', + id: :on_log_event + ) + end raise Error::WebDriverError, "Don't know how to handle #{kind} events" unless KINDS.include?(kind) enabled = log_listeners[kind].any? diff --git a/rb/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb b/rb/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb index 3339426157d91..54abcecba87c7 100644 --- a/rb/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +++ b/rb/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb @@ -60,6 +60,13 @@ module HasNetworkInterception # def intercept(&) + if browser == :firefox + WebDriver.logger.deprecate( + 'Driver#intercept on Firefox', + 'the new bidi.network.add_intercept method', + id: :intercept + ) + end @interceptor ||= DevTools::NetworkInterceptor.new(devtools) @interceptor.intercept(&) end From 99ee404532924e4e21db387fd6bca82de6ad5f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sautter?= Date: Thu, 21 Nov 2024 20:51:09 +0100 Subject: [PATCH 23/58] [java] search windows by name without recursion #14782 --- .../org/openqa/selenium/remote/RemoteWebDriver.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java index 58f08763b2ebd..737be829226d7 100644 --- a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java +++ b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java @@ -1148,12 +1148,16 @@ public WebDriver window(String windowHandleOrName) { // simulate search by name String original = getWindowHandle(); for (String handle : getWindowHandles()) { - switchTo().window(handle); - if (windowHandleOrName.equals(executeScript("return window.name"))) { - return RemoteWebDriver.this; // found by name + try { + execute(DriverCommand.SWITCH_TO_WINDOW(handle)); + if (windowHandleOrName.equals(executeScript("return window.name"))) { + return RemoteWebDriver.this; // found by name + } + } catch (NoSuchWindowException nswe) { + // swallow } } - switchTo().window(original); + execute(DriverCommand.SWITCH_TO_WINDOW(original)); throw nsw; } } From e2e9ac5f7e5ca2a2326bea9d16425525ce43da57 Mon Sep 17 00:00:00 2001 From: Viet Nguyen Duc Date: Fri, 22 Nov 2024 10:42:38 +0700 Subject: [PATCH 24/58] [py] Deprecate CDP methods on Firefox (#14787) Signed-off-by: Viet Nguyen Duc --- .github/workflows/ci-python.yml | 20 +++++++++++++++++-- py/requirements.txt | 1 + py/requirements_lock.txt | 9 +++++++++ py/selenium/webdriver/remote/webdriver.py | 6 ++++++ .../webdriver/common/devtools_tests.py | 11 +++++++++- .../firefox/firefox_service_tests.py | 4 +++- .../remote/remote_firefox_profile_tests.py | 4 +++- 7 files changed, 50 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml index e0c906c4d8885..00040c5d40ddf 100644 --- a/.github/workflows/ci-python.yml +++ b/.github/workflows/ci-python.yml @@ -100,8 +100,6 @@ jobs: fail-fast: false matrix: include: - - browser: safari - os: macos - browser: chrome os: ubuntu - browser: edge @@ -116,3 +114,21 @@ jobs: run: | bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:common-${{ matrix.browser }}-bidi bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:test-${{ matrix.browser }} + + safari-tests: + name: Browser Tests + needs: build + uses: ./.github/workflows/bazel.yml + strategy: + fail-fast: false + matrix: + include: + - browser: safari + os: macos + with: + name: Integration Tests (${{ matrix.browser }}, ${{ matrix.os }}) + browser: ${{ matrix.browser }} + os: ${{ matrix.os }} + cache-key: py-browser-${{ matrix.browser }} + run: | + bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:test-${{ matrix.browser }} diff --git a/py/requirements.txt b/py/requirements.txt index 5f4dc4d646d0b..ab36a657d16d1 100644 --- a/py/requirements.txt +++ b/py/requirements.txt @@ -3,6 +3,7 @@ attrs==23.2.0 certifi==2023.11.17 cffi==1.16.0 cryptography==42.0.8 +secretstorage==3.3.3 debugpy==1.8.7 filetype==1.2.0 h11==0.14.0 diff --git a/py/requirements_lock.txt b/py/requirements_lock.txt index 2da2d212d25cf..4b1abe117b69f 100644 --- a/py/requirements_lock.txt +++ b/py/requirements_lock.txt @@ -208,6 +208,7 @@ cryptography==42.0.8 \ # via # -r py/requirements.txt # pyopenssl + # secretstorage debugpy==1.8.7 \ --hash=sha256:11ad72eb9ddb436afb8337891a986302e14944f0f755fd94e90d0d71e9100bba \ --hash=sha256:171899588bcd412151e593bd40d9907133a7622cd6ecdbdb75f89d1551df13c2 \ @@ -288,6 +289,10 @@ jaraco-classes==3.3.0 \ --hash=sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb \ --hash=sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621 # via keyring +jeepney==0.8.0 \ + --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ + --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 + # via secretstorage keyring==24.3.0 \ --hash=sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836 \ --hash=sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25 @@ -512,6 +517,10 @@ rich==13.7.0 \ --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \ --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235 # via twine +secretstorage==3.3.3 \ + --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ + --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 + # via -r py/requirements.txt sniffio==1.3.1 \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc diff --git a/py/selenium/webdriver/remote/webdriver.py b/py/selenium/webdriver/remote/webdriver.py index c2dc89551d6ba..eace710c20310 100644 --- a/py/selenium/webdriver/remote/webdriver.py +++ b/py/selenium/webdriver/remote/webdriver.py @@ -1057,6 +1057,12 @@ def start_devtools(self): raise WebDriverException("Unable to find url to connect to from capabilities") devtools = cdp.import_devtools(version) + if self.caps["browserName"].lower() == "firefox": + warnings.warn( + "CDP support for Firefox is deprecated and will be removed in future versions. Please switch to WebDriver BiDi.", + DeprecationWarning, + stacklevel=2, + ) self._websocket_connection = WebSocketConnection(ws_url) targets = self._websocket_connection.execute(devtools.target.get_targets()) target_id = targets[0].target_id diff --git a/py/test/selenium/webdriver/common/devtools_tests.py b/py/test/selenium/webdriver/common/devtools_tests.py index b4b3bcbce361a..de194cddbcddf 100644 --- a/py/test/selenium/webdriver/common/devtools_tests.py +++ b/py/test/selenium/webdriver/common/devtools_tests.py @@ -21,9 +21,18 @@ @pytest.mark.xfail_safari def test_check_console_messages(driver, pages): - devtools, connection = driver.start_devtools() + with pytest.warns(None) as record: + devtools, connection = driver.start_devtools() console_api_calls = [] + if driver.caps["browserName"].lower() == "firefox": + assert ( + record[0].message.args[0] + == "CDP support for Firefox is deprecated and will be removed in future versions. Please switch to WebDriver BiDi." + ) + else: + assert len(record) == 0 + connection.execute(devtools.runtime.enable()) connection.on(devtools.runtime.ConsoleAPICalled, console_api_calls.append) driver.execute_script("console.log('I love cheese')") diff --git a/py/test/selenium/webdriver/firefox/firefox_service_tests.py b/py/test/selenium/webdriver/firefox/firefox_service_tests.py index 2a57d0341acee..509a138d375d5 100644 --- a/py/test/selenium/webdriver/firefox/firefox_service_tests.py +++ b/py/test/selenium/webdriver/firefox/firefox_service_tests.py @@ -27,7 +27,9 @@ def test_log_output_as_filename() -> None: log_file = "geckodriver.log" service = Service(log_output=log_file) try: - driver = Firefox(service=service) + with pytest.warns(None) as record: + driver = Firefox(service=service) + assert len(record) == 0 with open(log_file) as fp: assert "geckodriver\tINFO\tListening" in fp.readline() finally: diff --git a/py/test/selenium/webdriver/remote/remote_firefox_profile_tests.py b/py/test/selenium/webdriver/remote/remote_firefox_profile_tests.py index 70f756e91726f..6d5c1d0cb54df 100644 --- a/py/test/selenium/webdriver/remote/remote_firefox_profile_tests.py +++ b/py/test/selenium/webdriver/remote/remote_firefox_profile_tests.py @@ -22,7 +22,9 @@ @pytest.fixture def driver(options): - driver = webdriver.Remote(options=options) + with pytest.warns(None) as record: + driver = webdriver.Remote(options=options) + assert len(record) == 0 yield driver driver.quit() From 4b7d17441352f990a3a3c322aabde51e392abad7 Mon Sep 17 00:00:00 2001 From: Augustin Gottlieb <33221555+aguspe@users.noreply.github.com> Date: Fri, 22 Nov 2024 08:37:43 +0100 Subject: [PATCH 25/58] [rb] Downgrade steep to 1.5.2 to avoid issues on windows based pipelines (#14790) Downgrade steep to 1.5.2 --- rb/Gemfile | 2 +- rb/Gemfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rb/Gemfile b/rb/Gemfile index 740e559bae308..e2ec24a906f31 100644 --- a/rb/Gemfile +++ b/rb/Gemfile @@ -7,4 +7,4 @@ end gem 'curb', '~> 1.0.5', require: false, platforms: %i[mri mingw x64_mingw] gem 'debug', '~> 1.7', require: false, platforms: %i[mri mingw x64_mingw] -gem 'steep', '~> 1.5.0', require: false, platforms: %i[mri mingw x64_mingw] +gem 'steep', '1.5.2', require: false, platforms: %i[mri mingw x64_mingw] diff --git a/rb/Gemfile.lock b/rb/Gemfile.lock index 830962b3bc08b..495e79ef76e86 100644 --- a/rb/Gemfile.lock +++ b/rb/Gemfile.lock @@ -67,7 +67,7 @@ GEM rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) logger (1.6.1) - minitest (5.25.1) + minitest (5.25.2) parallel (1.26.3) parser (3.3.6.0) ast (~> 2.4.1) @@ -137,8 +137,8 @@ GEM rubocop (~> 1.61) ruby-progressbar (1.13.0) rubyzip (2.3.2) - securerandom (0.3.1) - steep (1.5.3) + securerandom (0.3.2) + steep (1.5.2) activesupport (>= 5.1) concurrent-ruby (>= 1.1.10) csv (>= 3.0.9) @@ -192,7 +192,7 @@ DEPENDENCIES rubocop-rspec (~> 2.16) selenium-devtools! selenium-webdriver! - steep (~> 1.5.0) + steep (= 1.5.2) webmock (~> 3.5) webrick (~> 1.7) yard (~> 0.9.11, >= 0.9.36) From d6e718d134987d62cd8ffff476821fb3ca1797c2 Mon Sep 17 00:00:00 2001 From: Selenium CI Bot Date: Mon, 25 Nov 2024 11:37:21 +0100 Subject: [PATCH 26/58] [build] Prepare for release of Selenium 4.27.0 (#14780) * Update pinned browser versions * Update supported versions for Chrome DevTools * Update selenium manager version * Update authors file * FIX CHANGELOGS BEFORE MERGING! Update versions and change logs to release Selenium 4.27.0 * [create-pull-request] automated change * [dotnet] Update dependency System.Text.Json to 8.0.5 Signed-off-by: Viet Nguyen Duc * Update CHANGELOG for all Signed-off-by: Viet Nguyen Duc * Update CHANGELOG for rust Signed-off-by: Viet Nguyen Duc * [dotnet] Upgrade System.Text.Json to 8.0.5 in package metadata * [rb] Rollback the update in Gemfile.lock Signed-off-by: Viet Nguyen Duc --------- Signed-off-by: Viet Nguyen Duc Co-authored-by: Selenium CI Bot Co-authored-by: Viet Nguyen Duc Co-authored-by: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> --- AUTHORS | 4 + MODULE.bazel | 42 +-- Rakefile | 2 +- .../chromium/{v128 => v131}/BUILD.bazel | 0 .../{v128 => v131}/browser_protocol.pdl | 259 ++++++++++++++++-- .../chromium/{v128 => v131}/js_protocol.pdl | 15 +- common/repositories.bzl | 20 +- common/selenium_manager.bzl | 12 +- dotnet/CHANGELOG | 23 ++ dotnet/paket.dependencies | 2 +- dotnet/paket.lock | 2 +- dotnet/selenium-dotnet-version.bzl | 4 +- .../src/webdriver/DevTools/DevToolsDomains.cs | 2 +- .../V128Domains.cs => v131/V131Domains.cs} | 22 +- .../V131JavaScript.cs} | 16 +- .../{v128/V128Log.cs => v131/V131Log.cs} | 14 +- .../V128Network.cs => v131/V131Network.cs} | 24 +- .../V128Target.cs => v131/V131Target.cs} | 14 +- .../webdriver/WebDriver.StrongNamed.nuspec | 2 +- dotnet/src/webdriver/WebDriver.csproj | 2 +- dotnet/src/webdriver/WebDriver.nuspec | 2 +- .../StableChannelChromeDriver.cs | 2 +- .../common/DevTools/DevToolsConsoleTest.cs | 2 +- .../test/common/DevTools/DevToolsLogTest.cs | 2 +- .../common/DevTools/DevToolsNetworkTest.cs | 2 +- .../DevTools/DevToolsPerformanceTest.cs | 2 +- .../common/DevTools/DevToolsProfilerTest.cs | 2 +- .../common/DevTools/DevToolsSecurityTest.cs | 2 +- .../test/common/DevTools/DevToolsTabsTest.cs | 2 +- .../common/DevTools/DevToolsTargetTest.cs | 4 +- java/CHANGELOG | 30 ++ java/maven_install.json | 257 ++++++++--------- .../devtools/{v128 => v131}/BUILD.bazel | 2 +- .../v131CdpInfo.java} | 8 +- .../v131Domains.java} | 26 +- .../v128Events.java => v131/v131Events.java} | 18 +- .../v131Javascript.java} | 14 +- .../{v128/v128Log.java => v131/v131Log.java} | 10 +- .../v131Network.java} | 20 +- .../v128Target.java => v131/v131Target.java} | 24 +- .../org/openqa/selenium/devtools/versions.bzl | 2 +- java/version.bzl | 2 +- .../node/selenium-webdriver/BUILD.bazel | 4 +- javascript/node/selenium-webdriver/CHANGES.md | 9 + .../node/selenium-webdriver/package.json | 2 +- py/BUILD.bazel | 4 +- py/CHANGES | 10 + py/docs/source/conf.py | 2 +- py/pyproject.toml | 2 +- py/selenium/__init__.py | 2 +- py/selenium/webdriver/__init__.py | 2 +- rb/CHANGES | 11 + rb/Gemfile.lock | 4 +- rb/lib/selenium/devtools/BUILD.bazel | 2 +- rb/lib/selenium/devtools/version.rb | 2 +- rb/lib/selenium/webdriver/version.rb | 2 +- rust/CHANGELOG.md | 7 + 57 files changed, 651 insertions(+), 330 deletions(-) rename common/devtools/chromium/{v128 => v131}/BUILD.bazel (100%) rename common/devtools/chromium/{v128 => v131}/browser_protocol.pdl (98%) rename common/devtools/chromium/{v128 => v131}/js_protocol.pdl (99%) rename dotnet/src/webdriver/DevTools/{v128/V128Domains.cs => v131/V131Domains.cs} (78%) rename dotnet/src/webdriver/DevTools/{v128/V128JavaScript.cs => v131/V131JavaScript.cs} (94%) rename dotnet/src/webdriver/DevTools/{v128/V128Log.cs => v131/V131Log.cs} (88%) rename dotnet/src/webdriver/DevTools/{v128/V128Network.cs => v131/V131Network.cs} (95%) rename dotnet/src/webdriver/DevTools/{v128/V128Target.cs => v131/V131Target.cs} (94%) rename java/src/org/openqa/selenium/devtools/{v128 => v131}/BUILD.bazel (98%) rename java/src/org/openqa/selenium/devtools/{v128/v128CdpInfo.java => v131/v131CdpInfo.java} (86%) rename java/src/org/openqa/selenium/devtools/{v128/v128Domains.java => v131/v131Domains.java} (77%) rename java/src/org/openqa/selenium/devtools/{v128/v128Events.java => v131/v131Events.java} (86%) rename java/src/org/openqa/selenium/devtools/{v128/v128Javascript.java => v131/v131Javascript.java} (85%) rename java/src/org/openqa/selenium/devtools/{v128/v128Log.java => v131/v131Log.java} (89%) rename java/src/org/openqa/selenium/devtools/{v128/v128Network.java => v131/v131Network.java} (92%) rename java/src/org/openqa/selenium/devtools/{v128/v128Target.java => v131/v131Target.java} (83%) diff --git a/AUTHORS b/AUTHORS index c5dd7ca1b1756..4eeedcf9c0014 100644 --- a/AUTHORS +++ b/AUTHORS @@ -68,6 +68,7 @@ Andrei Andrei Botalov Andrei Rusu Andrei Solntsev +Andrew Nesbitt Andrey Botalov Andrii Rohovets Andy Duncan @@ -334,6 +335,7 @@ Harshit Agrawal <94462364+harshit-bs@users.noreply.github.com> havja Haw-bin Chai hectorhon +HeeJun <64578367+syber911911@users.noreply.github.com> Heky helen3141 <54561656+helen3141@users.noreply.github.com> Henrik Skupin @@ -458,6 +460,7 @@ Jonathan Lipps Jonathon Kereliuk Jongkuen Hong Jordan Mace +Jose D. Gomez R. <1josegomezr@gmail.com> josephg Josh Goldberg Joshua Bruning @@ -633,6 +636,7 @@ MustafaAgamy Muthu Kannan MWschutte <72599545+MWschutte@users.noreply.github.com> myslak71 +Natalia Pozhidaeva Nate Lowry Nathan Isom native-api diff --git a/MODULE.bazel b/MODULE.bazel index 979f4cfa7885a..9a98a3348bb0d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -177,35 +177,35 @@ maven.install( "com.google.auto:auto-common:1.2.2", "com.google.auto.service:auto-service:1.1.1", "com.google.auto.service:auto-service-annotations:1.1.1", - "com.google.googlejavaformat:google-java-format:jar:1.24.0", + "com.google.googlejavaformat:google-java-format:jar:1.25.0", "com.graphql-java:graphql-java:22.3", "dev.failsafe:failsafe:3.3.2", "io.grpc:grpc-context:1.68.1", - "io.lettuce:lettuce-core:6.4.0.RELEASE", - "io.netty:netty-buffer:4.1.114.Final", - "io.netty:netty-codec-http:4.1.114.Final", - "io.netty:netty-codec-http2:4.1.114.Final", - "io.netty:netty-common:4.1.114.Final", - "io.netty:netty-handler:4.1.114.Final", - "io.netty:netty-handler-proxy:4.1.114.Final", - "io.netty:netty-transport:4.1.114.Final", - "io.opentelemetry:opentelemetry-api:1.43.0", - "io.opentelemetry:opentelemetry-context:1.43.0", - "io.opentelemetry:opentelemetry-exporter-logging:1.43.0", - "io.opentelemetry:opentelemetry-sdk:1.43.0", - "io.opentelemetry:opentelemetry-sdk-common:1.43.0", - "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:1.43.0", - "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:1.43.0", - "io.opentelemetry:opentelemetry-sdk-testing:1.43.0", - "io.opentelemetry:opentelemetry-sdk-trace:1.43.0", + "io.lettuce:lettuce-core:6.5.0.RELEASE", + "io.netty:netty-buffer:4.1.115.Final", + "io.netty:netty-codec-http:4.1.115.Final", + "io.netty:netty-codec-http2:4.1.115.Final", + "io.netty:netty-common:4.1.115.Final", + "io.netty:netty-handler:4.1.115.Final", + "io.netty:netty-handler-proxy:4.1.115.Final", + "io.netty:netty-transport:4.1.115.Final", + "io.opentelemetry:opentelemetry-api:1.44.1", + "io.opentelemetry:opentelemetry-context:1.44.1", + "io.opentelemetry:opentelemetry-exporter-logging:1.44.1", + "io.opentelemetry:opentelemetry-sdk:1.44.1", + "io.opentelemetry:opentelemetry-sdk-common:1.44.1", + "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:1.44.1", + "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:1.44.1", + "io.opentelemetry:opentelemetry-sdk-testing:1.44.1", + "io.opentelemetry:opentelemetry-sdk-trace:1.44.1", "io.opentelemetry.semconv:opentelemetry-semconv:1.25.0-alpha", "it.ozimov:embedded-redis:0.7.3", "net.bytebuddy:byte-buddy:1.15.10", - "org.htmlunit:htmlunit-core-js:4.5.0", + "org.htmlunit:htmlunit-core-js:4.6.0", "org.apache.commons:commons-exec:1.4.0", "org.apache.logging.log4j:log4j-core:2.24.1", "org.assertj:assertj-core:3.26.3", - "org.bouncycastle:bcpkix-jdk18on:1.78.1", + "org.bouncycastle:bcpkix-jdk18on:1.79", "org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5", "org.hsqldb:hsqldb:2.7.4", "org.jspecify:jspecify:1.0.0", @@ -217,7 +217,7 @@ maven.install( "org.junit.platform:junit-platform-commons:1.11.3", "org.junit.platform:junit-platform-engine:1.11.3", "org.mockito:mockito-core:5.14.2", - "org.redisson:redisson:3.37.0", + "org.redisson:redisson:3.39.0", "org.slf4j:slf4j-api:2.0.16", "org.slf4j:slf4j-jdk14:2.0.16", "org.tomlj:tomlj:1.1.1", diff --git a/Rakefile b/Rakefile index 454096c176366..7ee7099acb135 100644 --- a/Rakefile +++ b/Rakefile @@ -97,7 +97,7 @@ task '//java/test/org/openqa/selenium/environment/webserver:webserver:uber' => [ JAVA_RELEASE_TARGETS = %w[ //java/src/org/openqa/selenium/chrome:chrome.publish //java/src/org/openqa/selenium/chromium:chromium.publish - //java/src/org/openqa/selenium/devtools/v128:v128.publish + //java/src/org/openqa/selenium/devtools/v131:v131.publish //java/src/org/openqa/selenium/devtools/v129:v129.publish //java/src/org/openqa/selenium/devtools/v130:v130.publish //java/src/org/openqa/selenium/devtools/v85:v85.publish diff --git a/common/devtools/chromium/v128/BUILD.bazel b/common/devtools/chromium/v131/BUILD.bazel similarity index 100% rename from common/devtools/chromium/v128/BUILD.bazel rename to common/devtools/chromium/v131/BUILD.bazel diff --git a/common/devtools/chromium/v128/browser_protocol.pdl b/common/devtools/chromium/v131/browser_protocol.pdl similarity index 98% rename from common/devtools/chromium/v128/browser_protocol.pdl rename to common/devtools/chromium/v131/browser_protocol.pdl index 95b6a8e9e021c..49df8017971a7 100644 --- a/common/devtools/chromium/v128/browser_protocol.pdl +++ b/common/devtools/chromium/v131/browser_protocol.pdl @@ -532,6 +532,8 @@ experimental domain Audits WarnDomainNonASCII WarnThirdPartyPhaseout WarnCrossSiteRedirectDowngradeChangesInclusion + WarnDeprecationTrialMetadata + WarnThirdPartyCookieHeuristic type CookieOperation extends string enum @@ -743,6 +745,7 @@ experimental domain Audits NoRegisterTriggerHeader NoRegisterOsSourceHeader NoRegisterOsTriggerHeader + NavigationRegistrationUniqueScopeAlreadySet type SharedDictionaryError extends string enum @@ -915,7 +918,7 @@ experimental domain Audits ThirdPartyCookiesBlocked NotSignedInWithIdp MissingTransientUserActivation - ReplacedByButtonMode + ReplacedByActiveMode InvalidFieldsSpecified RelyingPartyOriginIsOpaque TypeNotMatching @@ -1102,13 +1105,20 @@ experimental domain Audits parameters InspectorIssue issue -# Defines commands and events for browser extensions. Available if the client -# is connected using the --remote-debugging-pipe flag and -# the --enable-unsafe-extension-debugging flag is set. +# Defines commands and events for browser extensions. experimental domain Extensions + # Storage areas. + type StorageArea extends string + enum + session + local + sync + managed # Installs an unpacked extension from the filesystem similar to # --load-extension CLI flags. Returns extension ID once the extension - # has been installed. + # has been installed. Available if the client is connected using the + # --remote-debugging-pipe flag and the --enable-unsafe-extension-debugging + # flag is set. command loadUnpacked parameters # Absolute file path. @@ -1116,6 +1126,44 @@ experimental domain Extensions returns # Extension id. string id + # Gets data from extension storage in the given `storageArea`. If `keys` is + # specified, these are used to filter the result. + command getStorageItems + parameters + # ID of extension. + string id + # StorageArea to retrieve data from. + StorageArea storageArea + # Keys to retrieve. + optional array of string keys + returns + object data + # Removes `keys` from extension storage in the given `storageArea`. + command removeStorageItems + parameters + # ID of extension. + string id + # StorageArea to remove data from. + StorageArea storageArea + # Keys to remove. + array of string keys + # Clears extension storage in the given `storageArea`. + command clearStorageItems + parameters + # ID of extension. + string id + # StorageArea to remove data from. + StorageArea storageArea + # Sets `values` in extension storage in the given `storageArea`. The provided `values` + # will be merged with existing values in the storage area. + command setStorageItems + parameters + # ID of extension. + string id + # StorageArea to set data in. + StorageArea storageArea + # Values to set. + object values # Defines commands and events for Autofill. experimental domain Autofill @@ -1347,6 +1395,7 @@ domain Browser videoCapturePanTiltZoom wakeLockScreen wakeLockSystem + webAppInstallation windowManagement experimental type PermissionSetting extends string @@ -2011,13 +2060,6 @@ experimental domain CSS # Associated style declaration. CSSStyle style - # CSS position-fallback rule representation. - deprecated type CSSPositionFallbackRule extends object - properties - Value name - # List of keyframes. - array of CSSTryRule tryRules - # CSS @position-try rule representation. type CSSPositionTryRule extends object properties @@ -2204,8 +2246,6 @@ experimental domain CSS optional array of InheritedPseudoElementMatches inheritedPseudoElements # A list of CSS keyframed animations matching this node. optional array of CSSKeyframesRule cssKeyframesRules - # A list of CSS position fallbacks matching this node. - deprecated optional array of CSSPositionFallbackRule cssPositionFallbackRules # A list of CSS @position-try rules matching this node, based on the position-try-fallbacks property. optional array of CSSPositionTryRule cssPositionTryRules # Index of the active fallback in the applied position-try-fallback property, @@ -2641,6 +2681,7 @@ domain DOM after marker backdrop + column selection search-text target-text @@ -2650,6 +2691,8 @@ domain DOM first-line-inherited scroll-marker scroll-marker-group + scroll-next-button + scroll-prev-button scrollbar scrollbar-thumb scrollbar-button @@ -2663,6 +2706,12 @@ domain DOM view-transition-image-pair view-transition-old view-transition-new + placeholder + file-selector-button + details-content + select-fallback-button + select-fallback-button-text + picker # Shadow root type. type ShadowRootType extends string @@ -2767,6 +2816,13 @@ domain DOM optional boolean isSVG optional CompatibilityMode compatibilityMode optional BackendNode assignedSlot + experimental optional boolean isScrollable + + # A structure to hold the top-level node of a detached tree and an array of its retained descendants. + type DetachedElementInfo extends object + properties + Node treeNode + array of NodeId retainedNodeIds # A structure holding an RGBA color. type RGBA extends object @@ -3278,6 +3334,12 @@ domain DOM returns string path + # Returns list of detached nodes + experimental command getDetachedDomNodes + returns + # The list of detached nodes + array of DetachedElementInfo detachedNodes + # Enables console to refer to the node with given id via $x (see Command Line API for more details # $x functions). experimental command setInspectedNode @@ -3444,6 +3506,14 @@ domain DOM # Called when top layer elements are changed. experimental event topLayerElementsUpdated + # Fired when a node's scrollability state changes. + experimental event scrollableFlagUpdated + parameters + # The id of the node. + DOM.NodeId nodeId + # If the node is scrollable. + boolean isScrollable + # Called when a pseudo element is removed from an element. experimental event pseudoElementRemoved parameters @@ -4153,7 +4223,6 @@ domain Emulation gyroscope linear-acceleration magnetometer - proximity relative-orientation experimental type SensorMetadata extends object @@ -5472,12 +5541,21 @@ experimental domain Memory moderate critical + # Retruns current DOM object counters. command getDOMCounters returns integer documents integer nodes integer jsEventListeners + # Retruns DOM object counters after preparing renderer for leak detection. + command getDOMCountersForLeakDetection + returns + # DOM object counters. + array of DOMCounter counters + + # Prepares for leak detection by terminating workers, stopping spellcheckers, + # dropping non-essential internal caches, running garbage collections, etc. command prepareForLeakDetection # Simulate OomIntervention by purging V8 memory. @@ -5553,6 +5631,15 @@ experimental domain Memory # Size of the module in bytes. number size + # DOM object counter data. + type DOMCounter extends object + properties + # Object name. Note: object names should be presumed volatile and clients should not expect + # the returned names to be consistent across runs. + string name + # Object count. + integer count + # Network domain allows tracking network activities of the page. It exposes information about http, # file, data and other requests and responses, their headers, bodies, timing, etc. domain Network @@ -6290,6 +6377,8 @@ domain Network TPCDMetadata # The cookie should have been blocked by 3PCD but is exempted by Deprecation Trial mitigation. TPCDDeprecationTrial + # The cookie should have been blocked by 3PCD but is exempted by Top-level Deprecation Trial mitigation. + TopLevelTPCDDeprecationTrial # The cookie should have been blocked by 3PCD but is exempted by heuristics mitigation. TPCDHeuristics # The cookie should have been blocked by 3PCD but is exempted by Enterprise Policy. @@ -6298,8 +6387,6 @@ domain Network StorageAccess # The cookie should have been blocked by 3PCD but is exempted by Top-level Storage Access API. TopLevelStorageAccess - # The cookie should have been blocked by 3PCD but is exempted by CORS opt-in. - CorsOptIn # The cookie should have been blocked by 3PCD but is exempted by the first-party URL scheme. Scheme @@ -7838,8 +7925,8 @@ experimental domain Overlay # True for showing hit-test borders boolean show - # Request that backend shows an overlay with web vital metrics. - command setShowWebVitals + # Deprecated, no longer has any effect. + deprecated command setShowWebVitals parameters boolean show @@ -7964,6 +8051,7 @@ domain Page experimental type PermissionsPolicyFeature extends string enum accelerometer + all-screens-capture ambient-light-sensor attribution-reporting autoplay @@ -7997,10 +8085,12 @@ domain Page clipboard-read clipboard-write compute-pressure + controlled-frame cross-origin-isolated deferred-fetch digital-credentials-get direct-sockets + direct-sockets-private display-capture document-domain encrypted-media @@ -8020,11 +8110,13 @@ domain Page keyboard-map local-fonts magnetometer + media-playback-while-not-visible microphone midi otp-credentials payment picture-in-picture + popins private-aggregation private-state-token-issuance private-state-token-redemption @@ -8045,6 +8137,7 @@ domain Page usb usb-unrestricted vertical-scroll + web-app-installation web-printing web-share window-management @@ -8357,14 +8450,16 @@ domain Page experimental type ClientNavigationReason extends string enum + anchorClick formSubmissionGet formSubmissionPost httpHeaderRefresh - scriptInitiated + initialFrameNavigation metaTagRefresh + other pageBlockInterstitial reload - anchorClick + scriptInitiated experimental type ClientNavigationDisposition extends string enum @@ -9142,6 +9237,13 @@ domain Page # A new frame target will be created (see Target.attachedToTarget). swap + # Fired before frame subtree is detached. Emitted before any frame of the + # subtree is actually detached. + experimental event frameSubtreeWillBeDetached + parameters + # Id of the frame that is the root of the subtree that will be detached. + FrameId frameId + # The type of a frameNavigated event. experimental type NavigationType extends string enum @@ -9399,6 +9501,7 @@ domain Page ContentWebUSB ContentMediaSessionService ContentScreenReader + ContentDiscarded # See components/back_forward_cache/back_forward_cache_disable.h for explanations. EmbedderPopupBlockerTabHelper @@ -9417,6 +9520,7 @@ domain Page EmbedderExtensionMessagingForOpenPort EmbedderExtensionSentMessageToCachedFrame RequestedByWebViewClient + PostMessageByWebViewClient # Types of not restored reasons for back-forward cache. experimental type BackForwardCacheNotRestoredReasonType extends string @@ -9484,6 +9588,15 @@ domain Page FrameId frameId # Frame's new url. string url + # Navigation type + enum navigationType + # Navigation due to fragment navigation. + fragment + # Navigation due to history API usage. + historyApi + # Navigation due to other reasons. + other + # Compressed image data requested by the `startScreencast`. experimental event screencastFrame @@ -10573,6 +10686,14 @@ experimental domain Storage array of AttributionReportingAggregatableDebugReportingData debugData optional string aggregationCoordinatorOrigin + experimental type AttributionScopesData extends object + properties + array of string values + # number instead of integer because not all uint32 can be represented by + # int + number limit + number maxEventStates + experimental type AttributionReportingSourceRegistration extends object properties Network.TimeSinceEpoch time @@ -10593,6 +10714,7 @@ experimental domain Storage AttributionReportingTriggerDataMatching triggerDataMatching SignedInt64AsBase10 destinationLimitPriority AttributionReportingAggregatableDebugReportingConfig aggregatableDebugReportingConfig + optional AttributionScopesData scopesData experimental type AttributionReportingSourceRegistrationResult extends string enum @@ -10608,7 +10730,9 @@ experimental domain Storage destinationBothLimitsReached reportingOriginsPerSiteLimitReached exceedsMaxChannelCapacity + exceedsMaxScopesChannelCapacity exceedsMaxTriggerStateCardinality + exceedsMaxEventStatesLimit destinationPerDayReportingLimitReached experimental event attributionReportingSourceRegistered @@ -10667,6 +10791,7 @@ experimental domain Storage AttributionReportingSourceRegistrationTimeConfig sourceRegistrationTimeConfig optional string triggerContextId AttributionReportingAggregatableDebugReportingConfig aggregatableDebugReportingConfig + array of string scopes experimental type AttributionReportingEventLevelResult extends string enum @@ -11869,6 +11994,13 @@ experimental domain WebAuthn # flag set to this value. Defaults to the authenticator's # defaultBackupState value. optional boolean backupState + # The credential's user.name property. Equivalent to empty if not set. + # https://w3c.github.io/webauthn/#dom-publickeycredentialentity-name + optional string userName + # The credential's user.displayName property. Equivalent to empty if + # not set. + # https://w3c.github.io/webauthn/#dom-publickeycredentialuserentity-displayname + optional string userDisplayName # Enable the WebAuthn domain and start intercepting credential storage and # retrieval with a virtual authenticator. @@ -11972,6 +12104,20 @@ experimental domain WebAuthn AuthenticatorId authenticatorId Credential credential + # Triggered when a credential is deleted, e.g. through + # PublicKeyCredential.signalUnknownCredential(). + event credentialDeleted + parameters + AuthenticatorId authenticatorId + binary credentialId + + # Triggered when a credential is updated, e.g. through + # PublicKeyCredential.signalCurrentUserDetails(). + event credentialUpdated + parameters + AuthenticatorId authenticatorId + Credential credential + # Triggered when a credential is used in a webauthn assertion. event credentialAsserted parameters @@ -12283,6 +12429,10 @@ experimental domain Preload JavaScriptInterfaceRemoved AllPrerenderingCanceled WindowClosed + SlowNetwork + OtherPrerenderedPageActivated + V8OptimizerDisabled + PrerenderFailedDuringPrefetch # Fired when a preload enabled state is updated. event preloadEnabledStateUpdated @@ -12316,7 +12466,6 @@ experimental domain Preload PrefetchFailedMIMENotSupported PrefetchFailedNetError PrefetchFailedNon2XX - PrefetchFailedPerPageLimitExceeded PrefetchEvictedAfterCandidateRemoved PrefetchEvictedForNewerPrefetch PrefetchHeldback @@ -12447,7 +12596,7 @@ experimental domain FedCm parameters # Allows callers to disable the promise rejection delay that would # normally happen, if this is unimportant to what's being tested. - # (step 4 of https://w3c-fedid.github.io/FedCM/#browser-api-rp-sign-in) + # (step 4 of https://fedidcg.github.io/FedCM/#browser-api-rp-sign-in) optional boolean disableRejectionDelay command disable @@ -12598,3 +12747,67 @@ experimental domain PWA # supported yet. optional boolean linkCapturing optional DisplayMode displayMode + +# This domain allows configuring virtual Bluetooth devices to test +# the web-bluetooth API. +experimental domain BluetoothEmulation + # Indicates the various states of Central. + type CentralState extends string + enum + absent + powered-off + powered-on + + # Stores the manufacturer data + type ManufacturerData extends object + properties + # Company identifier + # https://bitbucket.org/bluetooth-SIG/public/src/main/assigned_numbers/company_identifiers/company_identifiers.yaml + # https://usb.org/developers + integer key + # Manufacturer-specific data + binary data + + # Stores the byte data of the advertisement packet sent by a Bluetooth device. + type ScanRecord extends object + properties + optional string name + optional array of string uuids + # Stores the external appearance description of the device. + optional integer appearance + # Stores the transmission power of a broadcasting device. + optional integer txPower + # Key is the company identifier and the value is an array of bytes of + # manufacturer specific data. + optional array of ManufacturerData manufacturerData + + # Stores the advertisement packet information that is sent by a Bluetooth device. + type ScanEntry extends object + properties + string deviceAddress + integer rssi + ScanRecord scanRecord + + # Enable the BluetoothEmulation domain. + command enable + parameters + # State of the simulated central. + CentralState state + + # Disable the BluetoothEmulation domain. + command disable + + # Simulates a peripheral with |address|, |name| and |knownServiceUuids| + # that has already been connected to the system. + command simulatePreconnectedPeripheral + parameters + string address + string name + array of ManufacturerData manufacturerData + array of string knownServiceUuids + + # Simulates an advertisement packet described in |entry| being received by + # the central. + command simulateAdvertisement + parameters + ScanEntry entry diff --git a/common/devtools/chromium/v128/js_protocol.pdl b/common/devtools/chromium/v131/js_protocol.pdl similarity index 99% rename from common/devtools/chromium/v128/js_protocol.pdl rename to common/devtools/chromium/v131/js_protocol.pdl index 8dad9c98de9f6..b96102b7f8f79 100644 --- a/common/devtools/chromium/v128/js_protocol.pdl +++ b/common/devtools/chromium/v131/js_protocol.pdl @@ -369,6 +369,14 @@ domain Debugger # call stacks (default). integer maxDepth + # Replace previous blackbox execution contexts with passed ones. Forces backend to skip + # stepping/pausing in scripts in these execution contexts. VM will try to leave blackboxed script by + # performing 'step in' several times, finally resorting to 'step out' if unsuccessful. + experimental command setBlackboxExecutionContexts + parameters + # Array of execution context unique ids for the debugger to ignore. + array of string uniqueIds + # Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in # scripts with url matching one of the patterns. VM will try to leave blackboxed script by # performing 'step in' several times, finally resorting to 'step out' if unsuccessful. @@ -376,6 +384,8 @@ domain Debugger parameters # Array of regexps that will be used to check script url for blackbox state. array of string patterns + # If true, also ignore scripts with no source url. + optional boolean skipAnonymous # Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted # scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. @@ -606,7 +616,6 @@ domain Debugger properties # Type of the debug symbols. enum type - None SourceMap EmbeddedDWARF ExternalDWARF @@ -689,8 +698,8 @@ domain Debugger experimental optional integer codeOffset # The language of the script. experimental optional Debugger.ScriptLanguage scriptLanguage - # If the scriptLanguage is WebASsembly, the source of debug symbols for the module. - experimental optional Debugger.DebugSymbols debugSymbols + # If the scriptLanguage is WebAssembly, the source of debug symbols for the module. + experimental optional array of Debugger.DebugSymbols debugSymbols # The name the embedder supplied for this script. experimental optional string embedderName diff --git a/common/repositories.bzl b/common/repositories.bzl index 08eacbcf17615..ba420b18bf293 100644 --- a/common/repositories.bzl +++ b/common/repositories.bzl @@ -182,8 +182,8 @@ js_library( http_archive( name = "mac_edgedriver", - url = "https://msedgedriver.azureedge.net/131.0.2903.52/edgedriver_mac64.zip", - sha256 = "719f54eb9376df5963e80da727c8ab8bacf6a1f57b785602a53a22fe330bb160", + url = "https://msedgedriver.azureedge.net/131.0.2903.56/edgedriver_mac64.zip", + sha256 = "4f4d1d5b45849677f8d8e706f7b5ca9ebb99f40ed3b4ee203c2535a3429e0d5b", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -199,8 +199,8 @@ js_library( http_archive( name = "linux_chrome", - url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.69/linux64/chrome-linux64.zip", - sha256 = "3e33f61511e5e9dabac0d7a57b4bb975555ed1d4dababa7898205c030f82e4e3", + url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.85/linux64/chrome-linux64.zip", + sha256 = "3a6d928b0002ec012a53b6bb65dcaf95add008adc223c961d566d824982a767e", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -221,8 +221,8 @@ js_library( http_archive( name = "mac_chrome", - url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.69/mac-x64/chrome-mac-x64.zip", - sha256 = "72a52967c80f9f145856d08d91052eaa27f6b951f9a4d8ab279f192b98784e41", + url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.85/mac-x64/chrome-mac-x64.zip", + sha256 = "e26a606e2a3da403c6e1e93617a7b51ee010706614eb88de5b16470276e0896b", strip_prefix = "chrome-mac-x64", patch_cmds = [ "mv 'Google Chrome for Testing.app' Chrome.app", @@ -243,8 +243,8 @@ js_library( http_archive( name = "linux_chromedriver", - url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.69/linux64/chromedriver-linux64.zip", - sha256 = "afc7b41aa0e1606e8cc177c776287d836635690964e39eab1ed94d63a0c96be2", + url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.85/linux64/chromedriver-linux64.zip", + sha256 = "33910b16568feabd2b50a26a2c4456d154c760d6e28347427f99c025661a4f3e", strip_prefix = "chromedriver-linux64", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") @@ -261,8 +261,8 @@ js_library( http_archive( name = "mac_chromedriver", - url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.69/mac-x64/chromedriver-mac-x64.zip", - sha256 = "92583e52f601951d3e0849891239bb2f6ff00dd8f8fd6c908473cc21c0533dd2", + url = "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.85/mac-x64/chromedriver-mac-x64.zip", + sha256 = "ee194eba1d52dea61dfbf08b05a2ce139660e9c7d20d15024c3a0757ac4a5fcb", strip_prefix = "chromedriver-mac-x64", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") diff --git a/common/selenium_manager.bzl b/common/selenium_manager.bzl index 50f890f1e2029..79d240b28c204 100644 --- a/common/selenium_manager.bzl +++ b/common/selenium_manager.bzl @@ -6,22 +6,22 @@ def selenium_manager(): http_file( name = "download_sm_linux", executable = True, - sha256 = "97ab346b907a813c236f1c6b9eb0e1b878702374b0768894415629c2cf05d97e", - url = "https://github.com/SeleniumHQ/selenium_manager_artifacts/releases/download/selenium-manager-33ad1b2/selenium-manager-linux", + sha256 = "8fa14a9c6e36de33485d69915861fe6d459f854f56d4b70e7f07f1783c4f4f08", + url = "https://github.com/SeleniumHQ/selenium_manager_artifacts/releases/download/selenium-manager-694e399/selenium-manager-linux", ) http_file( name = "download_sm_macos", executable = True, - sha256 = "ef27b5c2d274dc4ab4417334116a1530571edc3deaf4740068e35484e275f28a", - url = "https://github.com/SeleniumHQ/selenium_manager_artifacts/releases/download/selenium-manager-33ad1b2/selenium-manager-macos", + sha256 = "c3c08dd30bb2ede7996574be09aeac2d452bf232b9f0d77568765adeac1f2af9", + url = "https://github.com/SeleniumHQ/selenium_manager_artifacts/releases/download/selenium-manager-694e399/selenium-manager-macos", ) http_file( name = "download_sm_windows", executable = True, - sha256 = "15113137d8d0d3648be9948c52e56e1f4c605bc5d9623962991198e8d0d413b6", - url = "https://github.com/SeleniumHQ/selenium_manager_artifacts/releases/download/selenium-manager-33ad1b2/selenium-manager-windows.exe", + sha256 = "b7f87a63eb197a8e3a85d553755fec79a259f57c1216169e2377db2b89bc6b8b", + url = "https://github.com/SeleniumHQ/selenium_manager_artifacts/releases/download/selenium-manager-694e399/selenium-manager-windows.exe", ) def _selenium_manager_artifacts_impl(_ctx): diff --git a/dotnet/CHANGELOG b/dotnet/CHANGELOG index ba87fcdaa96da..d0ead0419bcf8 100644 --- a/dotnet/CHANGELOG +++ b/dotnet/CHANGELOG @@ -1,3 +1,26 @@ +v4.27.0 +====== +* Copyright dotnet (#13522) +* Add CDP for Chrome 131 and remove 128 +* Add CDP deprecation warning for Firefox (#14759) +* Add ChromiumNetworkConditions to command serialization (#14716) +* Add Dictionary as well-known types for json serialization +* Add more well-known dictionary types for capability json serialization +* Add reflection-based JSON serialization fallback to `Command`s (#14732) +* Allow `RemoteSessionSettings` to use any value for metadata (#14726) +* Deprecate WebElement.GetAttribute() (#14676) +* Enable NRT on exceptional types (#14672) +* Fix API docs static generation (#14651) +* Fix `RelativeBy.Near` and empty list return (#14737) +* Gracefully handle clashing device names in Actions (#14713) +* Make FirefoxProfile AOT-safe (#14742) +* Make Selenium Manager's AOT safety explicit (#14733) +* Modernize exception handling in tests via assert that throws (#14776) +* Propagate async throughout test setup and teardown (#14775) +* Remove JSON serialization from `.ToString()` methods (#14736) +* Solidify nullability of `PinnedScript` (#14708) +* Update dependency System.Text.Json to 8.0.5 + v4.26.1 ====== * [bidi] Reveal browsing context module in bidi instance (#14684) diff --git a/dotnet/paket.dependencies b/dotnet/paket.dependencies index 35689c811683c..58d951d7f4bf2 100644 --- a/dotnet/paket.dependencies +++ b/dotnet/paket.dependencies @@ -24,5 +24,5 @@ nuget System.Diagnostics.Tools 4.3.0 nuget System.Drawing.Common 7.0.0 nuget System.Runtime 4.3.1 nuget System.Runtime.InteropServices 4.3.0 -nuget System.Text.Json 8.0.4 +nuget System.Text.Json 8.0.5 nuget Runfiles 0.12.0 diff --git a/dotnet/paket.lock b/dotnet/paket.lock index 7edf7af4bafbf..d442f8f04bb68 100644 --- a/dotnet/paket.lock +++ b/dotnet/paket.lock @@ -100,7 +100,7 @@ NUGET System.Buffers (>= 4.5.1) - restriction: || (&& (== net7.0) (>= net462)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) System.Memory (>= 4.5.5) - restriction: || (&& (== net7.0) (>= net462)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (&& (== net7.0) (>= net462)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) - System.Text.Json (8.0.4) + System.Text.Json (8.0.5) Microsoft.Bcl.AsyncInterfaces (>= 8.0) - restriction: || (&& (== net7.0) (>= net462)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) System.Buffers (>= 4.5.1) - restriction: || (&& (== net7.0) (>= net462)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) System.Memory (>= 4.5.5) - restriction: || (&& (== net7.0) (>= net462)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) diff --git a/dotnet/selenium-dotnet-version.bzl b/dotnet/selenium-dotnet-version.bzl index eb9c52953feee..2b2c122b24997 100644 --- a/dotnet/selenium-dotnet-version.bzl +++ b/dotnet/selenium-dotnet-version.bzl @@ -1,12 +1,12 @@ # BUILD FILE SYNTAX: STARLARK -SE_VERSION = "4.27.0-nightly202410311906" +SE_VERSION = "4.27.0" ASSEMBLY_VERSION = "4.0.0.0" SUPPORTED_NET_STANDARD_VERSIONS = ["netstandard2.0"] SUPPORTED_DEVTOOLS_VERSIONS = [ "v85", - "v128", + "v131", "v129", "v130", ] diff --git a/dotnet/src/webdriver/DevTools/DevToolsDomains.cs b/dotnet/src/webdriver/DevTools/DevToolsDomains.cs index 53631416e161c..81bb52e829206 100644 --- a/dotnet/src/webdriver/DevTools/DevToolsDomains.cs +++ b/dotnet/src/webdriver/DevTools/DevToolsDomains.cs @@ -39,7 +39,7 @@ public abstract class DevToolsDomains { { 130, typeof(V130.V130Domains) }, { 129, typeof(V129.V129Domains) }, - { 128, typeof(V128.V128Domains) }, + { 131, typeof(V131.V131Domains) }, { 85, typeof(V85.V85Domains) } }; diff --git a/dotnet/src/webdriver/DevTools/v128/V128Domains.cs b/dotnet/src/webdriver/DevTools/v131/V131Domains.cs similarity index 78% rename from dotnet/src/webdriver/DevTools/v128/V128Domains.cs rename to dotnet/src/webdriver/DevTools/v131/V131Domains.cs index ad7fd36277336..66fd521bf9f09 100644 --- a/dotnet/src/webdriver/DevTools/v128/V128Domains.cs +++ b/dotnet/src/webdriver/DevTools/v131/V131Domains.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -17,20 +17,20 @@ // under the License. // -namespace OpenQA.Selenium.DevTools.V128 +namespace OpenQA.Selenium.DevTools.V131 { /// - /// Class containing the domain implementation for version 128 of the DevTools Protocol. + /// Class containing the domain implementation for version 131 of the DevTools Protocol. /// - public class V128Domains : DevToolsDomains + public class V131Domains : DevToolsDomains { private DevToolsSessionDomains domains; /// - /// Initializes a new instance of the V128Domains class. + /// Initializes a new instance of the V131Domains class. /// /// The DevToolsSession to use with this set of domains. - public V128Domains(DevToolsSession session) + public V131Domains(DevToolsSession session) { this.domains = new DevToolsSessionDomains(session); } @@ -38,7 +38,7 @@ public V128Domains(DevToolsSession session) /// /// Gets the DevTools Protocol version for which this class is valid. /// - public static int DevToolsVersion => 128; + public static int DevToolsVersion => 131; /// /// Gets the version-specific domains for the DevTools session. This value must be cast to a version specific type to be at all useful. @@ -48,21 +48,21 @@ public V128Domains(DevToolsSession session) /// /// Gets the object used for manipulating network information in the browser. /// - public override DevTools.Network Network => new V128Network(domains.Network, domains.Fetch); + public override DevTools.Network Network => new V131Network(domains.Network, domains.Fetch); /// /// Gets the object used for manipulating the browser's JavaScript execution. /// - public override JavaScript JavaScript => new V128JavaScript(domains.Runtime, domains.Page); + public override JavaScript JavaScript => new V131JavaScript(domains.Runtime, domains.Page); /// /// Gets the object used for manipulating DevTools Protocol targets. /// - public override DevTools.Target Target => new V128Target(domains.Target); + public override DevTools.Target Target => new V131Target(domains.Target); /// /// Gets the object used for manipulating the browser's logs. /// - public override DevTools.Log Log => new V128Log(domains.Log); + public override DevTools.Log Log => new V131Log(domains.Log); } } diff --git a/dotnet/src/webdriver/DevTools/v128/V128JavaScript.cs b/dotnet/src/webdriver/DevTools/v131/V131JavaScript.cs similarity index 94% rename from dotnet/src/webdriver/DevTools/v128/V128JavaScript.cs rename to dotnet/src/webdriver/DevTools/v131/V131JavaScript.cs index 023efade5ff8f..98ca5dc7f514a 100644 --- a/dotnet/src/webdriver/DevTools/v128/V128JavaScript.cs +++ b/dotnet/src/webdriver/DevTools/v131/V131JavaScript.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -17,28 +17,28 @@ // under the License. // -using OpenQA.Selenium.DevTools.V128.Page; -using OpenQA.Selenium.DevTools.V128.Runtime; +using OpenQA.Selenium.DevTools.V131.Page; +using OpenQA.Selenium.DevTools.V131.Runtime; using System; using System.Collections.Generic; using System.Threading.Tasks; -namespace OpenQA.Selenium.DevTools.V128 +namespace OpenQA.Selenium.DevTools.V131 { /// - /// Class containing the JavaScript implementation for version 128 of the DevTools Protocol. + /// Class containing the JavaScript implementation for version 131 of the DevTools Protocol. /// - public class V128JavaScript : JavaScript + public class V131JavaScript : JavaScript { private RuntimeAdapter runtime; private PageAdapter page; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The DevTools Protocol adapter for the Runtime domain. /// The DevTools Protocol adapter for the Page domain. - public V128JavaScript(RuntimeAdapter runtime, PageAdapter page) + public V131JavaScript(RuntimeAdapter runtime, PageAdapter page) { this.runtime = runtime; this.page = page; diff --git a/dotnet/src/webdriver/DevTools/v128/V128Log.cs b/dotnet/src/webdriver/DevTools/v131/V131Log.cs similarity index 88% rename from dotnet/src/webdriver/DevTools/v128/V128Log.cs rename to dotnet/src/webdriver/DevTools/v131/V131Log.cs index 617a42447f7a9..4b4ab1d667b70 100644 --- a/dotnet/src/webdriver/DevTools/v128/V128Log.cs +++ b/dotnet/src/webdriver/DevTools/v131/V131Log.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -17,23 +17,23 @@ // under the License. // -using OpenQA.Selenium.DevTools.V128.Log; +using OpenQA.Selenium.DevTools.V131.Log; using System.Threading.Tasks; -namespace OpenQA.Selenium.DevTools.V128 +namespace OpenQA.Selenium.DevTools.V131 { /// - /// Class containing the browser's log as referenced by version 128 of the DevTools Protocol. + /// Class containing the browser's log as referenced by version 131 of the DevTools Protocol. /// - public class V128Log : DevTools.Log + public class V131Log : DevTools.Log { private LogAdapter adapter; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The adapter for the Log domain. - public V128Log(LogAdapter adapter) + public V131Log(LogAdapter adapter) { this.adapter = adapter; this.adapter.EntryAdded += OnAdapterEntryAdded; diff --git a/dotnet/src/webdriver/DevTools/v128/V128Network.cs b/dotnet/src/webdriver/DevTools/v131/V131Network.cs similarity index 95% rename from dotnet/src/webdriver/DevTools/v128/V128Network.cs rename to dotnet/src/webdriver/DevTools/v131/V131Network.cs index bd403f423dc9b..30e6e68f03e21 100644 --- a/dotnet/src/webdriver/DevTools/v128/V128Network.cs +++ b/dotnet/src/webdriver/DevTools/v131/V131Network.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -17,29 +17,29 @@ // under the License. // -using OpenQA.Selenium.DevTools.V128.Fetch; -using OpenQA.Selenium.DevTools.V128.Network; +using OpenQA.Selenium.DevTools.V131.Fetch; +using OpenQA.Selenium.DevTools.V131.Network; using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; -namespace OpenQA.Selenium.DevTools.V128 +namespace OpenQA.Selenium.DevTools.V131 { /// - /// Class providing functionality for manipulating network calls using version 128 of the DevTools Protocol + /// Class providing functionality for manipulating network calls using version 131 of the DevTools Protocol /// - public class V128Network : DevTools.Network + public class V131Network : DevTools.Network { private FetchAdapter fetch; private NetworkAdapter network; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The adapter for the Network domain. /// The adapter for the Fetch domain. - public V128Network(NetworkAdapter network, FetchAdapter fetch) + public V131Network(NetworkAdapter network, FetchAdapter fetch) { this.network = network; this.fetch = fetch; @@ -217,9 +217,9 @@ public override async Task ContinueWithAuth(string requestId, string userName, s await fetch.ContinueWithAuth(new ContinueWithAuthCommandSettings() { RequestId = requestId, - AuthChallengeResponse = new V128.Fetch.AuthChallengeResponse() + AuthChallengeResponse = new V131.Fetch.AuthChallengeResponse() { - Response = V128.Fetch.AuthChallengeResponseResponseValues.ProvideCredentials, + Response = V131.Fetch.AuthChallengeResponseResponseValues.ProvideCredentials, Username = userName, Password = password } @@ -236,9 +236,9 @@ public override async Task CancelAuth(string requestId) await fetch.ContinueWithAuth(new ContinueWithAuthCommandSettings() { RequestId = requestId, - AuthChallengeResponse = new OpenQA.Selenium.DevTools.V128.Fetch.AuthChallengeResponse() + AuthChallengeResponse = new OpenQA.Selenium.DevTools.V131.Fetch.AuthChallengeResponse() { - Response = V128.Fetch.AuthChallengeResponseResponseValues.CancelAuth + Response = V131.Fetch.AuthChallengeResponseResponseValues.CancelAuth } }).ConfigureAwait(false); } diff --git a/dotnet/src/webdriver/DevTools/v128/V128Target.cs b/dotnet/src/webdriver/DevTools/v131/V131Target.cs similarity index 94% rename from dotnet/src/webdriver/DevTools/v128/V128Target.cs rename to dotnet/src/webdriver/DevTools/v131/V131Target.cs index e2a532074d3c7..3bf15943cbfec 100644 --- a/dotnet/src/webdriver/DevTools/v128/V128Target.cs +++ b/dotnet/src/webdriver/DevTools/v131/V131Target.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -17,26 +17,26 @@ // under the License. // -using OpenQA.Selenium.DevTools.V128.Target; +using OpenQA.Selenium.DevTools.V131.Target; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Threading.Tasks; -namespace OpenQA.Selenium.DevTools.V128 +namespace OpenQA.Selenium.DevTools.V131 { /// - /// Class providing functionality for manipulating targets for version 128 of the DevTools Protocol + /// Class providing functionality for manipulating targets for version 131 of the DevTools Protocol /// - public class V128Target : DevTools.Target + public class V131Target : DevTools.Target { private TargetAdapter adapter; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The adapter for the Target domain. - public V128Target(TargetAdapter adapter) + public V131Target(TargetAdapter adapter) { this.adapter = adapter; adapter.DetachedFromTarget += OnDetachedFromTarget; diff --git a/dotnet/src/webdriver/WebDriver.StrongNamed.nuspec b/dotnet/src/webdriver/WebDriver.StrongNamed.nuspec index 9c7dea901536f..34f1966e68b50 100644 --- a/dotnet/src/webdriver/WebDriver.StrongNamed.nuspec +++ b/dotnet/src/webdriver/WebDriver.StrongNamed.nuspec @@ -24,7 +24,7 @@ - + diff --git a/dotnet/src/webdriver/WebDriver.csproj b/dotnet/src/webdriver/WebDriver.csproj index e9acf442d70c1..c6369e782047e 100644 --- a/dotnet/src/webdriver/WebDriver.csproj +++ b/dotnet/src/webdriver/WebDriver.csproj @@ -52,7 +52,7 @@ - + diff --git a/dotnet/src/webdriver/WebDriver.nuspec b/dotnet/src/webdriver/WebDriver.nuspec index b582625550670..4a66fae656f90 100644 --- a/dotnet/src/webdriver/WebDriver.nuspec +++ b/dotnet/src/webdriver/WebDriver.nuspec @@ -24,7 +24,7 @@ - + diff --git a/dotnet/test/common/CustomDriverConfigs/StableChannelChromeDriver.cs b/dotnet/test/common/CustomDriverConfigs/StableChannelChromeDriver.cs index 9ed2a32bddfc0..fe5728aa971df 100644 --- a/dotnet/test/common/CustomDriverConfigs/StableChannelChromeDriver.cs +++ b/dotnet/test/common/CustomDriverConfigs/StableChannelChromeDriver.cs @@ -39,7 +39,7 @@ public StableChannelChromeDriver(ChromeDriverService service, ChromeOptions opti public static ChromeOptions DefaultOptions { - get { return new ChromeOptions() { BrowserVersion = "130" }; } + get { return new ChromeOptions() { BrowserVersion = "131" }; } } } } diff --git a/dotnet/test/common/DevTools/DevToolsConsoleTest.cs b/dotnet/test/common/DevTools/DevToolsConsoleTest.cs index e352e575c773e..a91bc591a7abc 100644 --- a/dotnet/test/common/DevTools/DevToolsConsoleTest.cs +++ b/dotnet/test/common/DevTools/DevToolsConsoleTest.cs @@ -25,7 +25,7 @@ namespace OpenQA.Selenium.DevTools { - using CurrentCdpVersion = V130; + using CurrentCdpVersion = V131; [TestFixture] public class DevToolsConsoleTest : DevToolsTestFixture diff --git a/dotnet/test/common/DevTools/DevToolsLogTest.cs b/dotnet/test/common/DevTools/DevToolsLogTest.cs index 00872c8729252..f9e96be1a7bd1 100644 --- a/dotnet/test/common/DevTools/DevToolsLogTest.cs +++ b/dotnet/test/common/DevTools/DevToolsLogTest.cs @@ -25,7 +25,7 @@ namespace OpenQA.Selenium.DevTools { - using CurrentCdpVersion = V130; + using CurrentCdpVersion = V131; [TestFixture] public class DevToolsLogTest : DevToolsTestFixture diff --git a/dotnet/test/common/DevTools/DevToolsNetworkTest.cs b/dotnet/test/common/DevTools/DevToolsNetworkTest.cs index d9a45c3652be4..a842e1445c27c 100644 --- a/dotnet/test/common/DevTools/DevToolsNetworkTest.cs +++ b/dotnet/test/common/DevTools/DevToolsNetworkTest.cs @@ -25,7 +25,7 @@ namespace OpenQA.Selenium.DevTools { - using CurrentCdpVersion = V130; + using CurrentCdpVersion = V131; [TestFixture] public class DevToolsNetworkTest : DevToolsTestFixture diff --git a/dotnet/test/common/DevTools/DevToolsPerformanceTest.cs b/dotnet/test/common/DevTools/DevToolsPerformanceTest.cs index 50b235311155f..5dc5c4011b6f5 100644 --- a/dotnet/test/common/DevTools/DevToolsPerformanceTest.cs +++ b/dotnet/test/common/DevTools/DevToolsPerformanceTest.cs @@ -22,7 +22,7 @@ namespace OpenQA.Selenium.DevTools { - using CurrentCdpVersion = V130; + using CurrentCdpVersion = V131; [TestFixture] public class DevToolsPerformanceTest : DevToolsTestFixture diff --git a/dotnet/test/common/DevTools/DevToolsProfilerTest.cs b/dotnet/test/common/DevTools/DevToolsProfilerTest.cs index 0a5c13d16234c..985a336e2c94e 100644 --- a/dotnet/test/common/DevTools/DevToolsProfilerTest.cs +++ b/dotnet/test/common/DevTools/DevToolsProfilerTest.cs @@ -24,7 +24,7 @@ namespace OpenQA.Selenium.DevTools { - using CurrentCdpVersion = V130; + using CurrentCdpVersion = V131; [TestFixture] public class DevToolsProfilerTest : DevToolsTestFixture diff --git a/dotnet/test/common/DevTools/DevToolsSecurityTest.cs b/dotnet/test/common/DevTools/DevToolsSecurityTest.cs index 6ecffc5ab1795..47af8e49a0c5a 100644 --- a/dotnet/test/common/DevTools/DevToolsSecurityTest.cs +++ b/dotnet/test/common/DevTools/DevToolsSecurityTest.cs @@ -25,7 +25,7 @@ namespace OpenQA.Selenium.DevTools { - using CurrentCdpVersion = V130; + using CurrentCdpVersion = V131; [TestFixture] public class DevToolsSecurityTest : DevToolsTestFixture diff --git a/dotnet/test/common/DevTools/DevToolsTabsTest.cs b/dotnet/test/common/DevTools/DevToolsTabsTest.cs index 5bb4065d4fcbe..23ad303e0dea3 100644 --- a/dotnet/test/common/DevTools/DevToolsTabsTest.cs +++ b/dotnet/test/common/DevTools/DevToolsTabsTest.cs @@ -22,7 +22,7 @@ namespace OpenQA.Selenium.DevTools { - using CurrentCdpVersion = V130; + using CurrentCdpVersion = V131; [TestFixture] public class DevToolsTabsTest : DevToolsTestFixture diff --git a/dotnet/test/common/DevTools/DevToolsTargetTest.cs b/dotnet/test/common/DevTools/DevToolsTargetTest.cs index 5b1358bbdf2b9..2752d6dc347f2 100644 --- a/dotnet/test/common/DevTools/DevToolsTargetTest.cs +++ b/dotnet/test/common/DevTools/DevToolsTargetTest.cs @@ -25,12 +25,12 @@ namespace OpenQA.Selenium.DevTools { - using CurrentCdpVersion = V130; + using CurrentCdpVersion = V131; [TestFixture] public class DevToolsTargetTest : DevToolsTestFixture { - private int id = 130; + private int id = 131; [Test] [IgnoreBrowser(Selenium.Browser.IE, "IE does not support Chrome DevTools Protocol")] diff --git a/java/CHANGELOG b/java/CHANGELOG index 98cf2a20a00a6..75b10d630960f 100644 --- a/java/CHANGELOG +++ b/java/CHANGELOG @@ -1,3 +1,33 @@ +v4.27.0 +====== +* Add CDP for Chrome 131 and remove 128 +* Add Firefox CDP deprecation warnings +* Throw Error When Using Unsupported Linux ARM (#14616) +* Enhance error message for NoSuchElementException and return unmodifiable set for pinned scripts (#14707) +* Fix SpotBugs bugs in the Selenium manager (#14608) +* Allow to cancel a pending http request +* Case insensitive header names in http requests (#14095) +* Consume the input of the connection +* Deleted the deprecated FormEncodedData (#14688) +* Add method to select options containing the provided text (#14426) +* Remove toml parser warning (#14711) +* Simplify reading http headers +* Mark WebElement.getAttribute deprecated (#14666) +* Search windows by name without recursion (#14782) +* [bidi] Add network request handler APIs (#14424) +* [bidi] Fix the mode "closed" for a node +* [grid] TomlConfig: migrate TOML library to tomlj/tomlj (#14470) +* [grid] Avoid starting a session which will be disposed after start +* [grid] Cancel pending request on client timeout +* [grid] Check session ownership once +* [grid] Detect a client timeout while session creation #14743 +* [grid] Prevent NPE in handling request with unsupported http method +* [grid] Retry creating a session in a distributed grid +* [grid] Shutdown the server backend on stop +* [grid] Speed up the server shutdown +* [grid] Stop a stale session more graceful +* [grid] Stop polling events on close + v4.26.0 ====== * Add CDP for Chrome 130 and remove 127 diff --git a/java/maven_install.json b/java/maven_install.json index a0078edf86f7c..89ea3131ad63b 100644 --- a/java/maven_install.json +++ b/java/maven_install.json @@ -1,7 +1,7 @@ { "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", - "__INPUT_ARTIFACTS_HASH": -740136818, - "__RESOLVED_ARTIFACTS_HASH": 314475666, + "__INPUT_ARTIFACTS_HASH": 329453186, + "__RESOLVED_ARTIFACTS_HASH": -9148858, "conflict_resolution": { "com.google.code.gson:gson:2.8.9": "com.google.code.gson:gson:2.11.0", "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.28.0", @@ -19,10 +19,10 @@ }, "com.esotericsoftware:kryo": { "shasums": { - "jar": "ead0f39530d6f30d27791eeb81621f3d7445331a06c32b3302e0ebe9e04b3a5d", - "sources": "fe808d5e9370797ebeddd87f1aefb84c15281a18148388645c79c2382acc1e5f" + "jar": "4e8b1d2f4977187af8a51a957329722dc1cdc56a7c94fbb5a791e82897629cff", + "sources": "acd9090539befa5421466ea1001dd808927af3f7d0ff12340ff518c15a9c5f4e" }, - "version": "5.6.0" + "version": "5.6.2" }, "com.esotericsoftware:minlog": { "shasums": { @@ -40,31 +40,31 @@ }, "com.fasterxml.jackson.core:jackson-annotations": { "shasums": { - "jar": "a09367d2eeb526873abf737ff754c5085f82073a382ee72c3bbe15412217671f", - "sources": "506c61d1efe6cf7aff5ec13a4b87532185e7a872dc2ffea66dc57bdcc1108f15" + "jar": "b7f9df5dac9a85f47fdb2769455ee8ba9cf2fe9b7c4cf636e0aec83479d7882f", + "sources": "de28b02b11bbbfa1c067473de8fa48ca2d1265b9410a27030426732dbb3dbeaf" }, - "version": "2.18.0" + "version": "2.18.1" }, "com.fasterxml.jackson.core:jackson-core": { "shasums": { - "jar": "215bbd7c8fd65be504cb92ff3aa1c4b790fc7b14cca72f4546aac4143c101bb5", - "sources": "afb36a31e0038a31d79e30719315ad5c7a1e140443ef400108d104d72c943162" + "jar": "ebe19596ad19f7a0514c8bb8f7b0acf85239a4eff5ae03229e9760d268d29c22", + "sources": "9b5089257fc20d3ba139b671e816c02b7c925705a8ad6c4a9937eb067581ea58" }, - "version": "2.18.0" + "version": "2.18.1" }, "com.fasterxml.jackson.core:jackson-databind": { "shasums": { - "jar": "2bf1927b7f3224683ed0157a1ec3b0ede75179da3e597d78c572d56ed00f9f3c", - "sources": "0531788c8193e81e40e16ff7c16401d7c5cb629ed493bb13d091d980bc425123" + "jar": "711bc3bf86d31d02968b9279efb07a6ad60adfc0baa0e9fe66d71a0ac2556234", + "sources": "992f36c82e422e4847f5f63f7acf3e4266a4154ea0af9408d56bc81392473615" }, - "version": "2.18.0" + "version": "2.18.1" }, "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { "shasums": { - "jar": "1e14646be85443e9be00c18fe7d67b71953edaed97ce0b30ce822279933aeaca", - "sources": "6fb2e6b2b39e2a93787f5d8ce3ea851623af6f1ecdbce2a724732936ade12fd4" + "jar": "b764452d6cdd644666bba2da35ef8e6dfb86b7a59d24d1d98ea2fcf1e6bb08b2", + "sources": "5abfc0355821094c67dacb3a0688a755053858c3e0ebeefc488afea75867ad81" }, - "version": "2.18.0" + "version": "2.18.1" }, "com.github.javaparser:javaparser-core": { "shasums": { @@ -145,10 +145,10 @@ }, "com.google.googlejavaformat:google-java-format": { "shasums": { - "jar": "9a4e0b9f4ec4d71a8a1d3641fd481118100fda2eeab712dbdfd4b2a06e9de4ce", - "sources": "d4dfd144c7dceca98cfa479591398160558c0311750eed069ebd796cda420d55" + "jar": "e9e3f83d1bf47a47d28d93b06ff0263421bc2dc5de75e238a12d8aea682ccbfd", + "sources": "40c30f0d367502d24da61c7d692f6f7d0f0e5b4d12289f99c53f1fa669bbad3d" }, - "version": "1.24.0" + "version": "1.25.0" }, "com.google.guava:failureaccess": { "shasums": { @@ -257,101 +257,101 @@ }, "io.lettuce:lettuce-core": { "shasums": { - "jar": "3257b7708b94597aece90f8ff234761f422b458e68907a67d7711fde7ec87111", - "sources": "694ec0daa3961915bd84f78ce1f7cc8d5e4183a14d1dd71b1497a46f8df82a59" + "jar": "bcadafb28f41343d39bf90820b8349e3462e43d7e5c0edc3f9886aa661972015", + "sources": "67d988cdd8d2e62a8c9c3c86ea812bf0020e59090ebd3469bfc0cca554d8d631" }, - "version": "6.4.0.RELEASE" + "version": "6.5.0.RELEASE" }, "io.netty:netty-buffer": { "shasums": { - "jar": "436ea25725d92c1f590a857d46dc1c8f5c54d7f2775984db2655e5e3bc0d97c9", - "sources": "62bec4230845ec978832f602b9a118b57955cf816da07b99fccd33430d5da3a8" + "jar": "4a7b331d3770c566ab70eb02a0d1feed63b95cf6e4d68c8fe778c4c9de2d116d", + "sources": "4fab39fb7a6ff8aed28433aa89c3d29e1286e8a8b2b2e77d5e542c801859cb1e" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-codec": { "shasums": { - "jar": "71d145491456b53212e38e24787bbbed0c77d850f7352e24e535d26a6eea913b", - "sources": "f0bc1dcab04f9c9fb9fb5450eb1636c7c99b67a772ceb7896e80094400e8c74c" + "jar": "cd189afb70ec6eacfcdfdd3a5f472b4e705a5c91d5bd3ef0386421f2ae15ec77", + "sources": "0546519a1db0ab595107ca451e6296ff9c7f3139bd569d6eabe232af98eedeab" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-codec-dns": { "shasums": { - "jar": "65d9690298403ada696a7cbf9ebab2106e9d6a9056ae51d5fda7c4c553d9a21a", - "sources": "edf01b849d83b8f6bbd754ed324e418a2c8cabf8659fa5316b285580307b85dd" + "jar": "23dd6806bcc326855f13e69838c6411d0490e6b1aeb12e217a19a3dd6ad3f10d", + "sources": "9fced4a3fc93413b03a25ddbbd2477f7032947fa0fe606fe796a1a6102c3e555" }, - "version": "4.1.113.Final" + "version": "4.1.115.Final" }, "io.netty:netty-codec-http": { "shasums": { - "jar": "56150ce900f6d931fce37a7fb05d7d75478d6d0b8b556a21781972eb9c3ed7df", - "sources": "69a06bd827300e88736660df76fc1d590379f2a161ca1fbc6aaaf8e1c9554ada" + "jar": "e6dbe971c59373bbae9802021c63b9bc1d8800fead382863d67e79e79b023166", + "sources": "b0228c970b95d394e0f42b3c3c1620c6eba4e9b5a8fd5943063258a39eaaf9c2" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-codec-http2": { "shasums": { - "jar": "e3e45427a46a8d5b03307a5bcd2eab3706b8b8d903c6a056fa3d1c9bf9738f24", - "sources": "e8e3f6c709ddcef83bfff99b144bc532e235dc8bdd685621179a7a08ddb763bd" + "jar": "cbed9829a5d582e91e314e209edce9a0c2eb369f23bb4fb74a5bc8b7990222c2", + "sources": "2b412de41e256fae0ecebad3e91c8b7f8ea5584467fe3305578102d8bd494c11" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-codec-socks": { "shasums": { - "jar": "2e48cb5af7cae82acbb8dcb7b0c9d67b9dddff3d6dd262cb8911fd4b5fd62ee2", - "sources": "2d90b45bc6f02c2c708c1773aae010b344b260bb4b033fbd01d054aed56f9c9e" + "jar": "e9b1cc744dc6195894450b1fd4d271a821ab167fe21ae3c459b27cdadc70e81f", + "sources": "9a731bc23fafca14775692bfbd23ad08826566eeed991335d181440eb0bae992" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-common": { "shasums": { - "jar": "d6b053b3b27cc568207f254902dcb6f95dd238c1b9d55ef719d2c4f8eb476223", - "sources": "fac8937c115808c600fcae35964e54ae4eef344b81c22f8de8913ca95ddbcebf" + "jar": "39f1b5a2aaa4eab5d036dfd0486e35a4276df412e092d36b2d88b494705a134d", + "sources": "c845481b98d301c7716a786b07cf0e94b1151db02e06da1878538a73489903e3" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-handler": { "shasums": { - "jar": "57be25ec6c8fa7052fe90119373d8bc979cd37fa0070a135c0e69f5f8e0ddad0", - "sources": "f07c13c7bd69f481136983bdf722fe64be29405065842010669d443455379c24" + "jar": "5972028cc863b74927ce0d11fb8d58f65da2560bef5602fe8ce8903bd306ca07", + "sources": "c1facec3ea662bbb8e918ab46fa8d0959ef49163f867b1351edb3a6bc028cda1" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-handler-proxy": { "shasums": { - "jar": "35555b41624c8384de773bc3d17eb2447f5449842119db0435a366372aceefd1", - "sources": "af00561a494ad88a960b02ffae8153bd7c04cd2aa87183e884ad146fee67cda9" + "jar": "807e67cfb17136927d11db42df62031169d1fa0883e13f254906994c84ffbe87", + "sources": "4a3a309e72ecff5efaed3bbf80475d49b884f2c32de25d7293e593900b2b8cac" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-resolver": { "shasums": { - "jar": "19661e7f1dbdee97fe99a227fbed0696d29c3cdf3f8f2d9839a790695c2bf0ac", - "sources": "83ddf3e14d989e90d28811e7c2697dfef35061fe63b8939ddaf42e5c91235681" + "jar": "7b3455d14f59828765a00573bc3967dc59379e874bd62a67eb1926d6512109d1", + "sources": "b56c0ad382a2ba9586df13c4b3dab11f65fadec95b2728997f8793634724298c" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-resolver-dns": { "shasums": { - "jar": "65c3bd4569bbe7d3d9b7b9991ac5fd2b1336d6f7a19e76fc60aa23a9bfe3b8f9", - "sources": "cfb42f6612adce6345ee5eca93fe4f5bf6540314fd3c2b8c561c255ac3299d53" + "jar": "4aca31593e5896c64ab7e041bbc6c0d851bd9634ec3a4354208141a35576619f", + "sources": "6fde922a5f66d3e550f14571f3d180de0bfed7a2ea95ac520076c4def42de53f" }, - "version": "4.1.113.Final" + "version": "4.1.115.Final" }, "io.netty:netty-transport": { "shasums": { - "jar": "2a8609fe6a8b4c9d5965c6b901777b4bd0b26600647ee2aa7d4d93f4d5c780de", - "sources": "dd4923fb040730ea5ddb4cb66a0e236ffe75385a201badd7902a99e5fad81ee4" + "jar": "c3d71faaa736ffd2c9260ab0b498024b814c39c7d764bea8113fa98de6e2bdd2", + "sources": "162c3531b2819f6b51ca9c59b54508b782e462549b1fffeed9771a1a718a84eb" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.netty:netty-transport-native-unix-common": { "shasums": { - "jar": "fd64c07c9e068f80dc271f6277278246328a171be669abdfe0bc8b2226d980de", - "sources": "84e5081550855aa7567a215b94fdc6cd7e8c62dabc9503fc2c3c72e0c3855a48" + "jar": "4b03e716272657c296b0204b57c140b2b2ca96b1a746c92da41f595892ec6d88", + "sources": "5bfbcb52d0f0d52b996a427eb1b77927d182026c367366548d2c49d0825b5dd9" }, - "version": "4.1.114.Final" + "version": "4.1.115.Final" }, "io.opentelemetry.semconv:opentelemetry-semconv": { "shasums": { @@ -362,87 +362,87 @@ }, "io.opentelemetry:opentelemetry-api": { "shasums": { - "jar": "4d08915aa1590bd64b3fced39bae06489e3f597c4bf7fa12f413e13c5a98be39", - "sources": "e8d0fbee6a7a19408e776bda9caecb2a4adeedf64cc196cfefd977837eb27300" + "jar": "097e2e71c8b8c813f4a13176baafbbbb124b1253f5c9fffd110bc2add74ace93", + "sources": "0d9d8c1391c2a8a79ebcb013f38c172ad4cbef6b52e690501e8cb55effabc9da" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-api-incubator": { "shasums": { - "jar": "a64d48638cdd4324e5ffab80c85784173f8c5068f059c07d8380f428d7c39ec8", - "sources": "871b4ef83803384b4a4ce794ea7b2384e0df70c8a15dc48afcf318525d7547f0" + "jar": "8dbf451ce580fa0252ee9ca77331fd21710710ca9b735a1359241ead3be8ebe5", + "sources": "400ee017921af6a987de5ca9aabd2afbd2989c1f3c9eaedc4f1ff8299eace6c1" }, - "version": "1.43.0-alpha" + "version": "1.44.1-alpha" }, "io.opentelemetry:opentelemetry-context": { "shasums": { - "jar": "83d54bed8a7aa74a8648d43974c743f470c9ceab3dea57f26a938667a2dc0160", - "sources": "6cbaf1ff211bd61fd5ac2dd5762e18db56913035c43c963c3863eeff2bb25888" + "jar": "006b3f7c3880356a86f02c40eedeba124f226a2f145fe904cc1b7def0088bab0", + "sources": "50f136587f0d1bf317fbfdd9cf5f589a321d7fd366e3cbea1dc511e458115324" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-exporter-logging": { "shasums": { - "jar": "68dff3d10b0875db8fa4c137f3e1f42f3fde8470f87463feae9c10acdcef7e32", - "sources": "652b5381cdba31eff8b8d402a296b03bdf49da423db0135251aee23794d5903d" + "jar": "9e8f887dcee2d71cab1a0215e09560f03f8d5c1d11edb41cf5512e4c75d3c483", + "sources": "97f391be2e361a7c200033418503d6bd71f09490f2aa7942cecb8bdc3e6313d5" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-sdk": { "shasums": { - "jar": "99fd821997190e9fa1a6f6820b8cedd8e38297ab727b3b98db4d86ab518c0155", - "sources": "d798a21f2338674cd9dc7249d67963f7328b9a0a702c91f65c9d20b4b1eff664" + "jar": "7c64f330ec197a1eb88059b97dc9376fdb9836695027c96a0cb4e74ef917cebe", + "sources": "567caff6fe790a8eef0195c712368c13bae2f5d69ebf51bf3f5393166be43e11" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-sdk-common": { "shasums": { - "jar": "8d0cc91322e85ea6f71dbf5d35f829808958fd0427e0c43aa3fdd2e94e56a48b", - "sources": "e240713669cc161a6898c9c405fdf0903f69ff35abde95827d1f6660df58c0cc" + "jar": "3770fc477ee0fab21e796bb559f0a996d38c744f3a170868d1b3b85b63b827d0", + "sources": "e1801125d48e0ba0cb016db0cea3445aaec57c322e6765ac788e3f9b959a3ec1" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure": { "shasums": { - "jar": "c731376048e1b2c89cf184227abfdb2e5baafb687fa4091901e97b4f3e8c6985", - "sources": "0cc04966769b3b65c8df3769ef90908eae77aa16fb6f82895d4ff80a4a198d75" + "jar": "22c312cbfefb1a6a8ab0973f3fffe82c32690898264aa5ba7941fbed333f46b7", + "sources": "948d49771e99dc47807e74f709d22d757af5a4c7d12725eeafa6d6486fab292a" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi": { "shasums": { - "jar": "ae0b08fbe8b3146ff2a8e14cc48af418d6f8f808527d00406b0778748cd07f24", - "sources": "c92792a6f691b68f513ae3b9d4a1bc97299881b08399f3fb1900e947e5434dca" + "jar": "f3478af96e4f2f5fd60283522553de4ce99c03606a16e460d07bc6eee12f9f95", + "sources": "46b251d7737595cf49cfb2f3bae905951efc4cf78085ba02c625f7fed781b89f" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-sdk-logs": { "shasums": { - "jar": "5465297bac529a32be7c3e37bc854f1f683df967551cc092397deaa2596f4462", - "sources": "234fb21e31806e054c53044cf97d82786390b3634cc94fd42b4fe5c12d86a553" + "jar": "ba4a97966ded2927dcaae6e91bf0a1707867e44cc3dd2ae4c7ef8214bdf8daf7", + "sources": "f6c63d81b3189fe1a76a712f4eff11b60300c093ce4d65ad73fee5b811648ca6" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-sdk-metrics": { "shasums": { - "jar": "b3cd4906157c559005d6890441d367730c337ad4d860adeee7ceda1106cfc245", - "sources": "d7523f6dbeb161fd4f0dabf1c6e414ab3eac153479acb95547155f5b16f8e557" + "jar": "3c09668a96f1e9443d2894ae456674c8c38b221c096c391fc81616daa672bf68", + "sources": "afe4b9c4cb2328bb2180cf4bc280293191eb3ab8b4165ab725bab9e73a194a1b" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-sdk-testing": { "shasums": { - "jar": "37512f646f55312cc0a646a0b508495d993d818aae2df5403497c5a096cd5571", - "sources": "bf62824394d155329ce095e4ad64cb6d3b2daf3f7a4b5c15dea21c5e3196ba5b" + "jar": "eff023fee9b71101eab3c70ab67cac1c28cbf41e357316eefc5dcafc161bad99", + "sources": "5e8e5636f16ce53ee91b5108a4b9fd232d171cfd98e0e6fafb4b968a2cd6e528" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.opentelemetry:opentelemetry-sdk-trace": { "shasums": { - "jar": "7e28072cf33eaa7d5e5f3ab2f8b2e51e54d24e0fe3dae3482769b0f6ff0dfcfc", - "sources": "b75d547249b04ad5163c17253018159f3f40a99d6d89719a82d11eb3d64588f1" + "jar": "ff013ab945567dccb5dde638f7a366519defbd2d138df1370936e847ef608c87", + "sources": "24f7b867a0f2f3203e4eb2069137bbd01936e7df7d08d3ec2dfcad478444ae27" }, - "version": "1.43.0" + "version": "1.44.1" }, "io.projectreactor:reactor-core": { "shasums": { @@ -593,24 +593,24 @@ }, "org.bouncycastle:bcpkix-jdk18on": { "shasums": { - "jar": "4b48ea084e5232b9d79ebca1887b9de037b124931807cd60710748c2aee08cc9", - "sources": "ce8a110efa6f2beb40f5fa518e5a8b647cedd05d282df593f450cf5acd7d8ea2" + "jar": "3639a24ddf9ba4b7eba0659b44770e91eba816421888e571f285aadefe532cd6", + "sources": "e68973be5e2eed5c887e9e85d4ac68ceafe4d907e0f03bfb36db80964c904922" }, - "version": "1.78.1" + "version": "1.79" }, "org.bouncycastle:bcprov-jdk18on": { "shasums": { - "jar": "add5915e6acfc6ab5836e1fd8a5e21c6488536a8c1f21f386eeb3bf280b702d7", - "sources": "be87a544d921152cedcef4b740155047ef2f402544d47382b8c0b15dec11a642" + "jar": "0d81ecc3124536b539bce9aa3fe9621b7f84c9cee371b635a5b31c78b79ab1da", + "sources": "ddab0541b2490e3013cac96179c1c4a8a50685d9b39f29ce5b233b310061ed23" }, - "version": "1.78.1" + "version": "1.79" }, "org.bouncycastle:bcutil-jdk18on": { "shasums": { - "jar": "d9fa56f97b0f761ce3bc8d9d74c5d7137a987bf5bd3abfe1003f9bafa45a1d2f", - "sources": "667b6334ff25c4303d3b1af02599f8547fcc37d0d55393bcb17de4f179c78baa" + "jar": "c70b88ada58938cbc2f005d40329054078bcfa1149e6ffc03e9242eb6ab21836", + "sources": "eea160325180797639d715311a04af9702e45ceaed3dbb487ab28ca778434cb6" }, - "version": "1.78.1" + "version": "1.79" }, "org.checkerframework:checker-qual": { "shasums": { @@ -642,17 +642,17 @@ }, "org.htmlunit:htmlunit-core-js": { "shasums": { - "jar": "70c9a224a75670a6d135e65deac885462e34a6756559170527cffcd613f3ca1a", - "sources": "87645340ab720096be5267b9ac820d60d968f690c024e8190be2942afe027309" + "jar": "709c43eaab5b407468239b49ba990a7170ee582cbaa6a11c09a6118da22fdedc", + "sources": "458acacd14d851ad0ad20310787b35d3224d0c31155bd6b17d41de2b352bb1b7" }, - "version": "4.5.0" + "version": "4.6.0" }, "org.jodd:jodd-util": { "shasums": { - "jar": "c9859921c4b94ac0c35fb2ce9a0bfc11d3e388888791c503e4cd085c5a436cf9", - "sources": "96202cfb22dc8e1832c0a9ad7731e2153594ef72b48a95decb054b79505c9767" + "jar": "e5c676715897124101f74900dd1f98ebbcad9da3ab2dffbac6e7712612094427", + "sources": "15b9eb016cc8fe52de6332cd9fb23eadba29393b0087635294aa2e23586b809f" }, - "version": "6.2.2" + "version": "6.3.0" }, "org.jspecify:jspecify": { "shasums": { @@ -719,10 +719,10 @@ }, "org.objenesis:objenesis": { "shasums": { - "jar": "02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb", - "sources": "d06164f8ca002c8ef193cef2d682822014dd330505616af93a3fb64226fc131d" + "jar": "95488102feaf2e2858adf6b299353677dac6c15294006f8ed1c5556f8e3cd251", + "sources": "896fa899a262c2f0f7e661848025fad22349300a5247ac175510993a9a5eede9" }, - "version": "3.3" + "version": "3.4" }, "org.opentest4j:opentest4j": { "shasums": { @@ -775,10 +775,10 @@ }, "org.redisson:redisson": { "shasums": { - "jar": "c9840ce1cc8ccf03e95ac6901add9e6342711caf5a1c00f52687b960d979209b", - "sources": "a26f27c9386b38d72d539e21664bc331db2c5b014b925226cb2227c9625057ee" + "jar": "6e905eabe16b5b53ee021293ac1fc4b56db2296ecdb341f6e2e27e93e8fefd22", + "sources": "654232025331ac2191a5e522f82fdf56253976c17ea54a269cf0cbcdb738d2d9" }, - "version": "3.37.0" + "version": "3.39.0" }, "org.slf4j:slf4j-api": { "shasums": { @@ -818,10 +818,10 @@ }, "org.yaml:snakeyaml": { "shasums": { - "jar": "1467931448a0817696ae2805b7b8b20bfb082652bf9c4efaed528930dc49389b", - "sources": "8f7cf911cf63db55fd980a926d155bd846317737351a2f48ef1c1088c414538a" + "jar": "63a76fe66b652360bd4c2c107e6f0258daa7d4bb492008ba8c26fcd230ff9146", + "sources": "127d0e66b80324f65821451827affb8c2f70914f0d7b7b0cb99d56d12e9901cc" }, - "version": "2.2" + "version": "2.3" }, "org.zeromq:jeromq": { "shasums": { @@ -1219,7 +1219,7 @@ "com.fasterxml.jackson.core.exc", "com.fasterxml.jackson.core.filter", "com.fasterxml.jackson.core.format", - "com.fasterxml.jackson.core.internal.shaded.fdp.v2_18_0", + "com.fasterxml.jackson.core.internal.shaded.fdp.v2_18_1", "com.fasterxml.jackson.core.io", "com.fasterxml.jackson.core.io.schubfach", "com.fasterxml.jackson.core.json", @@ -1391,7 +1391,6 @@ "com.google.googlejavaformat", "com.google.googlejavaformat.java", "com.google.googlejavaformat.java.filer", - "com.google.googlejavaformat.java.java17", "com.google.googlejavaformat.java.java21", "com.google.googlejavaformat.java.javadoc" ], @@ -1582,6 +1581,8 @@ "io.lettuce.core.event.jfr", "io.lettuce.core.event.metrics", "io.lettuce.core.internal", + "io.lettuce.core.json", + "io.lettuce.core.json.arguments", "io.lettuce.core.masterreplica", "io.lettuce.core.masterslave", "io.lettuce.core.metrics", @@ -1794,7 +1795,6 @@ "io.opentelemetry.sdk.trace.data", "io.opentelemetry.sdk.trace.export", "io.opentelemetry.sdk.trace.internal", - "io.opentelemetry.sdk.trace.internal.data", "io.opentelemetry.sdk.trace.samplers" ], "io.projectreactor:reactor-core": [ @@ -2392,7 +2392,10 @@ "org.bouncycastle.jcajce.provider.asymmetric.elgamal", "org.bouncycastle.jcajce.provider.asymmetric.gost", "org.bouncycastle.jcajce.provider.asymmetric.ies", + "org.bouncycastle.jcajce.provider.asymmetric.mldsa", + "org.bouncycastle.jcajce.provider.asymmetric.mlkem", "org.bouncycastle.jcajce.provider.asymmetric.rsa", + "org.bouncycastle.jcajce.provider.asymmetric.slhdsa", "org.bouncycastle.jcajce.provider.asymmetric.util", "org.bouncycastle.jcajce.provider.asymmetric.x509", "org.bouncycastle.jcajce.provider.config", @@ -2430,18 +2433,20 @@ "org.bouncycastle.pqc.crypto.bike", "org.bouncycastle.pqc.crypto.cmce", "org.bouncycastle.pqc.crypto.crystals.dilithium", - "org.bouncycastle.pqc.crypto.crystals.kyber", "org.bouncycastle.pqc.crypto.falcon", "org.bouncycastle.pqc.crypto.frodo", "org.bouncycastle.pqc.crypto.gemss", "org.bouncycastle.pqc.crypto.hqc", "org.bouncycastle.pqc.crypto.lms", + "org.bouncycastle.pqc.crypto.mldsa", + "org.bouncycastle.pqc.crypto.mlkem", "org.bouncycastle.pqc.crypto.newhope", "org.bouncycastle.pqc.crypto.ntru", "org.bouncycastle.pqc.crypto.ntruprime", "org.bouncycastle.pqc.crypto.picnic", "org.bouncycastle.pqc.crypto.rainbow", "org.bouncycastle.pqc.crypto.saber", + "org.bouncycastle.pqc.crypto.slhdsa", "org.bouncycastle.pqc.crypto.sphincs", "org.bouncycastle.pqc.crypto.sphincsplus", "org.bouncycastle.pqc.crypto.util", diff --git a/java/src/org/openqa/selenium/devtools/v128/BUILD.bazel b/java/src/org/openqa/selenium/devtools/v131/BUILD.bazel similarity index 98% rename from java/src/org/openqa/selenium/devtools/v128/BUILD.bazel rename to java/src/org/openqa/selenium/devtools/v131/BUILD.bazel index 18d0136322a52..acf72d7a52e00 100644 --- a/java/src/org/openqa/selenium/devtools/v128/BUILD.bazel +++ b/java/src/org/openqa/selenium/devtools/v131/BUILD.bazel @@ -2,7 +2,7 @@ load("//common:defs.bzl", "copy_file") load("//java:defs.bzl", "java_export", "java_library") load("//java:version.bzl", "SE_VERSION") -cdp_version = "v128" +cdp_version = "v131" java_export( name = cdp_version, diff --git a/java/src/org/openqa/selenium/devtools/v128/v128CdpInfo.java b/java/src/org/openqa/selenium/devtools/v131/v131CdpInfo.java similarity index 86% rename from java/src/org/openqa/selenium/devtools/v128/v128CdpInfo.java rename to java/src/org/openqa/selenium/devtools/v131/v131CdpInfo.java index f721fa6e7f83a..399ff1ba568ac 100644 --- a/java/src/org/openqa/selenium/devtools/v128/v128CdpInfo.java +++ b/java/src/org/openqa/selenium/devtools/v131/v131CdpInfo.java @@ -15,15 +15,15 @@ // specific language governing permissions and limitations // under the License. -package org.openqa.selenium.devtools.v128; +package org.openqa.selenium.devtools.v131; import com.google.auto.service.AutoService; import org.openqa.selenium.devtools.CdpInfo; @AutoService(CdpInfo.class) -public class v128CdpInfo extends CdpInfo { +public class v131CdpInfo extends CdpInfo { - public v128CdpInfo() { - super(128, v128Domains::new); + public v131CdpInfo() { + super(131, v131Domains::new); } } diff --git a/java/src/org/openqa/selenium/devtools/v128/v128Domains.java b/java/src/org/openqa/selenium/devtools/v131/v131Domains.java similarity index 77% rename from java/src/org/openqa/selenium/devtools/v128/v128Domains.java rename to java/src/org/openqa/selenium/devtools/v131/v131Domains.java index e6bfa0a3ad0a5..f5a796cd476b1 100644 --- a/java/src/org/openqa/selenium/devtools/v128/v128Domains.java +++ b/java/src/org/openqa/selenium/devtools/v131/v131Domains.java @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package org.openqa.selenium.devtools.v128; +package org.openqa.selenium.devtools.v131; import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.idealized.Domains; @@ -26,21 +26,21 @@ import org.openqa.selenium.devtools.idealized.target.Target; import org.openqa.selenium.internal.Require; -public class v128Domains implements Domains { +public class v131Domains implements Domains { - private final v128Javascript js; - private final v128Events events; - private final v128Log log; - private final v128Network network; - private final v128Target target; + private final v131Javascript js; + private final v131Events events; + private final v131Log log; + private final v131Network network; + private final v131Target target; - public v128Domains(DevTools devtools) { + public v131Domains(DevTools devtools) { Require.nonNull("DevTools", devtools); - events = new v128Events(devtools); - js = new v128Javascript(devtools); - log = new v128Log(); - network = new v128Network(devtools); - target = new v128Target(); + events = new v131Events(devtools); + js = new v131Javascript(devtools); + log = new v131Log(); + network = new v131Network(devtools); + target = new v131Target(); } @Override diff --git a/java/src/org/openqa/selenium/devtools/v128/v128Events.java b/java/src/org/openqa/selenium/devtools/v131/v131Events.java similarity index 86% rename from java/src/org/openqa/selenium/devtools/v128/v128Events.java rename to java/src/org/openqa/selenium/devtools/v131/v131Events.java index cf237296b0fc1..128be8849d4b9 100644 --- a/java/src/org/openqa/selenium/devtools/v128/v128Events.java +++ b/java/src/org/openqa/selenium/devtools/v131/v131Events.java @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package org.openqa.selenium.devtools.v128; +package org.openqa.selenium.devtools.v131; import java.time.Instant; import java.util.List; @@ -28,15 +28,15 @@ import org.openqa.selenium.devtools.events.ConsoleEvent; import org.openqa.selenium.devtools.idealized.Events; import org.openqa.selenium.devtools.idealized.runtime.model.RemoteObject; -import org.openqa.selenium.devtools.v128.runtime.Runtime; -import org.openqa.selenium.devtools.v128.runtime.model.ConsoleAPICalled; -import org.openqa.selenium.devtools.v128.runtime.model.ExceptionDetails; -import org.openqa.selenium.devtools.v128.runtime.model.ExceptionThrown; -import org.openqa.selenium.devtools.v128.runtime.model.StackTrace; +import org.openqa.selenium.devtools.v131.runtime.Runtime; +import org.openqa.selenium.devtools.v131.runtime.model.ConsoleAPICalled; +import org.openqa.selenium.devtools.v131.runtime.model.ExceptionDetails; +import org.openqa.selenium.devtools.v131.runtime.model.ExceptionThrown; +import org.openqa.selenium.devtools.v131.runtime.model.StackTrace; -public class v128Events extends Events { +public class v131Events extends Events { - public v128Events(DevTools devtools) { + public v131Events(DevTools devtools) { super(devtools); } @@ -77,7 +77,7 @@ protected ConsoleEvent toConsoleEvent(ConsoleAPICalled event) { protected JavascriptException toJsException(ExceptionThrown event) { ExceptionDetails details = event.getExceptionDetails(); Optional maybeTrace = details.getStackTrace(); - Optional maybeException = + Optional maybeException = details.getException(); String message = diff --git a/java/src/org/openqa/selenium/devtools/v128/v128Javascript.java b/java/src/org/openqa/selenium/devtools/v131/v131Javascript.java similarity index 85% rename from java/src/org/openqa/selenium/devtools/v128/v128Javascript.java rename to java/src/org/openqa/selenium/devtools/v131/v131Javascript.java index 658413ddac340..8d10c51773831 100644 --- a/java/src/org/openqa/selenium/devtools/v128/v128Javascript.java +++ b/java/src/org/openqa/selenium/devtools/v131/v131Javascript.java @@ -15,21 +15,21 @@ // specific language governing permissions and limitations // under the License. -package org.openqa.selenium.devtools.v128; +package org.openqa.selenium.devtools.v131; import java.util.Optional; import org.openqa.selenium.devtools.Command; import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.Event; import org.openqa.selenium.devtools.idealized.Javascript; -import org.openqa.selenium.devtools.v128.page.Page; -import org.openqa.selenium.devtools.v128.page.model.ScriptIdentifier; -import org.openqa.selenium.devtools.v128.runtime.Runtime; -import org.openqa.selenium.devtools.v128.runtime.model.BindingCalled; +import org.openqa.selenium.devtools.v131.page.Page; +import org.openqa.selenium.devtools.v131.page.model.ScriptIdentifier; +import org.openqa.selenium.devtools.v131.runtime.Runtime; +import org.openqa.selenium.devtools.v131.runtime.model.BindingCalled; -public class v128Javascript extends Javascript { +public class v131Javascript extends Javascript { - public v128Javascript(DevTools devtools) { + public v131Javascript(DevTools devtools) { super(devtools); } diff --git a/java/src/org/openqa/selenium/devtools/v128/v128Log.java b/java/src/org/openqa/selenium/devtools/v131/v131Log.java similarity index 89% rename from java/src/org/openqa/selenium/devtools/v128/v128Log.java rename to java/src/org/openqa/selenium/devtools/v131/v131Log.java index 888f06076e022..1f864978660f6 100644 --- a/java/src/org/openqa/selenium/devtools/v128/v128Log.java +++ b/java/src/org/openqa/selenium/devtools/v131/v131Log.java @@ -15,19 +15,19 @@ // specific language governing permissions and limitations // under the License. -package org.openqa.selenium.devtools.v128; +package org.openqa.selenium.devtools.v131; import java.util.function.Function; import java.util.logging.Level; import org.openqa.selenium.devtools.Command; import org.openqa.selenium.devtools.ConverterFunctions; import org.openqa.selenium.devtools.Event; -import org.openqa.selenium.devtools.v128.log.Log; -import org.openqa.selenium.devtools.v128.log.model.LogEntry; -import org.openqa.selenium.devtools.v128.runtime.model.Timestamp; +import org.openqa.selenium.devtools.v131.log.Log; +import org.openqa.selenium.devtools.v131.log.model.LogEntry; +import org.openqa.selenium.devtools.v131.runtime.model.Timestamp; import org.openqa.selenium.json.JsonInput; -public class v128Log implements org.openqa.selenium.devtools.idealized.log.Log { +public class v131Log implements org.openqa.selenium.devtools.idealized.log.Log { @Override public Command enable() { diff --git a/java/src/org/openqa/selenium/devtools/v128/v128Network.java b/java/src/org/openqa/selenium/devtools/v131/v131Network.java similarity index 92% rename from java/src/org/openqa/selenium/devtools/v128/v128Network.java rename to java/src/org/openqa/selenium/devtools/v131/v131Network.java index ccbdcee9426f3..5994a2a6d7af9 100644 --- a/java/src/org/openqa/selenium/devtools/v128/v128Network.java +++ b/java/src/org/openqa/selenium/devtools/v131/v131Network.java @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package org.openqa.selenium.devtools.v128; +package org.openqa.selenium.devtools.v131; import static java.net.HttpURLConnection.HTTP_OK; @@ -30,35 +30,35 @@ import org.openqa.selenium.devtools.DevToolsException; import org.openqa.selenium.devtools.Event; import org.openqa.selenium.devtools.idealized.Network; -import org.openqa.selenium.devtools.v128.fetch.Fetch; -import org.openqa.selenium.devtools.v128.fetch.model.*; -import org.openqa.selenium.devtools.v128.network.model.Request; +import org.openqa.selenium.devtools.v131.fetch.Fetch; +import org.openqa.selenium.devtools.v131.fetch.model.*; +import org.openqa.selenium.devtools.v131.network.model.Request; import org.openqa.selenium.internal.Either; import org.openqa.selenium.remote.http.HttpRequest; import org.openqa.selenium.remote.http.HttpResponse; -public class v128Network extends Network { +public class v131Network extends Network { - private static final Logger LOG = Logger.getLogger(v128Network.class.getName()); + private static final Logger LOG = Logger.getLogger(v131Network.class.getName()); - public v128Network(DevTools devTools) { + public v131Network(DevTools devTools) { super(devTools); } @Override protected Command setUserAgentOverride(UserAgent userAgent) { - return org.openqa.selenium.devtools.v128.network.Network.setUserAgentOverride( + return org.openqa.selenium.devtools.v131.network.Network.setUserAgentOverride( userAgent.userAgent(), userAgent.acceptLanguage(), userAgent.platform(), Optional.empty()); } @Override protected Command enableNetworkCaching() { - return org.openqa.selenium.devtools.v128.network.Network.setCacheDisabled(false); + return org.openqa.selenium.devtools.v131.network.Network.setCacheDisabled(false); } @Override protected Command disableNetworkCaching() { - return org.openqa.selenium.devtools.v128.network.Network.setCacheDisabled(true); + return org.openqa.selenium.devtools.v131.network.Network.setCacheDisabled(true); } @Override diff --git a/java/src/org/openqa/selenium/devtools/v128/v128Target.java b/java/src/org/openqa/selenium/devtools/v131/v131Target.java similarity index 83% rename from java/src/org/openqa/selenium/devtools/v128/v128Target.java rename to java/src/org/openqa/selenium/devtools/v131/v131Target.java index 67b1082920ff9..7c8ed6dc5ce42 100644 --- a/java/src/org/openqa/selenium/devtools/v128/v128Target.java +++ b/java/src/org/openqa/selenium/devtools/v131/v131Target.java @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package org.openqa.selenium.devtools.v128; +package org.openqa.selenium.devtools.v131; import java.util.List; import java.util.Map; @@ -28,21 +28,21 @@ import org.openqa.selenium.devtools.idealized.browser.model.BrowserContextID; import org.openqa.selenium.devtools.idealized.target.model.SessionID; import org.openqa.selenium.devtools.idealized.target.model.TargetID; -import org.openqa.selenium.devtools.v128.target.Target; -import org.openqa.selenium.devtools.v128.target.model.TargetInfo; +import org.openqa.selenium.devtools.v131.target.Target; +import org.openqa.selenium.devtools.v131.target.model.TargetInfo; import org.openqa.selenium.json.JsonInput; import org.openqa.selenium.json.TypeToken; -public class v128Target implements org.openqa.selenium.devtools.idealized.target.Target { +public class v131Target implements org.openqa.selenium.devtools.idealized.target.Target { @Override public Command detachFromTarget( Optional sessionId, Optional targetId) { return Target.detachFromTarget( sessionId.map( - id -> new org.openqa.selenium.devtools.v128.target.model.SessionID(id.toString())), + id -> new org.openqa.selenium.devtools.v131.target.model.SessionID(id.toString())), targetId.map( - id -> new org.openqa.selenium.devtools.v128.target.model.TargetID(id.toString()))); + id -> new org.openqa.selenium.devtools.v131.target.model.TargetID(id.toString()))); } @Override @@ -74,19 +74,19 @@ public Command detachFromTarget( @Override public Command attachToTarget(TargetID targetId) { - Function mapper = + Function mapper = ConverterFunctions.map( - "sessionId", org.openqa.selenium.devtools.v128.target.model.SessionID.class); + "sessionId", org.openqa.selenium.devtools.v131.target.model.SessionID.class); return new Command<>( "Target.attachToTarget", Map.of( "targetId", - new org.openqa.selenium.devtools.v128.target.model.TargetID(targetId.toString()), + new org.openqa.selenium.devtools.v131.target.model.TargetID(targetId.toString()), "flatten", true), input -> { - org.openqa.selenium.devtools.v128.target.model.SessionID id = mapper.apply(input); + org.openqa.selenium.devtools.v131.target.model.SessionID id = mapper.apply(input); return new SessionID(id.toString()); }); } @@ -101,9 +101,9 @@ public Event detached() { return new Event<>( "Target.detachedFromTarget", input -> { - Function converter = + Function converter = ConverterFunctions.map( - "targetId", org.openqa.selenium.devtools.v128.target.model.TargetID.class); + "targetId", org.openqa.selenium.devtools.v131.target.model.TargetID.class); return new TargetID(converter.apply(input).toString()); }); } diff --git a/java/src/org/openqa/selenium/devtools/versions.bzl b/java/src/org/openqa/selenium/devtools/versions.bzl index 59129be697b12..a56339287b69e 100644 --- a/java/src/org/openqa/selenium/devtools/versions.bzl +++ b/java/src/org/openqa/selenium/devtools/versions.bzl @@ -1,6 +1,6 @@ CDP_VERSIONS = [ "v85", # Required by Firefox - "v128", + "v131", "v129", "v130", ] diff --git a/java/version.bzl b/java/version.bzl index f882c57e1cd55..baea21a792b82 100644 --- a/java/version.bzl +++ b/java/version.bzl @@ -1,2 +1,2 @@ -SE_VERSION = "4.27.0-SNAPSHOT" +SE_VERSION = "4.27.0" TOOLS_JAVA_VERSION = "17" diff --git a/javascript/node/selenium-webdriver/BUILD.bazel b/javascript/node/selenium-webdriver/BUILD.bazel index 874c0b18b8bb1..687d3a9f48b85 100644 --- a/javascript/node/selenium-webdriver/BUILD.bazel +++ b/javascript/node/selenium-webdriver/BUILD.bazel @@ -11,11 +11,11 @@ load("//javascript/private:browsers.bzl", "BROWSERS") npm_link_all_packages(name = "node_modules") -VERSION = "4.27.0-nightly202410301443" +VERSION = "4.27.0" BROWSER_VERSIONS = [ "v85", - "v128", + "v131", "v129", "v130", ] diff --git a/javascript/node/selenium-webdriver/CHANGES.md b/javascript/node/selenium-webdriver/CHANGES.md index 451efc75eb701..287f3adc8e205 100644 --- a/javascript/node/selenium-webdriver/CHANGES.md +++ b/javascript/node/selenium-webdriver/CHANGES.md @@ -1,3 +1,12 @@ +## 4.27.0 + +- Add CDP for Chrome 131 and remove 128 +- Add Firefox CDP deprecation warnings +- Update supported versions for Chrome DevTools +- [bidi] Allow passing in uri for authentication handlers (#14386) +- [bidi] Enable locate node tests for Chrome and Edge +- [bidi] Ensure start nodes are serialized + ## 4.26.0 - Add CDP for Chrome 130 and remove 127 diff --git a/javascript/node/selenium-webdriver/package.json b/javascript/node/selenium-webdriver/package.json index aaa10a9f2a682..513f761f98de2 100644 --- a/javascript/node/selenium-webdriver/package.json +++ b/javascript/node/selenium-webdriver/package.json @@ -1,6 +1,6 @@ { "name": "selenium-webdriver", - "version": "4.27.0-nightly202410301443", + "version": "4.27.0", "description": "The official WebDriver JavaScript bindings from the Selenium project", "license": "Apache-2.0", "keywords": [ diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 25c084a6f745d..bef50ad8498a0 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -62,11 +62,11 @@ compile_pip_requirements( ], ) -SE_VERSION = "4.27.0.202410311942" +SE_VERSION = "4.27.0" BROWSER_VERSIONS = [ "v85", - "v128", + "v131", "v129", "v130", ] diff --git a/py/CHANGES b/py/CHANGES index b7dabbf9d6b9b..c0db6781b2ec8 100644 --- a/py/CHANGES +++ b/py/CHANGES @@ -1,3 +1,13 @@ +Selenium 4.27.0 +* Add CDP for Chrome 131 and remove 128 +* Add Firefox CDP deprecation warnings (#14787) +* Cleaned up Py doc sphinx warnings/errors and added README (#14191) +* Added Deprecation of WebElement.get_attribute() per #13334 (#14675) +* Fix TypeError when init Safari webdriver (#14699) +* Set user_agent and extra_headers via ClientConfig (#14718) +* Updated Handling for DetachedShadowRoot Exception (#14677) +* Support FedCM commands (#14710) + Selenium 4.26.1 * DeprecationWarning raised in default webdriver init (#14690) * Remote connection use timeout from ClientConfig (#14692) diff --git a/py/docs/source/conf.py b/py/docs/source/conf.py index 41a620b368248..52640b39e5076 100644 --- a/py/docs/source/conf.py +++ b/py/docs/source/conf.py @@ -58,7 +58,7 @@ # The short X.Y version. version = '4.27' # The full version, including alpha/beta/rc tags. -release = '4.27.0.202410311942' +release = '4.27.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/py/pyproject.toml b/py/pyproject.toml index 6488cda070f56..4af5df0747f56 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "selenium" -version = "4.27.0.202410311942" +version = "4.27.0" license = "Apache 2.0" description = "Official Python bindings for Selenium WebDriver." readme = "README.rst" diff --git a/py/selenium/__init__.py b/py/selenium/__init__.py index 8fa1fd3219d4d..feee963d69b24 100644 --- a/py/selenium/__init__.py +++ b/py/selenium/__init__.py @@ -16,4 +16,4 @@ # under the License. -__version__ = "4.27.0.202410311942" +__version__ = "4.27.0" diff --git a/py/selenium/webdriver/__init__.py b/py/selenium/webdriver/__init__.py index c57217aefb69f..e9e8082671e9b 100644 --- a/py/selenium/webdriver/__init__.py +++ b/py/selenium/webdriver/__init__.py @@ -44,7 +44,7 @@ from .wpewebkit.service import Service as WPEWebKitService # noqa from .wpewebkit.webdriver import WebDriver as WPEWebKit # noqa -__version__ = "4.27.0.202410311942" +__version__ = "4.27.0" # We need an explicit __all__ because the above won't otherwise be exported. __all__ = [ diff --git a/rb/CHANGES b/rb/CHANGES index 00357fb0c0c52..f3811e1de8cc3 100644 --- a/rb/CHANGES +++ b/rb/CHANGES @@ -1,3 +1,14 @@ +4.27.0 (2024-11-21) +========================= +* Add CDP for Chrome 131 and remove 128 +* Add Firefox CDP deprecation warnings (#14763) +* Add Bidi network commands for authentication and interception (#14523) +* Handle graceful webdriver shutdown (#14430) +* Reduce RBS errors to 0 (#14661) +* Resolve `uri` gem deprecation warning (#14770) +* Update minimum Ruby to 3.1 (#14685) +* Implement navigation commands with BiDi (#14094) + 4.26.0 (2024-10-28) ========================= * Add CDP for Chrome 130 and remove 127 diff --git a/rb/Gemfile.lock b/rb/Gemfile.lock index 495e79ef76e86..37e39602205e7 100644 --- a/rb/Gemfile.lock +++ b/rb/Gemfile.lock @@ -1,9 +1,9 @@ PATH remote: . specs: - selenium-devtools (0.130.0) + selenium-devtools (0.131.0) selenium-webdriver (~> 4.2) - selenium-webdriver (4.27.0.nightly) + selenium-webdriver (4.27.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) diff --git a/rb/lib/selenium/devtools/BUILD.bazel b/rb/lib/selenium/devtools/BUILD.bazel index c974adf9ba317..9a045e89da29f 100644 --- a/rb/lib/selenium/devtools/BUILD.bazel +++ b/rb/lib/selenium/devtools/BUILD.bazel @@ -5,7 +5,7 @@ package(default_visibility = ["//rb:__subpackages__"]) CDP_VERSIONS = [ "v85", - "v128", + "v131", "v129", "v130", ] diff --git a/rb/lib/selenium/devtools/version.rb b/rb/lib/selenium/devtools/version.rb index d75521bb415aa..c12441f05fd4b 100644 --- a/rb/lib/selenium/devtools/version.rb +++ b/rb/lib/selenium/devtools/version.rb @@ -19,6 +19,6 @@ module Selenium module DevTools - VERSION = '0.130.0' + VERSION = '0.131.0' end # DevTools end # Selenium diff --git a/rb/lib/selenium/webdriver/version.rb b/rb/lib/selenium/webdriver/version.rb index 3a8d951f55562..8a49d22be451d 100644 --- a/rb/lib/selenium/webdriver/version.rb +++ b/rb/lib/selenium/webdriver/version.rb @@ -19,6 +19,6 @@ module Selenium module WebDriver - VERSION = '4.27.0.nightly' + VERSION = '4.27.0' end # WebDriver end # Selenium diff --git a/rust/CHANGELOG.md b/rust/CHANGELOG.md index 12049809f5d18..0c032578b8be3 100644 --- a/rust/CHANGELOG.md +++ b/rust/CHANGELOG.md @@ -1,3 +1,10 @@ +0.4.27 +====== +* Use endpoint for stable versions first to manage Firefox (#14536) (#14613) +* Selenium Manager honors full browser version (#13419) (#14619) +* Selenium Manager honors full browser version (#13419) +* Minor change related to variable name + 0.4.26 ====== * Selenium Manager checks invalid browser version (#14511) From 2421c6634fcb0f589eed4b808622e800234869ca Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Mon, 25 Nov 2024 20:22:55 +0100 Subject: [PATCH 27/58] [ci] Bumping versions for nightly --- dotnet/selenium-dotnet-version.bzl | 2 +- java/version.bzl | 2 +- javascript/node/selenium-webdriver/BUILD.bazel | 2 +- .../node/selenium-webdriver/package.json | 2 +- py/BUILD.bazel | 2 +- py/docs/source/conf.py | 4 ++-- py/pyproject.toml | 2 +- py/selenium/__init__.py | 2 +- py/selenium/webdriver/__init__.py | 2 +- rb/Gemfile.lock | 18 ++++++++++-------- rb/lib/selenium/webdriver/version.rb | 2 +- 11 files changed, 21 insertions(+), 19 deletions(-) diff --git a/dotnet/selenium-dotnet-version.bzl b/dotnet/selenium-dotnet-version.bzl index 2b2c122b24997..cb2640bcfe884 100644 --- a/dotnet/selenium-dotnet-version.bzl +++ b/dotnet/selenium-dotnet-version.bzl @@ -1,6 +1,6 @@ # BUILD FILE SYNTAX: STARLARK -SE_VERSION = "4.27.0" +SE_VERSION = "4.28.0-nightly202411252021" ASSEMBLY_VERSION = "4.0.0.0" SUPPORTED_NET_STANDARD_VERSIONS = ["netstandard2.0"] diff --git a/java/version.bzl b/java/version.bzl index baea21a792b82..2ccba1f975dd3 100644 --- a/java/version.bzl +++ b/java/version.bzl @@ -1,2 +1,2 @@ -SE_VERSION = "4.27.0" +SE_VERSION = "4.28.0-SNAPSHOT" TOOLS_JAVA_VERSION = "17" diff --git a/javascript/node/selenium-webdriver/BUILD.bazel b/javascript/node/selenium-webdriver/BUILD.bazel index 687d3a9f48b85..bc6e68042597d 100644 --- a/javascript/node/selenium-webdriver/BUILD.bazel +++ b/javascript/node/selenium-webdriver/BUILD.bazel @@ -11,7 +11,7 @@ load("//javascript/private:browsers.bzl", "BROWSERS") npm_link_all_packages(name = "node_modules") -VERSION = "4.27.0" +VERSION = "4.28.0-nightly202411252022" BROWSER_VERSIONS = [ "v85", diff --git a/javascript/node/selenium-webdriver/package.json b/javascript/node/selenium-webdriver/package.json index 513f761f98de2..c19e244758cf4 100644 --- a/javascript/node/selenium-webdriver/package.json +++ b/javascript/node/selenium-webdriver/package.json @@ -1,6 +1,6 @@ { "name": "selenium-webdriver", - "version": "4.27.0", + "version": "4.28.0-nightly202411252022", "description": "The official WebDriver JavaScript bindings from the Selenium project", "license": "Apache-2.0", "keywords": [ diff --git a/py/BUILD.bazel b/py/BUILD.bazel index bef50ad8498a0..95bc85084095f 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -62,7 +62,7 @@ compile_pip_requirements( ], ) -SE_VERSION = "4.27.0" +SE_VERSION = "4.28.0.202411252021" BROWSER_VERSIONS = [ "v85", diff --git a/py/docs/source/conf.py b/py/docs/source/conf.py index 52640b39e5076..a849406e4f2bf 100644 --- a/py/docs/source/conf.py +++ b/py/docs/source/conf.py @@ -56,9 +56,9 @@ # built documents. # # The short X.Y version. -version = '4.27' +version = '4.28' # The full version, including alpha/beta/rc tags. -release = '4.27.0' +release = '4.28.0.202411252021' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/py/pyproject.toml b/py/pyproject.toml index 4af5df0747f56..7da47ebed42bb 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "selenium" -version = "4.27.0" +version = "4.28.0.202411252021" license = "Apache 2.0" description = "Official Python bindings for Selenium WebDriver." readme = "README.rst" diff --git a/py/selenium/__init__.py b/py/selenium/__init__.py index feee963d69b24..e3ff880df800d 100644 --- a/py/selenium/__init__.py +++ b/py/selenium/__init__.py @@ -16,4 +16,4 @@ # under the License. -__version__ = "4.27.0" +__version__ = "4.28.0.202411252021" diff --git a/py/selenium/webdriver/__init__.py b/py/selenium/webdriver/__init__.py index e9e8082671e9b..febdae5a03698 100644 --- a/py/selenium/webdriver/__init__.py +++ b/py/selenium/webdriver/__init__.py @@ -44,7 +44,7 @@ from .wpewebkit.service import Service as WPEWebKitService # noqa from .wpewebkit.webdriver import WebDriver as WPEWebKit # noqa -__version__ = "4.27.0" +__version__ = "4.28.0.202411252021" # We need an explicit __all__ because the above won't otherwise be exported. __all__ = [ diff --git a/rb/Gemfile.lock b/rb/Gemfile.lock index 37e39602205e7..3c9f67c9bf9f8 100644 --- a/rb/Gemfile.lock +++ b/rb/Gemfile.lock @@ -3,7 +3,7 @@ PATH specs: selenium-devtools (0.131.0) selenium-webdriver (~> 4.2) - selenium-webdriver (4.27.0) + selenium-webdriver (4.28.0.nightly) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) @@ -13,7 +13,7 @@ PATH GEM remote: https://rubygems.org/ specs: - activesupport (7.2.2) + activesupport (8.0.0) base64 benchmark (>= 0.3) bigdecimal @@ -25,6 +25,7 @@ GEM minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) ast (2.4.2) @@ -51,7 +52,7 @@ GEM git (1.19.1) addressable (~> 2.8) rchardet (~> 1.8) - hashdiff (1.1.1) + hashdiff (1.1.2) i18n (1.14.6) concurrent-ruby (~> 1.0) io-console (0.7.2) @@ -60,8 +61,8 @@ GEM rdoc (>= 4.0.0) reline (>= 0.4.2) jar-dependencies (0.4.1) - json (2.8.1) - json (2.8.1-java) + json (2.8.2) + json (2.8.2-java) language_server-protocol (3.17.0.3) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) @@ -88,7 +89,7 @@ GEM rbs (3.6.1) logger rchardet (1.8.0) - rdoc (6.7.0) + rdoc (6.8.1) psych (>= 4.0.0) regexp_parser (2.9.2) reline (0.5.11) @@ -117,13 +118,13 @@ GEM rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.34.1) + rubocop-ast (1.36.1) parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) rubocop-factory_bot (2.26.1) rubocop (~> 1.61) - rubocop-performance (1.22.1) + rubocop-performance (1.23.0) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) rubocop-rake (0.6.0) @@ -161,6 +162,7 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.6.0) + uri (1.0.2) webmock (3.24.0) addressable (>= 2.8.0) crack (>= 0.3.2) diff --git a/rb/lib/selenium/webdriver/version.rb b/rb/lib/selenium/webdriver/version.rb index 8a49d22be451d..cdf4ebe9ed252 100644 --- a/rb/lib/selenium/webdriver/version.rb +++ b/rb/lib/selenium/webdriver/version.rb @@ -19,6 +19,6 @@ module Selenium module WebDriver - VERSION = '4.27.0' + VERSION = '4.28.0.nightly' end # WebDriver end # Selenium From b50158997e81d57ee6a8dfd7af767ce499c58b3f Mon Sep 17 00:00:00 2001 From: Michael Render Date: Mon, 25 Nov 2024 14:31:06 -0500 Subject: [PATCH 28/58] [dotnet] Add nullability annotations to print types (#14773) --- dotnet/src/webdriver/EncodedFile.cs | 31 +++-- dotnet/src/webdriver/ISupportsPrint.cs | 5 + dotnet/src/webdriver/PrintDocument.cs | 17 +++ dotnet/src/webdriver/PrintOptions.cs | 168 +++++++++++++------------ dotnet/src/webdriver/Screenshot.cs | 9 ++ dotnet/src/webdriver/WebDriver.cs | 6 + dotnet/test/common/PrintTest.cs | 33 +++++ 7 files changed, 173 insertions(+), 96 deletions(-) diff --git a/dotnet/src/webdriver/EncodedFile.cs b/dotnet/src/webdriver/EncodedFile.cs index c8f9e1626a3f9..45ab15a74f64a 100644 --- a/dotnet/src/webdriver/EncodedFile.cs +++ b/dotnet/src/webdriver/EncodedFile.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium { /// @@ -26,34 +28,32 @@ namespace OpenQA.Selenium /// public abstract class EncodedFile { - private string base64Encoded = string.Empty; - private byte[] byteArray; - /// /// Initializes a new instance of the class. /// /// The file as a Base64-encoded string. + /// If is . + /// + /// The length of , ignoring white-space characters, is not zero or a multiple of 4. + /// -or- + /// The format of is invalid. contains a non-base-64 character, + /// more than two padding characters, or a non-white space-character among the padding characters. + /// protected EncodedFile(string base64EncodedFile) { - this.base64Encoded = base64EncodedFile; - this.byteArray = Convert.FromBase64String(this.base64Encoded); + this.AsBase64EncodedString = base64EncodedFile ?? throw new ArgumentNullException(nameof(base64EncodedFile)); + this.AsByteArray = Convert.FromBase64String(base64EncodedFile); } /// /// Gets the value of the encoded file as a Base64-encoded string. /// - public string AsBase64EncodedString - { - get { return this.base64Encoded; } - } + public string AsBase64EncodedString { get; } /// /// Gets the value of the encoded file as an array of bytes. /// - public byte[] AsByteArray - { - get { return this.byteArray; } - } + public byte[] AsByteArray { get; } /// /// Saves the file, overwriting it if it already exists. @@ -65,9 +65,6 @@ public byte[] AsByteArray /// Returns a String that represents the current Object. /// /// A String that represents the current Object. - public override string ToString() - { - return this.base64Encoded; - } + public override string ToString() => this.AsBase64EncodedString; } } diff --git a/dotnet/src/webdriver/ISupportsPrint.cs b/dotnet/src/webdriver/ISupportsPrint.cs index 6c79abf1a08e5..84c712c15aca6 100644 --- a/dotnet/src/webdriver/ISupportsPrint.cs +++ b/dotnet/src/webdriver/ISupportsPrint.cs @@ -17,6 +17,10 @@ // under the License. // +using System; + +#nullable enable + namespace OpenQA.Selenium { /// @@ -29,6 +33,7 @@ public interface ISupportsPrint /// /// A object describing the options of the printed document. /// The object containing the PDF-formatted print representation of the page. + /// If is . PrintDocument Print(PrintOptions options); } } diff --git a/dotnet/src/webdriver/PrintDocument.cs b/dotnet/src/webdriver/PrintDocument.cs index 7244a9c42dde7..61e558a756b0a 100644 --- a/dotnet/src/webdriver/PrintDocument.cs +++ b/dotnet/src/webdriver/PrintDocument.cs @@ -20,6 +20,8 @@ using System; using System.IO; +#nullable enable + namespace OpenQA.Selenium { /// @@ -31,6 +33,13 @@ public class PrintDocument : EncodedFile /// Initializes a new instance of the class. /// /// The printed document as a Base64-encoded string. + /// If is . + /// + /// The length of , ignoring white-space characters, is not zero or a multiple of 4. + /// -or- + /// The format of is invalid. contains a non-base-64 character, + /// more than two padding characters, or a non-white space-character among the padding characters. + /// public PrintDocument(string base64EncodedDocument) : base(base64EncodedDocument) { } @@ -39,6 +48,14 @@ public PrintDocument(string base64EncodedDocument) : base(base64EncodedDocument) /// Saves this as a PDF formatted file, overwriting the file if it already exists. /// /// The full path and file name to save the printed document to. + /// + /// If is or whitespace. + /// -or- + /// refers to a non-file device, such as "con:", "com1:", "lpt1:", etc. in an NTFS environment. + /// + /// refers to a non-file device, such as "con:", "com1:", "lpt1:", etc. in a non-NTFS environment. + /// The specified path is invalid, such as being on an unmapped drive. + /// The specified path, file name, or both exceed the system-defined maximum length. public override void SaveAsFile(string fileName) { if (string.IsNullOrEmpty(fileName)) diff --git a/dotnet/src/webdriver/PrintOptions.cs b/dotnet/src/webdriver/PrintOptions.cs index f1d9660565618..b1f3efd30692e 100644 --- a/dotnet/src/webdriver/PrintOptions.cs +++ b/dotnet/src/webdriver/PrintOptions.cs @@ -21,6 +21,8 @@ using System.Collections.Generic; using System.Globalization; +#nullable enable + namespace OpenQA.Selenium { /// @@ -49,96 +51,80 @@ public class PrintOptions private const double DefaultPageWidth = 27.94; private const double CentimetersPerInch = 2.54; - private PrintOrientation orientation = PrintOrientation.Portrait; private double scale = 1.0; - private bool background = false; - private bool shrinkToFit = true; private PageSize pageSize = new PageSize(); private Margins margins = new Margins(); - private HashSet pageRanges = new HashSet(); + private readonly HashSet pageRanges = new HashSet(); /// /// Gets or sets the orientation of the pages in the printed document. /// - public PrintOrientation Orientation - { - get { return orientation; } - set { orientation = value; } - } + public PrintOrientation Orientation { get; set; } = PrintOrientation.Portrait; /// /// Gets or sets the amount which the printed content is zoomed. Valid values are 0.1 to 2.0. /// + /// If the value is not set between 0.1 and 2.0. public double ScaleFactor { - get { return scale; } + get => this.scale; set { if (value < 0.1 || value > 2.0) { - throw new ArgumentException("Scale factor must be between 0.1 and 2.0."); + throw new ArgumentOutOfRangeException(nameof(value), "Scale factor must be between 0.1 and 2.0."); } - scale = value; + this.scale = value; } } /// /// Gets or sets a value indicating whether to print background images in the printed document. /// - public bool OutputBackgroundImages - { - get { return background; } - set { background = value; } - } + public bool OutputBackgroundImages { get; set; } /// /// Gets or sets a value indicating whether to shrink the content to fit the printed page size. /// - public bool ShrinkToFit - { - get { return shrinkToFit; } - set { shrinkToFit = value; } - } + public bool ShrinkToFit { get; set; } = true; /// /// Gets or sets the dimensions for each page in the printed document. /// + /// If the value is set to . public PageSize PageDimensions { - get { return pageSize; } - set - { - pageSize = value ?? throw new ArgumentNullException(nameof(value)); - } + get => this.pageSize; + set => this.pageSize = value ?? throw new ArgumentNullException(nameof(value)); } /// /// Gets or sets the margins for each page in the doucment. /// + /// If the value is set to . public Margins PageMargins { - get { return margins; } - set - { - margins = value ?? throw new ArgumentNullException(nameof(value)); - } + get => this.margins; + set => this.margins = value ?? throw new ArgumentNullException(nameof(value)); } /// /// Adds a page to the list of pages to be included in the document. /// /// The page number to be included in the document. + /// If is negative. + /// If the requested page has already been added. public void AddPageToPrint(int pageNumber) { if (pageNumber < 0) { - throw new ArgumentException("Page number must be greater than or equal to zero"); + throw new ArgumentOutOfRangeException(nameof(pageNumber), "Page number must be greater than or equal to zero"); } if (this.pageRanges.Contains(pageNumber)) { - throw new ArgumentException("Cannot add the same page number twice"); + throw new ArgumentException("Cannot add the same page number twice", nameof(pageNumber)); } this.pageRanges.Add(pageNumber); @@ -148,28 +134,42 @@ public void AddPageToPrint(int pageNumber) /// Adds a range of pages to be included in the document. /// /// A string of the form "x-y" representing the page numbers to include. + /// + /// If is or . + /// -or- + /// If the requested is already included. + /// -or- + /// If the requested has multiple '-' separators. + /// -or- + /// If a bound value is neither empty nor a number. + /// + /// + /// If has a negative lower bound. + /// -or- + /// If has an upper bound less than the lower bound. + /// public void AddPageRangeToPrint(string pageRange) { if (string.IsNullOrEmpty(pageRange)) { - throw new ArgumentException("Page range cannot be null or the empty string"); + throw new ArgumentException("Page range cannot be null or the empty string", nameof(pageRange)); } if (this.pageRanges.Contains(pageRange)) { - throw new ArgumentException("Cannot add the same page range twice"); + throw new ArgumentException("Cannot add the same page range twice", nameof(pageRange)); } string[] pageRangeParts = pageRange.Trim().Split('-'); if (pageRangeParts.Length > 2) { - throw new ArgumentException("Page range cannot have multiple separators"); + throw new ArgumentException("Page range cannot have multiple separators", nameof(pageRange)); } int startPage = ParsePageRangePart(pageRangeParts[0], 1); if (startPage < 1) { - throw new ArgumentException("Start of a page range must be greater than or equal to 1"); + throw new ArgumentOutOfRangeException(nameof(pageRange), "Start of a page range must be greater than or equal to 1"); } if (pageRangeParts.Length == 2) @@ -177,20 +177,20 @@ public void AddPageRangeToPrint(string pageRange) int endPage = ParsePageRangePart(pageRangeParts[1], int.MaxValue); if (endPage < startPage) { - throw new ArgumentException("End of a page range must be greater than or equal to the start of the page range"); + throw new ArgumentOutOfRangeException(nameof(pageRange), "End of a page range must be greater than or equal to the start of the page range"); } } this.pageRanges.Add(pageRange); } - internal Dictionary ToDictionary() + internal Dictionary ToDictionary() { - Dictionary toReturn = new Dictionary(); + Dictionary toReturn = new Dictionary(); - if (this.orientation != PrintOrientation.Portrait) + if (this.Orientation != PrintOrientation.Portrait) { - toReturn["orientation"] = this.orientation.ToString().ToLowerInvariant(); + toReturn["orientation"] = this.Orientation.ToString().ToLowerInvariant(); } if (this.scale != 1.0) @@ -198,19 +198,19 @@ internal Dictionary ToDictionary() toReturn["scale"] = this.scale; } - if (this.background) + if (this.OutputBackgroundImages) { - toReturn["background"] = this.background; + toReturn["background"] = this.OutputBackgroundImages; } - if (!this.shrinkToFit) + if (!this.ShrinkToFit) { - toReturn["shrinkToFit"] = this.shrinkToFit; + toReturn["shrinkToFit"] = this.ShrinkToFit; } if (this.pageSize.Height != DefaultPageHeight || this.pageSize.Width != DefaultPageWidth) { - Dictionary pageSizeDictionary = new Dictionary(); + Dictionary pageSizeDictionary = new Dictionary(); pageSizeDictionary["width"] = this.pageSize.Width; pageSizeDictionary["height"] = this.pageSize.Height; toReturn["page"] = pageSizeDictionary; @@ -218,7 +218,7 @@ internal Dictionary ToDictionary() if (this.margins.Top != DefaultMarginSize || this.margins.Bottom != DefaultMarginSize || this.margins.Left != DefaultMarginSize || this.margins.Right != DefaultMarginSize) { - Dictionary marginsDictionary = new Dictionary(); + Dictionary marginsDictionary = new Dictionary(); marginsDictionary["top"] = this.margins.Top; marginsDictionary["bottom"] = this.margins.Bottom; marginsDictionary["left"] = this.margins.Left; @@ -228,7 +228,7 @@ internal Dictionary ToDictionary() if (this.pageRanges.Count > 0) { - toReturn["pageRanges"] = new List(this.pageRanges); + toReturn["pageRanges"] = new List(this.pageRanges); } return toReturn; @@ -237,16 +237,18 @@ internal Dictionary ToDictionary() private static int ParsePageRangePart(string pageRangePart, int defaultValue) { pageRangePart = pageRangePart.Trim(); - int pageRangePartValue = defaultValue; - if (!string.IsNullOrEmpty(pageRangePart)) + + if (string.IsNullOrEmpty(pageRangePart)) { - if (!int.TryParse(pageRangePart, NumberStyles.Integer, CultureInfo.InvariantCulture, out pageRangePartValue)) - { - throw new ArgumentException("Parts of a page range must be an empty string or an integer"); - } + return defaultValue; + } + + if (int.TryParse(pageRangePart, NumberStyles.Integer, CultureInfo.InvariantCulture, out int pageRangePartValue)) + { + return pageRangePartValue; } - return pageRangePartValue; + throw new ArgumentException("Parts of a page range must be an empty string or an integer"); } /// @@ -260,53 +262,57 @@ public class PageSize /// /// Gets or sets the height of each page in centimeters. /// + /// If the value is set to a negative value. public double Height { - get { return height; } + get => this.height; set { if (value < 0) { - throw new ArgumentException("Height must be greater than or equal to zero."); + throw new ArgumentOutOfRangeException(nameof(value), "Height must be greater than or equal to zero."); } - height = value; + this.height = value; } } /// /// Gets or sets the width of each page in centimeters. /// + /// If the value is set to a negative value. public double Width { - get { return width; } + get => this.width; set { if (value < 0) { - throw new ArgumentException("Width must be greater than or equal to zero."); + throw new ArgumentOutOfRangeException(nameof(value), "Width must be greater than or equal to zero."); } - width = value; + this.width = value; } } /// /// Gets or sets the height of each page in inches. /// + /// If the value is set to a negative value. public double HeightInInches { - get { return Height / CentimetersPerInch; } - set { Height = value * CentimetersPerInch; } + get => this.Height / CentimetersPerInch; + set => this.Height = value * CentimetersPerInch; } /// /// Gets or sets the width of each page in inches. /// + /// If the value is set to a negative value. public double WidthInInches { - get { return Width / CentimetersPerInch; } - set { Width = value * CentimetersPerInch; } + get => this.Width / CentimetersPerInch; + set => this.Width = value * CentimetersPerInch; } } @@ -323,68 +329,72 @@ public class Margins /// /// Gets or sets the top margin of the print options. /// + /// If the value is set to a negative value. public double Top { - get { return top; } + get => this.top; set { if (value < 0) { - throw new ArgumentException("Top margin must be greater than or equal to zero."); + throw new ArgumentOutOfRangeException(nameof(value), "Top margin must be greater than or equal to zero."); } - top = value; + this.top = value; } } /// /// Gets or sets the bottom margin of the print options. /// + /// If the value is set to a negative value. public double Bottom { - get { return bottom; } + get => this.bottom; set { if (value < 0) { - throw new ArgumentException("Bottom margin must be greater than or equal to zero."); + throw new ArgumentOutOfRangeException(nameof(value), "Bottom margin must be greater than or equal to zero."); } - bottom = value; + this.bottom = value; } } /// /// Gets or sets the left margin of the print options. /// + /// If the value is set to a negative value. public double Left { - get { return left; } + get => this.left; set { if (value < 0) { - throw new ArgumentException("Left margin must be greater than or equal to zero."); + throw new ArgumentOutOfRangeException(nameof(value), "Left margin must be greater than or equal to zero."); } - left = value; + this.left = value; } } /// /// Gets or sets the right margin of the print options. /// + /// If the value is set to a negative value. public double Right { - get { return right; } + get => this.right; set { if (value < 0) { - throw new ArgumentException("Right margin must be greater than or equal to zero."); + throw new ArgumentOutOfRangeException(nameof(value), "Right margin must be greater than or equal to zero."); } - right = value; + this.right = value; } } } diff --git a/dotnet/src/webdriver/Screenshot.cs b/dotnet/src/webdriver/Screenshot.cs index 67b59aab6ac01..7b5f869fb6728 100644 --- a/dotnet/src/webdriver/Screenshot.cs +++ b/dotnet/src/webdriver/Screenshot.cs @@ -20,6 +20,8 @@ using System; using System.IO; +#nullable enable + namespace OpenQA.Selenium { /// @@ -32,6 +34,13 @@ public class Screenshot : EncodedFile /// Initializes a new instance of the class. /// /// The image of the page as a Base64-encoded string. + /// If is . + /// + /// The length of , ignoring white-space characters, is not zero or a multiple of 4. + /// -or- + /// The format of is invalid. contains a non-base-64 character, + /// more than two padding characters, or a non-white space-character among the padding characters. + /// public Screenshot(string base64EncodedScreenshot) : base(base64EncodedScreenshot) { } diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 6bd964136c928..235b2e648058e 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -380,8 +380,14 @@ public Screenshot GetScreenshot() /// /// A object describing the options of the printed document. /// The object containing the PDF-formatted print representation of the page. + /// If is . public PrintDocument Print(PrintOptions printOptions) { + if (printOptions is null) + { + throw new ArgumentNullException(nameof(printOptions)); + } + Response commandResponse = this.Execute(DriverCommand.Print, printOptions.ToDictionary()); string base64 = commandResponse.Value.ToString(); return new PrintDocument(base64); diff --git a/dotnet/test/common/PrintTest.cs b/dotnet/test/common/PrintTest.cs index f48f63f4815fc..324fc6e399c48 100644 --- a/dotnet/test/common/PrintTest.cs +++ b/dotnet/test/common/PrintTest.cs @@ -89,5 +89,38 @@ public void MarginsCannotBeNull() { Assert.That(() => new PrintOptions { PageMargins = null }, Throws.InstanceOf()); } + + [Test] + public void PageNumberCannotHaveInvalidValues() + { + Assert.That(() => new PrintOptions().AddPageToPrint(-1), Throws.TypeOf()); + Assert.That(() => new PrintOptions().AddPageRangeToPrint(null), Throws.TypeOf()); + Assert.That(() => new PrintOptions().AddPageRangeToPrint(""), Throws.TypeOf()); + Assert.That(() => new PrintOptions().AddPageRangeToPrint("1-2-3"), Throws.TypeOf()); + Assert.That(() => + { + var options = new PrintOptions(); + options.AddPageToPrint(1); + options.AddPageToPrint(1); + }, Throws.TypeOf()); + } + + [Test] + public void PageSizeCannotHaveNegativeValues() + { + Assert.That(() => new PrintOptions.PageSize { Height = -1 }, Throws.TypeOf()); + Assert.That(() => new PrintOptions.PageSize { HeightInInches = -1 }, Throws.TypeOf()); + Assert.That(() => new PrintOptions.PageSize { Width = -1 }, Throws.TypeOf()); + Assert.That(() => new PrintOptions.PageSize { WidthInInches = -1 }, Throws.TypeOf()); + } + + [Test] + public void MarginsCannotHaveNegativeValues() + { + Assert.That(() => new PrintOptions.Margins { Top = -1 }, Throws.TypeOf()); + Assert.That(() => new PrintOptions.Margins { Bottom = -1 }, Throws.TypeOf()); + Assert.That(() => new PrintOptions.Margins { Left = -1 }, Throws.TypeOf()); + Assert.That(() => new PrintOptions.Margins { Right = -1 }, Throws.TypeOf()); + } } } From b3ef505846a1813b64d0d22798a22f96b90f7ffd Mon Sep 17 00:00:00 2001 From: Michael Render Date: Mon, 25 Nov 2024 14:50:31 -0500 Subject: [PATCH 29/58] [dotnet] Propagate `IWebDriver.GetAttribute` obsoletion to `WebDriver` (#14802) --- dotnet/src/support/Events/EventFiringWebDriver.cs | 1 + dotnet/src/webdriver/WebElement.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/dotnet/src/support/Events/EventFiringWebDriver.cs b/dotnet/src/support/Events/EventFiringWebDriver.cs index e68b261e387c3..cfcc7d0cc5154 100644 --- a/dotnet/src/support/Events/EventFiringWebDriver.cs +++ b/dotnet/src/support/Events/EventFiringWebDriver.cs @@ -1613,6 +1613,7 @@ public void Click() /// /// Attribute you wish to get details of /// The attribute's current value or null if the value is not set. + [Obsolete("Use GetDomAttribute(string attributeName) or GetDomProperty(string propertyName). GetAttribute(string attributeName) will be removed in Selenium 6.")] public string GetAttribute(string attributeName) { string attribute = string.Empty; diff --git a/dotnet/src/webdriver/WebElement.cs b/dotnet/src/webdriver/WebElement.cs index 51cce73e1eb67..b3e4356ca55b1 100644 --- a/dotnet/src/webdriver/WebElement.cs +++ b/dotnet/src/webdriver/WebElement.cs @@ -411,6 +411,7 @@ public virtual ReadOnlyCollection FindElements(string mechanism, st /// via JavaScript. /// /// Thrown when the target element is no longer valid in the document DOM. + [Obsolete("Use GetDomAttribute(string attributeName) or GetDomProperty(string propertyName). GetAttribute(string attributeName) will be removed in Selenium 6.")] public virtual string GetAttribute(string attributeName) { Response commandResponse = null; From d87cd359a64a2cf5a8333f067ce1fd48e2d59dc0 Mon Sep 17 00:00:00 2001 From: Selenium CI Bot Date: Tue, 26 Nov 2024 00:21:02 +0000 Subject: [PATCH 30/58] Update mirror info (Tue Nov 26 00:21:02 UTC 2024) --- common/mirror/selenium | 49 ++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/common/mirror/selenium b/common/mirror/selenium index 664bf8d6e5a1b..829332bd46f9c 100644 --- a/common/mirror/selenium +++ b/common/mirror/selenium @@ -1,15 +1,35 @@ [ + { + "tag_name": "selenium-4.27.0", + "assets": [ + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-dotnet-4.27.0.zip" + }, + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-dotnet-strongnamed-4.27.0.zip" + }, + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-java-4.27.0.zip" + }, + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-server-4.27.0.jar" + }, + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-server-4.27.0.zip" + } + ] + }, { "tag_name": "nightly", "assets": [ { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-java-4.27.0-SNAPSHOT.zip" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-java-4.28.0-SNAPSHOT.zip" }, { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.27.0-SNAPSHOT.jar" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.28.0-SNAPSHOT.jar" }, { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.27.0-SNAPSHOT.zip" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.28.0-SNAPSHOT.zip" } ] }, @@ -932,28 +952,5 @@ "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.0.0-rc-3/selenium-server-4.0.0-rc-3.zip" } ] - }, - { - "tag_name": "selenium-4.0.0-rc-2", - "assets": [ - { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.0.0-rc-2/selenium-dotnet-4.0.0-rc2.zip" - }, - { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.0.0-rc-2/selenium-dotnet-strongnamed-4.0.0-rc2.zip" - }, - { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.0.0-rc-2/selenium-html-runner-4.0.0-rc-2.jar" - }, - { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.0.0-rc-2/selenium-java-4.0.0-rc-2.zip" - }, - { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.0.0-rc-2/selenium-server-4.0.0-rc-2.jar" - }, - { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.0.0-rc-2/selenium-server-4.0.0-rc-2.zip" - } - ] } ] From 12106346db9c5233ba0109a4e66c3fd6f0eaa920 Mon Sep 17 00:00:00 2001 From: Viet Nguyen Duc Date: Tue, 26 Nov 2024 20:42:01 +0700 Subject: [PATCH 31/58] [py] Revert the Deprecation warnings of WebElement.get_attribute() (#14808) Revert "[py] Added Deprecation of WebElement.get_attribute() per #13334 (#14675)" This reverts commit bb3053ba23a5798fa65fd2bb52bbb174ac0a98d2. --- py/selenium/webdriver/remote/webelement.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/py/selenium/webdriver/remote/webelement.py b/py/selenium/webdriver/remote/webelement.py index e5a3adad0d7b4..08c772eaad56e 100644 --- a/py/selenium/webdriver/remote/webelement.py +++ b/py/selenium/webdriver/remote/webelement.py @@ -173,13 +173,6 @@ def get_attribute(self, name) -> str | None: # Check if the "active" CSS class is applied to an element. is_active = "active" in target_element.get_attribute("class") """ - - warnings.warn( - "using WebElement.get_attribute() has been deprecated. Please use get_dom_attribute() instead.", - DeprecationWarning, - stacklevel=2, - ) - if getAttribute_js is None: _load_js() attribute_value = self.parent.execute_script( From 1895c6e2faeaff125afbe9018a0d3559a5e12bdc Mon Sep 17 00:00:00 2001 From: Viet Nguyen Duc Date: Tue, 26 Nov 2024 21:30:56 +0700 Subject: [PATCH 32/58] [py] Fix `pyproject.toml` for installable from sdist (#14806) * [ci][py] Add rules validate-pyproject Signed-off-by: Viet Nguyen Duc * [py] Bump version to 4.27.1 Signed-off-by: Viet Nguyen Duc * Update CHANGELOG Signed-off-by: Viet Nguyen Duc --------- Signed-off-by: Viet Nguyen Duc Co-authored-by: Diego Molina --- py/BUILD.bazel | 2 +- py/CHANGES | 4 ++++ py/docs/source/conf.py | 4 ++-- py/pyproject.toml | 7 ++++--- py/selenium/__init__.py | 2 +- py/selenium/webdriver/__init__.py | 2 +- py/tox.ini | 14 +++++++++++--- 7 files changed, 24 insertions(+), 11 deletions(-) diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 95bc85084095f..4537f6b9a6e14 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -62,7 +62,7 @@ compile_pip_requirements( ], ) -SE_VERSION = "4.28.0.202411252021" +SE_VERSION = "4.27.1" BROWSER_VERSIONS = [ "v85", diff --git a/py/CHANGES b/py/CHANGES index c0db6781b2ec8..ea3cdf8db4397 100644 --- a/py/CHANGES +++ b/py/CHANGES @@ -1,3 +1,7 @@ +Selenium 4.27.1 +* Fix `pyproject.toml` for installable from sdist (#14806) +* Revert the Deprecation warnings of WebElement.get_attribute() (#14808) + Selenium 4.27.0 * Add CDP for Chrome 131 and remove 128 * Add Firefox CDP deprecation warnings (#14787) diff --git a/py/docs/source/conf.py b/py/docs/source/conf.py index a849406e4f2bf..4e78039a603c0 100644 --- a/py/docs/source/conf.py +++ b/py/docs/source/conf.py @@ -56,9 +56,9 @@ # built documents. # # The short X.Y version. -version = '4.28' +version = '4.27' # The full version, including alpha/beta/rc tags. -release = '4.28.0.202411252021' +release = '4.27.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/py/pyproject.toml b/py/pyproject.toml index 7da47ebed42bb..4f7ee07119c2d 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta" [project] name = "selenium" -version = "4.28.0.202411252021" -license = "Apache 2.0" +version = "4.27.1" +license = { text = "Apache 2.0" } description = "Official Python bindings for Selenium WebDriver." readme = "README.rst" requires-python = "~=3.8" @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] dependencies = [ "urllib3[socks]>=1.26,<3", @@ -40,7 +41,7 @@ zip-safe = false [tool.setuptools.packages.find] include = ["selenium*"] exclude = ["test*"] -namespace = false +namespaces = false # include-package-data is `true` by default in pyproject.toml [project.urls] diff --git a/py/selenium/__init__.py b/py/selenium/__init__.py index e3ff880df800d..2a9f1e1a9cdfb 100644 --- a/py/selenium/__init__.py +++ b/py/selenium/__init__.py @@ -16,4 +16,4 @@ # under the License. -__version__ = "4.28.0.202411252021" +__version__ = "4.27.1" diff --git a/py/selenium/webdriver/__init__.py b/py/selenium/webdriver/__init__.py index febdae5a03698..8880c5a91ff21 100644 --- a/py/selenium/webdriver/__init__.py +++ b/py/selenium/webdriver/__init__.py @@ -44,7 +44,7 @@ from .wpewebkit.service import Service as WPEWebKitService # noqa from .wpewebkit.webdriver import WebDriver as WPEWebKit # noqa -__version__ = "4.28.0.202411252021" +__version__ = "4.27.1" # We need an explicit __all__ because the above won't otherwise be exported. __all__ = [ diff --git a/py/tox.ini b/py/tox.ini index 3ba7d4be20ccc..083da94651e71 100644 --- a/py/tox.ini +++ b/py/tox.ini @@ -1,5 +1,13 @@ [tox] -envlist = docs, flake8, isort +envlist = docs, flake8, isort, validate-pyproject + +[testenv:validate-pyproject] +skip_install = true +deps = + validate-pyproject==0.23 + packaging==24.2 +commands = + validate-pyproject ./pyproject.toml [testenv:docs] skip_install = true @@ -7,10 +15,10 @@ deps = -r {toxinidir}/docs/requirements.txt -r {toxinidir}/requirements.txt -commands = +commands = ; regenerate autodoc stub pages sphinx-autogen docs/source/api.rst - ; build api docs + ; build api docs sphinx-build -b html -d ../build/docs/doctrees docs/source ../build/docs/api/py {posargs} setenv = PYTHONPATH = {toxinidir}/. From 7ba6fc579a1a297e9179d2cc42f3cc68eef3d4bf Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Tue, 26 Nov 2024 16:20:18 +0100 Subject: [PATCH 33/58] [py] Bumping versions for nightly --- py/BUILD.bazel | 2 +- py/docs/source/conf.py | 4 ++-- py/pyproject.toml | 2 +- py/selenium/__init__.py | 2 +- py/selenium/webdriver/__init__.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 4537f6b9a6e14..47158c4ab59ed 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -62,7 +62,7 @@ compile_pip_requirements( ], ) -SE_VERSION = "4.27.1" +SE_VERSION = "4.28.0.202411261607" BROWSER_VERSIONS = [ "v85", diff --git a/py/docs/source/conf.py b/py/docs/source/conf.py index 4e78039a603c0..2cf687329c477 100644 --- a/py/docs/source/conf.py +++ b/py/docs/source/conf.py @@ -56,9 +56,9 @@ # built documents. # # The short X.Y version. -version = '4.27' +version = '4.28' # The full version, including alpha/beta/rc tags. -release = '4.27.1' +release = '4.28.0.202411261607' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/py/pyproject.toml b/py/pyproject.toml index 4f7ee07119c2d..e99a03cd5d7a2 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "selenium" -version = "4.27.1" +version = "4.28.0.202411261607" license = { text = "Apache 2.0" } description = "Official Python bindings for Selenium WebDriver." readme = "README.rst" diff --git a/py/selenium/__init__.py b/py/selenium/__init__.py index 2a9f1e1a9cdfb..af337bd8b7304 100644 --- a/py/selenium/__init__.py +++ b/py/selenium/__init__.py @@ -16,4 +16,4 @@ # under the License. -__version__ = "4.27.1" +__version__ = "4.28.0.202411261607" diff --git a/py/selenium/webdriver/__init__.py b/py/selenium/webdriver/__init__.py index 8880c5a91ff21..4ae671ba788b1 100644 --- a/py/selenium/webdriver/__init__.py +++ b/py/selenium/webdriver/__init__.py @@ -44,7 +44,7 @@ from .wpewebkit.service import Service as WPEWebKitService # noqa from .wpewebkit.webdriver import WebDriver as WPEWebKit # noqa -__version__ = "4.27.1" +__version__ = "4.28.0.202411261607" # We need an explicit __all__ because the above won't otherwise be exported. __all__ = [ From 2e8816febd17233d54c1773e09d427b88c859a24 Mon Sep 17 00:00:00 2001 From: Selenium CI Bot Date: Wed, 27 Nov 2024 12:08:30 +0000 Subject: [PATCH 34/58] Update mirror info (Wed Nov 27 12:08:30 UTC 2024) --- common/mirror/selenium | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/common/mirror/selenium b/common/mirror/selenium index 829332bd46f9c..3f7b7af0c7a31 100644 --- a/common/mirror/selenium +++ b/common/mirror/selenium @@ -1,35 +1,35 @@ [ { - "tag_name": "selenium-4.27.0", + "tag_name": "nightly", "assets": [ { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-dotnet-4.27.0.zip" - }, - { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-dotnet-strongnamed-4.27.0.zip" - }, - { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-java-4.27.0.zip" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-java-4.28.0-SNAPSHOT.zip" }, { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-server-4.27.0.jar" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.28.0-SNAPSHOT.jar" }, { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-server-4.27.0.zip" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.28.0-SNAPSHOT.zip" } ] }, { - "tag_name": "nightly", + "tag_name": "selenium-4.27.0", "assets": [ { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-java-4.28.0-SNAPSHOT.zip" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-dotnet-4.27.0.zip" }, { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.28.0-SNAPSHOT.jar" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-dotnet-strongnamed-4.27.0.zip" }, { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.28.0-SNAPSHOT.zip" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-java-4.27.0.zip" + }, + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-server-4.27.0.jar" + }, + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.27.0/selenium-server-4.27.0.zip" } ] }, From 59aa1a0b5128fcd5e12fe918fd109d443e9f5586 Mon Sep 17 00:00:00 2001 From: Navin Chandra <98466550+navin772@users.noreply.github.com> Date: Wed, 27 Nov 2024 18:05:19 +0530 Subject: [PATCH 35/58] [java]: encapsulate `additionalCommands` with getter method (#14816) * change scope of `additionalCommands` to `protected` * expose getter `getAdditionalCommands` * add unit test for `additionalCommands` --------- Co-authored-by: Diego Molina --- .../selenium/remote/HttpCommandExecutor.java | 27 ++++++++++++++++++- .../RemoteWebDriverInitializationTest.java | 19 +++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/java/src/org/openqa/selenium/remote/HttpCommandExecutor.java b/java/src/org/openqa/selenium/remote/HttpCommandExecutor.java index 03fc84bc45b19..1eb3283eae014 100644 --- a/java/src/org/openqa/selenium/remote/HttpCommandExecutor.java +++ b/java/src/org/openqa/selenium/remote/HttpCommandExecutor.java @@ -25,6 +25,8 @@ import java.io.IOException; import java.net.URL; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; import org.openqa.selenium.NoSuchSessionException; import org.openqa.selenium.SessionNotCreatedException; @@ -109,11 +111,34 @@ public HttpCommandExecutor( ClientConfig config, HttpClient.Factory httpClientFactory) { remoteServer = Require.nonNull("HTTP client configuration", config).baseUrl(); - this.additionalCommands = Require.nonNull("Additional commands", additionalCommands); + this.additionalCommands = + new HashMap<>(Require.nonNull("Additional commands", additionalCommands)); this.httpClientFactory = Require.nonNull("HTTP client factory", httpClientFactory); this.client = this.httpClientFactory.createClient(config); } + /** + * Returns an immutable view of the additional commands. + * + * @return an unmodifiable map of additional commands. + */ + public Map getAdditionalCommands() { + return Collections.unmodifiableMap(additionalCommands); + } + + /** + * Adds or updates additional commands. This method is protected to allow subclasses to define + * their commands. + * + * @param commandName the name of the command to add or update. + * @param info the CommandInfo for the command. + */ + protected void addAdditionalCommand(String commandName, CommandInfo info) { + Require.nonNull("Command name", commandName); + Require.nonNull("Command info", info); + this.additionalCommands.put(commandName, info); + } + /** * It may be useful to extend the commands understood by this {@code HttpCommandExecutor} at run * time, and this can be achieved via this method. Note, this is protected, and expected usage is diff --git a/java/test/org/openqa/selenium/remote/RemoteWebDriverInitializationTest.java b/java/test/org/openqa/selenium/remote/RemoteWebDriverInitializationTest.java index 111cac68e5085..8c01983488ed3 100644 --- a/java/test/org/openqa/selenium/remote/RemoteWebDriverInitializationTest.java +++ b/java/test/org/openqa/selenium/remote/RemoteWebDriverInitializationTest.java @@ -51,6 +51,7 @@ import org.openqa.selenium.remote.http.ClientConfig; import org.openqa.selenium.remote.http.Contents; import org.openqa.selenium.remote.http.HttpClient; +import org.openqa.selenium.remote.http.HttpMethod; import org.openqa.selenium.remote.http.HttpResponse; @Tag("UnitTests") @@ -234,4 +235,22 @@ public void quit() { quitCalled = true; } } + + @Test + void additionalCommandsCanBeModified() throws MalformedURLException { + HttpClient client = mock(HttpClient.class); + HttpClient.Factory factory = mock(HttpClient.Factory.class); + + when(factory.createClient(any(ClientConfig.class))).thenReturn(client); + + URL url = new URL("http://localhost:4444/"); + HttpCommandExecutor executor = + new HttpCommandExecutor(emptyMap(), ClientConfig.defaultConfig().baseUrl(url), factory); + + String commandName = "customCommand"; + CommandInfo commandInfo = new CommandInfo("/session/:sessionId/custom", HttpMethod.GET); + executor.addAdditionalCommand(commandName, commandInfo); + + assertThat(executor.getAdditionalCommands()).containsEntry(commandName, commandInfo); + } } From 8594d5e61fa3e46661a62c7f4f88daf55567f429 Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Wed, 27 Nov 2024 15:16:21 +0100 Subject: [PATCH 36/58] [java] Ignoring no shadow root test due to https://issues.chromium.org/issues/375892677 Related to #14631 --- java/test/org/openqa/selenium/NoSuchShadowRootTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/test/org/openqa/selenium/NoSuchShadowRootTest.java b/java/test/org/openqa/selenium/NoSuchShadowRootTest.java index 4fe1be1ecec08..f945aa6d4561e 100644 --- a/java/test/org/openqa/selenium/NoSuchShadowRootTest.java +++ b/java/test/org/openqa/selenium/NoSuchShadowRootTest.java @@ -18,13 +18,18 @@ package org.openqa.selenium; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.openqa.selenium.testing.drivers.Browser.CHROME; +import static org.openqa.selenium.testing.drivers.Browser.EDGE; import org.junit.jupiter.api.Test; +import org.openqa.selenium.testing.Ignore; import org.openqa.selenium.testing.JupiterTestBase; public class NoSuchShadowRootTest extends JupiterTestBase { @Test + @Ignore(value = CHROME, reason = "https://issues.chromium.org/issues/375892677") + @Ignore(value = EDGE, reason = "https://issues.chromium.org/issues/375892677") public void getNoSuchShadowRoot() { driver.get(pages.shadowRootPage); WebElement nonExistentShadowRootElement = driver.findElement(By.id("noShadowRoot")); From e71f0dbef35cb1efdea6057e3e7361277a1da56d Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Wed, 27 Nov 2024 15:16:34 +0100 Subject: [PATCH 37/58] [dotnet] Ignoring no shadow root test due to https://issues.chromium.org/issues/375892677 Related to #14631 --- dotnet/test/common/ShadowRootHandlingTest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dotnet/test/common/ShadowRootHandlingTest.cs b/dotnet/test/common/ShadowRootHandlingTest.cs index 2d014aa865e95..7fa25654dd10f 100644 --- a/dotnet/test/common/ShadowRootHandlingTest.cs +++ b/dotnet/test/common/ShadowRootHandlingTest.cs @@ -47,6 +47,8 @@ public void ShouldFindElementUnderShadowRoot() } [Test] + [IgnoreBrowser(Browser.Chrome, "https://issues.chromium.org/issues/375892677")] + [IgnoreBrowser(Browser.Edge, "https://issues.chromium.org/issues/375892677")] public void ShouldThrowGettingShadowRootWithElementNotHavingShadowRoot() { driver.Url = shadowRootPage; From 4fe2a56aab3a977dc2bbbc4ea8200bb0841ac99f Mon Sep 17 00:00:00 2001 From: Michael Render Date: Wed, 27 Nov 2024 14:00:07 -0500 Subject: [PATCH 38/58] [dotnet] Add nullability annotations to `ShadowRoot` (#14812) --- dotnet/src/webdriver/ISearchContext.cs | 2 + dotnet/src/webdriver/IWrapsDriver.cs | 2 + .../Internal/IWebDriverObjectReference.cs | 2 + dotnet/src/webdriver/ShadowRoot.cs | 57 ++++++++++--------- dotnet/src/webdriver/WebDriver.cs | 4 +- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/dotnet/src/webdriver/ISearchContext.cs b/dotnet/src/webdriver/ISearchContext.cs index 53c5f33ae36da..a8e244ffdddee 100644 --- a/dotnet/src/webdriver/ISearchContext.cs +++ b/dotnet/src/webdriver/ISearchContext.cs @@ -20,6 +20,8 @@ using System; using System.Collections.ObjectModel; +#nullable enable + namespace OpenQA.Selenium { /// diff --git a/dotnet/src/webdriver/IWrapsDriver.cs b/dotnet/src/webdriver/IWrapsDriver.cs index 27af4c7e56faa..15fe5afa2bcf3 100644 --- a/dotnet/src/webdriver/IWrapsDriver.cs +++ b/dotnet/src/webdriver/IWrapsDriver.cs @@ -17,6 +17,8 @@ // under the License. // +#nullable enable + namespace OpenQA.Selenium { /// diff --git a/dotnet/src/webdriver/Internal/IWebDriverObjectReference.cs b/dotnet/src/webdriver/Internal/IWebDriverObjectReference.cs index bc67fdd7c6a6b..a62286ca57676 100644 --- a/dotnet/src/webdriver/Internal/IWebDriverObjectReference.cs +++ b/dotnet/src/webdriver/Internal/IWebDriverObjectReference.cs @@ -19,6 +19,8 @@ using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.Internal { /// diff --git a/dotnet/src/webdriver/ShadowRoot.cs b/dotnet/src/webdriver/ShadowRoot.cs index 459674b27c1d5..a872d4fbc7d74 100644 --- a/dotnet/src/webdriver/ShadowRoot.cs +++ b/dotnet/src/webdriver/ShadowRoot.cs @@ -21,6 +21,9 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; + +#nullable enable namespace OpenQA.Selenium { @@ -34,49 +37,46 @@ public class ShadowRoot : ISearchContext, IWrapsDriver, IWebDriverObjectReferenc /// public const string ShadowRootReferencePropertyName = "shadow-6066-11e4-a52e-4f735466cecf"; - private WebDriver driver; - private string shadowRootId; + private readonly WebDriver driver; + private readonly string shadowRootId; /// /// Initializes a new instance of the class. /// /// The instance that is driving this shadow root. /// The ID value provided to identify the shadow root. + /// If or are . public ShadowRoot(WebDriver parentDriver, string id) { - this.driver = parentDriver; - this.shadowRootId = id; + this.driver = parentDriver ?? throw new ArgumentNullException(nameof(parentDriver)); + this.shadowRootId = id ?? throw new ArgumentNullException(nameof(id)); } /// /// Gets the driving this shadow root. /// - public IWebDriver WrappedDriver - { - get { return this.driver; } - } + public IWebDriver WrappedDriver => this.driver; /// /// Gets the internal ID for this ShadowRoot. /// - string IWebDriverObjectReference.ObjectReferenceId - { - get { return this.shadowRootId; } - } + string IWebDriverObjectReference.ObjectReferenceId => this.shadowRootId; - internal static bool ContainsShadowRootReference(Dictionary shadowRootDictionary) + internal static bool TryCreate(WebDriver parentDriver, Dictionary shadowRootDictionary, [NotNullWhen(true)] out ShadowRoot? shadowRoot) { - if (shadowRootDictionary == null) + if (shadowRootDictionary is null) { throw new ArgumentNullException(nameof(shadowRootDictionary), "The dictionary containing the shadow root reference cannot be null"); } - return shadowRootDictionary.ContainsKey(ShadowRootReferencePropertyName); - } + if (shadowRootDictionary.TryGetValue(ShadowRootReferencePropertyName, out object? shadowRootValue)) + { + shadowRoot = new ShadowRoot(parentDriver, shadowRootValue?.ToString()!); + return true; + } - internal static ShadowRoot FromDictionary(WebDriver driver, Dictionary shadowRootDictionary) - { - return new ShadowRoot(driver, shadowRootDictionary[ShadowRoot.ShadowRootReferencePropertyName].ToString()); + shadowRoot = null; + return false; } /// @@ -84,18 +84,20 @@ internal static ShadowRoot FromDictionary(WebDriver driver, Dictionary /// The locating mechanism to use. /// The first matching on the current context. + /// If is . /// If no element matches the criteria. public IWebElement FindElement(By by) { - if (by == null) + if (by is null) { - throw new ArgumentNullException(nameof(@by), "by cannot be null"); + throw new ArgumentNullException(nameof(by), "by cannot be null"); } Dictionary parameters = new Dictionary(); parameters.Add("id", this.shadowRootId); parameters.Add("using", by.Mechanism); parameters.Add("value", by.Criteria); + Response commandResponse = this.driver.InternalExecute(DriverCommand.FindShadowChildElement, parameters); return this.driver.GetElementFromResponse(commandResponse); } @@ -107,26 +109,29 @@ public IWebElement FindElement(By by) /// The locating mechanism to use. /// A of all WebElements /// matching the current criteria, or an empty list if nothing matches. + /// If is . public ReadOnlyCollection FindElements(By by) { - if (by == null) + if (by is null) { - throw new ArgumentNullException(nameof(@by), "by cannot be null"); + throw new ArgumentNullException(nameof(by), "by cannot be null"); } Dictionary parameters = new Dictionary(); parameters.Add("id", this.shadowRootId); parameters.Add("using", by.Mechanism); parameters.Add("value", by.Criteria); + Response commandResponse = this.driver.InternalExecute(DriverCommand.FindShadowChildElements, parameters); return this.driver.GetElementsFromResponse(commandResponse); } Dictionary IWebDriverObjectReference.ToDictionary() { - Dictionary shadowRootDictionary = new Dictionary(); - shadowRootDictionary.Add(ShadowRootReferencePropertyName, this.shadowRootId); - return shadowRootDictionary; + return new Dictionary + { + [ShadowRootReferencePropertyName] = this.shadowRootId + }; } } } diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 235b2e648058e..0720811caba33 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -980,9 +980,9 @@ private object ParseJavaScriptReturnValue(object responseValue) { returnValue = this.elementFactory.CreateElement(resultAsDictionary); } - else if (ShadowRoot.ContainsShadowRootReference(resultAsDictionary)) + else if (ShadowRoot.TryCreate(this, resultAsDictionary, out ShadowRoot shadowRoot)) { - returnValue = ShadowRoot.FromDictionary(this, resultAsDictionary); + returnValue = shadowRoot; } else { From cfaa8c45cf785e716c521bf6d14d9bad2bfa7d79 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Wed, 27 Nov 2024 14:25:47 -0500 Subject: [PATCH 39/58] [dotnet] Fix `WebDriver.AuthenticatorId` to return proper state set by user (#14814) --- dotnet/src/webdriver/WebDriver.cs | 21 +++++++++---------- .../VirtualAuthn/VirtualAuthenticatorTest.cs | 5 ++++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 0720811caba33..d9960ea97b235 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -45,7 +45,6 @@ public class WebDriver : IWebDriver, ISearchContext, IJavaScriptExecutor, IFinds private NetworkManager network; private WebElementFactory elementFactory; private SessionId sessionId; - private String authenticatorId; private List registeredCommands = new List(); /// @@ -1046,8 +1045,8 @@ public string AddVirtualAuthenticator(VirtualAuthenticatorOptions options) { Response commandResponse = this.Execute(DriverCommand.AddVirtualAuthenticator, options.ToDictionary()); string id = commandResponse.Value.ToString(); - this.authenticatorId = id; - return this.authenticatorId; + this.AuthenticatorId = id; + return this.AuthenticatorId; } /// @@ -1057,15 +1056,15 @@ public string AddVirtualAuthenticator(VirtualAuthenticatorOptions options) public void RemoveVirtualAuthenticator(string authenticatorId) { Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.authenticatorId); + parameters.Add("authenticatorId", this.AuthenticatorId); this.Execute(DriverCommand.RemoveVirtualAuthenticator, parameters); - this.authenticatorId = null; + this.AuthenticatorId = null; } /// /// Gets the virtual authenticator ID for this WebDriver instance. /// - public string AuthenticatorId { get; } + public string AuthenticatorId { get; private set; } /// /// Add a credential to the Virtual Authenticator/ @@ -1074,7 +1073,7 @@ public void RemoveVirtualAuthenticator(string authenticatorId) public void AddCredential(Credential credential) { Dictionary parameters = new Dictionary(credential.ToDictionary()); - parameters.Add("authenticatorId", this.authenticatorId); + parameters.Add("authenticatorId", this.AuthenticatorId); this.Execute(driverCommandToExecute: DriverCommand.AddCredential, parameters); } @@ -1086,7 +1085,7 @@ public void AddCredential(Credential credential) public List GetCredentials() { Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.authenticatorId); + parameters.Add("authenticatorId", this.AuthenticatorId); object[] commandResponse = (object[])this.Execute(driverCommandToExecute: DriverCommand.GetCredentials, parameters).Value; @@ -1117,7 +1116,7 @@ public void RemoveCredential(byte[] credentialId) public void RemoveCredential(string credentialId) { Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.authenticatorId); + parameters.Add("authenticatorId", this.AuthenticatorId); parameters.Add("credentialId", credentialId); this.Execute(driverCommandToExecute: DriverCommand.RemoveCredential, parameters); @@ -1129,7 +1128,7 @@ public void RemoveCredential(string credentialId) public void RemoveAllCredentials() { Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.authenticatorId); + parameters.Add("authenticatorId", this.AuthenticatorId); this.Execute(driverCommandToExecute: DriverCommand.RemoveAllCredentials, parameters); } @@ -1141,7 +1140,7 @@ public void RemoveAllCredentials() public void SetUserVerified(bool verified) { Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.authenticatorId); + parameters.Add("authenticatorId", this.AuthenticatorId); parameters.Add("isUserVerified", verified); this.Execute(driverCommandToExecute: DriverCommand.SetUserVerified, parameters); diff --git a/dotnet/test/common/VirtualAuthn/VirtualAuthenticatorTest.cs b/dotnet/test/common/VirtualAuthn/VirtualAuthenticatorTest.cs index a5a8d53d73da4..e6c16e11b673a 100644 --- a/dotnet/test/common/VirtualAuthn/VirtualAuthenticatorTest.cs +++ b/dotnet/test/common/VirtualAuthn/VirtualAuthenticatorTest.cs @@ -71,7 +71,8 @@ public void Setup() [TearDown] public void Teardown() { - if (webDriver.AuthenticatorId != null) + if (webDriver.AuthenticatorId is not null && + webDriver.SessionId is not null) { webDriver.RemoveVirtualAuthenticator(webDriver.AuthenticatorId); } @@ -186,6 +187,8 @@ public void ShouldRemoveAuthenticator() { VirtualAuthenticatorOptions options = new VirtualAuthenticatorOptions(); string authenticatorId = webDriver.AddVirtualAuthenticator(options); + Assert.That(webDriver.AuthenticatorId, Is.EqualTo(authenticatorId)); + webDriver.RemoveVirtualAuthenticator(authenticatorId); Assert.IsNull(webDriver.AuthenticatorId); From 6dc99f5178482fb97e8df0e212d8013cc37f9b35 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Wed, 27 Nov 2024 17:20:04 -0500 Subject: [PATCH 40/58] [dotnet] Add future-proofing note on `Base64UrlEncoder` (#14821) --- dotnet/src/webdriver/Internal/Base64UrlEncoder.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dotnet/src/webdriver/Internal/Base64UrlEncoder.cs b/dotnet/src/webdriver/Internal/Base64UrlEncoder.cs index 23c2fc5fae5f9..87fb7085e86c5 100644 --- a/dotnet/src/webdriver/Internal/Base64UrlEncoder.cs +++ b/dotnet/src/webdriver/Internal/Base64UrlEncoder.cs @@ -19,8 +19,17 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Internal { + /* + * Based on: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/6.19.0/src/Microsoft.IdentityModel.Tokens/Base64UrlEncoder.cs + * + * Now it is a part of .NET 9+ as System.Buffers.Text.Base64Url + * https://github.com/SeleniumHQ/selenium/issues/14813 + */ + /// /// Encodes and Decodes strings as Base64Url encoding. /// @@ -45,8 +54,6 @@ public static class Base64UrlEncoder base64UrlCharacter63 }; - // https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/6.19.0/src/Microsoft.IdentityModel.Tokens/Base64UrlEncoder.cs#L85 - /// /// Converts a subset of an array of 8-bit unsigned integers to its equivalent string representation which is encoded with base-64-url digits. /// @@ -115,8 +122,6 @@ public static string Encode(byte[] inArray) return new string(output, 0, j); } - // https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/6.19.0/src/Microsoft.IdentityModel.Tokens/Base64UrlEncoder.cs#L179 - /// /// Converts the specified string, which encodes binary data as base-64-url digits, to an equivalent 8-bit unsigned integer array. /// base64Url encoded string. From a96f6aad1ad91008f5fae1d948cb9310a710e902 Mon Sep 17 00:00:00 2001 From: mk868 Date: Thu, 28 Nov 2024 12:03:37 +0100 Subject: [PATCH 41/58] [java] SpotBugs exclude `NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE` from the `firefox.AddHasExtensions$1` (#14766) Co-authored-by: Puja Jagani --- java/spotbugs-excludes.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/spotbugs-excludes.xml b/java/spotbugs-excludes.xml index d62598f910a60..2ae98dc7e6050 100644 --- a/java/spotbugs-excludes.xml +++ b/java/spotbugs-excludes.xml @@ -54,6 +54,11 @@ + + + + + From 17a2c339ea4bb8ab2d57f7e60633974ed07aaa94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sautter?= Date: Thu, 28 Nov 2024 18:03:04 +0100 Subject: [PATCH 42/58] [java] read complete output of selenium manager #14820 --- .../selenium/manager/SeleniumManager.java | 5 ++- .../openqa/selenium/os/ExternalProcess.java | 38 +++++++++++++------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/java/src/org/openqa/selenium/manager/SeleniumManager.java b/java/src/org/openqa/selenium/manager/SeleniumManager.java index b907d8ab755ec..97e23c85f4cb6 100644 --- a/java/src/org/openqa/selenium/manager/SeleniumManager.java +++ b/java/src/org/openqa/selenium/manager/SeleniumManager.java @@ -123,7 +123,10 @@ private static Result runCommand(Path binary, List arguments) { String output; int code; try { - ExternalProcess.Builder processBuilder = ExternalProcess.builder(); + ExternalProcess.Builder processBuilder = + ExternalProcess.builder() + // keep all output of the process to avoid JSON syntax errors while parsing + .bufferSize(-1); Properties properties = System.getProperties(); for (String name : properties.stringPropertyNames()) { diff --git a/java/src/org/openqa/selenium/os/ExternalProcess.java b/java/src/org/openqa/selenium/os/ExternalProcess.java index 2bbb7ceb01b9c..e4ae0ec9c46fa 100644 --- a/java/src/org/openqa/selenium/os/ExternalProcess.java +++ b/java/src/org/openqa/selenium/os/ExternalProcess.java @@ -19,6 +19,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -159,8 +160,8 @@ public Builder directory(File directory) { } /** - * Where to copy the combined stdout and stderr output to, {@code OsProcess#getOutput} is still - * working when called. + * Where to copy the combined stdout and stderr output to, {@code ExternalProcess#getOutput} is + * still working when called. * * @param stream where to copy the combined output to * @return this instance to continue building @@ -172,9 +173,9 @@ public Builder copyOutputTo(OutputStream stream) { } /** - * The number of bytes to buffer for {@code OsProcess#getOutput} calls. + * The number of bytes to buffer for {@code ExternalProcess#getOutput} calls. * - * @param toKeep the number of bytes, default is 4096 + * @param toKeep the number of bytes, default is 32768 * @return this instance to continue building */ public Builder bufferSize(int toKeep) { @@ -195,13 +196,19 @@ public ExternalProcess start() throws UncheckedIOException { } try { - CircularOutputStream circular = new CircularOutputStream(bufferSize); + OutputStream buffer; + + if (bufferSize != -1) { + buffer = new CircularOutputStream(bufferSize); + } else { + buffer = new ByteArrayOutputStream(); + } Thread worker = new Thread( () -> { // copyOutputTo might be system.out or system.err, do not to close - OutputStream output = new MultiOutputStream(circular, copyOutputTo); + OutputStream output = new MultiOutputStream(buffer, copyOutputTo); // closing the InputStream does somehow disturb the process, do not to close InputStream input = process.getInputStream(); // use the CircularOutputStream as mandatory, we know it will never raise a @@ -221,7 +228,7 @@ public ExternalProcess start() throws UncheckedIOException { worker.setDaemon(true); worker.start(); - return new ExternalProcess(process, circular, worker); + return new ExternalProcess(process, buffer, worker); } catch (Throwable t) { // ensure we do not leak a process in case of failures try { @@ -239,10 +246,10 @@ public static Builder builder() { } private final Process process; - private final CircularOutputStream outputStream; + private final OutputStream outputStream; private final Thread worker; - public ExternalProcess(Process process, CircularOutputStream outputStream, Thread worker) { + public ExternalProcess(Process process, OutputStream outputStream, Thread worker) { this.process = process; this.outputStream = outputStream; this.worker = worker; @@ -250,7 +257,7 @@ public ExternalProcess(Process process, CircularOutputStream outputStream, Threa /** * The last N bytes of the combined stdout and stderr as String, the value of N is set while - * building the OsProcess. + * building the ExternalProcess. * * @return stdout and stderr as String in Charset.defaultCharset() encoding */ @@ -260,13 +267,20 @@ public String getOutput() { /** * The last N bytes of the combined stdout and stderr as String, the value of N is set while - * building the OsProcess. + * building the ExternalProcess. * * @param encoding the encoding to decode the stream * @return stdout and stderr as String in the given encoding */ public String getOutput(Charset encoding) { - return outputStream.toString(encoding); + if (outputStream instanceof CircularOutputStream) { + return ((CircularOutputStream) outputStream).toString(encoding); + } else if (outputStream instanceof ByteArrayOutputStream) { + return ((ByteArrayOutputStream) outputStream).toString(encoding); + } else { + throw new IllegalStateException( + "unexpected OutputStream implementation: " + outputStream.getClass().getSimpleName()); + } } public boolean isAlive() { From 5c49a66f048d625703491879f7cf0c237ab51f6b Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Fri, 29 Nov 2024 11:11:04 +0100 Subject: [PATCH 43/58] [py] fix packaging (#14823) Ensure `selenium.webdriver.common.fedcm` gets packaged in. --- py/selenium/webdriver/common/fedcm/__init__.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 py/selenium/webdriver/common/fedcm/__init__.py diff --git a/py/selenium/webdriver/common/fedcm/__init__.py b/py/selenium/webdriver/common/fedcm/__init__.py new file mode 100644 index 0000000000000..a5b1e6f85a09e --- /dev/null +++ b/py/selenium/webdriver/common/fedcm/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. From 5e3d04f6ffcc025de8302a72a4c1532dc9194ad1 Mon Sep 17 00:00:00 2001 From: Simon Mavi Stewart Date: Fri, 29 Nov 2024 15:02:26 +0200 Subject: [PATCH 44/58] Run update_copyright script. No logical changes --- dotnet/src/webdriver/Internal/Base64UrlEncoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotnet/src/webdriver/Internal/Base64UrlEncoder.cs b/dotnet/src/webdriver/Internal/Base64UrlEncoder.cs index 87fb7085e86c5..c8b22e7223e8b 100644 --- a/dotnet/src/webdriver/Internal/Base64UrlEncoder.cs +++ b/dotnet/src/webdriver/Internal/Base64UrlEncoder.cs @@ -25,9 +25,9 @@ namespace OpenQA.Selenium.Internal { /* * Based on: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/6.19.0/src/Microsoft.IdentityModel.Tokens/Base64UrlEncoder.cs - * + * * Now it is a part of .NET 9+ as System.Buffers.Text.Base64Url - * https://github.com/SeleniumHQ/selenium/issues/14813 + * https://github.com/SeleniumHQ/selenium/issues/14813 */ /// From ff7fa5266013f5b2a53278390fc80f12487d7682 Mon Sep 17 00:00:00 2001 From: Simon Stewart Date: Fri, 29 Nov 2024 17:29:48 +0200 Subject: [PATCH 45/58] [bazel] Bump `rules_jvm_external` to 6.6 and use the maven resolver (#14829) By using the maven resolver, we can make use of BOMs, which mean less duplication of version numbers within the `install` tag. --- MODULE.bazel | 56 ++++++++++++++++------------- java/maven_install.json | 80 ++++++++++++++++++----------------------- 2 files changed, 65 insertions(+), 71 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 9a98a3348bb0d..ffb74a8cfbaf4 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -19,7 +19,7 @@ bazel_dep(name = "rules_cc", version = "0.0.9", dev_dependency = True) bazel_dep(name = "rules_dotnet", version = "0.16.1") bazel_dep(name = "rules_java", version = "7.11.1") -bazel_dep(name = "rules_jvm_external", version = "6.3") +bazel_dep(name = "rules_jvm_external", version = "6.6") bazel_dep(name = "rules_nodejs", version = "6.3.0") bazel_dep(name = "rules_oci", version = "1.7.6") bazel_dep(name = "rules_pkg", version = "0.10.1") @@ -182,23 +182,23 @@ maven.install( "dev.failsafe:failsafe:3.3.2", "io.grpc:grpc-context:1.68.1", "io.lettuce:lettuce-core:6.5.0.RELEASE", - "io.netty:netty-buffer:4.1.115.Final", - "io.netty:netty-codec-http:4.1.115.Final", - "io.netty:netty-codec-http2:4.1.115.Final", - "io.netty:netty-common:4.1.115.Final", - "io.netty:netty-handler:4.1.115.Final", - "io.netty:netty-handler-proxy:4.1.115.Final", - "io.netty:netty-transport:4.1.115.Final", - "io.opentelemetry:opentelemetry-api:1.44.1", - "io.opentelemetry:opentelemetry-context:1.44.1", - "io.opentelemetry:opentelemetry-exporter-logging:1.44.1", - "io.opentelemetry:opentelemetry-sdk:1.44.1", - "io.opentelemetry:opentelemetry-sdk-common:1.44.1", - "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:1.44.1", - "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:1.44.1", - "io.opentelemetry:opentelemetry-sdk-testing:1.44.1", - "io.opentelemetry:opentelemetry-sdk-trace:1.44.1", - "io.opentelemetry.semconv:opentelemetry-semconv:1.25.0-alpha", + "io.netty:netty-buffer", + "io.netty:netty-codec-http", + "io.netty:netty-codec-http2", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-handler-proxy", + "io.netty:netty-transport", + "io.opentelemetry:opentelemetry-api", + "io.opentelemetry:opentelemetry-context", + "io.opentelemetry:opentelemetry-exporter-logging", + "io.opentelemetry:opentelemetry-sdk", + "io.opentelemetry:opentelemetry-sdk-common", + "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure", + "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi", + "io.opentelemetry:opentelemetry-sdk-testing", + "io.opentelemetry:opentelemetry-sdk-trace", + "io.opentelemetry.semconv:opentelemetry-semconv:1.28.0-alpha", "it.ozimov:embedded-redis:0.7.3", "net.bytebuddy:byte-buddy:1.15.10", "org.htmlunit:htmlunit-core-js:4.6.0", @@ -209,13 +209,13 @@ maven.install( "org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5", "org.hsqldb:hsqldb:2.7.4", "org.jspecify:jspecify:1.0.0", - "org.junit.jupiter:junit-jupiter-api:5.11.3", - "org.junit.jupiter:junit-jupiter-engine:5.11.3", - "org.junit.jupiter:junit-jupiter-params:5.11.3", - "org.junit.platform:junit-platform-launcher:1.11.3", - "org.junit.platform:junit-platform-reporting:1.11.3", - "org.junit.platform:junit-platform-commons:1.11.3", - "org.junit.platform:junit-platform-engine:1.11.3", + "org.junit.jupiter:junit-jupiter-api", + "org.junit.jupiter:junit-jupiter-engine", + "org.junit.jupiter:junit-jupiter-params", + "org.junit.platform:junit-platform-launcher", + "org.junit.platform:junit-platform-reporting", + "org.junit.platform:junit-platform-commons", + "org.junit.platform:junit-platform-engine", "org.mockito:mockito-core:5.14.2", "org.redisson:redisson:3.39.0", "org.slf4j:slf4j-api:2.0.16", @@ -223,6 +223,11 @@ maven.install( "org.tomlj:tomlj:1.1.1", "org.zeromq:jeromq:0.6.0", ], + boms = [ + "io.opentelemetry:opentelemetry-bom:1.44.1", + "io.netty:netty-bom:4.1.115.Final", + "org.junit:junit-bom:5.11.3", + ], excluded_artifacts = [ "org.hamcrest:hamcrest-all", # Replaced by hamcrest 2 "org.hamcrest:hamcrest-core", @@ -235,6 +240,7 @@ maven.install( repositories = [ "https://repo1.maven.org/maven2", ], + resolver = "maven", strict_visibility = True, ) use_repo(maven, "maven", "unpinned_maven") diff --git a/java/maven_install.json b/java/maven_install.json index 89ea3131ad63b..f7a2f0fe6bcde 100644 --- a/java/maven_install.json +++ b/java/maven_install.json @@ -1,14 +1,7 @@ { "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", - "__INPUT_ARTIFACTS_HASH": 329453186, - "__RESOLVED_ARTIFACTS_HASH": -9148858, - "conflict_resolution": { - "com.google.code.gson:gson:2.8.9": "com.google.code.gson:gson:2.11.0", - "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.28.0", - "com.google.guava:guava:31.1-jre": "com.google.guava:guava:33.3.1-jre", - "com.google.j2objc:j2objc-annotations:1.3": "com.google.j2objc:j2objc-annotations:3.0.0", - "org.mockito:mockito-core:4.3.1": "org.mockito:mockito-core:5.14.2" - }, + "__INPUT_ARTIFACTS_HASH": -756051712, + "__RESOLVED_ARTIFACTS_HASH": -748733705, "artifacts": { "com.beust:jcommander": { "shasums": { @@ -138,10 +131,10 @@ }, "com.google.errorprone:error_prone_annotations": { "shasums": { - "jar": "f3fc8a3a0a4020706a373b00e7f57c2512dd26d1f83d28c7d38768f8682b231e", - "sources": "2936e9b315d790d8a6364f0574bcec9c8b2d78688b317e1765c4a16f9ef80632" + "jar": "357cd6cfb067c969226c442451502aee13800a24e950fdfde77bcdb4565a668d", + "sources": "7ce688ed1582a67097228c050192b7cfd00479a81d2b921f7cd5116994f1402d" }, - "version": "2.28.0" + "version": "2.3.2" }, "com.google.googlejavaformat:google-java-format": { "shasums": { @@ -173,17 +166,16 @@ }, "com.google.guava:listenablefuture": { "shasums": { - "jar": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99", - "sources": null + "jar": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" }, "version": "9999.0-empty-to-avoid-conflict-with-guava" }, "com.google.j2objc:j2objc-annotations": { "shasums": { - "jar": "88241573467ddca44ffd4d74aa04c2bbfd11bf7c17e0c342c94c9de7a70a7c64", - "sources": "bd60019a0423c3a025ef6ab24fe0761f5f45ffb48a8cca74a01b678de1105d38" + "jar": "21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b", + "sources": "ba4df669fec153fa4cd0ef8d02c6d3ef0702b7ac4cabe080facf3b6e490bb972" }, - "version": "3.0.0" + "version": "1.3" }, "com.google.truth:truth": { "shasums": { @@ -355,10 +347,10 @@ }, "io.opentelemetry.semconv:opentelemetry-semconv": { "shasums": { - "jar": "745a86a75ecb5e03f464f05ea2dc76e0f04d07273c5509fa74f393bff9b222b7", - "sources": "58a375cd34943d8dd4f64233b19fee6a5094e3ae533f77d527e75c276626d49e" + "jar": "e8ab86e93cef09e421a6213f4cf18421fcc6e1f9cf0ab94b9a31ed4460ddf553", + "sources": "b0588ae0617071c30451fe0f4916b2cde7aa8d24b542ee696a7bf59f7d7f46a8" }, - "version": "1.25.0-alpha" + "version": "1.28.0-alpha" }, "io.opentelemetry:opentelemetry-api": { "shasums": { @@ -446,10 +438,10 @@ }, "io.projectreactor:reactor-core": { "shasums": { - "jar": "44f055fbd033b6c976c53fb2e04b59027e79fb2312c37d2eaa54c77ea1ea80fe", - "sources": "fee913ed4e41d79ce1cf7db4526d23e848719083b65a4041dea590f91b1ef2f6" + "jar": "6e235f0be9732ebd6a42c585dfd53274065978bfbc28d721d7ecf487fde27b52", + "sources": "57e48b121636923ec362aa337556150edc8bc29ccba686c21d36016e05207b23" }, - "version": "3.6.6" + "version": "3.6.2" }, "io.reactivex.rxjava3:rxjava": { "shasums": { @@ -530,10 +522,10 @@ }, "org.apache.commons:commons-lang3": { "shasums": { - "jar": "7b96bf3ee68949abb5bc465559ac270e0551596fa34523fddf890ec418dde13c", - "sources": "ab3b86afb898f1026dbe43aaf71e9c1d719ec52d6e41887b362d86777c299b6f" + "jar": "d919d904486c037f8d193412da0c92e22a9fa24230b9d67a57855c5c31c7e94e", + "sources": "325a4551eee7d99f7616aa05b00ee3ca9d0cdc8face1b252a9864f2d945c58b3" }, - "version": "3.14.0" + "version": "3.12.0" }, "org.apache.commons:commons-text": { "shasums": { @@ -614,10 +606,10 @@ }, "org.checkerframework:checker-qual": { "shasums": { - "jar": "3fbc2e98f05854c3df16df9abaa955b91b15b3ecac33623208ed6424640ef0f6", - "sources": "d6bdee58964cd05aabfca4e44947d3cbdada6bf617ed618b62b3b0d5a21de339" + "jar": "ab0468b1ba35bb2ae45f61a60dc4960bd887660ab8f05113a662a7e675eae776", + "sources": "cbe362ef1dfacb927e0e4bf78a97b1b92ba50ca38b4406ae58b8c11e41ef2075" }, - "version": "3.43.0" + "version": "3.9.1" }, "org.dom4j:dom4j": { "shasums": { @@ -733,10 +725,10 @@ }, "org.ow2.asm:asm": { "shasums": { - "jar": "adf46d5e34940bdf148ecdd26a9ee8eea94496a72034ff7141066b3eea5c4e9d", - "sources": "11dfd88129204be18c0f592f8e066d0c07d8a6bc001f6c7b2cce5ff0588d5d71" + "jar": "0df97574914aee92fd349d0cb4e00f3345d45b2c239e0bb50f0a90ead47888e0", + "sources": "829bc5eb0ccd705a7c8afbf7cdc4b7e9a9f733d3a1a954b9afffd99c8e063366" }, - "version": "9.7" + "version": "9.0" }, "org.ow2.asm:asm-analysis": { "shasums": { @@ -1042,9 +1034,6 @@ "io.opentelemetry:opentelemetry-api-incubator", "io.opentelemetry:opentelemetry-sdk-common" ], - "io.projectreactor:reactor-core": [ - "org.reactivestreams:reactive-streams" - ], "io.reactivex.rxjava3:rxjava": [ "org.reactivestreams:reactive-streams" ], @@ -1182,9 +1171,6 @@ "eu.neilalexander:jnacl" ] }, - "skipped": [ - "com.google.guava:listenablefuture:jar:sources" - ], "packages": { "com.beust:jcommander": [ "com.beust.ah", @@ -1957,9 +1943,6 @@ "net.bytebuddy.agent", "net.bytebuddy.agent.utility.nullability" ], - "net.bytebuddy:byte-buddy:jar:sources": [ - "net.bytebuddy.build" - ], "net.sf.saxon:Saxon-HE": [ "net.sf.saxon", "net.sf.saxon.dom", @@ -2063,8 +2046,7 @@ "org.apache.commons.lang3.text", "org.apache.commons.lang3.text.translate", "org.apache.commons.lang3.time", - "org.apache.commons.lang3.tuple", - "org.apache.commons.lang3.util" + "org.apache.commons.lang3.tuple" ], "org.apache.commons:commons-text": [ "org.apache.commons.text", @@ -2551,32 +2533,38 @@ "org.checkerframework.checker.calledmethods.qual", "org.checkerframework.checker.compilermsgs.qual", "org.checkerframework.checker.fenum.qual", + "org.checkerframework.checker.formatter", "org.checkerframework.checker.formatter.qual", "org.checkerframework.checker.guieffect.qual", "org.checkerframework.checker.i18n.qual", + "org.checkerframework.checker.i18nformatter", "org.checkerframework.checker.i18nformatter.qual", "org.checkerframework.checker.index.qual", "org.checkerframework.checker.initialization.qual", "org.checkerframework.checker.interning.qual", "org.checkerframework.checker.lock.qual", - "org.checkerframework.checker.mustcall.qual", + "org.checkerframework.checker.nullness", "org.checkerframework.checker.nullness.qual", "org.checkerframework.checker.optional.qual", "org.checkerframework.checker.propkey.qual", + "org.checkerframework.checker.regex", "org.checkerframework.checker.regex.qual", "org.checkerframework.checker.signature.qual", + "org.checkerframework.checker.signedness", "org.checkerframework.checker.signedness.qual", "org.checkerframework.checker.tainting.qual", + "org.checkerframework.checker.units", "org.checkerframework.checker.units.qual", "org.checkerframework.common.aliasing.qual", "org.checkerframework.common.initializedfields.qual", "org.checkerframework.common.reflection.qual", "org.checkerframework.common.returnsreceiver.qual", "org.checkerframework.common.subtyping.qual", - "org.checkerframework.common.util.count.report.qual", + "org.checkerframework.common.util.report.qual", "org.checkerframework.common.value.qual", "org.checkerframework.dataflow.qual", - "org.checkerframework.framework.qual" + "org.checkerframework.framework.qual", + "org.checkerframework.framework.util" ], "org.dom4j:dom4j": [ "org.dom4j", From 209e275840956e7005e7864ea12b9bac559303c2 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Sat, 30 Nov 2024 16:52:12 -0500 Subject: [PATCH 46/58] [dotnet] Add nullable reference annotations to `Platform` (#14834) --- .../Chromium/ChromiumDriverService.cs | 9 +- .../webdriver/Firefox/FirefoxDriverService.cs | 8 +- dotnet/src/webdriver/Platform.cs | 115 ++++++------------ 3 files changed, 39 insertions(+), 93 deletions(-) diff --git a/dotnet/src/webdriver/Chromium/ChromiumDriverService.cs b/dotnet/src/webdriver/Chromium/ChromiumDriverService.cs index 04a4e8994118f..95958e44812f4 100644 --- a/dotnet/src/webdriver/Chromium/ChromiumDriverService.cs +++ b/dotnet/src/webdriver/Chromium/ChromiumDriverService.cs @@ -208,7 +208,7 @@ protected static string ChromiumDriverServiceFileName(string fileName = DefaultC // straightforward as you might hope. // See: http://mono.wikia.com/wiki/Detecting_the_execution_platform // and https://msdn.microsoft.com/en-us/library/3a8hyw88(v=vs.110).aspx - const int PlatformMonoUnixValue = 128; + const PlatformID PlatformIDMonoUnix = (PlatformID)128; switch (Environment.OSVersion.Platform) { @@ -221,17 +221,14 @@ protected static string ChromiumDriverServiceFileName(string fileName = DefaultC case PlatformID.MacOSX: case PlatformID.Unix: + case PlatformIDMonoUnix: break; // Don't handle the Xbox case. Let default handle it. // case PlatformID.Xbox: // break; - default: - if ((int)Environment.OSVersion.Platform == PlatformMonoUnixValue) - { - break; - } + default: throw new WebDriverException("Unsupported platform: " + Environment.OSVersion.Platform); } diff --git a/dotnet/src/webdriver/Firefox/FirefoxDriverService.cs b/dotnet/src/webdriver/Firefox/FirefoxDriverService.cs index 6c58457461a22..3d35057e69e64 100644 --- a/dotnet/src/webdriver/Firefox/FirefoxDriverService.cs +++ b/dotnet/src/webdriver/Firefox/FirefoxDriverService.cs @@ -263,7 +263,7 @@ private static string FirefoxDriverServiceFileName() // straightforward as you might hope. // See: http://mono.wikia.com/wiki/Detecting_the_execution_platform // and https://msdn.microsoft.com/en-us/library/3a8hyw88(v=vs.110).aspx - const int PlatformMonoUnixValue = 128; + const PlatformID PlatformIDMonoUnix = (PlatformID)128; switch (Environment.OSVersion.Platform) { @@ -276,17 +276,13 @@ private static string FirefoxDriverServiceFileName() case PlatformID.MacOSX: case PlatformID.Unix: + case PlatformIDMonoUnix: break; // Don't handle the Xbox case. Let default handle it. // case PlatformID.Xbox: // break; default: - if ((int)Environment.OSVersion.Platform == PlatformMonoUnixValue) - { - break; - } - throw new WebDriverException("Unsupported platform: " + Environment.OSVersion.Platform); } diff --git a/dotnet/src/webdriver/Platform.cs b/dotnet/src/webdriver/Platform.cs index c143fd682d3b7..4ea2cc9be61c8 100644 --- a/dotnet/src/webdriver/Platform.cs +++ b/dotnet/src/webdriver/Platform.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium { /// @@ -84,10 +86,7 @@ public enum PlatformType /// public class Platform { - private static Platform current; - private PlatformType platformTypeValue; - private int major; - private int minor; + private static Platform? current; /// /// Initializes a new instance of the class for a specific platform type. @@ -95,39 +94,39 @@ public class Platform /// The platform type. public Platform(PlatformType typeValue) { - this.platformTypeValue = typeValue; + this.PlatformType = typeValue; } private Platform() { - this.major = Environment.OSVersion.Version.Major; - this.minor = Environment.OSVersion.Version.Minor; + this.MajorVersion = Environment.OSVersion.Version.Major; + this.MinorVersion = Environment.OSVersion.Version.Minor; switch (Environment.OSVersion.Platform) { case PlatformID.Win32NT: - if (this.major == 5) + if (this.MajorVersion == 5) { - this.platformTypeValue = PlatformType.XP; + this.PlatformType = PlatformType.XP; } - else if (this.major == 6) + else if (this.MajorVersion == 6) { - this.platformTypeValue = PlatformType.Vista; + this.PlatformType = PlatformType.Vista; } else { - this.platformTypeValue = PlatformType.Windows; + this.PlatformType = PlatformType.Windows; } break; // Thanks to a bug in Mono Mac and Linux will be treated the same https://bugzilla.novell.com/show_bug.cgi?id=515570 but adding this in case case PlatformID.MacOSX: - this.platformTypeValue = PlatformType.Mac; + this.PlatformType = PlatformType.Mac; break; case PlatformID.Unix: - this.platformTypeValue = PlatformType.Unix; + this.PlatformType = PlatformType.Unix; break; } } @@ -135,87 +134,44 @@ private Platform() /// /// Gets the current platform. /// - public static Platform CurrentPlatform - { - get - { - if (current == null) - { - current = new Platform(); - } - - return current; - } - } + public static Platform CurrentPlatform => current ??= new Platform(); /// /// Gets the major version of the platform operating system. /// - public int MajorVersion - { - get { return this.major; } - } + public int MajorVersion { get; } /// /// Gets the major version of the platform operating system. /// - public int MinorVersion - { - get { return this.minor; } - } + public int MinorVersion { get; } /// /// Gets the type of the platform. /// - public PlatformType PlatformType - { - get { return this.platformTypeValue; } - } + public PlatformType PlatformType { get; } /// /// Gets the value of the platform type for transmission using the JSON Wire Protocol. /// - public string ProtocolPlatformType - { - get { return this.platformTypeValue.ToString("G").ToUpperInvariant(); } - } + public string ProtocolPlatformType => this.PlatformType.ToString("G").ToUpperInvariant(); /// /// Compares the platform to the specified type. /// - /// A value to compare to. + /// A value to compare to. /// if the platforms match; otherwise . public bool IsPlatformType(PlatformType compareTo) { - bool platformIsType = false; - switch (compareTo) + return compareTo switch { - case PlatformType.Any: - platformIsType = true; - break; - - case PlatformType.Windows: - platformIsType = this.platformTypeValue == PlatformType.Windows || this.platformTypeValue == PlatformType.XP || this.platformTypeValue == PlatformType.Vista; - break; - - case PlatformType.Vista: - platformIsType = this.platformTypeValue == PlatformType.Windows || this.platformTypeValue == PlatformType.Vista; - break; - - case PlatformType.XP: - platformIsType = this.platformTypeValue == PlatformType.Windows || this.platformTypeValue == PlatformType.XP; - break; - - case PlatformType.Linux: - platformIsType = this.platformTypeValue == PlatformType.Linux || this.platformTypeValue == PlatformType.Unix; - break; - - default: - platformIsType = this.platformTypeValue == compareTo; - break; - } - - return platformIsType; + PlatformType.Any => true, + PlatformType.Windows => this.PlatformType is PlatformType.Windows or PlatformType.XP or PlatformType.Vista, + PlatformType.Vista => this.PlatformType is PlatformType.Windows or PlatformType.Vista, + PlatformType.XP => this.PlatformType is PlatformType.Windows or PlatformType.XP, + PlatformType.Linux => this.PlatformType is PlatformType.Linux or PlatformType.Unix, + _ => this.PlatformType == compareTo, + }; } /// @@ -224,7 +180,7 @@ public bool IsPlatformType(PlatformType compareTo) /// The string value for this platform type. public override string ToString() { - return this.platformTypeValue.ToString(); + return this.PlatformType.ToString(); } /// @@ -234,18 +190,15 @@ public override string ToString() /// The Platform object represented by the string name. internal static Platform FromString(string platformName) { - PlatformType platformTypeFromString = PlatformType.Any; - try + if (Enum.TryParse(platformName, ignoreCase: true, out PlatformType platformTypeFromString)) { - platformTypeFromString = (PlatformType)Enum.Parse(typeof(PlatformType), platformName, true); - } - catch (ArgumentException) - { - // If the requested platform string is not a valid platform type, - // ignore it and use PlatformType.Any. + return new Platform(platformTypeFromString); } - return new Platform(platformTypeFromString); + // If the requested platform string is not a valid platform type, + // ignore it and use PlatformType.Any. + + return new Platform(PlatformType.Any); } } } From b256c5f619d8c2686b0918bab148689e18eeaba4 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Sun, 1 Dec 2024 04:41:51 -0500 Subject: [PATCH 47/58] [dotnet] Fix Virtual Authenticator removal, annotate NRT (#14822) --- .../src/webdriver/VirtualAuth/Credential.cs | 82 ++++++++----------- .../VirtualAuth/IHasVirtualAuthenticator.cs | 14 ++++ .../VirtualAuthenticatorOptions.cs | 55 +++++++------ dotnet/src/webdriver/WebDriver.cs | 79 ++++++++++++++---- .../VirtualAuthn/VirtualAuthenticatorTest.cs | 56 ++++++++++++- 5 files changed, 195 insertions(+), 91 deletions(-) diff --git a/dotnet/src/webdriver/VirtualAuth/Credential.cs b/dotnet/src/webdriver/VirtualAuth/Credential.cs index 170677b12e035..57dbcbe76ff45 100644 --- a/dotnet/src/webdriver/VirtualAuth/Credential.cs +++ b/dotnet/src/webdriver/VirtualAuth/Credential.cs @@ -18,31 +18,30 @@ // using OpenQA.Selenium.Internal; +using System; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.VirtualAuth { /// /// A credential stored in a virtual authenticator. - /// Refer https://w3c.github.io/webauthn/#credential-parameters + /// Refer /// - public class Credential + public sealed class Credential { private readonly byte[] id; - private readonly bool isResidentCredential; - private readonly string rpId; - private readonly string privateKey; - private readonly byte[] userHandle; - private readonly int signCount; + private readonly byte[]? userHandle; - private Credential(byte[] id, bool isResidentCredential, string rpId, string privateKey, byte[] userHandle, int signCount) + private Credential(byte[] id, bool isResidentCredential, string rpId, string privateKey, byte[]? userHandle, int signCount) { - this.id = id; - this.isResidentCredential = isResidentCredential; - this.rpId = rpId; - this.privateKey = privateKey; + this.id = id ?? throw new ArgumentNullException(nameof(id)); + this.IsResidentCredential = isResidentCredential; + this.RpId = rpId ?? throw new ArgumentNullException(nameof(rpId)); + this.PrivateKey = privateKey ?? throw new ArgumentNullException(nameof(privateKey)); this.userHandle = userHandle; - this.signCount = signCount; + this.SignCount = signCount; } /// @@ -53,6 +52,7 @@ private Credential(byte[] id, bool isResidentCredential, string rpId, string pri /// The private Key for the credentials. /// The signature counter for the credentials. /// The created instance of the Credential class. + /// If , , or are . public static Credential CreateNonResidentCredential(byte[] id, string rpId, string privateKey, int signCount) { return new Credential(id, false, rpId, privateKey, null, signCount); @@ -67,6 +67,7 @@ public static Credential CreateNonResidentCredential(byte[] id, string rpId, str /// The user handle associated to the credential. /// The signature counter for the credentials. /// The created instance of the Credential class. + /// If , , or are . public static Credential CreateResidentCredential(byte[] id, string rpId, string privateKey, byte[] userHandle, int signCount) { return new Credential(id, true, rpId, privateKey, userHandle, signCount); @@ -75,50 +76,32 @@ public static Credential CreateResidentCredential(byte[] id, string rpId, string /// /// Gets the byte array of the ID of the credential. /// - public byte[] Id - { - get { return (byte[])id.Clone(); } - } + public byte[] Id => (byte[])id.Clone(); /// /// Gets a value indicating whether this Credential is a resident credential. /// - public bool IsResidentCredential - { - get { return this.isResidentCredential; } - } + public bool IsResidentCredential { get; } /// /// Gets the ID of the relying party of this credential. /// - public string RpId - { - get { return this.rpId; } - } + public string RpId { get; } /// /// Gets the private key of the credential. /// - public string PrivateKey - { - get { return this.privateKey; } - } + public string PrivateKey { get; } /// /// Gets the user handle of the credential. /// - public byte[] UserHandle - { - get { return userHandle == null ? null : (byte[])userHandle.Clone(); } - } + public byte[]? UserHandle => (byte[]?)userHandle?.Clone(); /// /// Gets the signature counter associated to the public key credential source. /// - public int SignCount - { - get { return this.signCount; } - } + public int SignCount { get; } /// /// Creates a Credential instance from a dictionary of values. @@ -127,13 +110,14 @@ public int SignCount /// The created instance of the Credential. public static Credential FromDictionary(Dictionary dictionary) { - return new Credential( - Base64UrlEncoder.DecodeBytes((string)dictionary["credentialId"]), - (bool)dictionary["isResidentCredential"], - dictionary.ContainsKey("rpId") ? (string)dictionary["rpId"] : null, - (string)dictionary["privateKey"], - dictionary.ContainsKey("userHandle") ? Base64UrlEncoder.DecodeBytes((string)dictionary["userHandle"]) : null, - (int)((long)dictionary["signCount"])); + byte[] id = Base64UrlEncoder.DecodeBytes((string)dictionary["credentialId"]); + bool isResidentCredential = (bool)dictionary["isResidentCredential"]; + string? rpId = dictionary.TryGetValue("rpId", out object? r) ? (string)r : null; + string privateKey = (string)dictionary["privateKey"]; + byte[]? userHandle = dictionary.TryGetValue("userHandle", out object? u) ? Base64UrlEncoder.DecodeBytes((string)u) : null; + int signCount = (int)(long)dictionary["signCount"]; + + return new Credential(id, isResidentCredential, rpId, privateKey, userHandle, signCount); } /// @@ -145,11 +129,11 @@ public Dictionary ToDictionary() Dictionary toReturn = new Dictionary(); toReturn["credentialId"] = Base64UrlEncoder.Encode(this.id); - toReturn["isResidentCredential"] = this.isResidentCredential; - toReturn["rpId"] = this.rpId; - toReturn["privateKey"] = this.privateKey; - toReturn["signCount"] = this.signCount; - if (this.userHandle != null) + toReturn["isResidentCredential"] = this.IsResidentCredential; + toReturn["rpId"] = this.RpId; + toReturn["privateKey"] = this.PrivateKey; + toReturn["signCount"] = this.SignCount; + if (this.userHandle is not null) { toReturn["userHandle"] = Base64UrlEncoder.Encode(this.userHandle); } diff --git a/dotnet/src/webdriver/VirtualAuth/IHasVirtualAuthenticator.cs b/dotnet/src/webdriver/VirtualAuth/IHasVirtualAuthenticator.cs index 92619ded68acb..2d8616416f90e 100644 --- a/dotnet/src/webdriver/VirtualAuth/IHasVirtualAuthenticator.cs +++ b/dotnet/src/webdriver/VirtualAuth/IHasVirtualAuthenticator.cs @@ -17,8 +17,11 @@ // under the License. // +using System; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.VirtualAuth { /// @@ -31,18 +34,23 @@ public interface IHasVirtualAuthenticator /// /// The VirtualAuthenticatorOptions to use in creating the authenticator. /// The ID of the added virtual authenticator. + /// If is . string AddVirtualAuthenticator(VirtualAuthenticatorOptions options); /// /// Removes a virtual authenticator. /// /// The ID of the virtual authenticator to remove. + /// If is . + /// If the specified virtual authenticator does not exist. void RemoveVirtualAuthenticator(string id); /// /// Adds a credential to the virtual authenticator. /// /// The credential to add to the authenticator. + /// If is . + /// If a Virtual Authenticator has not been added yet. void AddCredential(Credential credential); /// @@ -55,23 +63,29 @@ public interface IHasVirtualAuthenticator /// Removes a credential from the virtual authenticator. /// /// A byte array representing the ID of the credential to remove. + /// If is . + /// If a Virtual Authenticator has not been added yet. void RemoveCredential(byte[] credentialId); /// /// Removes a credential from the virtual authenticator. /// /// A string representing the ID of the credential to remove. + /// If is . + /// If a Virtual Authenticator has not been added yet. void RemoveCredential(string credentialId); /// /// Removes all credentials registered to this virtual authenticator. /// + /// If a Virtual Authenticator has not been added yet. void RemoveAllCredentials(); /// /// Sets whether or not a user is verified in this virtual authenticator. /// /// if the user is verified; otherwise . + /// If a Virtual Authenticator has not been added yet. void SetUserVerified(bool verified); } } diff --git a/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs b/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs index 6e118df89e037..502d1368f9d0f 100644 --- a/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs +++ b/dotnet/src/webdriver/VirtualAuth/VirtualAuthenticatorOptions.cs @@ -20,6 +20,8 @@ using System; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.VirtualAuth { /// @@ -78,10 +80,13 @@ public static class Transport private bool isUserVerified = false; /// - /// Sets the protocol the Virtual Authenticator speaks + /// Sets the Client to Authenticator Protocol (CTAP) this Virtual Authenticator speaks. /// - /// Valid protocol value - /// VirtualAuthenticatorOptions + /// The CTAP protocol identifier. + /// This options instance for chaining. + /// Valid protocols are available on the type. + /// If is not a supported protocol value. + /// public VirtualAuthenticatorOptions SetProtocol(string protocol) { if (string.Equals(Protocol.CTAP2, protocol) || string.Equals(Protocol.U2F, protocol)) @@ -92,15 +97,19 @@ public VirtualAuthenticatorOptions SetProtocol(string protocol) else { throw new ArgumentException("Enter a valid protocol value." + - "Refer to https://www.w3.org/TR/webauthn-2/#sctn-automation-virtual-authenticators for supported protocols."); + "Refer to https://www.w3.org/TR/webauthn-2/#sctn-automation-virtual-authenticators for supported protocols."); } } /// - /// Sets the transport authenticator needs to implement to communicate with clients + /// Sets the Authenticator Transport this Virtual Authenticator needs to implement, to communicate with clients. /// - /// Valid transport value - /// VirtualAuthenticatorOptions + /// Valid transport value. + /// + /// This options instance for chaining. + /// Valid protocols are available on the type. + /// If is not a supported transport value. + /// public VirtualAuthenticatorOptions SetTransport(string transport) { if (Transport.BLE == transport || Transport.INTERNAL == transport || Transport.NFC == transport || Transport.USB == transport) @@ -111,16 +120,15 @@ public VirtualAuthenticatorOptions SetTransport(string transport) else { throw new ArgumentException("Enter a valid transport value." + - "Refer to https://www.w3.org/TR/webauthn-2/#enum-transport for supported transport values."); + "Refer to https://www.w3.org/TR/webauthn-2/#enum-transport for supported transport values."); } } /// - /// If set to true the authenticator will support client-side discoverable credentials. - /// Refer https://w3c.github.io/webauthn/#client-side-discoverable-credential + /// If set to , the authenticator will support Client-side discoverable Credentials. /// - /// boolean value to set - /// VirtualAuthenticatorOptions + /// Whether authenticator will support client-side discoverable credentials. + /// This options instance for chaining. public VirtualAuthenticatorOptions SetHasResidentKey(bool hasResidentKey) { this.hasResidentKey = hasResidentKey; @@ -128,11 +136,10 @@ public VirtualAuthenticatorOptions SetHasResidentKey(bool hasResidentKey) } /// - /// If set to true, the authenticator supports user verification. - /// Refer https://w3c.github.io/webauthn/#user-verification. + /// If set to , the authenticator will support User Verification. /// - /// boolean value to set - /// + /// Whether the authenticator supports user verification. + /// This options instance for chaining. public VirtualAuthenticatorOptions SetHasUserVerification(bool hasUserVerification) { this.hasUserVerification = hasUserVerification; @@ -140,11 +147,10 @@ public VirtualAuthenticatorOptions SetHasUserVerification(bool hasUserVerificati } /// - /// If set to true, a user consent will always be granted. - /// Refer https://w3c.github.io/webauthn/#user-consent + /// If set to , a User Consent will always be granted. /// - /// boolean value to set - /// VirtualAuthenticatorOptions + /// Whether a user consent will always be granted. + /// This options instance for chaining. public VirtualAuthenticatorOptions SetIsUserConsenting(bool isUserConsenting) { this.isUserConsenting = isUserConsenting; @@ -152,11 +158,10 @@ public VirtualAuthenticatorOptions SetIsUserConsenting(bool isUserConsenting) } /// - /// If set to true, User Verification will always succeed. - /// Refer https://w3c.github.io/webauthn/#user-verification + /// If set to , User Verification will always succeed. /// - /// boolean value to set - /// VirtualAuthenticatorOptions + /// Whether User Verification will always succeed. + /// This options instance for chaining. public VirtualAuthenticatorOptions SetIsUserVerified(bool isUserVerified) { this.isUserVerified = isUserVerified; @@ -164,7 +169,7 @@ public VirtualAuthenticatorOptions SetIsUserVerified(bool isUserVerified) } /// - /// Serializes this set of options to a dictionary of key-value pairs. + /// Serializes this set of options into a dictionary of key-value pairs. /// /// The dictionary containing the values of this set of options. public Dictionary ToDictionary() diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index d9960ea97b235..9bcca8b28f8b3 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -1036,44 +1036,68 @@ private object ParseJavaScriptReturnValue(object responseValue) return returnValue; } +#nullable enable + /// /// Creates a Virtual Authenticator. /// - /// VirtualAuthenticator Options (https://w3c.github.io/webauthn/#sctn-automation-virtual-authenticators) + /// Virtual Authenticator Options. /// Authenticator id as string + /// If is . public string AddVirtualAuthenticator(VirtualAuthenticatorOptions options) { + if (options is null) + { + throw new ArgumentNullException(nameof(options)); + } + Response commandResponse = this.Execute(DriverCommand.AddVirtualAuthenticator, options.ToDictionary()); - string id = commandResponse.Value.ToString(); + string id = (string)commandResponse.Value!; this.AuthenticatorId = id; - return this.AuthenticatorId; + return id; } /// /// Removes the Virtual Authenticator /// - /// Id as string that uniquely identifies a Virtual Authenticator + /// Id as string that uniquely identifies a Virtual Authenticator. + /// If is . public void RemoveVirtualAuthenticator(string authenticatorId) { + if (authenticatorId is null) + { + throw new ArgumentNullException(nameof(authenticatorId)); + } + Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.AuthenticatorId); + parameters.Add("authenticatorId", authenticatorId); + this.Execute(DriverCommand.RemoveVirtualAuthenticator, parameters); this.AuthenticatorId = null; } /// - /// Gets the virtual authenticator ID for this WebDriver instance. + /// Gets the cached virtual authenticator ID, or if no authenticator ID is set. /// - public string AuthenticatorId { get; private set; } + public string? AuthenticatorId { get; private set; } /// /// Add a credential to the Virtual Authenticator/ /// /// The credential to be stored in the Virtual Authenticator + /// If is . + /// If a Virtual Authenticator has not been added yet. public void AddCredential(Credential credential) { + if (credential is null) + { + throw new ArgumentNullException(nameof(credential)); + } + + string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); + Dictionary parameters = new Dictionary(credential.ToDictionary()); - parameters.Add("authenticatorId", this.AuthenticatorId); + parameters.Add("authenticatorId", authenticatorId); this.Execute(driverCommandToExecute: DriverCommand.AddCredential, parameters); } @@ -1082,18 +1106,25 @@ public void AddCredential(Credential credential) /// Retrieves all the credentials stored in the Virtual Authenticator /// /// List of credentials + /// If a Virtual Authenticator has not been added yet. public List GetCredentials() { + string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); + Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.AuthenticatorId); + parameters.Add("authenticatorId", authenticatorId); - object[] commandResponse = (object[])this.Execute(driverCommandToExecute: DriverCommand.GetCredentials, parameters).Value; + Response getCredentialsResponse = this.Execute(driverCommandToExecute: DriverCommand.GetCredentials, parameters); - List credentials = new List(); + if (getCredentialsResponse.Value is not object?[] credentialsList) + { + throw new WebDriverException($"Get credentials call succeeded, but the response was not a list of credentials: {getCredentialsResponse.Value}"); + } - foreach (object dictionary in commandResponse) + List credentials = new List(credentialsList.Length); + foreach (object? dictionary in credentialsList) { - Credential credential = Credential.FromDictionary((Dictionary)dictionary); + Credential credential = Credential.FromDictionary((Dictionary)dictionary!); credentials.Add(credential); } @@ -1104,6 +1135,8 @@ public List GetCredentials() /// Removes the credential identified by the credentialId from the Virtual Authenticator. /// /// The id as byte array that uniquely identifies a credential + /// If is . + /// If a Virtual Authenticator has not been added yet. public void RemoveCredential(byte[] credentialId) { RemoveCredential(Base64UrlEncoder.Encode(credentialId)); @@ -1113,10 +1146,19 @@ public void RemoveCredential(byte[] credentialId) /// Removes the credential identified by the credentialId from the Virtual Authenticator. /// /// The id as string that uniquely identifies a credential + /// If is . + /// If a Virtual Authenticator has not been added yet. public void RemoveCredential(string credentialId) { + if (credentialId is null) + { + throw new ArgumentNullException(nameof(credentialId)); + } + + string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); + Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.AuthenticatorId); + parameters.Add("authenticatorId", authenticatorId); parameters.Add("credentialId", credentialId); this.Execute(driverCommandToExecute: DriverCommand.RemoveCredential, parameters); @@ -1125,10 +1167,13 @@ public void RemoveCredential(string credentialId) /// /// Removes all the credentials stored in the Virtual Authenticator. /// + /// If a Virtual Authenticator has not been added yet. public void RemoveAllCredentials() { + string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); + Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.AuthenticatorId); + parameters.Add("authenticatorId", authenticatorId); this.Execute(driverCommandToExecute: DriverCommand.RemoveAllCredentials, parameters); } @@ -1139,8 +1184,10 @@ public void RemoveAllCredentials() /// The boolean value representing value to be set public void SetUserVerified(bool verified) { + string authenticatorId = this.AuthenticatorId ?? throw new InvalidOperationException("Virtual Authenticator needs to be added before it can perform operations"); + Dictionary parameters = new Dictionary(); - parameters.Add("authenticatorId", this.AuthenticatorId); + parameters.Add("authenticatorId", authenticatorId); parameters.Add("isUserVerified", verified); this.Execute(driverCommandToExecute: DriverCommand.SetUserVerified, parameters); diff --git a/dotnet/test/common/VirtualAuthn/VirtualAuthenticatorTest.cs b/dotnet/test/common/VirtualAuthn/VirtualAuthenticatorTest.cs index e6c16e11b673a..c46d541dcb548 100644 --- a/dotnet/test/common/VirtualAuthn/VirtualAuthenticatorTest.cs +++ b/dotnet/test/common/VirtualAuthn/VirtualAuthenticatorTest.cs @@ -194,6 +194,26 @@ public void ShouldRemoveAuthenticator() Assert.IsNull(webDriver.AuthenticatorId); } + [Test] + [NeedsFreshDriver(IsCreatedAfterTest = true)] + [IgnoreBrowser(Selenium.Browser.IE, "IE does not support Virtual Authenticator")] + [IgnoreBrowser(Selenium.Browser.Firefox, "Firefox does not support Virtual Authenticator")] + [IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Virtual Authenticator")] + public void ShouldSupportMultipleVirtualAuthenticatorsAtOnce() + { + VirtualAuthenticatorOptions options = new VirtualAuthenticatorOptions(); + + string authenticatorId1 = webDriver.AddVirtualAuthenticator(options); + Assert.That(webDriver.AuthenticatorId, Is.EqualTo(authenticatorId1)); + + string authenticatorId2 = webDriver.AddVirtualAuthenticator(options); + + webDriver.RemoveVirtualAuthenticator(authenticatorId1); + webDriver.RemoveVirtualAuthenticator(authenticatorId2); + + Assert.IsNull(webDriver.AuthenticatorId); + } + [Test] [NeedsFreshDriver(IsCreatedAfterTest = true)] [IgnoreBrowser(Selenium.Browser.IE, "IE does not support Virtual Authenticator")] @@ -302,7 +322,9 @@ public void AddResidentCredentialNotSupportedWhenAuthenticatorUsesU2FProtocol() byte[] userHandle = { 1 }; Credential credential = Credential.CreateResidentCredential( credentialId, "localhost", base64EncodedEC256PK, userHandle, /*signCount=*/0); - Assert.Throws(() => webDriver.AddCredential(credential)); + Assert.That( + () => webDriver.AddCredential(credential), + Throws.TypeOf().With.Message.Contains("The Authenticator does not support Resident Credentials.")); } [Test] @@ -492,5 +514,37 @@ public void testSetUserVerified() Assert.True(error.StartsWith("NotAllowedError")); } + + [Test] + [NeedsFreshDriver(IsCreatedAfterTest = true)] + [IgnoreBrowser(Selenium.Browser.IE, "IE does not support Virtual Authenticator")] + [IgnoreBrowser(Selenium.Browser.Firefox, "Firefox does not support Virtual Authenticator")] + [IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Virtual Authenticator")] + public void ShouldThrowOnInvalidArguments() + { + Assert.That( + () => webDriver.AddVirtualAuthenticator(null), + Throws.ArgumentNullException); + + Assert.That( + () => webDriver.RemoveVirtualAuthenticator(null), + Throws.ArgumentNullException); + + Assert.That( + () => webDriver.AddCredential(null), + Throws.ArgumentNullException); + + Assert.That( + () => webDriver.RemoveCredential((byte[])null), + Throws.ArgumentNullException); + + Assert.That( + () => webDriver.RemoveCredential((string)null), + Throws.ArgumentNullException); + + Assert.That( + () => webDriver.RemoveVirtualAuthenticator("non-existant"), + Throws.TypeOf()); + } } } From 51e72677c73f11bacb1b7a81a306d57989efd136 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Sun, 1 Dec 2024 15:49:50 -0500 Subject: [PATCH 48/58] [dotnet] Annotate Nullable Reference Types on `OpenQA.Selenium.Internal` (#14840) --- dotnet/src/webdriver/ICapabilities.cs | 4 +- .../src/webdriver/Internal/AndroidOptions.cs | 26 +++-------- .../src/webdriver/Internal/FileUtilities.cs | 12 ++--- .../src/webdriver/Internal/IFindsElement.cs | 2 + .../Internal/IHasCapabilitiesDictionary.cs | 2 + .../webdriver/Internal/ResourceUtilities.cs | 33 ++++++-------- .../Internal/ResponseValueJsonConverter.cs | 14 +++--- .../Internal/ReturnedCapabilities.cs | 45 +++++++------------ 8 files changed, 59 insertions(+), 79 deletions(-) diff --git a/dotnet/src/webdriver/ICapabilities.cs b/dotnet/src/webdriver/ICapabilities.cs index 1a66162ffb098..df0c8a776c77e 100644 --- a/dotnet/src/webdriver/ICapabilities.cs +++ b/dotnet/src/webdriver/ICapabilities.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium { /// @@ -49,6 +51,6 @@ public interface ICapabilities /// The capability to get. /// An object associated with the capability, or /// if the capability is not set on the browser. - object GetCapability(string capability); + object? GetCapability(string capability); } } diff --git a/dotnet/src/webdriver/Internal/AndroidOptions.cs b/dotnet/src/webdriver/Internal/AndroidOptions.cs index e2d9e5b94763c..d002d1e6acc81 100644 --- a/dotnet/src/webdriver/Internal/AndroidOptions.cs +++ b/dotnet/src/webdriver/Internal/AndroidOptions.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Internal { /// @@ -26,14 +28,11 @@ namespace OpenQA.Selenium.Internal /// public class AndroidOptions { - private string androidPackage; - private string androidDeviceSerial; - private string androidActivity; - /// /// Initializes a new instance of the class. /// /// + /// If is or . protected AndroidOptions(string androidPackage) { if (string.IsNullOrEmpty(androidPackage)) @@ -41,33 +40,22 @@ protected AndroidOptions(string androidPackage) throw new ArgumentException("The Android package cannot be null or the empty string", nameof(androidPackage)); } - this.androidPackage = androidPackage; + this.AndroidPackage = androidPackage; } /// /// The package name of the application to automate. /// - public string AndroidPackage - { - get { return this.androidPackage; } - } + public string AndroidPackage { get; } /// /// The serial number of the device on which to launch the application. /// - public string AndroidDeviceSerial - { - get { return this.androidDeviceSerial; } - set { this.androidDeviceSerial = value; } - } + public string? AndroidDeviceSerial { get; set; } /// /// Gets or sets the name of the Activity hosting the app. /// - public string AndroidActivity - { - get { return this.androidActivity; } - set { this.androidActivity = value; } - } + public string? AndroidActivity { get; set; } } } diff --git a/dotnet/src/webdriver/Internal/FileUtilities.cs b/dotnet/src/webdriver/Internal/FileUtilities.cs index 0d83a6927aeca..d288a58e5f296 100644 --- a/dotnet/src/webdriver/Internal/FileUtilities.cs +++ b/dotnet/src/webdriver/Internal/FileUtilities.cs @@ -23,6 +23,8 @@ using System.IO; using System.Reflection; +#nullable enable + namespace OpenQA.Selenium.Internal { /// @@ -40,7 +42,7 @@ internal static class FileUtilities /// if the copy is completed; otherwise . public static bool CopyDirectory(string sourceDirectory, string destinationDirectory) { - bool copyComplete = false; + bool copyComplete; DirectoryInfo sourceDirectoryInfo = new DirectoryInfo(sourceDirectory); DirectoryInfo destinationDirectoryInfo = new DirectoryInfo(destinationDirectory); @@ -132,7 +134,7 @@ public static string FindFile(string fileName) // If it's not in the same directory as the executing assembly, // try looking in the system path. - string systemPath = Environment.GetEnvironmentVariable("PATH"); + string? systemPath = Environment.GetEnvironmentVariable("PATH"); if (!string.IsNullOrEmpty(systemPath)) { string expandedPath = Environment.ExpandEnvironmentVariables(systemPath); @@ -165,7 +167,7 @@ public static string FindFile(string fileName) public static string GetCurrentDirectory() { Assembly executingAssembly = typeof(FileUtilities).Assembly; - string location = null; + string? location = null; // Make sure not to call Path.GetDirectoryName if assembly location is null or empty if (!string.IsNullOrEmpty(executingAssembly.Location)) @@ -184,13 +186,13 @@ public static string GetCurrentDirectory() location = Directory.GetCurrentDirectory(); } - string currentDirectory = location; + string currentDirectory = location!; // If we're shadow copying, get the directory from the codebase instead if (AppDomain.CurrentDomain.ShadowCopyFiles) { Uri uri = new Uri(executingAssembly.CodeBase); - currentDirectory = Path.GetDirectoryName(uri.LocalPath); + currentDirectory = Path.GetDirectoryName(uri.LocalPath)!; } return currentDirectory; diff --git a/dotnet/src/webdriver/Internal/IFindsElement.cs b/dotnet/src/webdriver/Internal/IFindsElement.cs index a43055f9c91bd..7bcd08751a8fb 100644 --- a/dotnet/src/webdriver/Internal/IFindsElement.cs +++ b/dotnet/src/webdriver/Internal/IFindsElement.cs @@ -19,6 +19,8 @@ using System.Collections.ObjectModel; +#nullable enable + namespace OpenQA.Selenium.Internal { /// diff --git a/dotnet/src/webdriver/Internal/IHasCapabilitiesDictionary.cs b/dotnet/src/webdriver/Internal/IHasCapabilitiesDictionary.cs index 8c281818c4e0d..8723b5b11e580 100644 --- a/dotnet/src/webdriver/Internal/IHasCapabilitiesDictionary.cs +++ b/dotnet/src/webdriver/Internal/IHasCapabilitiesDictionary.cs @@ -19,6 +19,8 @@ using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.Internal { /// diff --git a/dotnet/src/webdriver/Internal/ResourceUtilities.cs b/dotnet/src/webdriver/Internal/ResourceUtilities.cs index 2f854a70214d4..0f22a33681c83 100644 --- a/dotnet/src/webdriver/Internal/ResourceUtilities.cs +++ b/dotnet/src/webdriver/Internal/ResourceUtilities.cs @@ -22,6 +22,8 @@ using System.Reflection; using System.Runtime.InteropServices; +#nullable enable + namespace OpenQA.Selenium.Internal { /// @@ -29,8 +31,8 @@ namespace OpenQA.Selenium.Internal /// internal static class ResourceUtilities { - private static string productVersion; - private static string platformFamily; + private static string? productVersion; + private static string? platformFamily; /// /// Gets a string representing the informational version of the Selenium product. @@ -60,18 +62,7 @@ public static string ProductVersion /// /// Gets a string representing the platform family on which the Selenium assembly is executing. /// - public static string PlatformFamily - { - get - { - if (string.IsNullOrEmpty(platformFamily)) - { - platformFamily = GetPlatformString(); - } - - return platformFamily; - } - } + public static string PlatformFamily => platformFamily ??= GetPlatformString(); /// /// Gets a that contains the resource to use. @@ -94,7 +85,7 @@ public static string PlatformFamily /// public static Stream GetResourceStream(string fileName, string resourceId) { - Stream resourceStream = null; + Stream? resourceStream; string resourceFilePath = Path.Combine(FileUtilities.GetCurrentDirectory(), Path.GetFileName(fileName)); if (File.Exists(resourceFilePath)) { @@ -125,20 +116,22 @@ public static Stream GetResourceStream(string fileName, string resourceId) private static string GetPlatformString() { - string platformName = "unknown"; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - platformName = "windows"; + return "windows"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - platformName = "linux"; + return "linux"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - platformName = "mac"; + return "mac"; + } + else + { + return "unknown"; } - return platformName; } } } diff --git a/dotnet/src/webdriver/Internal/ResponseValueJsonConverter.cs b/dotnet/src/webdriver/Internal/ResponseValueJsonConverter.cs index 2732cebbd13a2..66b962b2878a8 100644 --- a/dotnet/src/webdriver/Internal/ResponseValueJsonConverter.cs +++ b/dotnet/src/webdriver/Internal/ResponseValueJsonConverter.cs @@ -22,6 +22,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.Internal { /// @@ -29,7 +31,7 @@ namespace OpenQA.Selenium.Internal /// internal class ResponseValueJsonConverter : JsonConverter { - public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return ProcessReadToken(ref reader, options); } @@ -67,19 +69,19 @@ public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOp } } - private static object ProcessReadToken(ref Utf8JsonReader reader, JsonSerializerOptions options) + private static object? ProcessReadToken(ref Utf8JsonReader reader, JsonSerializerOptions options) { // Recursively processes a token. This is required for elements that next other elements. - object processedObject; + object? processedObject; switch (reader.TokenType) { case JsonTokenType.StartObject: { - Dictionary dictionaryValue = []; + Dictionary dictionaryValue = []; while (reader.Read() && reader.TokenType != JsonTokenType.EndObject) { - string elementKey = reader.GetString(); + string elementKey = reader.GetString()!; reader.Read(); dictionaryValue.Add(elementKey, ProcessReadToken(ref reader, options)); } @@ -90,7 +92,7 @@ private static object ProcessReadToken(ref Utf8JsonReader reader, JsonSerializer case JsonTokenType.StartArray: { - List arrayValue = []; + List arrayValue = []; while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) { arrayValue.Add(ProcessReadToken(ref reader, options)); diff --git a/dotnet/src/webdriver/Internal/ReturnedCapabilities.cs b/dotnet/src/webdriver/Internal/ReturnedCapabilities.cs index 3bac423108923..2932b75273e84 100644 --- a/dotnet/src/webdriver/Internal/ReturnedCapabilities.cs +++ b/dotnet/src/webdriver/Internal/ReturnedCapabilities.cs @@ -22,13 +22,15 @@ using System.Collections.ObjectModel; using System.Globalization; +#nullable enable + namespace OpenQA.Selenium.Internal { /// /// Class to Create the capabilities of the browser you require for . /// If you wish to use default values use the static methods /// - internal class ReturnedCapabilities : ICapabilities, IHasCapabilitiesDictionary + internal sealed class ReturnedCapabilities : ICapabilities, IHasCapabilitiesDictionary { private readonly Dictionary capabilities = new Dictionary(); @@ -43,32 +45,26 @@ public ReturnedCapabilities() /// Initializes a new instance of the class /// /// Dictionary of items for the remote driver - public ReturnedCapabilities(Dictionary rawMap) + public ReturnedCapabilities(Dictionary? rawMap) { if (rawMap != null) { - foreach (string key in rawMap.Keys) + foreach (KeyValuePair rawItem in rawMap) { - this.capabilities[key] = rawMap[key]; + this.capabilities[rawItem.Key] = rawItem.Value; } } } /// - /// Gets the browser name + /// Gets the browser name, or if not specified. /// public string BrowserName { get { - string name = string.Empty; - object capabilityValue = this.GetCapability(CapabilityType.BrowserName); - if (capabilityValue != null) - { - name = capabilityValue.ToString(); - } - - return name; + object? capabilityValue = this.GetCapability(CapabilityType.BrowserName); + return capabilityValue?.ToString() ?? string.Empty; } } @@ -84,30 +80,24 @@ public object this[string capabilityName] { get { - if (!this.capabilities.ContainsKey(capabilityName)) + if (!this.capabilities.TryGetValue(capabilityName, out object? capabilityValue)) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The capability {0} is not present in this set of capabilities", capabilityName)); } - return this.capabilities[capabilityName]; + return capabilityValue; } } /// /// Gets the underlying Dictionary for a given set of capabilities. /// - IDictionary IHasCapabilitiesDictionary.CapabilitiesDictionary - { - get { return this.CapabilitiesDictionary; } - } + IDictionary IHasCapabilitiesDictionary.CapabilitiesDictionary => this.CapabilitiesDictionary; /// /// Gets the internal capabilities dictionary. /// - internal IDictionary CapabilitiesDictionary - { - get { return new ReadOnlyDictionary(this.capabilities); } - } + internal IDictionary CapabilitiesDictionary => new ReadOnlyDictionary(this.capabilities); /// /// Gets a value indicating whether the browser has a given capability. @@ -125,15 +115,14 @@ public bool HasCapability(string capability) /// The capability to get. /// An object associated with the capability, or /// if the capability is not set on the browser. - public object GetCapability(string capability) + public object? GetCapability(string capability) { - object capabilityValue = null; - if (this.capabilities.ContainsKey(capability)) + if (this.capabilities.TryGetValue(capability, out object? capabilityValue)) { - capabilityValue = this.capabilities[capability]; + return capabilityValue; } - return capabilityValue; + return null; } /// From 4f07e4a4b7e4e415ad0596a3c7fcbd776cd57f57 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Sun, 1 Dec 2024 16:52:39 -0500 Subject: [PATCH 49/58] [dotnet] Annotate nullable reference types in internal logging (#14819) --- .../Internal/Logging/ConsoleLogHandler.cs | 2 ++ .../Internal/Logging/FileLogHandler.cs | 8 +++-- .../webdriver/Internal/Logging/ILogContext.cs | 2 ++ .../webdriver/Internal/Logging/ILogHandler.cs | 2 ++ .../Internal/Logging/ILogHandlerList.cs | 2 ++ .../src/webdriver/Internal/Logging/ILogger.cs | 2 ++ dotnet/src/webdriver/Internal/Logging/Log.cs | 14 ++++---- .../webdriver/Internal/Logging/LogContext.cs | 17 +++++----- .../Internal/Logging/LogContextManager.cs | 32 ++++++------------- .../webdriver/Internal/Logging/LogEvent.cs | 5 ++- .../Internal/Logging/LogEventLevel.cs | 2 ++ .../Internal/Logging/LogHandlerList.cs | 4 ++- .../src/webdriver/Internal/Logging/Logger.cs | 4 ++- 13 files changed, 51 insertions(+), 45 deletions(-) diff --git a/dotnet/src/webdriver/Internal/Logging/ConsoleLogHandler.cs b/dotnet/src/webdriver/Internal/Logging/ConsoleLogHandler.cs index 32a51421bf524..30a1a36efe128 100644 --- a/dotnet/src/webdriver/Internal/Logging/ConsoleLogHandler.cs +++ b/dotnet/src/webdriver/Internal/Logging/ConsoleLogHandler.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// diff --git a/dotnet/src/webdriver/Internal/Logging/FileLogHandler.cs b/dotnet/src/webdriver/Internal/Logging/FileLogHandler.cs index 8c92cf46aa3b4..7bb673486f793 100644 --- a/dotnet/src/webdriver/Internal/Logging/FileLogHandler.cs +++ b/dotnet/src/webdriver/Internal/Logging/FileLogHandler.cs @@ -20,6 +20,8 @@ using System; using System.IO; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// @@ -40,6 +42,7 @@ public class FileLogHandler : ILogHandler, IDisposable /// Initializes a new instance of the class with the specified file path. /// /// The path of the log file. + /// If is or . public FileLogHandler(string filePath) : this(filePath, overwrite: true) { @@ -51,6 +54,7 @@ public FileLogHandler(string filePath) /// /// The path of the log file. /// Specifies whether the file should be overwritten if it exists on the disk. + /// If is or . public FileLogHandler(string filePath, bool overwrite) { if (string.IsNullOrEmpty(filePath)) throw new ArgumentException("File log path cannot be null or empty.", nameof(filePath)); @@ -112,9 +116,9 @@ protected virtual void Dispose(bool disposing) if (disposing) { _streamWriter?.Dispose(); - _streamWriter = null; + _streamWriter = null!; _fileStream?.Dispose(); - _fileStream = null; + _fileStream = null!; } _isDisposed = true; diff --git a/dotnet/src/webdriver/Internal/Logging/ILogContext.cs b/dotnet/src/webdriver/Internal/Logging/ILogContext.cs index d1cc52cae4509..321c2bc99bd07 100644 --- a/dotnet/src/webdriver/Internal/Logging/ILogContext.cs +++ b/dotnet/src/webdriver/Internal/Logging/ILogContext.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// diff --git a/dotnet/src/webdriver/Internal/Logging/ILogHandler.cs b/dotnet/src/webdriver/Internal/Logging/ILogHandler.cs index 59c8133d007b3..c7ab4cc7bb0c1 100644 --- a/dotnet/src/webdriver/Internal/Logging/ILogHandler.cs +++ b/dotnet/src/webdriver/Internal/Logging/ILogHandler.cs @@ -17,6 +17,8 @@ // under the License. // +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// diff --git a/dotnet/src/webdriver/Internal/Logging/ILogHandlerList.cs b/dotnet/src/webdriver/Internal/Logging/ILogHandlerList.cs index f27b10a53b416..4930613c86957 100644 --- a/dotnet/src/webdriver/Internal/Logging/ILogHandlerList.cs +++ b/dotnet/src/webdriver/Internal/Logging/ILogHandlerList.cs @@ -19,6 +19,8 @@ using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// diff --git a/dotnet/src/webdriver/Internal/Logging/ILogger.cs b/dotnet/src/webdriver/Internal/Logging/ILogger.cs index a92a43e0d8445..ab2713722894b 100644 --- a/dotnet/src/webdriver/Internal/Logging/ILogger.cs +++ b/dotnet/src/webdriver/Internal/Logging/ILogger.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// diff --git a/dotnet/src/webdriver/Internal/Logging/Log.cs b/dotnet/src/webdriver/Internal/Logging/Log.cs index 884e147c8659a..01b40ac2bc9fd 100644 --- a/dotnet/src/webdriver/Internal/Logging/Log.cs +++ b/dotnet/src/webdriver/Internal/Logging/Log.cs @@ -18,6 +18,9 @@ // using System; +using System.Diagnostics.CodeAnalysis; + +#nullable enable namespace OpenQA.Selenium.Internal.Logging { @@ -65,16 +68,11 @@ public static ILogContext CreateContext(LogEventLevel minimumLevel) /// /// Gets or sets the current log context. /// + [AllowNull] internal static ILogContext CurrentContext { - get - { - return _logContextManager.CurrentContext; - } - set - { - _logContextManager.CurrentContext = value; - } + get => _logContextManager.CurrentContext; + set => _logContextManager.CurrentContext = value; } /// diff --git a/dotnet/src/webdriver/Internal/Logging/LogContext.cs b/dotnet/src/webdriver/Internal/Logging/LogContext.cs index ccf902fb9b35b..bb4d9feede2c5 100644 --- a/dotnet/src/webdriver/Internal/Logging/LogContext.cs +++ b/dotnet/src/webdriver/Internal/Logging/LogContext.cs @@ -22,6 +22,8 @@ using System.Collections.Generic; using System.Linq; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// @@ -30,15 +32,15 @@ namespace OpenQA.Selenium.Internal.Logging /// internal class LogContext : ILogContext { - private ConcurrentDictionary _loggers; + private ConcurrentDictionary? _loggers; private LogEventLevel _level; - private readonly ILogContext _parentLogContext; + private readonly ILogContext? _parentLogContext; private readonly Lazy _lazyLogHandlerList; - public LogContext(LogEventLevel level, ILogContext parentLogContext, ConcurrentDictionary loggers, IEnumerable handlers) + public LogContext(LogEventLevel level, ILogContext? parentLogContext, ConcurrentDictionary? loggers, IEnumerable? handlers) { _level = level; @@ -63,7 +65,7 @@ public ILogContext CreateContext() public ILogContext CreateContext(LogEventLevel minimumLevel) { - ConcurrentDictionary loggers = null; + ConcurrentDictionary? loggers = null; if (_loggers != null) { @@ -89,12 +91,9 @@ public ILogger GetLogger(Type type) throw new ArgumentNullException(nameof(type)); } - if (_loggers is null) - { - _loggers = new ConcurrentDictionary(); - } + _loggers ??= new ConcurrentDictionary(); - return _loggers.GetOrAdd(type, _ => new Logger(type, _level)); + return _loggers.GetOrAdd(type, type => new Logger(type, _level)); } public bool IsEnabled(ILogger logger, LogEventLevel level) diff --git a/dotnet/src/webdriver/Internal/Logging/LogContextManager.cs b/dotnet/src/webdriver/Internal/Logging/LogContextManager.cs index 41594f1125447..834e806d8b74a 100644 --- a/dotnet/src/webdriver/Internal/Logging/LogContextManager.cs +++ b/dotnet/src/webdriver/Internal/Logging/LogContextManager.cs @@ -17,45 +17,31 @@ // under the License. // +using System.Diagnostics.CodeAnalysis; using System.Threading; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { internal class LogContextManager { - private readonly ILogContext _globalLogContext; - - private readonly AsyncLocal _currentAmbientLogContext = new AsyncLocal(); + private readonly AsyncLocal _currentAmbientLogContext = new AsyncLocal(); public LogContextManager() { var defaulConsoleLogHandler = new ConsoleLogHandler(); - _globalLogContext = new LogContext(LogEventLevel.Info, null, null, new[] { defaulConsoleLogHandler }); + GlobalContext = new LogContext(LogEventLevel.Info, null, null, new[] { defaulConsoleLogHandler }); } - public ILogContext GlobalContext - { - get { return _globalLogContext; } - } + public ILogContext GlobalContext { get; } + [AllowNull] public ILogContext CurrentContext { - get - { - if (_currentAmbientLogContext.Value is null) - { - return _globalLogContext; - } - else - { - return _currentAmbientLogContext.Value; - } - } - set - { - _currentAmbientLogContext.Value = value; - } + get => _currentAmbientLogContext.Value ?? GlobalContext; + set => _currentAmbientLogContext.Value = value; } } } diff --git a/dotnet/src/webdriver/Internal/Logging/LogEvent.cs b/dotnet/src/webdriver/Internal/Logging/LogEvent.cs index 2a4f9daaf27f9..2fad19a93dc2b 100644 --- a/dotnet/src/webdriver/Internal/Logging/LogEvent.cs +++ b/dotnet/src/webdriver/Internal/Logging/LogEvent.cs @@ -19,6 +19,8 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// @@ -33,9 +35,10 @@ public sealed class LogEvent /// The timestamp of the log event. /// The level of the log event. /// The message of the log event. + /// If is . public LogEvent(Type issuedBy, DateTimeOffset timestamp, LogEventLevel level, string message) { - IssuedBy = issuedBy; + IssuedBy = issuedBy ?? throw new ArgumentNullException(nameof(issuedBy)); Timestamp = timestamp; Level = level; Message = message; diff --git a/dotnet/src/webdriver/Internal/Logging/LogEventLevel.cs b/dotnet/src/webdriver/Internal/Logging/LogEventLevel.cs index af8b728f0d326..57090b75de4e7 100644 --- a/dotnet/src/webdriver/Internal/Logging/LogEventLevel.cs +++ b/dotnet/src/webdriver/Internal/Logging/LogEventLevel.cs @@ -17,6 +17,8 @@ // under the License. // +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// diff --git a/dotnet/src/webdriver/Internal/Logging/LogHandlerList.cs b/dotnet/src/webdriver/Internal/Logging/LogHandlerList.cs index 7c75c36f4b2cf..9f05d3d5c52fa 100644 --- a/dotnet/src/webdriver/Internal/Logging/LogHandlerList.cs +++ b/dotnet/src/webdriver/Internal/Logging/LogHandlerList.cs @@ -19,13 +19,15 @@ using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// /// Represents a list of log handlers. /// /// - internal class LogHandlerList : List, ILogHandlerList + internal sealed class LogHandlerList : List, ILogHandlerList { private readonly ILogContext _logContext; diff --git a/dotnet/src/webdriver/Internal/Logging/Logger.cs b/dotnet/src/webdriver/Internal/Logging/Logger.cs index 0c92d0c0f299f..058d7944af153 100644 --- a/dotnet/src/webdriver/Internal/Logging/Logger.cs +++ b/dotnet/src/webdriver/Internal/Logging/Logger.cs @@ -19,13 +19,15 @@ using System; +#nullable enable + namespace OpenQA.Selenium.Internal.Logging { /// /// The implementation of the interface through which log messages are emitted. /// /// - internal class Logger : ILogger + internal sealed class Logger : ILogger { public Logger(Type issuer, LogEventLevel level) { From dd8c914110a7162511b295c145d94870997301ad Mon Sep 17 00:00:00 2001 From: Viet Nguyen Duc Date: Mon, 2 Dec 2024 20:11:04 +0700 Subject: [PATCH 50/58] [py] Update README command install source distribution from PyPI Follow https://packaging.python.org/en/latest/discussions/setup-py-deprecated/ --- py/docs/source/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/docs/source/index.rst b/py/docs/source/index.rst index 54123b5d600ca..9f8c9ed892d56 100755 --- a/py/docs/source/index.rst +++ b/py/docs/source/index.rst @@ -35,7 +35,7 @@ If you have `pip `_ on your system, you can simply install Alternately, you can download the source distribution from `PyPI `, unarchive it, and run:: - python setup.py install + python -m pip install . Note: You may want to consider using `virtualenv `_ to create isolated Python environments. From 901dc6ce912ea3ec92b680342f4a093726a73d79 Mon Sep 17 00:00:00 2001 From: Augustin Gottlieb <33221555+aguspe@users.noreply.github.com> Date: Tue, 3 Dec 2024 07:41:16 +0100 Subject: [PATCH 51/58] [rb] Add tests for the cookie named, and updates type (#14843) * add tests for the cookie named, and updates type * update gemfile lock --- rb/Gemfile.lock | 4 +--- rb/lib/selenium/webdriver/common/manager.rb | 2 +- rb/sig/lib/selenium/webdriver/common/manager.rbs | 4 ++-- rb/spec/integration/selenium/webdriver/manager_spec.rb | 5 +++++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/rb/Gemfile.lock b/rb/Gemfile.lock index 3c9f67c9bf9f8..b09123411d0c7 100644 --- a/rb/Gemfile.lock +++ b/rb/Gemfile.lock @@ -13,7 +13,7 @@ PATH GEM remote: https://rubygems.org/ specs: - activesupport (8.0.0) + activesupport (7.2.2) base64 benchmark (>= 0.3) bigdecimal @@ -25,7 +25,6 @@ GEM minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) - uri (>= 0.13.1) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) ast (2.4.2) @@ -162,7 +161,6 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.6.0) - uri (1.0.2) webmock (3.24.0) addressable (>= 2.8.0) crack (>= 0.3.2) diff --git a/rb/lib/selenium/webdriver/common/manager.rb b/rb/lib/selenium/webdriver/common/manager.rb index 6ba94fca8d829..d080e0ead6ef7 100644 --- a/rb/lib/selenium/webdriver/common/manager.rb +++ b/rb/lib/selenium/webdriver/common/manager.rb @@ -65,7 +65,7 @@ def add_cookie(opts = {}) # Get the cookie with the given name # # @param [String] name the name of the cookie - # @return [Hash, nil] the cookie, or nil if it wasn't found. + # @return [Hash, nil] the cookie, or throws a NoSuchCookieError if it wasn't found. # def cookie_named(name) diff --git a/rb/sig/lib/selenium/webdriver/common/manager.rbs b/rb/sig/lib/selenium/webdriver/common/manager.rbs index bf61f3e18c4b4..bb214a709a84b 100644 --- a/rb/sig/lib/selenium/webdriver/common/manager.rbs +++ b/rb/sig/lib/selenium/webdriver/common/manager.rbs @@ -11,7 +11,7 @@ module Selenium def add_cookie: (?Hash[Symbol, untyped] opts) -> void - def cookie_named: (String name) -> Hash[Symbol, untyped] + def cookie_named: (String name) -> (Hash[Symbol, untyped] | Error::NoSuchCookieError) def delete_cookie: (String name) -> String @@ -33,7 +33,7 @@ module Selenium def strip_port: (String str) -> String? - def convert_cookie: (Hash[String, untyped] cookie) -> Hash[Symbol, untyped] + def convert_cookie: (String) -> (Hash[Symbol, untyped] | Error::NoSuchCookieError) end end end diff --git a/rb/spec/integration/selenium/webdriver/manager_spec.rb b/rb/spec/integration/selenium/webdriver/manager_spec.rb index f06afd7302cc9..d8d9d791ddc74 100644 --- a/rb/spec/integration/selenium/webdriver/manager_spec.rb +++ b/rb/spec/integration/selenium/webdriver/manager_spec.rb @@ -248,6 +248,11 @@ module WebDriver driver.manage.delete_all_cookies expect(driver.manage.all_cookies).to be_empty end + + it 'throws error when fetching non-existent cookie' do + expect { driver.manage.cookie_named('non-existent') } + .to raise_exception(Error::NoSuchCookieError) + end end end # Options end # WebDriver From ce7448b5d232ec63ab1f1269b5e16d7ad6cb43ce Mon Sep 17 00:00:00 2001 From: Luke Hill <20105237+luke-hill@users.noreply.github.com> Date: Tue, 3 Dec 2024 08:46:53 +0000 Subject: [PATCH 52/58] [rb] Update note for return value of Hash (#14845) Update note for return value of Hash --- rb/lib/selenium/webdriver/common/manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rb/lib/selenium/webdriver/common/manager.rb b/rb/lib/selenium/webdriver/common/manager.rb index d080e0ead6ef7..99181d7700f67 100644 --- a/rb/lib/selenium/webdriver/common/manager.rb +++ b/rb/lib/selenium/webdriver/common/manager.rb @@ -65,7 +65,7 @@ def add_cookie(opts = {}) # Get the cookie with the given name # # @param [String] name the name of the cookie - # @return [Hash, nil] the cookie, or throws a NoSuchCookieError if it wasn't found. + # @return [Hash] the cookie, or throws a NoSuchCookieError if it wasn't found. # def cookie_named(name) From 966bed6c198aaebf3b1d2525cb3acd78317c1188 Mon Sep 17 00:00:00 2001 From: bgermann Date: Tue, 3 Dec 2024 18:49:31 +0100 Subject: [PATCH 53/58] [rust] xz uncompressor for Firefox Linux nightlies (#14832) * [rust] Add xz2 dependency The xz2 crate is already in the dependency tree, so use it for implementing a xz uncompressor. * [rust] Add XZ uncompressor Refactor the BZ uncompressor to be a generic tar uncompressor. Implement a new XZ uncompressor based on it so selenium-manager can deal with the new Firefox nightly builds for Linux. --- rust/Cargo.Bazel.lock | 7 ++++++- rust/Cargo.lock | 1 + rust/Cargo.toml | 1 + rust/src/files.rs | 22 ++++++++++++++++------ 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/rust/Cargo.Bazel.lock b/rust/Cargo.Bazel.lock index aa489691c16ae..202d60533b672 100644 --- a/rust/Cargo.Bazel.lock +++ b/rust/Cargo.Bazel.lock @@ -1,5 +1,5 @@ { - "checksum": "94895b25f9b1d0a76ec78d588887353422bc623faf9ef986467b199d2a966765", + "checksum": "0e8299f5a76cfec7030579fd20069b2debeacc1752e14c4a3b169492b2f18ed4", "crates": { "addr2line 0.21.0": { "name": "addr2line", @@ -14223,6 +14223,10 @@ "id": "which 6.0.3", "target": "which" }, + { + "id": "xz2 0.1.7", + "target": "xz2" + }, { "id": "zip 2.2.0", "target": "zip" @@ -22758,6 +22762,7 @@ "toml 0.8.19", "walkdir 2.5.0", "which 6.0.3", + "xz2 0.1.7", "zip 2.2.0" ], "direct_dev_deps": [ diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 2696beb8223eb..2d38bee267a87 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1907,6 +1907,7 @@ dependencies = [ "toml", "walkdir", "which", + "xz2", "zip", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index f5854e15f80ff..3106d43a81498 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -30,6 +30,7 @@ exitcode = "1.1.2" toml = "0.8.19" bzip2 = "0.4.4" sevenz-rust = "0.6.1" +xz2 = "0.1.7" walkdir = "2.5.0" debpkg = "0.6.0" anyhow = { version = "1.0.89", default-features = false, features = ["backtrace", "std"] } diff --git a/rust/src/files.rs b/rust/src/files.rs index a753f8456b358..bbbf1682d7b0f 100644 --- a/rust/src/files.rs +++ b/rust/src/files.rs @@ -35,6 +35,7 @@ use std::io::{BufReader, Cursor, Read}; use std::path::{Path, PathBuf}; use tar::Archive; use walkdir::{DirEntry, WalkDir}; +use xz2::read::XzDecoder; use zip::ZipArchive; pub const PARSE_ERROR: &str = "Wrong browser/driver version"; @@ -49,6 +50,7 @@ const DMG: &str = "dmg"; const EXE: &str = "exe"; const DEB: &str = "deb"; const MSI: &str = "msi"; +const XZ: &str = "xz"; const SEVEN_ZIP_HEADER: &[u8; 6] = b"7z\xBC\xAF\x27\x1C"; const UNCOMPRESS_MACOS_ERR_MSG: &str = "{} files are only supported in macOS"; @@ -123,7 +125,17 @@ pub fn uncompress( } else if extension.eq_ignore_ascii_case(GZ) { untargz(compressed_file, target, log)? } else if extension.eq_ignore_ascii_case(BZ2) { - uncompress_bz2(compressed_file, target, log)? + uncompress_tar( + &mut BzDecoder::new(File::open(compressed_file)?), + target, + log, + )? + } else if extension.eq_ignore_ascii_case(XZ) { + uncompress_tar( + &mut XzDecoder::new(File::open(compressed_file)?), + target, + log, + )? } else if extension.eq_ignore_ascii_case(PKG) { uncompress_pkg(compressed_file, target, log)? } else if extension.eq_ignore_ascii_case(DMG) { @@ -317,15 +329,13 @@ pub fn untargz(compressed_file: &str, target: &Path, log: &Logger) -> Result<(), Ok(()) } -pub fn uncompress_bz2(compressed_file: &str, target: &Path, log: &Logger) -> Result<(), Error> { +pub fn uncompress_tar(decoder: &mut dyn Read, target: &Path, log: &Logger) -> Result<(), Error> { log.trace(format!( - "Uncompress {} to {}", - compressed_file, + "Uncompress compressed tarball to {}", target.display() )); - let mut bz_decoder = BzDecoder::new(File::open(compressed_file)?); let mut buffer: Vec = Vec::new(); - bz_decoder.read_to_end(&mut buffer)?; + decoder.read_to_end(&mut buffer)?; let mut archive = Archive::new(Cursor::new(buffer)); if !target.exists() { for entry in archive.entries()? { From 454ae258efbea7cd60646999f236c01c92626e32 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 4 Dec 2024 12:48:41 +0700 Subject: [PATCH 54/58] [java] Enhance Null Check in Exception Handling (#14810) --- java/src/org/openqa/selenium/internal/Require.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/java/src/org/openqa/selenium/internal/Require.java b/java/src/org/openqa/selenium/internal/Require.java index 476966a597bb4..4ec171e5a305e 100644 --- a/java/src/org/openqa/selenium/internal/Require.java +++ b/java/src/org/openqa/selenium/internal/Require.java @@ -129,11 +129,8 @@ public static int positive(String argName, Integer number, String message) { throw new IllegalArgumentException(String.format(MUST_BE_SET, argName)); } if (number <= 0) { - if (message == null) { - throw new IllegalArgumentException(String.format(MUST_BE_POSITIVE, argName)); - } else { - throw new IllegalArgumentException(message); - } + throw new IllegalArgumentException( + Objects.requireNonNullElseGet(message, () -> String.format(MUST_BE_POSITIVE, argName))); } return number; } @@ -143,11 +140,8 @@ public static double positive(String argName, Double number, String message) { throw new IllegalArgumentException(String.format(MUST_BE_SET, argName)); } if (number <= 0) { - if (message == null) { - throw new IllegalArgumentException(String.format(MUST_BE_POSITIVE, argName)); - } else { - throw new IllegalArgumentException(message); - } + throw new IllegalArgumentException( + Objects.requireNonNullElseGet(message, () -> String.format(MUST_BE_POSITIVE, argName))); } return number; } From 875f0a61dfa3b2dafc50a87d91f81204bb51f21a Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 4 Dec 2024 12:51:00 +0700 Subject: [PATCH 55/58] [py] Typing package import enhancement (#14283) --- py/generate.py | 52 +++++++++---------- py/selenium/types.py | 12 +++-- py/selenium/webdriver/chrome/service.py | 10 ++-- py/selenium/webdriver/chromium/service.py | 12 +++-- .../webdriver/common/actions/pointer_input.py | 9 ++-- py/selenium/webdriver/common/bidi/cdp.py | 19 ++++--- py/selenium/webdriver/common/bidi/script.py | 4 +- py/selenium/webdriver/common/options.py | 9 ++-- py/selenium/webdriver/common/service.py | 18 ++++--- .../webdriver/common/virtual_authenticator.py | 17 +++--- py/selenium/webdriver/edge/service.py | 9 ++-- py/selenium/webdriver/firefox/service.py | 7 +-- py/selenium/webdriver/ie/service.py | 8 +-- py/selenium/webdriver/remote/webdriver.py | 10 ++-- py/selenium/webdriver/safari/options.py | 4 +- py/selenium/webdriver/safari/service.py | 11 ++-- .../support/event_firing_webdriver.py | 13 ++--- py/selenium/webdriver/support/wait.py | 8 +-- py/selenium/webdriver/webkitgtk/service.py | 14 ++--- py/selenium/webdriver/wpewebkit/options.py | 5 +- py/selenium/webdriver/wpewebkit/service.py | 12 +++-- 21 files changed, 152 insertions(+), 111 deletions(-) diff --git a/py/generate.py b/py/generate.py index 026e80673b40f..0763084423168 100644 --- a/py/generate.py +++ b/py/generate.py @@ -36,7 +36,7 @@ from pathlib import Path import re from textwrap import dedent, indent as tw_indent -import typing +from typing import Optional , cast, List, Union, Iterator import inflection # type: ignore @@ -206,11 +206,11 @@ def from_json(cls, type): class CdpProperty: ''' A property belonging to a non-primitive CDP type. ''' name: str - description: typing.Optional[str] - type: typing.Optional[str] - ref: typing.Optional[str] - enum: typing.List[str] - items: typing.Optional[CdpItems] + description: Optional[str] + type: Optional[str] + ref: Optional[str] + enum: List[str] + items: Optional[CdpItems] optional: bool experimental: bool deprecated: bool @@ -236,7 +236,7 @@ def py_annotation(self): ann = py_ref else: ann = CdpPrimitiveType.get_annotation( - typing.cast(str, self.type)) + cast(str, self.type)) if self.optional: ann = f'typing.Optional[{ann}]' return ann @@ -316,11 +316,11 @@ def generate_from_json(self, dict_): class CdpType: ''' A top-level CDP type. ''' id: str - description: typing.Optional[str] + description: Optional[str] type: str - items: typing.Optional[CdpItems] - enum: typing.List[str] - properties: typing.List[CdpProperty] + items: Optional[CdpItems] + enum: List[str] + properties: List[CdpProperty] @classmethod def from_json(cls, type_): @@ -500,7 +500,7 @@ def generate_code(self): py_type = f"{ref_to_python(self.ref)}" else: py_type = CdpPrimitiveType.get_annotation( - typing.cast(str, self.type)) + cast(str, self.type)) if self.optional: py_type = f'typing.Optional[{py_type}]' code = f"{self.py_name}: {py_type}" @@ -585,8 +585,8 @@ class CdpCommand: description: str experimental: bool deprecated: bool - parameters: typing.List[CdpParameter] - returns: typing.List[CdpReturn] + parameters: List[CdpParameter] + returns: List[CdpReturn] domain: str @property @@ -605,8 +605,8 @@ def from_json(cls, command, domain) -> 'CdpCommand': command.get('description'), command.get('experimental', False), command.get('deprecated', False), - [typing.cast(CdpParameter, CdpParameter.from_json(p)) for p in parameters], - [typing.cast(CdpReturn, CdpReturn.from_json(r)) for r in returns], + [cast(CdpParameter, CdpParameter.from_json(p)) for p in parameters], + [cast(CdpReturn, CdpReturn.from_json(r)) for r in returns], domain, ) @@ -712,10 +712,10 @@ def get_refs(self): class CdpEvent: ''' A CDP event object. ''' name: str - description: typing.Optional[str] + description: Optional[str] deprecated: bool experimental: bool - parameters: typing.List[CdpParameter] + parameters: List[CdpParameter] domain: str @property @@ -731,7 +731,7 @@ def from_json(cls, json: dict, domain: str): json.get('description'), json.get('deprecated', False), json.get('experimental', False), - [typing.cast(CdpParameter, CdpParameter.from_json(p)) + [cast(CdpParameter, CdpParameter.from_json(p)) for p in json.get('parameters', [])], domain ) @@ -786,12 +786,12 @@ def get_refs(self): class CdpDomain: ''' A CDP domain contains metadata, types, commands, and events. ''' domain: str - description: typing.Optional[str] + description: Optional[str] experimental: bool - dependencies: typing.List[str] - types: typing.List[CdpType] - commands: typing.List[CdpCommand] - events: typing.List[CdpEvent] + dependencies: List[str] + types: List[CdpType] + commands: List[CdpCommand] + events: List[CdpEvent] @property def module(self): @@ -826,8 +826,8 @@ def generate_code(self): code += import_code code += '\n\n' code += '\n' - item_iter_t = typing.Union[CdpEvent, CdpCommand, CdpType] - item_iter: typing.Iterator[item_iter_t] = itertools.chain( + item_iter_t = Union[CdpEvent, CdpCommand, CdpType] + item_iter: Iterator[item_iter_t] = itertools.chain( iter(self.types), iter(self.commands), iter(self.events), diff --git a/py/selenium/types.py b/py/selenium/types.py index a776904b4a4bd..f055ea1452fff 100644 --- a/py/selenium/types.py +++ b/py/selenium/types.py @@ -16,10 +16,14 @@ # under the License. """Selenium type definitions.""" -import typing +from typing import IO +from typing import Any +from typing import Iterable +from typing import Type +from typing import Union -AnyKey = typing.Union[str, int, float] -WaitExcTypes = typing.Iterable[typing.Type[Exception]] +AnyKey = Union[str, int, float] +WaitExcTypes = Iterable[Type[Exception]] # Service Types -SubprocessStdAlias = typing.Union[int, str, typing.IO[typing.Any]] +SubprocessStdAlias = Union[int, str, IO[Any]] diff --git a/py/selenium/webdriver/chrome/service.py b/py/selenium/webdriver/chrome/service.py index e151f768d5618..40f94841b2304 100644 --- a/py/selenium/webdriver/chrome/service.py +++ b/py/selenium/webdriver/chrome/service.py @@ -14,7 +14,11 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing + + +from typing import List +from typing import Mapping +from typing import Optional from selenium.types import SubprocessStdAlias from selenium.webdriver.chromium import service @@ -35,9 +39,9 @@ def __init__( self, executable_path=None, port: int = 0, - service_args: typing.Optional[typing.List[str]] = None, + service_args: Optional[List[str]] = None, log_output: SubprocessStdAlias = None, - env: typing.Optional[typing.Mapping[str, str]] = None, + env: Optional[Mapping[str, str]] = None, **kwargs, ) -> None: super().__init__( diff --git a/py/selenium/webdriver/chromium/service.py b/py/selenium/webdriver/chromium/service.py index aebedec40f509..f6c71e3ba719a 100644 --- a/py/selenium/webdriver/chromium/service.py +++ b/py/selenium/webdriver/chromium/service.py @@ -14,8 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing from io import IOBase +from typing import List +from typing import Mapping +from typing import Optional from selenium.types import SubprocessStdAlias from selenium.webdriver.common import service @@ -36,9 +38,9 @@ def __init__( self, executable_path: str = None, port: int = 0, - service_args: typing.Optional[typing.List[str]] = None, + service_args: Optional[List[str]] = None, log_output: SubprocessStdAlias = None, - env: typing.Optional[typing.Mapping[str, str]] = None, + env: Optional[Mapping[str, str]] = None, driver_path_env_key: str = None, **kwargs, ) -> None: @@ -47,7 +49,7 @@ def __init__( if isinstance(log_output, str): self.service_args.append(f"--log-path={log_output}") - self.log_output: typing.Optional[IOBase] = None + self.log_output: Optional[IOBase] = None elif isinstance(log_output, IOBase): self.log_output = log_output else: @@ -62,5 +64,5 @@ def __init__( **kwargs, ) - def command_line_args(self) -> typing.List[str]: + def command_line_args(self) -> List[str]: return [f"--port={self.port}"] + self.service_args diff --git a/py/selenium/webdriver/common/actions/pointer_input.py b/py/selenium/webdriver/common/actions/pointer_input.py index ce5e1c53c91f9..0d7e7a87188c1 100644 --- a/py/selenium/webdriver/common/actions/pointer_input.py +++ b/py/selenium/webdriver/common/actions/pointer_input.py @@ -14,7 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing + +from typing import Any +from typing import Dict +from typing import Optional from typing import Union from selenium.common.exceptions import InvalidArgumentException @@ -41,7 +44,7 @@ def create_pointer_move( duration=DEFAULT_MOVE_DURATION, x: float = 0, y: float = 0, - origin: typing.Optional[WebElement] = None, + origin: Optional[WebElement] = None, **kwargs, ): action = {"type": "pointerMove", "duration": duration, "x": x, "y": y, **kwargs} @@ -67,7 +70,7 @@ def create_pause(self, pause_duration: Union[int, float] = 0) -> None: def encode(self): return {"type": self.type, "parameters": {"pointerType": self.kind}, "id": self.name, "actions": self.actions} - def _convert_keys(self, actions: typing.Dict[str, typing.Any]): + def _convert_keys(self, actions: Dict[str, Any]): out = {} for k, v in actions.items(): if v is None: diff --git a/py/selenium/webdriver/common/bidi/cdp.py b/py/selenium/webdriver/common/bidi/cdp.py index c9ed47825e4da..2d40ed9ddc66e 100644 --- a/py/selenium/webdriver/common/bidi/cdp.py +++ b/py/selenium/webdriver/common/bidi/cdp.py @@ -30,18 +30,23 @@ import json import logging import pathlib -import typing from collections import defaultdict from contextlib import asynccontextmanager from contextlib import contextmanager from dataclasses import dataclass +from typing import Any +from typing import AsyncGenerator +from typing import AsyncIterator +from typing import Generator +from typing import Type +from typing import TypeVar import trio from trio_websocket import ConnectionClosed as WsConnectionClosed from trio_websocket import connect_websocket_url logger = logging.getLogger("trio_cdp") -T = typing.TypeVar("T") +T = TypeVar("T") MAX_WS_MESSAGE_SIZE = 2**24 devtools = None @@ -184,7 +189,7 @@ class CmEventProxy: value set that contains the returned event. """ - value: typing.Any = None + value: Any = None class CdpBase: @@ -197,7 +202,7 @@ def __init__(self, ws, session_id, target_id): self.inflight_cmd = {} self.inflight_result = {} - async def execute(self, cmd: typing.Generator[dict, T, typing.Any]) -> T: + async def execute(self, cmd: Generator[dict, T, Any]) -> T: """Execute a command on the server and wait for the result. :param cmd: any CDP command @@ -236,7 +241,7 @@ def listen(self, *event_types, buffer_size=10): return receiver @asynccontextmanager - async def wait_for(self, event_type: typing.Type[T], buffer_size=10) -> typing.AsyncGenerator[CmEventProxy, None]: + async def wait_for(self, event_type: Type[T], buffer_size=10) -> AsyncGenerator[CmEventProxy, None]: """Wait for an event of the given type and return it. This is an async context manager, so you should open it inside @@ -406,7 +411,7 @@ async def aclose(self): await self.ws.aclose() @asynccontextmanager - async def open_session(self, target_id) -> typing.AsyncIterator[CdpSession]: + async def open_session(self, target_id) -> AsyncIterator[CdpSession]: """This context manager opens a session and enables the "simple" style of calling CDP APIs. @@ -468,7 +473,7 @@ async def _reader_task(self): @asynccontextmanager -async def open_cdp(url) -> typing.AsyncIterator[CdpConnection]: +async def open_cdp(url) -> AsyncIterator[CdpConnection]: """This async context manager opens a connection to the browser specified by ``url`` before entering the block, then closes the connection when the block exits. diff --git a/py/selenium/webdriver/common/bidi/script.py b/py/selenium/webdriver/common/bidi/script.py index 6819a5cf63436..1dc8d101d670e 100644 --- a/py/selenium/webdriver/common/bidi/script.py +++ b/py/selenium/webdriver/common/bidi/script.py @@ -15,8 +15,8 @@ # specific language governing permissions and limitations # under the License. -import typing from dataclasses import dataclass +from typing import List from .session import session_subscribe from .session import session_unsubscribe @@ -76,7 +76,7 @@ class ConsoleLogEntry: text: str timestamp: str method: str - args: typing.List[dict] + args: List[dict] type_: str @classmethod diff --git a/py/selenium/webdriver/common/options.py b/py/selenium/webdriver/common/options.py index b31fcc348ce18..9d838a09c0fc2 100644 --- a/py/selenium/webdriver/common/options.py +++ b/py/selenium/webdriver/common/options.py @@ -14,11 +14,12 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing + import warnings from abc import ABCMeta from abc import abstractmethod from enum import Enum +from typing import Optional from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.common.proxy import Proxy @@ -457,9 +458,9 @@ def set_capability(self, name, value) -> None: def enable_mobile( self, - android_package: typing.Optional[str] = None, - android_activity: typing.Optional[str] = None, - device_serial: typing.Optional[str] = None, + android_package: Optional[str] = None, + android_activity: Optional[str] = None, + device_serial: Optional[str] = None, ) -> None: """Enables mobile browser use for browsers that support it. diff --git a/py/selenium/webdriver/common/service.py b/py/selenium/webdriver/common/service.py index 3afbced1a3e88..7d64d1826bcd6 100644 --- a/py/selenium/webdriver/common/service.py +++ b/py/selenium/webdriver/common/service.py @@ -18,14 +18,18 @@ import logging import os import subprocess -import typing from abc import ABC from abc import abstractmethod from io import IOBase from platform import system from subprocess import PIPE from time import sleep +from typing import IO +from typing import Any +from typing import List +from typing import Mapping from typing import Optional +from typing import Union from typing import cast from urllib import request from urllib.error import URLError @@ -53,16 +57,16 @@ def __init__( executable_path: str = None, port: int = 0, log_output: SubprocessStdAlias = None, - env: typing.Optional[typing.Mapping[typing.Any, typing.Any]] = None, + env: Optional[Mapping[Any, Any]] = None, driver_path_env_key: str = None, **kwargs, ) -> None: if isinstance(log_output, str): self.log_output = cast(IOBase, open(log_output, "a+", encoding="utf-8")) elif log_output == subprocess.STDOUT: - self.log_output = cast(typing.Optional[typing.Union[int, IOBase]], None) + self.log_output = cast(Optional[Union[int, IOBase]], None) elif log_output is None or log_output == subprocess.DEVNULL: - self.log_output = cast(typing.Optional[typing.Union[int, IOBase]], subprocess.DEVNULL) + self.log_output = cast(Optional[Union[int, IOBase]], subprocess.DEVNULL) else: self.log_output = log_output @@ -80,7 +84,7 @@ def service_url(self) -> str: return f"http://{utils.join_host_port('localhost', self.port)}" @abstractmethod - def command_line_args(self) -> typing.List[str]: + def command_line_args(self) -> List[str]: """A List of program arguments (excluding the executable).""" raise NotImplementedError("This method needs to be implemented in a sub class") @@ -215,8 +219,8 @@ def _start_process(self, path: str) -> None: cmd, env=self.env, close_fds=close_file_descriptors, - stdout=cast(typing.Optional[typing.Union[int, typing.IO[typing.Any]]], self.log_output), - stderr=cast(typing.Optional[typing.Union[int, typing.IO[typing.Any]]], self.log_output), + stdout=cast(Optional[Union[int, IO[Any]]], self.log_output), + stderr=cast(Optional[Union[int, IO[Any]]], self.log_output), stdin=PIPE, creationflags=self.creation_flags, startupinfo=start_info, diff --git a/py/selenium/webdriver/common/virtual_authenticator.py b/py/selenium/webdriver/common/virtual_authenticator.py index cfc467307f923..6e1deb684c898 100644 --- a/py/selenium/webdriver/common/virtual_authenticator.py +++ b/py/selenium/webdriver/common/virtual_authenticator.py @@ -16,10 +16,13 @@ # under the License. import functools -import typing from base64 import urlsafe_b64decode from base64 import urlsafe_b64encode from enum import Enum +from typing import Any +from typing import Dict +from typing import Optional +from typing import Union class Protocol(str, Enum): @@ -65,7 +68,7 @@ def __init__( self.is_user_consenting: bool = is_user_consenting self.is_user_verified: bool = is_user_verified - def to_dict(self) -> typing.Dict[str, typing.Union[str, bool]]: + def to_dict(self) -> Dict[str, Union[str, bool]]: return { "protocol": self.protocol, "transport": self.transport, @@ -82,7 +85,7 @@ def __init__( credential_id: bytes, is_resident_credential: bool, rp_id: str, - user_handle: typing.Optional[bytes], + user_handle: Optional[bytes], private_key: bytes, sign_count: int, ): @@ -117,7 +120,7 @@ def rp_id(self) -> str: return self._rp_id @property - def user_handle(self) -> typing.Optional[str]: + def user_handle(self) -> Optional[str]: if self._user_handle: return urlsafe_b64encode(self._user_handle).decode() return None @@ -147,7 +150,7 @@ def create_non_resident_credential(cls, id: bytes, rp_id: str, private_key: byte @classmethod def create_resident_credential( - cls, id: bytes, rp_id: str, user_handle: typing.Optional[bytes], private_key: bytes, sign_count: int + cls, id: bytes, rp_id: str, user_handle: Optional[bytes], private_key: bytes, sign_count: int ) -> "Credential": """Creates a resident (i.e. stateful) credential. @@ -163,7 +166,7 @@ def create_resident_credential( """ return cls(id, True, rp_id, user_handle, private_key, sign_count) - def to_dict(self) -> typing.Dict[str, typing.Any]: + def to_dict(self) -> Dict[str, Any]: credential_data = { "credentialId": self.id, "isResidentCredential": self._is_resident_credential, @@ -178,7 +181,7 @@ def to_dict(self) -> typing.Dict[str, typing.Any]: return credential_data @classmethod - def from_dict(cls, data: typing.Dict[str, typing.Any]) -> "Credential": + def from_dict(cls, data: Dict[str, Any]) -> "Credential": _id = urlsafe_b64decode(f"{data['credentialId']}==") is_resident_credential = bool(data["isResidentCredential"]) rp_id = data.get("rpId", None) diff --git a/py/selenium/webdriver/edge/service.py b/py/selenium/webdriver/edge/service.py index b2c7f02faf4f7..ea49d8c5ca3a0 100644 --- a/py/selenium/webdriver/edge/service.py +++ b/py/selenium/webdriver/edge/service.py @@ -14,7 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing + +from typing import List +from typing import Mapping +from typing import Optional from selenium.types import SubprocessStdAlias from selenium.webdriver.chromium import service @@ -36,8 +39,8 @@ def __init__( executable_path: str = None, port: int = 0, log_output: SubprocessStdAlias = None, - service_args: typing.Optional[typing.List[str]] = None, - env: typing.Optional[typing.Mapping[str, str]] = None, + service_args: Optional[List[str]] = None, + env: Optional[Mapping[str, str]] = None, driver_path_env_key: str = None, **kwargs, ) -> None: diff --git a/py/selenium/webdriver/firefox/service.py b/py/selenium/webdriver/firefox/service.py index e34431480547e..59c8c18058b3b 100644 --- a/py/selenium/webdriver/firefox/service.py +++ b/py/selenium/webdriver/firefox/service.py @@ -14,8 +14,9 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing from typing import List +from typing import Mapping +from typing import Optional from selenium.types import SubprocessStdAlias from selenium.webdriver.common import service @@ -37,9 +38,9 @@ def __init__( self, executable_path: str = None, port: int = 0, - service_args: typing.Optional[typing.List[str]] = None, + service_args: Optional[List[str]] = None, log_output: SubprocessStdAlias = None, - env: typing.Optional[typing.Mapping[str, str]] = None, + env: Optional[Mapping[str, str]] = None, driver_path_env_key: str = None, **kwargs, ) -> None: diff --git a/py/selenium/webdriver/ie/service.py b/py/selenium/webdriver/ie/service.py index b8fac381d9f35..bd9c116ced459 100644 --- a/py/selenium/webdriver/ie/service.py +++ b/py/selenium/webdriver/ie/service.py @@ -14,8 +14,8 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing from typing import List +from typing import Optional from selenium.types import SubprocessStdAlias from selenium.webdriver.common import service @@ -28,9 +28,9 @@ def __init__( self, executable_path: str = None, port: int = 0, - host: typing.Optional[str] = None, - service_args: typing.Optional[typing.List[str]] = None, - log_level: typing.Optional[str] = None, + host: Optional[str] = None, + service_args: Optional[List[str]] = None, + log_level: Optional[str] = None, log_output: SubprocessStdAlias = None, driver_path_env_key: str = None, **kwargs, diff --git a/py/selenium/webdriver/remote/webdriver.py b/py/selenium/webdriver/remote/webdriver.py index eace710c20310..27e6114e06d99 100644 --- a/py/selenium/webdriver/remote/webdriver.py +++ b/py/selenium/webdriver/remote/webdriver.py @@ -22,7 +22,6 @@ import pkgutil import tempfile import types -import typing import warnings import zipfile from abc import ABCMeta @@ -34,6 +33,7 @@ from typing import Dict from typing import List from typing import Optional +from typing import Type from typing import Union from selenium.common.exceptions import InvalidArgumentException @@ -252,9 +252,9 @@ def __enter__(self): def __exit__( self, - exc_type: typing.Optional[typing.Type[BaseException]], - exc: typing.Optional[BaseException], - traceback: typing.Optional[types.TracebackType], + exc_type: Optional[Type[BaseException]], + exc: Optional[BaseException], + traceback: Optional[types.TracebackType], ): self.quit() @@ -618,7 +618,7 @@ def get_cookies(self) -> List[dict]: """ return self.execute(Command.GET_ALL_COOKIES)["value"] - def get_cookie(self, name) -> typing.Optional[typing.Dict]: + def get_cookie(self, name) -> Optional[Dict]: """Get a single cookie by name. Returns the cookie if found, None if not. diff --git a/py/selenium/webdriver/safari/options.py b/py/selenium/webdriver/safari/options.py index 4e7ef0b63b01d..74b39609d6cda 100644 --- a/py/selenium/webdriver/safari/options.py +++ b/py/selenium/webdriver/safari/options.py @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing +from typing import Dict from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import ArgOptions @@ -111,5 +111,5 @@ class Options(ArgOptions): """ @property - def default_capabilities(self) -> typing.Dict[str, str]: + def default_capabilities(self) -> Dict[str, str]: return DesiredCapabilities.SAFARI.copy() diff --git a/py/selenium/webdriver/safari/service.py b/py/selenium/webdriver/safari/service.py index bd04ab66ff483..c20e2ec85df05 100644 --- a/py/selenium/webdriver/safari/service.py +++ b/py/selenium/webdriver/safari/service.py @@ -15,7 +15,10 @@ # specific language governing permissions and limitations # under the License. -import typing + +from typing import List +from typing import Mapping +from typing import Optional from selenium.webdriver.common import service @@ -35,8 +38,8 @@ def __init__( self, executable_path: str = None, port: int = 0, - service_args: typing.Optional[typing.List[str]] = None, - env: typing.Optional[typing.Mapping[str, str]] = None, + service_args: Optional[List[str]] = None, + env: Optional[Mapping[str, str]] = None, reuse_service=False, enable_logging: bool = False, driver_path_env_key: str = None, @@ -57,7 +60,7 @@ def __init__( **kwargs, ) - def command_line_args(self) -> typing.List[str]: + def command_line_args(self) -> List[str]: return ["-p", f"{self.port}"] + self.service_args @property diff --git a/py/selenium/webdriver/support/event_firing_webdriver.py b/py/selenium/webdriver/support/event_firing_webdriver.py index 544ffbb970b6e..6cfdf7b9fb93b 100644 --- a/py/selenium/webdriver/support/event_firing_webdriver.py +++ b/py/selenium/webdriver/support/event_firing_webdriver.py @@ -14,7 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing + +from typing import Any +from typing import List +from typing import Tuple from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By @@ -103,12 +106,10 @@ def quit(self) -> None: def find_element(self, by=By.ID, value=None) -> WebElement: return self._dispatch("find", (by, value, self._driver), "find_element", (by, value)) - def find_elements(self, by=By.ID, value=None) -> typing.List[WebElement]: + def find_elements(self, by=By.ID, value=None) -> List[WebElement]: return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value)) - def _dispatch( - self, l_call: str, l_args: typing.Tuple[typing.Any, ...], d_call: str, d_args: typing.Tuple[typing.Any, ...] - ): + def _dispatch(self, l_call: str, l_args: Tuple[Any, ...], d_call: str, d_args: Tuple[Any, ...]): getattr(self._listener, f"before_{l_call}")(*l_args) try: result = getattr(self._driver, d_call)(*d_args) @@ -187,7 +188,7 @@ def send_keys(self, *value) -> None: def find_element(self, by=By.ID, value=None) -> WebElement: return self._dispatch("find", (by, value, self._driver), "find_element", (by, value)) - def find_elements(self, by=By.ID, value=None) -> typing.List[WebElement]: + def find_elements(self, by=By.ID, value=None) -> List[WebElement]: return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value)) def _dispatch(self, l_call, l_args, d_call, d_args): diff --git a/py/selenium/webdriver/support/wait.py b/py/selenium/webdriver/support/wait.py index 35bd74a695eb8..f9e3815b6022f 100644 --- a/py/selenium/webdriver/support/wait.py +++ b/py/selenium/webdriver/support/wait.py @@ -16,10 +16,12 @@ # under the License. import time -import typing from typing import Callable from typing import Generic from typing import Literal +from typing import Optional +from typing import Tuple +from typing import Type from typing import TypeVar from typing import Union @@ -30,7 +32,7 @@ from selenium.webdriver.remote.webelement import WebElement POLL_FREQUENCY: float = 0.5 # How long to sleep in between calls to the method -IGNORED_EXCEPTIONS: typing.Tuple[typing.Type[Exception]] = (NoSuchElementException,) # default to be ignored. +IGNORED_EXCEPTIONS: Tuple[Type[Exception]] = (NoSuchElementException,) # default to be ignored. D = TypeVar("D", bound=Union[WebDriver, WebElement]) T = TypeVar("T") @@ -42,7 +44,7 @@ def __init__( driver: D, timeout: float, poll_frequency: float = POLL_FREQUENCY, - ignored_exceptions: typing.Optional[WaitExcTypes] = None, + ignored_exceptions: Optional[WaitExcTypes] = None, ): """Constructor, takes a WebDriver instance and timeout in seconds. diff --git a/py/selenium/webdriver/webkitgtk/service.py b/py/selenium/webdriver/webkitgtk/service.py index 5f42d31486143..7414556370bd0 100644 --- a/py/selenium/webdriver/webkitgtk/service.py +++ b/py/selenium/webdriver/webkitgtk/service.py @@ -14,8 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing import warnings +from typing import List +from typing import Mapping +from typing import Optional from selenium.webdriver.common import service @@ -37,10 +39,10 @@ def __init__( self, executable_path: str = DEFAULT_EXECUTABLE_PATH, port: int = 0, - log_path: typing.Optional[str] = None, - log_output: typing.Optional[str] = None, - service_args: typing.Optional[typing.List[str]] = None, - env: typing.Optional[typing.Mapping[str, str]] = None, + log_path: Optional[str] = None, + log_output: Optional[str] = None, + service_args: Optional[List[str]] = None, + env: Optional[Mapping[str, str]] = None, **kwargs, ) -> None: self.service_args = service_args or [] @@ -56,5 +58,5 @@ def __init__( **kwargs, ) - def command_line_args(self) -> typing.List[str]: + def command_line_args(self) -> List[str]: return ["-p", f"{self.port}"] + self.service_args diff --git a/py/selenium/webdriver/wpewebkit/options.py b/py/selenium/webdriver/wpewebkit/options.py index e1bb66c162a39..5a9736c72d29e 100644 --- a/py/selenium/webdriver/wpewebkit/options.py +++ b/py/selenium/webdriver/wpewebkit/options.py @@ -14,7 +14,8 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import typing + +from typing import Dict from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import ArgOptions @@ -60,5 +61,5 @@ def to_capabilities(self): return caps @property - def default_capabilities(self) -> typing.Dict[str, str]: + def default_capabilities(self) -> Dict[str, str]: return DesiredCapabilities.WPEWEBKIT.copy() diff --git a/py/selenium/webdriver/wpewebkit/service.py b/py/selenium/webdriver/wpewebkit/service.py index bd90f51daf61b..8f392cf522706 100644 --- a/py/selenium/webdriver/wpewebkit/service.py +++ b/py/selenium/webdriver/wpewebkit/service.py @@ -15,7 +15,9 @@ # specific language governing permissions and limitations # under the License. import shutil -import typing +from typing import List +from typing import Mapping +from typing import Optional from selenium.webdriver.common import service @@ -37,9 +39,9 @@ def __init__( self, executable_path: str = DEFAULT_EXECUTABLE_PATH, port: int = 0, - log_output: typing.Optional[str] = None, - service_args: typing.Optional[typing.List[str]] = None, - env: typing.Optional[typing.Mapping[str, str]] = None, + log_output: Optional[str] = None, + service_args: Optional[List[str]] = None, + env: Optional[Mapping[str, str]] = None, **kwargs, ): self.service_args = service_args or [] @@ -51,5 +53,5 @@ def __init__( **kwargs, ) - def command_line_args(self) -> typing.List[str]: + def command_line_args(self) -> List[str]: return ["-p", f"{self.port}"] + self.service_args From 30cf1bc65f75fed8b7b318976bd1bddbd7fc8b1c Mon Sep 17 00:00:00 2001 From: Sandeep Suryaprasad <26169602+sandeepsuryaprasad@users.noreply.github.com> Date: Thu, 5 Dec 2024 06:38:53 +0530 Subject: [PATCH 56/58] [py] Moved Rust binary settings to `pyproject.toml` from `setup.py` (#14837) * Moved Rust binary settings to pyproject.toml from setup.py * Update Rakefile to remove py/setup.py --------- Co-authored-by: Viet Nguyen Duc --- Rakefile | 5 +---- py/BUILD.bazel | 1 - py/pyproject.toml | 3 +++ py/setup.py | 38 -------------------------------------- 4 files changed, 4 insertions(+), 43 deletions(-) delete mode 100755 py/setup.py diff --git a/Rakefile b/Rakefile index 7ee7099acb135..24bb5ace8e78b 100644 --- a/Rakefile +++ b/Rakefile @@ -585,8 +585,7 @@ namespace :py do nightly = ".#{Time.now.strftime('%Y%m%d%H%M')}" new_version = updated_version(old_version, arguments[:version], nightly) - ['py/setup.py', - 'py/pyproject.toml', + ['py/pyproject.toml', 'py/BUILD.bazel', 'py/selenium/__init__.py', 'py/selenium/webdriver/__init__.py', @@ -1048,7 +1047,6 @@ namespace :all do 'py/selenium/webdriver/__init__.py', 'py/selenium/__init__.py', 'py/BUILD.bazel', - 'py/setup.py', 'rb/lib/selenium/webdriver/version.rb', 'rb/Gemfile.lock']) @@ -1110,7 +1108,6 @@ namespace :all do 'py/selenium/webdriver/__init__.py', 'py/BUILD.bazel', 'py/CHANGES', - 'py/setup.py', 'rb/lib/selenium/webdriver/version.rb', 'rb/CHANGES', 'rb/Gemfile.lock', diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 47158c4ab59ed..49fae4aecd61d 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -231,7 +231,6 @@ pkg_files( "CHANGES", "README.rst", "pyproject.toml", - "setup.py", ":license", ":selenium-pkg", ":selenium-pkginfo", diff --git a/py/pyproject.toml b/py/pyproject.toml index e99a03cd5d7a2..a30b604e49be0 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -44,6 +44,9 @@ exclude = ["test*"] namespaces = false # include-package-data is `true` by default in pyproject.toml +[[tool.setuptools-rust.bins]] +target = "selenium.webdriver.common.selenium-manager" + [project.urls] Repository = "https://github.com/SeleniumHQ/selenium/" BugTracker = "https://github.com/SeleniumHQ/selenium/issues" diff --git a/py/setup.py b/py/setup.py deleted file mode 100755 index 0f93e33f0ecae..0000000000000 --- a/py/setup.py +++ /dev/null @@ -1,38 +0,0 @@ -# Licensed to the Software Freedom Conservancy (SFC) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The SFC licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -from distutils.command.install import INSTALL_SCHEMES -from os.path import dirname, join, abspath -from setuptools import setup -from setuptools.command.install import install -from setuptools_rust import Binding, RustExtension - - -for scheme in INSTALL_SCHEMES.values(): - scheme['data'] = scheme['purelib'] - -setup_args = { - 'cmdclass': {'install': install}, - 'rust_extensions': [ - RustExtension( - {"selenium-manager": "selenium.webdriver.common.selenium-manager"}, - binding=Binding.Exec - ) - ], -} - -setup(**setup_args) From c28647347b16d46743d9e15157ddb417faed481d Mon Sep 17 00:00:00 2001 From: mk868 Date: Thu, 5 Dec 2024 06:28:40 +0100 Subject: [PATCH 57/58] [java] SpotBugs exclude `DMI_HARDCODED_ABSOLUTE_FILENAME` (#14597) Co-authored-by: Puja Jagani --- java/spotbugs-excludes.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/spotbugs-excludes.xml b/java/spotbugs-excludes.xml index 2ae98dc7e6050..b15a26f856cba 100644 --- a/java/spotbugs-excludes.xml +++ b/java/spotbugs-excludes.xml @@ -160,6 +160,11 @@ + + + + + From 7a93ff7fc7e7cfef6d1c394f70b7391b20107dcc Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 6 Dec 2024 11:15:52 +0700 Subject: [PATCH 58/58] [java]Replace lambdas with method references (#14857) --- java/src/org/openqa/selenium/chromium/ChromiumDriver.java | 2 +- .../openqa/selenium/devtools/SeleniumCdpConnection.java | 4 ++-- java/src/org/openqa/selenium/firefox/FirefoxDriver.java | 2 +- java/src/org/openqa/selenium/remote/RemoteWebDriver.java | 2 +- java/test/org/openqa/selenium/NoSuchShadowRootTest.java | 2 +- .../openqa/selenium/grid/node/relay/RelayOptionsTest.java | 5 +---- .../openqa/selenium/grid/server/BaseServerOptionsTest.java | 7 +------ 7 files changed, 8 insertions(+), 16 deletions(-) diff --git a/java/src/org/openqa/selenium/chromium/ChromiumDriver.java b/java/src/org/openqa/selenium/chromium/ChromiumDriver.java index f5518714d436f..b5f6dacb3a7bb 100644 --- a/java/src/org/openqa/selenium/chromium/ChromiumDriver.java +++ b/java/src/org/openqa/selenium/chromium/ChromiumDriver.java @@ -147,7 +147,7 @@ protected ChromiumDriver( try { try { - cdpUri = client.flatMap(httpClient -> CdpEndpointFinder.getCdpEndPoint(httpClient)); + cdpUri = client.flatMap(CdpEndpointFinder::getCdpEndPoint); } catch (Exception e) { try { client.ifPresent(HttpClient::close); diff --git a/java/src/org/openqa/selenium/devtools/SeleniumCdpConnection.java b/java/src/org/openqa/selenium/devtools/SeleniumCdpConnection.java index 33a8245ab14dc..12e26cdce1061 100644 --- a/java/src/org/openqa/selenium/devtools/SeleniumCdpConnection.java +++ b/java/src/org/openqa/selenium/devtools/SeleniumCdpConnection.java @@ -77,7 +77,7 @@ public static Optional create( client = reportedUri.map(uri -> CdpEndpointFinder.getHttpClient(clientFactory, uri)); try { - cdpUri = client.flatMap(httpClient -> CdpEndpointFinder.getCdpEndPoint(httpClient)); + cdpUri = client.flatMap(CdpEndpointFinder::getCdpEndPoint); } catch (Exception e) { try { client.ifPresent(HttpClient::close); @@ -87,7 +87,7 @@ public static Optional create( throw e; } - if (!cdpUri.isPresent()) { + if (cdpUri.isEmpty()) { try { client.ifPresent(HttpClient::close); } catch (Exception e) { diff --git a/java/src/org/openqa/selenium/firefox/FirefoxDriver.java b/java/src/org/openqa/selenium/firefox/FirefoxDriver.java index a6beac5461e85..01ec605d2fa08 100644 --- a/java/src/org/openqa/selenium/firefox/FirefoxDriver.java +++ b/java/src/org/openqa/selenium/firefox/FirefoxDriver.java @@ -176,7 +176,7 @@ private FirefoxDriver( Optional cdpUri; try { - cdpUri = client.flatMap(httpClient -> CdpEndpointFinder.getCdpEndPoint(httpClient)); + cdpUri = client.flatMap(CdpEndpointFinder::getCdpEndPoint); } catch (Exception e) { try { client.ifPresent(HttpClient::close); diff --git a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java index 737be829226d7..e0443aea24d89 100644 --- a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java +++ b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java @@ -1247,7 +1247,7 @@ public void addCredential(Credential credential) { Stream.concat( credential.toMap().entrySet().stream(), Stream.of(Map.entry("authenticatorId", id))) - .collect(Collectors.toUnmodifiableMap((e) -> e.getKey(), (e) -> e.getValue()))); + .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue))); } @Override diff --git a/java/test/org/openqa/selenium/NoSuchShadowRootTest.java b/java/test/org/openqa/selenium/NoSuchShadowRootTest.java index f945aa6d4561e..78e776366d512 100644 --- a/java/test/org/openqa/selenium/NoSuchShadowRootTest.java +++ b/java/test/org/openqa/selenium/NoSuchShadowRootTest.java @@ -34,6 +34,6 @@ public void getNoSuchShadowRoot() { driver.get(pages.shadowRootPage); WebElement nonExistentShadowRootElement = driver.findElement(By.id("noShadowRoot")); assertThatExceptionOfType(NoSuchShadowRootException.class) - .isThrownBy(() -> nonExistentShadowRootElement.getShadowRoot()); + .isThrownBy(nonExistentShadowRootElement::getShadowRoot); } } diff --git a/java/test/org/openqa/selenium/grid/node/relay/RelayOptionsTest.java b/java/test/org/openqa/selenium/grid/node/relay/RelayOptionsTest.java index 8b02b1e595f7c..e376c13e41fc4 100644 --- a/java/test/org/openqa/selenium/grid/node/relay/RelayOptionsTest.java +++ b/java/test/org/openqa/selenium/grid/node/relay/RelayOptionsTest.java @@ -137,10 +137,7 @@ void protocolVersionThrowsConfigException() { Config config = new TomlConfig(new StringReader(String.join("\n", rawConfig))); RelayOptions relayOptions = new RelayOptions(config); assertThatExceptionOfType(ConfigException.class) - .isThrownBy( - () -> { - relayOptions.getServiceProtocolVersion(); - }) + .isThrownBy(relayOptions::getServiceProtocolVersion) .withMessageContaining("Unsupported protocol version provided: HTTP/0.9"); } diff --git a/java/test/org/openqa/selenium/grid/server/BaseServerOptionsTest.java b/java/test/org/openqa/selenium/grid/server/BaseServerOptionsTest.java index 7aea4479e9300..c92225edfe7a1 100644 --- a/java/test/org/openqa/selenium/grid/server/BaseServerOptionsTest.java +++ b/java/test/org/openqa/selenium/grid/server/BaseServerOptionsTest.java @@ -52,12 +52,7 @@ void externalUriFailsForNonUriStrings() { BaseServerOptions options = new BaseServerOptions(new MapConfig(Map.of("server", Map.of("external-url", "not a URL")))); - Exception exception = - assertThrows( - RuntimeException.class, - () -> { - options.getExternalUri(); - }); + Exception exception = assertThrows(RuntimeException.class, options::getExternalUri); assertThat(exception.getMessage()) .as("External URI must be parseable as URI.")