diff --git a/.skipped-tests b/.skipped-tests index 16f00c9b99235..82b2d1c796077 100644 --- a/.skipped-tests +++ b/.skipped-tests @@ -19,6 +19,7 @@ -//javascript/atoms:test-chrome -//javascript/atoms:test-edge -//javascript/atoms:test-firefox-beta +-//javascript/chrome-driver/... -//javascript/node/selenium-webdriver:test-bidi-network-test.js-chrome -//javascript/node/selenium-webdriver:test-builder-test.js-chrome -//javascript/node/selenium-webdriver:test-builder-test.js-firefox @@ -54,3 +55,4 @@ -//rb/spec/integration/selenium/webdriver:element-chrome -//rb/spec/integration/selenium/webdriver:element-chrome-bidi -//rb/spec/integration/selenium/webdriver:element-chrome-remote +-//rust/tests/... diff --git a/MODULE.bazel b/MODULE.bazel index 509056c344299..0ee03b3fc581c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,7 +1,7 @@ module(name = "selenium") bazel_dep(name = "apple_rules_lint", version = "0.3.2") -bazel_dep(name = "aspect_bazel_lib", version = "2.7.7") +bazel_dep(name = "aspect_bazel_lib", version = "2.7.9") bazel_dep(name = "aspect_rules_esbuild", version = "0.20.1") bazel_dep(name = "aspect_rules_js", version = "1.42.3") bazel_dep(name = "aspect_rules_ts", version = "2.4.2") @@ -41,7 +41,11 @@ linter.register(name = "rust-rustfmt") node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") node.toolchain(node_version = "20.9.0") -pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm", dev_dependency = True) +pnpm = use_extension( + "@aspect_rules_js//npm:extensions.bzl", + "pnpm", + dev_dependency = True, +) use_repo(pnpm, "pnpm") npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm") @@ -206,6 +210,7 @@ maven.install( "org.bouncycastle:bcpkix-jdk18on:1.78.1", "org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5", "org.hsqldb:hsqldb:2.7.3", + "org.jspecify:jspecify:1.0.0", "org.junit.jupiter:junit-jupiter-api:5.10.3", "org.junit.jupiter:junit-jupiter-engine:5.10.3", "org.junit.jupiter:junit-jupiter-params:5.10.3", @@ -347,8 +352,7 @@ use_repo( "linux_beta_firefox", "linux_chrome", "linux_chromedriver", - # Commenting out `linux_edge` since this is not created, but it really should be. - #"linux_edge", + "linux_edge", "linux_edgedriver", "linux_firefox", "linux_geckodriver", diff --git a/common/geckodriver/geckodriver-support.json b/common/geckodriver/geckodriver-support.json index a88a09550fd5d..60a35a6212597 100644 --- a/common/geckodriver/geckodriver-support.json +++ b/common/geckodriver/geckodriver-support.json @@ -1,5 +1,9 @@ { "geckodriver-releases": [ + { + "geckodriver-version": "0.35.0", + "min-firefox-version": 115 + }, { "geckodriver-version": "0.34.0", "min-firefox-version": 115 diff --git a/common/mirror/selenium b/common/mirror/selenium index 3dd89850fa3b9..2cf5b54c309b9 100644 --- a/common/mirror/selenium +++ b/common/mirror/selenium @@ -3,13 +3,13 @@ "tag_name": "nightly", "assets": [ { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-java-4.23.0.zip" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-java-4.24.0-SNAPSHOT.zip" }, { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.23.0.jar" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.24.0-SNAPSHOT.jar" }, { - "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.23.0.zip" + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/nightly/selenium-server-4.24.0-SNAPSHOT.zip" } ] }, @@ -25,11 +25,20 @@ { "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.23.0/selenium-java-4.23.0.zip" }, + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.23.0/selenium-java-4.23.1.zip" + }, { "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.23.0/selenium-server-4.23.0.jar" }, { "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.23.0/selenium-server-4.23.0.zip" + }, + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.23.0/selenium-server-4.23.1.jar" + }, + { + "browser_download_url": "https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.23.0/selenium-server-4.23.1.zip" } ] }, diff --git a/common/repositories.bzl b/common/repositories.bzl index bb4fd2c9fe389..4331d1a017c2d 100644 --- a/common/repositories.bzl +++ b/common/repositories.bzl @@ -1,6 +1,7 @@ # This file has been generated using `bazel run scripts:pinned_browsers` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("//common/private:deb_archive.bzl", "deb_archive") load("//common/private:dmg_archive.bzl", "dmg_archive") load("//common/private:drivers.bzl", "local_drivers") load("//common/private:pkg_archive.bzl", "pkg_archive") @@ -140,10 +141,32 @@ js_library( """, ) + deb_archive( + name = "linux_edge", + url = "https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-stable/microsoft-edge-stable_127.0.2651.74-1_amd64.deb", + sha256 = "5d7363177d366c0247a304c9dc9caa09158d7768a632736c8cf36b0278340328", + build_file_content = """ +load("@aspect_rules_js//js:defs.bzl", "js_library") +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "files", + srcs = glob(["**/*"]), +) + +exports_files(["opt/microsoft/msedge/microsoft-edge"]) + +js_library( + name = "edge-js", + data = [":files"], +) +""", + ) + http_archive( name = "linux_edgedriver", - url = "https://msedgedriver.azureedge.net/127.0.2651.74/edgedriver_linux64.zip", - sha256 = "e6cb5d1a177cf4975efbf4b0868cc5de002d0e534611706c965008f78c28f5ae", + url = "https://msedgedriver.azureedge.net/127.0.2651.72/edgedriver_linux64.zip", + sha256 = "d549371e14bd6f3522d58ba88328cc411af86146b48f923fb9a9072569032103", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -159,8 +182,8 @@ js_library( http_archive( name = "mac_edgedriver", - url = "https://msedgedriver.azureedge.net/127.0.2651.74/edgedriver_mac64.zip", - sha256 = "2ec351cb1d4d3838b1c0917a513d14282560cd90b7b376d665cf981546274525", + url = "https://msedgedriver.azureedge.net/127.0.2651.72/edgedriver_mac64.zip", + sha256 = "bf409629b5a0e741048bb825dfe41a2327e2a90640e06c755c4df65596a569f0", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -176,8 +199,8 @@ js_library( http_archive( name = "linux_chrome", - url = "https://storage.googleapis.com/chrome-for-testing-public/127.0.6533.72/linux64/chrome-linux64.zip", - sha256 = "9ea898023336c4e5e0719fbe3cfc52caeaa93b1db51c8638178490b7a82e8146", + url = "https://storage.googleapis.com/chrome-for-testing-public/127.0.6533.88/linux64/chrome-linux64.zip", + sha256 = "20e2000334f8cefa115ad3e2c55d6ad0e3e254be33a5fd0b9178c3d1a9c78ba9", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") package(default_visibility = ["//visibility:public"]) @@ -198,8 +221,8 @@ js_library( http_archive( name = "mac_chrome", - url = "https://storage.googleapis.com/chrome-for-testing-public/127.0.6533.72/mac-x64/chrome-mac-x64.zip", - sha256 = "40d4c456d221e762859e82c1b5844fbfe86aedb2818d75f6094967382fbe72e7", + url = "https://storage.googleapis.com/chrome-for-testing-public/127.0.6533.88/mac-x64/chrome-mac-x64.zip", + sha256 = "91a010d846597e068f63b0d6ebb56f6a242ced697bc2b8375e22a24fc668582a", strip_prefix = "chrome-mac-x64", patch_cmds = [ "mv 'Google Chrome for Testing.app' Chrome.app", @@ -220,8 +243,8 @@ js_library( http_archive( name = "linux_chromedriver", - url = "https://storage.googleapis.com/chrome-for-testing-public/127.0.6533.72/linux64/chromedriver-linux64.zip", - sha256 = "a7971098c76d7bb4df4cfa2183eae922ccb2624d4e29235bd01c1a316987b82a", + url = "https://storage.googleapis.com/chrome-for-testing-public/127.0.6533.88/linux64/chromedriver-linux64.zip", + sha256 = "d603382aacda709d775f9366067da15ba2ff6bbccddb5ad264193a6b42230a8c", strip_prefix = "chromedriver-linux64", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") @@ -238,8 +261,8 @@ js_library( http_archive( name = "mac_chromedriver", - url = "https://storage.googleapis.com/chrome-for-testing-public/127.0.6533.72/mac-x64/chromedriver-mac-x64.zip", - sha256 = "73f94c90e7685bfb57e7ba2997fc1e24687f8b251e4d31795de8ecec8a40f908", + url = "https://storage.googleapis.com/chrome-for-testing-public/127.0.6533.88/mac-x64/chromedriver-mac-x64.zip", + sha256 = "056f37a603c988ac5d4352b8fbc28c0c606abd1f89de2fbc01998a7e76129969", strip_prefix = "chromedriver-mac-x64", build_file_content = """ load("@aspect_rules_js//js:defs.bzl", "js_library") diff --git a/dotnet/selenium-dotnet-version.bzl b/dotnet/selenium-dotnet-version.bzl index f699712bd705b..40ecf911659a8 100644 --- a/dotnet/selenium-dotnet-version.bzl +++ b/dotnet/selenium-dotnet-version.bzl @@ -1,6 +1,6 @@ # BUILD FILE SYNTAX: STARLARK -SE_VERSION = "4.23.0" +SE_VERSION = "4.24.0-nightly202407312116" ASSEMBLY_VERSION = "4.0.0.0" SUPPORTED_NET_STANDARD_VERSIONS = ["netstandard2.0"] diff --git a/dotnet/test/support/Events/BUILD.bazel b/dotnet/test/support/Events/BUILD.bazel index 497f55ad62b7f..250be2b042394 100644 --- a/dotnet/test/support/Events/BUILD.bazel +++ b/dotnet/test/support/Events/BUILD.bazel @@ -8,10 +8,10 @@ dotnet_nunit_test_suite( name = "SmallTests", size = "small", srcs = SMALL_TESTS, - target_frameworks = ["net7.0"], + target_frameworks = ["net8.0"], deps = [ "//dotnet/src/support", - "//dotnet/src/webdriver", + "//dotnet/src/webdriver:webdriver-net8.0", "//dotnet/test/common:fixtures", framework("nuget", "NUnit"), framework("nuget", "Moq"), @@ -36,10 +36,10 @@ dotnet_nunit_test_suite( data = [ "//dotnet/test/common:test-data", ], - target_frameworks = ["net7.0"], + target_frameworks = ["net8.0"], deps = [ "//dotnet/src/support", - "//dotnet/src/webdriver", + "//dotnet/src/webdriver:webdriver-net8.0", "//dotnet/test/common:fixtures", framework("nuget", "NUnit"), ], diff --git a/dotnet/test/support/Extensions/BUILD.bazel b/dotnet/test/support/Extensions/BUILD.bazel index 6d3db657b1dfe..b2468e129118d 100644 --- a/dotnet/test/support/Extensions/BUILD.bazel +++ b/dotnet/test/support/Extensions/BUILD.bazel @@ -4,10 +4,10 @@ dotnet_nunit_test_suite( name = "SmallTests", size = "small", srcs = glob(["*.cs"]), - target_frameworks = ["net7.0"], + target_frameworks = ["net8.0"], deps = [ "//dotnet/src/support", - "//dotnet/src/webdriver", + "//dotnet/src/webdriver:webdriver-net8.0", "//dotnet/test/common:fixtures", framework("nuget", "Moq"), framework("nuget", "NUnit"), diff --git a/dotnet/test/support/UI/BUILD.bazel b/dotnet/test/support/UI/BUILD.bazel index b8305c24c6fac..ef626213b0ebf 100644 --- a/dotnet/test/support/UI/BUILD.bazel +++ b/dotnet/test/support/UI/BUILD.bazel @@ -13,10 +13,10 @@ dotnet_nunit_test_suite( name = "SmallTests", size = "small", srcs = SMALL_TESTS, - target_frameworks = ["net7.0"], + target_frameworks = ["net8.0"], deps = [ "//dotnet/src/support", - "//dotnet/src/webdriver", + "//dotnet/src/webdriver:webdriver-net8.0", "//dotnet/test/common:fixtures", framework("nuget", "NUnit"), framework("nuget", "Moq"), @@ -41,10 +41,10 @@ dotnet_nunit_test_suite( data = [ "//dotnet/test/common:test-data", ], - target_frameworks = ["net7.0"], + target_frameworks = ["net8.0"], deps = [ "//dotnet/src/support", - "//dotnet/src/webdriver", + "//dotnet/src/webdriver:webdriver-net8.0", "//dotnet/test/common:fixtures", framework("nuget", "NUnit"), ], diff --git a/java/CHANGELOG b/java/CHANGELOG index 3676b97c47153..2180a73068525 100644 --- a/java/CHANGELOG +++ b/java/CHANGELOG @@ -1,3 +1,17 @@ +v4.23.1 +====== +* [bidi] Add dom mutation handler support (#14304) +* [grid] Exclude status DRAINING when distributor getting available nodes (#14282) +* [bidi] Add script pinning methods (#14305) +* Allow setting JDKHttpClient connectionTimeout, readTimeout, version via system property (#14306) +* remove package org.openqa.selenium.grid.session.remote (#14295) +* close the HttClient in case starting the session fails +* Adding system property to disable tracing `webdriver.remote.enableTracing` +* wait for the close response #14280 +* [bidi] Add authentication handlers (#14334) +* [grid] ensure the local_sessionmap.remove event is raised (#14337) +* [bidi] Add filter auth handler (#14349) + v4.23.0 ====== * Use Files.notExists to check files #14088 diff --git a/java/maven_install.json b/java/maven_install.json index 20c9884b32628..f5722636b1062 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": 966816920, - "__RESOLVED_ARTIFACTS_HASH": -1502533934, + "__INPUT_ARTIFACTS_HASH": -1798640815, + "__RESOLVED_ARTIFACTS_HASH": 890286156, "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.27.0", @@ -654,6 +654,13 @@ }, "version": "6.2.2" }, + "org.jspecify:jspecify": { + "shasums": { + "jar": "1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab", + "sources": "adf0898191d55937fb3192ba971826f4f294292c4a960740f3c27310e7b70296" + }, + "version": "1.0.0" + }, "org.junit.jupiter:junit-jupiter-api": { "shasums": { "jar": "6efe6e01ca1ff79b7bf4c6f1eed0b29292e166c27eaf7b00ac981a14d4de61aa", @@ -2620,6 +2627,9 @@ "jodd.typeconverter.impl", "jodd.util" ], + "org.jspecify:jspecify": [ + "org.jspecify.annotations" + ], "org.junit.jupiter:junit-jupiter-api": [ "org.junit.jupiter.api", "org.junit.jupiter.api.condition", @@ -3134,6 +3144,8 @@ "org.htmlunit:htmlunit-core-js:jar:sources", "org.jodd:jodd-util", "org.jodd:jodd-util:jar:sources", + "org.jspecify:jspecify", + "org.jspecify:jspecify:jar:sources", "org.junit.jupiter:junit-jupiter-api", "org.junit.jupiter:junit-jupiter-api:jar:sources", "org.junit.jupiter:junit-jupiter-engine", diff --git a/java/src/org/openqa/selenium/BUILD.bazel b/java/src/org/openqa/selenium/BUILD.bazel index 8a26ac79a8f4a..94d243ec83524 100644 --- a/java/src/org/openqa/selenium/BUILD.bazel +++ b/java/src/org/openqa/selenium/BUILD.bazel @@ -1,4 +1,4 @@ -load("//java:defs.bzl", "java_dist_zip", "java_export", "java_import", "javadoc") +load("//java:defs.bzl", "artifact", "java_dist_zip", "java_export", "java_import", "javadoc") load("//java:version.bzl", "SE_VERSION") load("//java/src/org/openqa/selenium/devtools:versions.bzl", "CDP_DEPS") @@ -32,8 +32,8 @@ java_export( pom_template = ":template-pom", visibility = ["//visibility:public"], deps = [ - # Nothing from third party ":manifest", + artifact("org.jspecify:jspecify"), ], ) diff --git a/java/src/org/openqa/selenium/SearchContext.java b/java/src/org/openqa/selenium/SearchContext.java index 1eb614b3aac4c..9da7967fe5b26 100644 --- a/java/src/org/openqa/selenium/SearchContext.java +++ b/java/src/org/openqa/selenium/SearchContext.java @@ -18,7 +18,9 @@ package org.openqa.selenium; import java.util.List; +import org.jspecify.annotations.NullMarked; +@NullMarked public interface SearchContext { /** * Find all elements within the current context using the given mechanism. diff --git a/java/src/org/openqa/selenium/WebElement.java b/java/src/org/openqa/selenium/WebElement.java index 5dc7b8c8d9113..8f9029ec2fd97 100644 --- a/java/src/org/openqa/selenium/WebElement.java +++ b/java/src/org/openqa/selenium/WebElement.java @@ -18,6 +18,8 @@ package org.openqa.selenium; import java.util.List; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * Represents an HTML element. Generally, all interesting operations to do with interacting with a @@ -28,6 +30,7 @@ * fails, then an {@link org.openqa.selenium.StaleElementReferenceException} is thrown, and all * future calls to this instance will fail. */ +@NullMarked public interface WebElement extends SearchContext, TakesScreenshot { /** * Click this element. If this causes a new page to load, you should discard all references to @@ -98,7 +101,7 @@ public interface WebElement extends SearchContext, TakesScreenshot { * @param name The name of the property. * @return The property's current value or null if the value is not set. */ - default String getDomProperty(String name) { + default @Nullable String getDomProperty(String name) { throw new UnsupportedOperationException("getDomProperty"); } @@ -122,7 +125,7 @@ default String getDomProperty(String name) { * @param name The name of the attribute. * @return The attribute's value or null if the value is not set. */ - default String getDomAttribute(String name) { + default @Nullable String getDomAttribute(String name) { throw new UnsupportedOperationException("getDomAttribute"); } @@ -163,7 +166,7 @@ default String getDomAttribute(String name) { * @param name The name of the attribute. * @return The attribute/property's current value or null if the value is not set. */ - String getAttribute(String name); + @Nullable String getAttribute(String name); /** * Gets result of computing the WAI-ARIA role of element. @@ -173,7 +176,7 @@ default String getDomAttribute(String name) { * * @return the WAI-ARIA role of the element. */ - default String getAriaRole() { + default @Nullable String getAriaRole() { throw new UnsupportedOperationException("getAriaRole"); } @@ -186,7 +189,7 @@ default String getAriaRole() { * * @return the accessible name of the element. */ - default String getAccessibleName() { + default @Nullable String getAccessibleName() { throw new UnsupportedOperationException("getAccessibleName"); } diff --git a/java/src/org/openqa/selenium/bidi/BiDi.java b/java/src/org/openqa/selenium/bidi/BiDi.java index 912355a75a61c..bb4c4ad1d5254 100644 --- a/java/src/org/openqa/selenium/bidi/BiDi.java +++ b/java/src/org/openqa/selenium/bidi/BiDi.java @@ -62,7 +62,7 @@ public long addListener(Event event, Consumer handler) { return connection.addListener(event, handler); } - public void addListener(String browsingContextId, Event event, Consumer handler) { + public long addListener(String browsingContextId, Event event, Consumer handler) { Require.nonNull("Event to listen for", event); Require.nonNull("Browsing context id", browsingContextId); Require.nonNull("Handler to call", handler); @@ -76,7 +76,7 @@ public void addListener(String browsingContextId, Event event, Consumer long addListener(Set browsingContextIds, Event event, Consumer handler) { diff --git a/java/src/org/openqa/selenium/bidi/module/Network.java b/java/src/org/openqa/selenium/bidi/module/Network.java index 5050e368b5519..1237fceeb5023 100644 --- a/java/src/org/openqa/selenium/bidi/module/Network.java +++ b/java/src/org/openqa/selenium/bidi/module/Network.java @@ -169,11 +169,11 @@ public void onResponseCompleted(Consumer consumer) { } } - public void onAuthRequired(Consumer consumer) { + public long onAuthRequired(Consumer consumer) { if (browsingContextIds.isEmpty()) { - this.bidi.addListener(authRequired, consumer); + return this.bidi.addListener(authRequired, consumer); } else { - this.bidi.addListener(browsingContextIds, authRequired, consumer); + return this.bidi.addListener(browsingContextIds, authRequired, consumer); } } diff --git a/java/src/org/openqa/selenium/grid/node/config/DriverServiceSessionFactory.java b/java/src/org/openqa/selenium/grid/node/config/DriverServiceSessionFactory.java index 211672f870bed..a70817d6654a2 100644 --- a/java/src/org/openqa/selenium/grid/node/config/DriverServiceSessionFactory.java +++ b/java/src/org/openqa/selenium/grid/node/config/DriverServiceSessionFactory.java @@ -146,6 +146,7 @@ public Either apply(CreateSessionRequest sess capabilities = removeCapability(capabilities, "browserVersion"); } + HttpClient client = null; try { service.start(); @@ -154,7 +155,7 @@ public Either apply(CreateSessionRequest sess ClientConfig clientConfig = ClientConfig.defaultConfig().readTimeout(sessionTimeout).baseUrl(serviceURL); - HttpClient client = clientFactory.createClient(clientConfig); + client = clientFactory.createClient(clientConfig); Command command = new Command(null, DriverCommand.NEW_SESSION(capabilities)); @@ -186,8 +187,10 @@ public Either apply(CreateSessionRequest sess caps = readDevToolsEndpointAndVersion(caps); caps = readVncEndpoint(capabilities, caps); + caps = readPrefixedCaps(capabilities, caps); span.addEvent("Driver service created session", attributeMap); + final HttpClient fClient = client; return Either.right( new DefaultActiveSession( tracer, @@ -201,8 +204,9 @@ public Either apply(CreateSessionRequest sess Instant.now()) { @Override public void stop() { - service.stop(); - client.close(); + try (fClient) { + service.stop(); + } } }); } catch (Exception e) { @@ -217,7 +221,9 @@ public void stop() { attributeMap.put(AttributeKey.EXCEPTION_MESSAGE.getKey(), errorMessage); span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap); - service.stop(); + try (final HttpClient fClient = client) { + service.stop(); + } return Either.left(new SessionNotCreatedException(errorMessage)); } } catch (Exception e) { @@ -295,6 +301,23 @@ private Capabilities readVncEndpoint(Capabilities requestedCaps, Capabilities re return returnedCaps; } + private Capabilities readPrefixedCaps(Capabilities requestedCaps, Capabilities returnedCaps) { + + PersistentCapabilities returnPrefixedCaps = new PersistentCapabilities(returnedCaps); + + Map requestedCapsMap = requestedCaps.asMap(); + Map returnedCapsMap = returnedCaps.asMap(); + + requestedCapsMap.forEach( + (k, v) -> { + if (k.startsWith("se:") && !returnedCapsMap.containsKey(k)) { + returnPrefixedCaps.setCapability(k, v); + } + }); + + return returnPrefixedCaps; + } + // We remove a capability before sending the caps to the driver because some drivers will // reject session requests when they cannot parse the specific capabilities (like platform or // browser version). diff --git a/java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java b/java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java index 9a681c1fdd434..48f567f576268 100644 --- a/java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java +++ b/java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java @@ -197,6 +197,7 @@ public Either apply(CreateSessionRequest sess String.format( "Unable to connect to docker server (container id: %s)", container.getId()); LOG.warning(message); + client.close(); return Either.left(new RetrySessionRequestException(message)); } LOG.info(String.format("Server is ready (container id: %s)", container.getId())); @@ -222,6 +223,7 @@ public Either apply(CreateSessionRequest sess container.stop(Duration.ofMinutes(1)); String message = "Unable to create session: " + e.getMessage(); LOG.log(Level.WARNING, message, e); + client.close(); return Either.left(new SessionNotCreatedException(message)); } @@ -348,9 +350,10 @@ private Container startVideoContainer( Container videoContainer = docker.create(containerConfig); videoContainer.start(); String videoContainerIp = runningInDocker ? videoContainer.inspect().getIp() : "localhost"; + URI videoContainerUrl = URI.create(String.format("http://%s:%s", videoContainerIp, videoPort)); + HttpClient videoClient = + clientFactory.createClient(ClientConfig.defaultConfig().baseUri(videoContainerUrl)); try { - URL videoContainerUrl = new URL(String.format("http://%s:%s", videoContainerIp, videoPort)); - HttpClient videoClient = clientFactory.createClient(videoContainerUrl); LOG.fine(String.format("Waiting for video recording... (id: %s)", videoContainer.getId())); waitForServerToStart(videoClient, Duration.ofMinutes(1)); } catch (Exception e) { @@ -360,6 +363,8 @@ private Container startVideoContainer( "Unable to verify video recording started (container id: %s), %s", videoContainer.getId(), e.getMessage()); LOG.warning(message); + videoClient.close(); + return null; } LOG.info(String.format("Video container started (id: %s)", videoContainer.getId())); return videoContainer; diff --git a/java/src/org/openqa/selenium/grid/node/relay/RelaySessionFactory.java b/java/src/org/openqa/selenium/grid/node/relay/RelaySessionFactory.java index 86860ab0919e1..fc0c9849ece97 100644 --- a/java/src/org/openqa/selenium/grid/node/relay/RelaySessionFactory.java +++ b/java/src/org/openqa/selenium/grid/node/relay/RelaySessionFactory.java @@ -215,6 +215,7 @@ public Either apply(CreateSessionRequest sess "Error while creating session with the service %s. %s", serviceUrl, e.getMessage()); attributeMap.put(EXCEPTION_MESSAGE.getKey(), errorMessage); span.addEvent(EXCEPTION_EVENT.getKey(), attributeMap); + client.close(); return Either.left(new SessionNotCreatedException(errorMessage)); } } catch (Exception e) { diff --git a/java/src/org/openqa/selenium/grid/sessionmap/local/LocalSessionMap.java b/java/src/org/openqa/selenium/grid/sessionmap/local/LocalSessionMap.java index 2dae2e5779e4f..6e2ff03859170 100644 --- a/java/src/org/openqa/selenium/grid/sessionmap/local/LocalSessionMap.java +++ b/java/src/org/openqa/selenium/grid/sessionmap/local/LocalSessionMap.java @@ -20,12 +20,12 @@ import static org.openqa.selenium.remote.RemoteTags.SESSION_ID; import static org.openqa.selenium.remote.RemoteTags.SESSION_ID_EVENT; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.ConcurrentMap; import java.util.logging.Logger; +import java.util.stream.Collectors; import org.openqa.selenium.NoSuchSessionException; import org.openqa.selenium.events.EventBus; import org.openqa.selenium.grid.config.Config; @@ -48,28 +48,14 @@ public class LocalSessionMap extends SessionMap { private static final Logger LOG = Logger.getLogger(LocalSessionMap.class.getName()); private final EventBus bus; - private final Map knownSessions = new ConcurrentHashMap<>(); - private final ReadWriteLock lock = new ReentrantReadWriteLock(/* be fair */ true); + private final ConcurrentMap knownSessions = new ConcurrentHashMap<>(); public LocalSessionMap(Tracer tracer, EventBus bus) { super(tracer); this.bus = Require.nonNull("Event bus", bus); - bus.addListener( - SessionClosedEvent.listener( - id -> { - try (Span span = tracer.getCurrentContext().createSpan("local_sessionmap.remove")) { - AttributeMap attributeMap = tracer.createAttributeMap(); - attributeMap.put(AttributeKey.LOGGER_CLASS.getKey(), getClass().getName()); - SESSION_ID.accept(span, id); - SESSION_ID_EVENT.accept(attributeMap, id); - knownSessions.remove(id); - String sessionDeletedMessage = "Deleted session from local Session Map"; - span.addEvent(sessionDeletedMessage, attributeMap); - LOG.info(String.format("%s, Id: %s", sessionDeletedMessage, id)); - } - })); + bus.addListener(SessionClosedEvent.listener(this::remove)); bus.addListener( NodeRemovedEvent.listener( @@ -77,14 +63,19 @@ public LocalSessionMap(Tracer tracer, EventBus bus) { nodeStatus.getSlots().stream() .filter(slot -> slot.getSession() != null) .map(slot -> slot.getSession().getId()) - .forEach(knownSessions::remove))); + .forEach(this::remove))); bus.addListener( NodeRestartedEvent.listener( - nodeStatus -> - knownSessions - .values() - .removeIf(value -> value.getUri().equals(nodeStatus.getExternalUri())))); + nodeStatus -> { + List toRemove = + knownSessions.entrySet().stream() + .filter((e) -> e.getValue().getUri().equals(nodeStatus.getExternalUri())) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + + toRemove.forEach(this::remove); + })); } public static SessionMap create(Config config) { @@ -103,8 +94,6 @@ public boolean isReady() { public boolean add(Session session) { Require.nonNull("Session", session); - Lock writeLock = lock.writeLock(); - writeLock.lock(); try (Span span = tracer.getCurrentContext().createSpan("local_sessionmap.add")) { AttributeMap attributeMap = tracer.createAttributeMap(); attributeMap.put(AttributeKey.LOGGER_CLASS.getKey(), getClass().getName()); @@ -115,8 +104,6 @@ public boolean add(Session session) { span.addEvent("Added session into local session map", attributeMap); return true; - } finally { - writeLock.unlock(); } } @@ -124,30 +111,27 @@ public boolean add(Session session) { public Session get(SessionId id) { Require.nonNull("Session ID", id); - Lock readLock = lock.readLock(); - readLock.lock(); - try { - Session session = knownSessions.get(id); - if (session == null) { - throw new NoSuchSessionException("Unable to find session with ID: " + id); - } - - return session; - } finally { - readLock.unlock(); + Session session = knownSessions.get(id); + if (session == null) { + throw new NoSuchSessionException("Unable to find session with ID: " + id); } + + return session; } @Override public void remove(SessionId id) { Require.nonNull("Session ID", id); - Lock writeLock = lock.writeLock(); - writeLock.lock(); - try { + try (Span span = tracer.getCurrentContext().createSpan("local_sessionmap.remove")) { + AttributeMap attributeMap = tracer.createAttributeMap(); + attributeMap.put(AttributeKey.LOGGER_CLASS.getKey(), getClass().getName()); + SESSION_ID.accept(span, id); + SESSION_ID_EVENT.accept(attributeMap, id); knownSessions.remove(id); - } finally { - writeLock.unlock(); + String sessionDeletedMessage = "Deleted session from local Session Map"; + span.addEvent(sessionDeletedMessage, attributeMap); + LOG.info(String.format("%s, Id: %s", sessionDeletedMessage, id)); } } } diff --git a/java/src/org/openqa/selenium/netty/server/WebSocketUpgradeHandler.java b/java/src/org/openqa/selenium/netty/server/WebSocketUpgradeHandler.java index ad14fff29298a..226be194c5950 100644 --- a/java/src/org/openqa/selenium/netty/server/WebSocketUpgradeHandler.java +++ b/java/src/org/openqa/selenium/netty/server/WebSocketUpgradeHandler.java @@ -44,10 +44,15 @@ import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import io.netty.util.AttributeKey; +import java.util.Arrays; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; import org.openqa.selenium.internal.Require; +import org.openqa.selenium.remote.http.CloseMessage; import org.openqa.selenium.remote.http.Message; // Plenty of code in this class is taken from Netty's own @@ -56,6 +61,7 @@ class WebSocketUpgradeHandler extends ChannelInboundHandlerAdapter { + private static final Logger LOG = Logger.getLogger(WebSocketUpgradeHandler.class.getName()); private final AttributeKey> key; private final BiFunction, Optional>> factory; private WebSocketServerHandshaker handshaker; @@ -180,6 +186,27 @@ private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame fram @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - ctx.close(); + try { + Consumer consumer = ctx.channel().attr(key).get(); + + if (consumer != null) { + byte[] reason = Objects.toString(cause).getBytes(UTF_8); + + // the spec defines it as max 123 bytes encoded in UTF_8 + if (reason.length > 123) { + reason = Arrays.copyOf(reason, 123); + Arrays.fill(reason, 120, 123, (byte) '.'); + } + + try { + consumer.accept(new CloseMessage(1011, new String(reason, UTF_8))); + } catch (Exception ex) { + LOG.log(Level.FINE, "failed to send the close message", ex); + } + } + } finally { + LOG.log(Level.FINE, "exception caught, close the context", cause); + ctx.close(); + } } } diff --git a/java/src/org/openqa/selenium/remote/BUILD.bazel b/java/src/org/openqa/selenium/remote/BUILD.bazel index 07cf0a0ffea52..ff6969e73fcc4 100644 --- a/java/src/org/openqa/selenium/remote/BUILD.bazel +++ b/java/src/org/openqa/selenium/remote/BUILD.bazel @@ -60,6 +60,7 @@ java_library( "//java/src/org/openqa/selenium/bidi", "//java/src/org/openqa/selenium/bidi/log", "//java/src/org/openqa/selenium/bidi/module", + "//java/src/org/openqa/selenium/bidi/network", "//java/src/org/openqa/selenium/bidi/script", "//java/src/org/openqa/selenium/concurrent", "//java/src/org/openqa/selenium/devtools", diff --git a/java/src/org/openqa/selenium/remote/Network.java b/java/src/org/openqa/selenium/remote/Network.java new file mode 100644 index 0000000000000..b64060b980237 --- /dev/null +++ b/java/src/org/openqa/selenium/remote/Network.java @@ -0,0 +1,35 @@ +// 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. + +package org.openqa.selenium.remote; + +import java.net.URI; +import java.util.function.Predicate; +import org.openqa.selenium.Beta; +import org.openqa.selenium.UsernameAndPassword; + +@Beta +public interface Network { + + long addAuthenticationHandler(UsernameAndPassword usernameAndPassword); + + long addAuthenticationHandler(Predicate filter, UsernameAndPassword usernameAndPassword); + + void removeAuthenticationHandler(long id); + + void clearAuthenticationHandlers(); +} diff --git a/java/src/org/openqa/selenium/remote/RemoteNetwork.java b/java/src/org/openqa/selenium/remote/RemoteNetwork.java new file mode 100644 index 0000000000000..4a1f921921d66 --- /dev/null +++ b/java/src/org/openqa/selenium/remote/RemoteNetwork.java @@ -0,0 +1,117 @@ +// 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. + +package org.openqa.selenium.remote; + +import java.net.URI; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Predicate; +import org.openqa.selenium.Beta; +import org.openqa.selenium.UsernameAndPassword; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.bidi.BiDi; +import org.openqa.selenium.bidi.HasBiDi; +import org.openqa.selenium.bidi.network.AddInterceptParameters; +import org.openqa.selenium.bidi.network.InterceptPhase; + +@Beta +class RemoteNetwork implements Network { + + private final BiDi biDi; + private final org.openqa.selenium.bidi.module.Network network; + + private final Map authHandlers = new ConcurrentHashMap<>(); + + private final AtomicLong callBackId = new AtomicLong(1); + + public RemoteNetwork(WebDriver driver) { + this.biDi = ((HasBiDi) driver).getBiDi(); + this.network = new org.openqa.selenium.bidi.module.Network(driver); + + interceptAuthTraffic(); + } + + private void interceptAuthTraffic() { + this.network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED)); + + network.onAuthRequired( + responseDetails -> { + String requestId = responseDetails.getRequest().getRequestId(); + + URI uri = URI.create(responseDetails.getRequest().getUrl()); + Optional authCredentials = getAuthCredentials(uri); + if (authCredentials.isPresent()) { + network.continueWithAuth(requestId, authCredentials.get()); + return; + } + + network.continueWithAuthNoCredentials(requestId); + }); + } + + private Optional getAuthCredentials(URI uri) { + return authHandlers.values().stream() + .filter(authDetails -> authDetails.getFilter().test(uri)) + .map(AuthDetails::getUsernameAndPassword) + .findFirst(); + } + + @Override + public long addAuthenticationHandler(UsernameAndPassword usernameAndPassword) { + return addAuthenticationHandler(url -> true, usernameAndPassword); + } + + @Override + public long addAuthenticationHandler( + Predicate filter, UsernameAndPassword usernameAndPassword) { + long id = this.callBackId.incrementAndGet(); + + authHandlers.put(id, new AuthDetails(filter, usernameAndPassword)); + return id; + } + + @Override + public void removeAuthenticationHandler(long id) { + authHandlers.remove(id); + } + + @Override + public void clearAuthenticationHandlers() { + authHandlers.clear(); + } + + private class AuthDetails { + private final Predicate filter; + private final UsernameAndPassword usernameAndPassword; + + public AuthDetails(Predicate filter, UsernameAndPassword usernameAndPassword) { + this.filter = filter; + this.usernameAndPassword = usernameAndPassword; + } + + public Predicate getFilter() { + return filter; + } + + public UsernameAndPassword getUsernameAndPassword() { + return usernameAndPassword; + } + } +} diff --git a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java index db470c89757eb..4afa13ea9be83 100644 --- a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java +++ b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java @@ -110,6 +110,10 @@ public class RemoteWebDriver TakesScreenshot { private static final Logger LOG = Logger.getLogger(RemoteWebDriver.class.getName()); + + /** Boolean system property that defines whether the tracing is enabled or not. */ + private static final String WEBDRIVER_REMOTE_ENABLE_TRACING = "webdriver.remote.enableTracing"; + private final ElementLocation elementLocation = new ElementLocation(); private Level level = Level.FINE; private ErrorHandler errorHandler = new ErrorHandler(); @@ -126,13 +130,18 @@ public class RemoteWebDriver private Script remoteScript; + private Network remoteNetwork; + // For cglib protected RemoteWebDriver() { this.capabilities = init(new ImmutableCapabilities()); } public RemoteWebDriver(Capabilities capabilities) { - this(getDefaultServerURL(), Require.nonNull("Capabilities", capabilities), true); + this( + getDefaultServerURL(), + Require.nonNull("Capabilities", capabilities), + Boolean.parseBoolean(System.getProperty(WEBDRIVER_REMOTE_ENABLE_TRACING, "true"))); } public RemoteWebDriver(Capabilities capabilities, boolean enableTracing) { @@ -141,7 +150,9 @@ public RemoteWebDriver(Capabilities capabilities, boolean enableTracing) { public RemoteWebDriver(URL remoteAddress, Capabilities capabilities) { this( - createExecutor(Require.nonNull("Server URL", remoteAddress), true), + createExecutor( + Require.nonNull("Server URL", remoteAddress), + Boolean.parseBoolean(System.getProperty(WEBDRIVER_REMOTE_ENABLE_TRACING, "true"))), Require.nonNull("Capabilities", capabilities)); } @@ -495,6 +506,13 @@ public Script script() { return this.remoteScript; } + public Network network() { + if (this.remoteNetwork == null) { + this.remoteNetwork = new RemoteNetwork(this); + } + return this.remoteNetwork; + } + protected JsonToWebElementConverter getElementConverter() { return converter; } diff --git a/java/src/org/openqa/selenium/remote/http/jdk/JdkHttpClient.java b/java/src/org/openqa/selenium/remote/http/jdk/JdkHttpClient.java index e936c725eb8f9..1f324de56fd52 100644 --- a/java/src/org/openqa/selenium/remote/http/jdk/JdkHttpClient.java +++ b/java/src/org/openqa/selenium/remote/http/jdk/JdkHttpClient.java @@ -164,6 +164,7 @@ public WebSocket openSocket(HttpRequest request, WebSocket.Listener listener) { throw new ConnectionFailedException("JdkWebSocket initial request execution error", e); } + CompletableFuture closed = new CompletableFuture<>(); CompletableFuture webSocketCompletableFuture = client .newWebSocketBuilder() @@ -222,6 +223,7 @@ public CompletionStage onBinary( public CompletionStage onClose( java.net.http.WebSocket webSocket, int statusCode, String reason) { LOG.fine("Closing websocket"); + closed.complete(statusCode); listener.onClose(statusCode, reason); return null; } @@ -277,7 +279,24 @@ public WebSocket send(Message message) { Level.FINE, "Sending close message, statusCode {0}, reason: {1}", new Object[] {statusCode, closeMessage.reason()}); - makeCall = () -> underlyingSocket.sendClose(statusCode, closeMessage.reason()); + makeCall = + () -> { + CompletableFuture future = + underlyingSocket.sendClose(statusCode, closeMessage.reason()); + try { + closed.get(4, TimeUnit.SECONDS); + } catch (ExecutionException e) { + LOG.log( + Level.WARNING, + "failed to wait for the websocket to close", + e.getCause()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (java.util.concurrent.TimeoutException e) { + LOG.finer("wait for the websocket to close timed out"); + } + return future; + }; } else { LOG.fine("Output is closed, not sending close message"); return this; diff --git a/java/test/org/openqa/selenium/WebNetworkTest.java b/java/test/org/openqa/selenium/WebNetworkTest.java new file mode 100644 index 0000000000000..8036b5edce59b --- /dev/null +++ b/java/test/org/openqa/selenium/WebNetworkTest.java @@ -0,0 +1,174 @@ +// 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. + +package org.openqa.selenium; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.net.URI; +import java.util.function.Predicate; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.environment.webserver.AppServer; +import org.openqa.selenium.environment.webserver.NettyAppServer; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.testing.Ignore; +import org.openqa.selenium.testing.JupiterTestBase; +import org.openqa.selenium.testing.drivers.Browser; + +class WebNetworkTest extends JupiterTestBase { + + private String page; + private AppServer server; + + @BeforeEach + public void setUp() { + server = new NettyAppServer(); + server.start(); + } + + @AfterEach + public void cleanUp() { + driver.quit(); + } + + @Test + @Ignore(Browser.CHROME) + @Ignore(Browser.EDGE) + void canAddAuthenticationHandler() { + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler(new UsernameAndPassword("test", "test")); + + page = server.whereIs("basicAuth"); + driver.get(page); + + assertThat(driver.findElement(By.tagName("h1")).getText()).isEqualTo("authorized"); + } + + @Test + @Ignore(Browser.CHROME) + @Ignore(Browser.EDGE) + void canAddAuthenticationHandlerWithFilter() { + Predicate filter = uri -> uri.getPath().contains("basicAuth"); + + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler(filter, new UsernameAndPassword("test", "test")); + + page = server.whereIs("basicAuth"); + driver.get(page); + + assertThat(driver.findElement(By.tagName("h1")).getText()).isEqualTo("authorized"); + } + + @Test + @Ignore(Browser.CHROME) + @Ignore(Browser.EDGE) + void canAddMultipleAuthenticationHandlersWithFilter() { + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler( + uri -> uri.getPath().contains("basicAuth"), new UsernameAndPassword("test", "test")); + + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler( + uri -> uri.getPath().contains("test"), new UsernameAndPassword("test1", "test1")); + + page = server.whereIs("basicAuth"); + driver.get(page); + + assertThat(driver.findElement(By.tagName("h1")).getText()).isEqualTo("authorized"); + } + + @Test + @Ignore(Browser.CHROME) + @Ignore(Browser.EDGE) + void canAddMultipleAuthenticationHandlersWithTheSameFilter() { + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler( + uri -> uri.getPath().contains("basicAuth"), new UsernameAndPassword("test", "test")); + + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler( + uri -> uri.getPath().contains("basicAuth"), new UsernameAndPassword("test", "test")); + + page = server.whereIs("basicAuth"); + driver.get(page); + + assertThat(driver.findElement(By.tagName("h1")).getText()).isEqualTo("authorized"); + } + + @Test + @Ignore(Browser.CHROME) + @Ignore(Browser.EDGE) + void canRemoveAuthenticationHandler() { + long id = + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler(new UsernameAndPassword("test", "test")); + + ((RemoteWebDriver) driver).network().removeAuthenticationHandler(id); + page = server.whereIs("basicAuth"); + driver.get(page); + + assertThatExceptionOfType(UnhandledAlertException.class) + .isThrownBy(() -> driver.findElement(By.tagName("h1"))); + } + + @Test + @Ignore(Browser.CHROME) + @Ignore(Browser.EDGE) + void canRemoveAuthenticationHandlerThatDoesNotExist() { + ((RemoteWebDriver) driver).network().removeAuthenticationHandler(5); + page = server.whereIs("basicAuth"); + driver.get(page); + + assertThatExceptionOfType(UnhandledAlertException.class) + .isThrownBy(() -> driver.findElement(By.tagName("h1"))); + } + + @Test + @Ignore(Browser.CHROME) + @Ignore(Browser.EDGE) + void canClearAuthenticationHandlers() { + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler( + uri -> uri.getPath().contains("basicAuth"), new UsernameAndPassword("test", "test")); + + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler(new UsernameAndPassword("test", "test")); + + ((RemoteWebDriver) driver) + .network() + .addAuthenticationHandler(new UsernameAndPassword("test1", "test1")); + + ((RemoteWebDriver) driver).network().clearAuthenticationHandlers(); + page = server.whereIs("basicAuth"); + driver.get(page); + + assertThatExceptionOfType(UnhandledAlertException.class) + .isThrownBy(() -> driver.findElement(By.tagName("h1"))); + } +} diff --git a/java/test/org/openqa/selenium/chrome/ChromeDriverFunctionalTest.java b/java/test/org/openqa/selenium/chrome/ChromeDriverFunctionalTest.java index 3a34b6ed4f12d..110f71b618c99 100644 --- a/java/test/org/openqa/selenium/chrome/ChromeDriverFunctionalTest.java +++ b/java/test/org/openqa/selenium/chrome/ChromeDriverFunctionalTest.java @@ -27,6 +27,7 @@ import com.google.common.util.concurrent.Uninterruptibles; import java.time.Duration; import java.util.List; +import java.util.Locale; import java.util.Map; import org.assertj.core.api.Assumptions; import org.junit.jupiter.api.Test; @@ -40,6 +41,7 @@ import org.openqa.selenium.chromium.HasCdp; import org.openqa.selenium.chromium.HasNetworkConditions; import org.openqa.selenium.chromium.HasPermissions; +import org.openqa.selenium.net.PortProber; import org.openqa.selenium.remote.RemoteWebDriverBuilder; import org.openqa.selenium.remote.http.ClientConfig; import org.openqa.selenium.testing.Ignore; @@ -200,4 +202,21 @@ void canExecuteCdpCommands() { assertThat(driver.getTitle()).isEqualTo("Hello WebDriver"); } + + @Test + @NoDriverBeforeTest + void shouldLaunchSuccessfullyWithArabicDate() { + Locale arabicLocale = new Locale("ar", "EG"); + Locale.setDefault(arabicLocale); + Locale.setDefault(Locale.US); + + int port = PortProber.findFreePort(); + ChromeDriverService.Builder builder = new ChromeDriverService.Builder(); + builder.usingPort(port); + ChromeDriverService service = builder.build(); + + driver = new ChromeDriver(service, (ChromeOptions) CHROME.getCapabilities()); + driver.get(pages.simpleTestPage); + assertThat(driver.getTitle()).isEqualTo("Hello WebDriver"); + } } diff --git a/java/test/org/openqa/selenium/edge/EdgeDriverFunctionalTest.java b/java/test/org/openqa/selenium/edge/EdgeDriverFunctionalTest.java index 7e070e7869c6b..7e7dce47248bb 100644 --- a/java/test/org/openqa/selenium/edge/EdgeDriverFunctionalTest.java +++ b/java/test/org/openqa/selenium/edge/EdgeDriverFunctionalTest.java @@ -26,6 +26,7 @@ import java.time.Duration; import java.util.List; +import java.util.Locale; import java.util.Map; import org.junit.jupiter.api.Test; import org.openqa.selenium.Capabilities; @@ -38,6 +39,7 @@ import org.openqa.selenium.chromium.HasCdp; import org.openqa.selenium.chromium.HasNetworkConditions; import org.openqa.selenium.chromium.HasPermissions; +import org.openqa.selenium.net.PortProber; import org.openqa.selenium.remote.RemoteWebDriverBuilder; import org.openqa.selenium.remote.http.ClientConfig; import org.openqa.selenium.testing.Ignore; @@ -193,4 +195,22 @@ void canExecuteCdpCommands() { assertThat(driver.getTitle()).isEqualTo("Hello WebDriver"); } + + @Test + @NoDriverBeforeTest + void shouldLaunchSuccessfullyWithArabicDate() { + Locale arabicLocale = new Locale("ar", "EG"); + Locale.setDefault(arabicLocale); + Locale.setDefault(Locale.US); + + int port = PortProber.findFreePort(); + EdgeDriverService.Builder builder = new EdgeDriverService.Builder(); + builder.usingPort(port); + EdgeDriverService service = builder.build(); + + driver = new EdgeDriver(service, (EdgeOptions) EDGE.getCapabilities()); + + driver.get(pages.simpleTestPage); + assertThat(driver.getTitle()).isEqualTo("Hello WebDriver"); + } } diff --git a/java/test/org/openqa/selenium/firefox/FirefoxDriverTest.java b/java/test/org/openqa/selenium/firefox/FirefoxDriverTest.java index 0dceb93216e48..8714a26938cf4 100644 --- a/java/test/org/openqa/selenium/firefox/FirefoxDriverTest.java +++ b/java/test/org/openqa/selenium/firefox/FirefoxDriverTest.java @@ -37,6 +37,7 @@ import java.io.IOException; import java.lang.reflect.Field; import java.time.Duration; +import java.util.Locale; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import org.mockito.ArgumentMatchers; @@ -50,6 +51,7 @@ import org.openqa.selenium.PageLoadStrategy; import org.openqa.selenium.SessionNotCreatedException; import org.openqa.selenium.WebElement; +import org.openqa.selenium.net.PortProber; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.Command; import org.openqa.selenium.remote.CommandExecutor; @@ -268,5 +270,22 @@ void canSetContext() { assertThat(context.getContext()).isEqualTo(FirefoxCommandContext.CHROME); } + @Test + @NoDriverBeforeTest + void shouldLaunchSuccessfullyWithArabicDate() { + Locale arabicLocale = new Locale("ar", "EG"); + Locale.setDefault(arabicLocale); + Locale.setDefault(Locale.US); + + int port = PortProber.findFreePort(); + GeckoDriverService.Builder builder = new GeckoDriverService.Builder(); + builder.usingPort(port); + GeckoDriverService service = builder.build(); + + driver = new FirefoxDriver(service, (FirefoxOptions) FIREFOX.getCapabilities()); + driver.get(pages.simpleTestPage); + assertThat(driver.getTitle()).isEqualTo("Hello WebDriver"); + } + private static class CustomFirefoxProfile extends FirefoxProfile {} } diff --git a/java/test/org/openqa/selenium/grid/node/local/LocalNodeTest.java b/java/test/org/openqa/selenium/grid/node/local/LocalNodeTest.java index e27e95d25c2ff..ccd2b44f3dae8 100644 --- a/java/test/org/openqa/selenium/grid/node/local/LocalNodeTest.java +++ b/java/test/org/openqa/selenium/grid/node/local/LocalNodeTest.java @@ -350,6 +350,35 @@ void seVncCdpUrlCapabilityWhenGridUrlWithTrailingSlash() throws URISyntaxExcepti assertThat(seCdp.toString().contains("wss://my.domain.com/session")).isTrue(); } + @Test + void responseCapsShowContainerName() throws URISyntaxException { + Tracer tracer = DefaultTestTracer.createTracer(); + EventBus bus = new GuavaEventBus(); + + String gridUrl = "http://localhost:7890/subPath"; + URI uri = new URI(gridUrl); + Capabilities stereotype = new ImmutableCapabilities("se:containerName", "container-1"); + + LocalNode.Builder builder = + LocalNode.builder(tracer, bus, uri, uri, registrationSecret) + .add( + stereotype, + new TestSessionFactory( + (id, caps) -> new Session(id, uri, stereotype, caps, Instant.now()))); + LocalNode localNode = builder.build(); + + Either response = + localNode.newSession( + new CreateSessionRequest(ImmutableSet.of(W3C), stereotype, ImmutableMap.of())); + assertThat(response.isRight()).isTrue(); + + CreateSessionResponse sessionResponse = response.right(); + Capabilities capabilities = sessionResponse.getSession().getCapabilities(); + Object seContainerName = capabilities.getCapability("se:containerName"); + assertThat(seContainerName).isNotNull(); + assertThat(seContainerName).isEqualTo("container-1"); + } + @Test void cdpIsDisabledAndResponseCapsShowThat() throws URISyntaxException { Tracer tracer = DefaultTestTracer.createTracer(); diff --git a/java/version.bzl b/java/version.bzl index 4cf7912512a3b..9f65a9fd3c6e2 100644 --- a/java/version.bzl +++ b/java/version.bzl @@ -1,2 +1,2 @@ -SE_VERSION = "4.23.0" +SE_VERSION = "4.24.0-SNAPSHOT" TOOLS_JAVA_VERSION = "17" diff --git a/javascript/node/selenium-webdriver/BUILD.bazel b/javascript/node/selenium-webdriver/BUILD.bazel index 66844cdac465b..3559f4ec6b25f 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.23.0" +VERSION = "4.24.0-nightly202407312115" BROWSER_VERSIONS = [ "v85", diff --git a/javascript/node/selenium-webdriver/bidi/network.js b/javascript/node/selenium-webdriver/bidi/network.js index b0ad6aeb80727..af80fcf145580 100644 --- a/javascript/node/selenium-webdriver/bidi/network.js +++ b/javascript/node/selenium-webdriver/bidi/network.js @@ -21,11 +21,22 @@ const { ContinueResponseParameters } = require('./continueResponseParameters') const { ContinueRequestParameters } = require('./continueRequestParameters') const { ProvideResponseParameters } = require('./provideResponseParameters') +const NetworkEvent = { + BEFORE_REQUEST_SENT: 'network.beforeRequestSent', + RESPONSE_STARTED: 'network.responseStarted', + RESPONSE_COMPLETED: 'network.responseCompleted', + AUTH_REQUIRED: 'network.authRequired', + FETCH_ERROR: 'network.fetchError', +} + /** * Represents all commands and events of Network module. * Described in https://w3c.github.io/webdriver-bidi/#module-network. */ class Network { + #callbackId = 0 + #listener + /** * Represents a Network object. * @constructor @@ -35,6 +46,43 @@ class Network { constructor(driver, browsingContextIds) { this._driver = driver this._browsingContextIds = browsingContextIds + this.#listener = new Map() + this.#listener.set(NetworkEvent.AUTH_REQUIRED, new Map()) + this.#listener.set(NetworkEvent.BEFORE_REQUEST_SENT, new Map()) + this.#listener.set(NetworkEvent.FETCH_ERROR, new Map()) + this.#listener.set(NetworkEvent.RESPONSE_STARTED, new Map()) + this.#listener.set(NetworkEvent.RESPONSE_COMPLETED, new Map()) + } + + addCallback(eventType, callback) { + const id = ++this.#callbackId + + const eventCallbackMap = this.#listener.get(eventType) + eventCallbackMap.set(id, callback) + return id + } + + removeCallback(id) { + let hasId = false + for (const [, callbacks] of this.#listener) { + if (callbacks.has(id)) { + callbacks.delete(id) + hasId = true + } + } + + if (!hasId) { + throw Error(`Callback with id ${id} not found`) + } + } + + invokeCallbacks(eventType, data) { + const callbacks = this.#listener.get(eventType) + if (callbacks) { + for (const [, callback] of callbacks) { + callback(data) + } + } } async init() { @@ -75,10 +123,10 @@ class Network { * Subscribes to the 'network.authRequired' event and handles it with the provided callback. * * @param {Function} callback - The callback function to handle the event. - * @returns {Promise} - A promise that resolves when the subscription is successful. + * @returns {Promise} - A promise that resolves when the subscription is successful. */ async authRequired(callback) { - await this.subscribeAndHandleEvent('network.authRequired', callback) + return await this.subscribeAndHandleEvent('network.authRequired', callback) } /** @@ -97,10 +145,8 @@ class Network { } else { await this.bidi.subscribe(eventType) } - await this._on(callback) - } + let id = this.addCallback(eventType, callback) - async _on(callback) { this.ws = await this.bidi.socket this.ws.on('message', (event) => { const { params } = JSON.parse(Buffer.from(event.toString())) @@ -134,9 +180,10 @@ class Network { params.errorText, ) } - callback(response) + this.invokeCallbacks(eventType, response) } }) + return id } /** diff --git a/javascript/node/selenium-webdriver/bidi/protocolValue.js b/javascript/node/selenium-webdriver/bidi/protocolValue.js index 059621b792e9e..4bfb27aa221ab 100644 --- a/javascript/node/selenium-webdriver/bidi/protocolValue.js +++ b/javascript/node/selenium-webdriver/bidi/protocolValue.js @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -const { PrimitiveType, NonPrimitiveType, RemoteType } = require('./protocolType') +const { PrimitiveType, NonPrimitiveType, RemoteType, SpecialNumberType } = require('./protocolType') const TYPE_CONSTANT = 'type' const VALUE_CONSTANT = 'value' @@ -189,6 +189,88 @@ class LocalValue { return new ReferenceValue(handle, sharedId) } + static getArgument(argument) { + let localValue = null + + if ( + argument === SpecialNumberType.NAN || + argument === SpecialNumberType.MINUS_ZERO || + argument === SpecialNumberType.INFINITY || + argument === SpecialNumberType.MINUS_INFINITY + ) { + localValue = LocalValue.createSpecialNumberValue(argument) + return localValue + } + + const type = typeof argument + + switch (type) { + case PrimitiveType.STRING: + localValue = LocalValue.createStringValue(argument) + break + case PrimitiveType.NUMBER: + localValue = LocalValue.createNumberValue(argument) + break + case PrimitiveType.BOOLEAN: + localValue = LocalValue.createBooleanValue(argument) + break + case PrimitiveType.BIGINT: + localValue = LocalValue.createBigIntValue(argument.toString()) + break + case PrimitiveType.UNDEFINED: + localValue = LocalValue.createUndefinedValue() + break + case NonPrimitiveType.OBJECT: + if (argument === null) { + localValue = LocalValue.createNullValue() + break + } + if (argument instanceof Date) { + localValue = LocalValue.createDateValue(argument) + } else if (argument instanceof Map) { + const map = [] + + argument.forEach((value, key) => { + let objectKey + if (typeof key === 'string') { + objectKey = key + } else { + objectKey = LocalValue.getArgument(key) + } + const objectValue = LocalValue.getArgument(value) + map.push([objectKey, objectValue]) + }) + localValue = new LocalValue(NonPrimitiveType.MAP, map) + } else if (argument instanceof Set) { + const set = [] + argument.forEach((value) => { + set.push(LocalValue.getArgument(value)) + }) + localValue = LocalValue.createSetValue(set) + } else if (argument instanceof Array) { + const arr = [] + argument.forEach((value) => { + arr.push(LocalValue.getArgument(value)) + }) + localValue = LocalValue.createArrayValue(arr) + } else if (argument instanceof RegExp) { + localValue = LocalValue.createRegularExpressionValue({ + pattern: argument.source, + flags: argument.flags, + }) + } else { + let value = [] + Object.entries(argument).forEach((entry) => { + value.push([LocalValue.getArgument(entry[0]), LocalValue.getArgument(entry[1])]) + }) + localValue = new LocalValue(NonPrimitiveType.OBJECT, value) + } + break + } + + return localValue + } + asMap() { let toReturn = {} toReturn[TYPE_CONSTANT] = this.type @@ -246,7 +328,7 @@ class RemoteValue { } deserializeValue(value, type) { - if ([NonPrimitiveType.MAP, NonPrimitiveType.OBJECT].includes(type)) { + if (type === NonPrimitiveType.OBJECT) { return Object.fromEntries(value) } else if (type === NonPrimitiveType.REGULAR_EXPRESSION) { return new RegExpValue(value.pattern, value.flags) diff --git a/javascript/node/selenium-webdriver/index.js b/javascript/node/selenium-webdriver/index.js index 61fb92739fa47..962b30c655bec 100644 --- a/javascript/node/selenium-webdriver/index.js +++ b/javascript/node/selenium-webdriver/index.js @@ -44,6 +44,7 @@ const BrowsingContext = require('./bidi/browsingContext') const BrowsingContextInspector = require('./bidi/browsingContextInspector') const ScriptManager = require('./bidi/scriptManager') const NetworkInspector = require('./bidi/networkInspector') +const version = require('./package.json').version const Browser = capabilities.Browser const Capabilities = capabilities.Capabilities @@ -794,3 +795,4 @@ exports.BrowsingContext = BrowsingContext exports.BrowsingContextInspector = BrowsingContextInspector exports.ScriptManager = ScriptManager exports.NetworkInspector = NetworkInspector +exports.version = version diff --git a/javascript/node/selenium-webdriver/lib/network.js b/javascript/node/selenium-webdriver/lib/network.js new file mode 100644 index 0000000000000..c047fd2a7ec4e --- /dev/null +++ b/javascript/node/selenium-webdriver/lib/network.js @@ -0,0 +1,78 @@ +// 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. + +const network = require('../bidi/network') +const { InterceptPhase } = require('../bidi/interceptPhase') +const { AddInterceptParameters } = require('../bidi/addInterceptParameters') + +class Network { + #driver + #network + #callBackInterceptIdMap = new Map() + + constructor(driver) { + this.#driver = driver + } + + // This should be done in the constructor. + // But since it needs to call async methods we cannot do that in the constructor. + // We can have a separate async method that initialises the Script instance. + // However, that pattern does not allow chaining the methods as we would like the user to use it. + // Since it involves awaiting to get the instance and then another await to call the method. + // Using this allows the user to do this "await driver.network.addAuthenticationHandler(callback)" + async #init() { + if (this.#network !== undefined) { + return + } + this.#network = await network(this.#driver) + } + + async addAuthenticationHandler(username, password) { + await this.#init() + + const interceptId = await this.#network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED)) + + const id = await this.#network.authRequired(async (event) => { + await this.#network.continueWithAuth(event.request.request, username, password) + }) + + this.#callBackInterceptIdMap.set(id, interceptId) + return id + } + + async removeAuthenticationHandler(id) { + await this.#init() + + const interceptId = this.#callBackInterceptIdMap.get(id) + + await this.#network.removeIntercept(interceptId) + await this.#network.removeCallback(id) + + this.#callBackInterceptIdMap.delete(id) + } + + async clearAuthenticationHandlers() { + for (const [key, value] of this.#callBackInterceptIdMap.entries()) { + await this.#network.removeIntercept(value) + await this.#network.removeCallback(key) + } + + this.#callBackInterceptIdMap.clear() + } +} + +module.exports = Network diff --git a/javascript/node/selenium-webdriver/lib/script.js b/javascript/node/selenium-webdriver/lib/script.js index 2a64dd03e7d56..04b8fac06787a 100644 --- a/javascript/node/selenium-webdriver/lib/script.js +++ b/javascript/node/selenium-webdriver/lib/script.js @@ -121,6 +121,22 @@ class Script { await this.#initScript() await this.#script.removePreloadScript(id) } + + async execute(script, ...args) { + await this.#initScript() + + const browsingContextId = await this.#driver.getWindowHandle() + + const argumentList = [] + + args.forEach((arg) => { + argumentList.push(LocalValue.getArgument(arg)) + }) + + const response = await this.#script.callFunctionInBrowsingContext(browsingContextId, script, true, argumentList) + + return response.result + } } module.exports = Script diff --git a/javascript/node/selenium-webdriver/lib/webdriver.js b/javascript/node/selenium-webdriver/lib/webdriver.js index add28497d0211..ac4e2e1a6a432 100644 --- a/javascript/node/selenium-webdriver/lib/webdriver.js +++ b/javascript/node/selenium-webdriver/lib/webdriver.js @@ -44,6 +44,7 @@ const BIDI = require('../bidi') const { PinnedScript } = require('./pinnedScript') const JSZip = require('jszip') const Script = require('./script') +const Network = require('./network') // Capability names that are defined in the W3C spec. const W3C_CAPABILITY_NAMES = new Set([ @@ -656,6 +657,7 @@ function filterNonW3CCaps(capabilities) { */ class WebDriver { #script = undefined + #network = undefined /** * @param {!(./session.Session|IThenable)} session Either * a known session or a promise that will be resolved to a session. @@ -1116,6 +1118,16 @@ class WebDriver { return this.#script } + network() { + // The Network maintains state of the callbacks. + // Returning a new instance of the same driver will not work while removing callbacks. + if (this.#network === undefined) { + this.#network = new Network(this) + } + + return this.#network + } + validatePrintPageParams(keys, object) { let page = {} let margin = {} diff --git a/javascript/node/selenium-webdriver/package.json b/javascript/node/selenium-webdriver/package.json index e422383fddba1..74317909198da 100644 --- a/javascript/node/selenium-webdriver/package.json +++ b/javascript/node/selenium-webdriver/package.json @@ -1,6 +1,6 @@ { "name": "selenium-webdriver", - "version": "4.23.0", + "version": "4.24.0-nightly202407312115", "description": "The official WebDriver JavaScript bindings from the Selenium project", "license": "Apache-2.0", "keywords": [ @@ -26,27 +26,27 @@ "@bazel/runfiles": "^5.8.1", "jszip": "^3.10.1", "tmp": "^0.2.3", - "ws": "^8.17.1" + "ws": "^8.18.0" }, "devDependencies": { - "@eslint/js": "^9.5.0", + "@eslint/js": "^9.8.0", "clean-jsdoc-theme": "^4.3.0", - "eslint": "^9.5.0", + "eslint": "^9.8.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-mocha": "^10.4.3", - "eslint-plugin-n": "^17.9.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-n": "^17.10.1", "eslint-plugin-no-only-tests": "^3.1.0", - "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-prettier": "^5.2.1", "express": "^4.19.2", - "globals": "^15.6.0", - "has-flag": "^4.0.0", + "globals": "^15.9.0", + "has-flag": "^5.0.1", "jsdoc": "^4.0.3", - "mocha": "^10.5.1", + "mocha": "^10.7.0", "mocha-junit-reporter": "^2.2.1", "multer": "1.4.5-lts.1", - "prettier": "^3.3.2", + "prettier": "^3.3.3", "serve-index": "^1.9.1", - "sinon": "^17.0.1", + "sinon": "^18.0.0", "supports-color": "^9.4.0" }, "scripts": { diff --git a/javascript/node/selenium-webdriver/test/bidi/local_value_test.js b/javascript/node/selenium-webdriver/test/bidi/local_value_test.js index d7bc7c4eeef5c..94c4f48bdc82e 100644 --- a/javascript/node/selenium-webdriver/test/bidi/local_value_test.js +++ b/javascript/node/selenium-webdriver/test/bidi/local_value_test.js @@ -350,9 +350,9 @@ suite( let resultValue = result.result.value - assert.equal(Object.keys(resultValue).length, 1) - assert.equal(resultValue['foobar'].type, 'string') - assert.equal(resultValue['foobar'].value, 'foobar') + assert.equal(resultValue[0][0], 'foobar') + assert.equal(resultValue[0][1].type, 'string') + assert.equal(resultValue[0][1].value, 'foobar') }) it('can call function with object argument', async function () { diff --git a/javascript/node/selenium-webdriver/test/bidi/locate_nodes_test.js b/javascript/node/selenium-webdriver/test/bidi/locate_nodes_test.js index a2736b5f40fab..109f2e07ad00e 100644 --- a/javascript/node/selenium-webdriver/test/bidi/locate_nodes_test.js +++ b/javascript/node/selenium-webdriver/test/bidi/locate_nodes_test.js @@ -201,9 +201,10 @@ suite( assert.equal(response.resultType, EvaluateResultType.SUCCESS) assert.equal(response.result.type, 'map') - const sharedId = response.result.value.sharedId + const value = response.result.value[0] - assert.strictEqual(sharedId.value, nodeId) + assert.strictEqual(value[1].type, 'string') + assert.strictEqual(value[1].value, nodeId) }) it('can find element', async function () { diff --git a/javascript/node/selenium-webdriver/test/bidi/network_commands_test.js b/javascript/node/selenium-webdriver/test/bidi/network_commands_test.js index 3c7a686991ebd..7c282aa913e37 100644 --- a/javascript/node/selenium-webdriver/test/bidi/network_commands_test.js +++ b/javascript/node/selenium-webdriver/test/bidi/network_commands_test.js @@ -130,7 +130,7 @@ suite( await driver.get(Pages.logEntryAdded) - assert.strictEqual(counter, 1) + assert.strictEqual(counter >= 1, true) }) it('can continue response', async function () { @@ -145,7 +145,7 @@ suite( await driver.get(Pages.logEntryAdded) - assert.strictEqual(counter, 1) + assert.strictEqual(counter >= 1, true) }) it('can provide response', async function () { @@ -160,7 +160,7 @@ suite( await driver.get(Pages.logEntryAdded) - assert.strictEqual(counter, 1) + assert.strictEqual(counter >= 1, true) }) }) }, diff --git a/javascript/node/selenium-webdriver/test/lib/webdriver_network_test.js b/javascript/node/selenium-webdriver/test/lib/webdriver_network_test.js new file mode 100644 index 0000000000000..538fefa87916d --- /dev/null +++ b/javascript/node/selenium-webdriver/test/lib/webdriver_network_test.js @@ -0,0 +1,80 @@ +// 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. + +'use strict' + +const assert = require('node:assert') +const { Browser } = require('selenium-webdriver') +const { Pages, suite } = require('../../lib/test') +const until = require('selenium-webdriver/lib/until') +const { By } = require('selenium-webdriver') + +suite( + function (env) { + let driver + + beforeEach(async function () { + driver = await env.builder().build() + }) + + afterEach(async function () { + await driver.quit() + }) + + describe('script()', function () { + it('can add authentication handler', async function () { + await driver.network().addAuthenticationHandler('genie', 'bottle') + await driver.get(Pages.basicAuth) + + await driver.wait(until.elementLocated(By.css('pre'))) + let source = await driver.getPageSource() + assert.equal(source.includes('Access granted'), true) + }) + + it('can remove authentication handler', async function () { + const id = await driver.network().addAuthenticationHandler('genie', 'bottle') + + await driver.network().removeAuthenticationHandler(id) + + try { + await driver.get(Pages.basicAuth) + await driver.wait(until.elementLocated(By.css('pre'))) + assert.fail('Page should not be loaded') + } catch (e) { + assert.strictEqual(e.name, 'UnexpectedAlertOpenError') + } + }) + + it('can clear authentication handlers', async function () { + await driver.network().addAuthenticationHandler('genie', 'bottle') + + await driver.network().addAuthenticationHandler('bottle', 'genie') + + await driver.network().clearAuthenticationHandlers() + + try { + await driver.get(Pages.basicAuth) + await driver.wait(until.elementLocated(By.css('pre'))) + assert.fail('Page should not be loaded') + } catch (e) { + assert.strictEqual(e.name, 'UnexpectedAlertOpenError') + } + }) + }) + }, + { browsers: [Browser.FIREFOX] }, +) diff --git a/javascript/node/selenium-webdriver/test/lib/webdriver_script_execute_test.js b/javascript/node/selenium-webdriver/test/lib/webdriver_script_execute_test.js new file mode 100644 index 0000000000000..79253b2db8d7c --- /dev/null +++ b/javascript/node/selenium-webdriver/test/lib/webdriver_script_execute_test.js @@ -0,0 +1,311 @@ +// 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. + +'use strict' + +const assert = require('node:assert') +const { Browser } = require('selenium-webdriver/') +const { suite } = require('../../lib/test') + +const ScriptManager = require('selenium-webdriver/bidi/scriptManager') +const { LocalValue, RegExpValue } = require('selenium-webdriver/bidi/protocolValue') +const { SpecialNumberType } = require('selenium-webdriver/bidi/protocolType') + +suite( + function (env) { + let driver + + beforeEach(async function () { + driver = await env.builder().build() + }) + + afterEach(async function () { + await driver.quit() + }) + + describe('Execute script', function () { + it('can execute script with undefined argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(arg!==undefined)\n' + + ' throw Error("Argument should be undefined, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + undefined, + ) + + assert.equal(result.type, 'undefined') + }) + + it('can execute script with null argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(arg!==null)\n' + + ' throw Error("Argument should be null, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + null, + ) + + assert.equal(result.type, 'null') + }) + it('can execute script with minus zero argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(arg!==-0)\n' + + ' throw Error("Argument should be -0, but was " + arg);\n' + + ' return arg;\n' + + ' }}', + SpecialNumberType.MINUS_ZERO, + ) + + assert.equal(result.type, 'number') + assert.equal(result.value, '-0') + }) + + it('can execute script with infinity argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(arg!==Infinity)\n' + + ' throw Error("Argument should be Infinity, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + SpecialNumberType.INFINITY, + ) + + assert.equal(result.type, 'number') + assert.equal(result.value, 'Infinity') + }) + + it('can execute script with minus infinity argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(arg!==-Infinity)\n' + + ' throw Error("Argument should be -Infinity, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + SpecialNumberType.MINUS_INFINITY, + ) + + assert.equal(result.type, 'number') + assert.equal(result.value, '-Infinity') + }) + + it('can execute script with number argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(arg!==1.4)\n' + + ' throw Error("Argument should be 1.4, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + 1.4, + ) + + assert.equal(result.type, 'number') + assert.equal(result.value, 1.4) + }) + + it('can execute script with boolean argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(arg!==true)\n' + + ' throw Error("Argument should be true, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + true, + ) + + assert.equal(result.type, 'boolean') + assert.equal(result.value, true) + }) + + it('can execute script with big int argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(arg!==42n)\n' + + ' throw Error("Argument should be 42n, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + 42n, + ) + + assert.equal(result.type, 'bigint') + assert.equal(result.value, '42') + }) + + it('can execute script with array argument', async function () { + let arrayValue = ['foobar'] + + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(! (arg instanceof Array))\n' + + ' throw Error("Argument type should be Array, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + arrayValue, + ) + + assert.equal(result.type, 'array') + + let resultValue = result.value + assert.equal(resultValue.length, 1) + assert.equal(resultValue[0].type, 'string') + assert.equal(resultValue[0].value, 'foobar') + }) + + it('can execute script with set argument', async function () { + let setValues = new Set() + setValues.add('foobar') + setValues.add('test') + + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(! (arg instanceof Set))\n' + + ' throw Error("Argument type should be Set, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + setValues, + ) + + assert.equal(result.type, 'set') + + let resultValue = result.value + assert.equal(resultValue.length, 2) + assert.equal(resultValue[0].type, 'string') + assert.equal(resultValue[0].value, 'foobar') + assert.equal(resultValue[1].type, 'string') + assert.equal(resultValue[1].value, 'test') + }) + + it('can execute script with date argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(! (arg instanceof Date))\n' + + ' throw Error("Argument type should be Date, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + new Date('2022-05-31T13:47:29.000Z'), + ) + + assert.equal(result.type, 'date') + assert.equal(result.value, '2022-05-31T13:47:29.000Z') + }) + + it('can execute script with map argument', async function () { + let mapValue = new Map() + mapValue.set(1, 2) + mapValue.set('foo', 'bar') + mapValue.set(true, false) + mapValue.set('baz', [1, 2, 3]) + + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(! (arg instanceof Map))\n' + + ' throw Error("Argument type should be Map, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + mapValue, + ) + assert.equal(result.type, 'map') + assert.notEqual(result.value, null) + + let resultValue = result.value + + assert.equal(resultValue.length, 4) + + assert.equal( + JSON.stringify(resultValue), + '[[{"type":"number","value":1},{"type":"number","value":2}],["foo",{"type":"string","value":"bar"}],[{"type":"boolean","value":true},{"type":"boolean","value":false}],["baz",{"type":"array","value":[{"type":"number","value":1},{"type":"number","value":2},{"type":"number","value":3}]}]]', + ) + }) + + it('can execute script with object argument', async function () { + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(! (arg instanceof Object))\n' + + ' throw Error("Argument type should be Object, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + { foobar: 'foobar' }, + ) + + assert.equal(result.type, 'object') + + let resultValue = result.value + assert.equal(resultValue['foobar'].type, 'string') + assert.equal(resultValue['foobar'].value, 'foobar') + }) + + it('can execute script with regex argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = LocalValue.createRegularExpressionValue(new RegExpValue('foo', 'g')) + argumentValues.push(value) + + const result = await driver + .script() + .execute( + '(arg) => {{\n' + + ' if(! (arg instanceof RegExp))\n' + + ' throw Error("Argument type should be RegExp, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + new RegExp('foo', 'g'), + ) + + let resultValue = result.value + + assert.equal(resultValue.pattern, 'foo') + assert.equal(resultValue.flags, 'g') + }) + }) + }, + { browsers: [Browser.FIREFOX, Browser.CHROME, Browser.EDGE] }, +) diff --git a/javascript/node/selenium-webdriver/testing/index.js b/javascript/node/selenium-webdriver/testing/index.js index 116009e26ea22..c96f18d453592 100644 --- a/javascript/node/selenium-webdriver/testing/index.js +++ b/javascript/node/selenium-webdriver/testing/index.js @@ -35,7 +35,6 @@ const fs = require('node:fs') const path = require('node:path') const { isatty } = require('node:tty') -const { runfiles } = require('@bazel/runfiles') const chrome = require('../chrome') const edge = require('../edge') const firefox = require('../firefox') @@ -46,6 +45,14 @@ const { Browser } = require('../lib/capabilities') const { Builder } = require('../index') const { getBinaryPaths } = require('../common/driverFinder') +let runfiles +try { + // Attempt to require @bazel/runfiles + runfiles = require('@bazel/runfiles').runfiles +} catch { + // Fall through +} + /** * Describes a browser targeted by a {@linkplain suite test suite}. * @record @@ -544,6 +551,10 @@ function locate(fileLike) { return fileLike } + if (!runfiles) { + throw new Error('Unable to find ' + fileLike) + } + try { return runfiles.resolve(fileLike) } catch { diff --git a/package-lock.json b/package-lock.json index 36d433820e1b5..4fdd4b22b2250 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1707,41 +1707,43 @@ } }, "javascript/node/selenium-webdriver": { - "version": "4.23.0", + "version": "4.24.0-nightly202407312115", "license": "Apache-2.0", "dependencies": { + "@bazel/runfiles": "^5.8.1", "jszip": "^3.10.1", "tmp": "^0.2.3", - "ws": ">=8.16.0" + "ws": "^8.18.0" }, "devDependencies": { - "@bazel/runfiles": "^5.8.1", - "@eslint/js": "^9.1.1", + "@eslint/js": "^9.8.0", "clean-jsdoc-theme": "^4.3.0", - "eslint": "^9.1.0", + "eslint": "^9.8.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-mocha": "^10.4.3", - "eslint-plugin-n": "^17.2.1", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-n": "^17.10.1", "eslint-plugin-no-only-tests": "^3.1.0", - "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-prettier": "^5.2.1", "express": "^4.19.2", - "globals": "^15.0.0", + "globals": "^15.9.0", + "has-flag": "^5.0.1", "jsdoc": "^4.0.3", - "mocha": "^10.4.0", + "mocha": "^10.7.0", "mocha-junit-reporter": "^2.2.1", - "multer": "^1.4.5-lts.1", - "prettier": "^3.2.5", + "multer": "1.4.5-lts.1", + "prettier": "^3.3.3", "serve-index": "^1.9.1", - "sinon": "^17.0.1" + "sinon": "^18.0.0", + "supports-color": "^9.4.0" }, "engines": { "node": ">= 14.21.0" } }, "javascript/node/selenium-webdriver/node_modules/@eslint/eslintrc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", - "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -1773,29 +1775,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "javascript/node/selenium-webdriver/node_modules/@eslint/js": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.1.1.tgz", - "integrity": "sha512-5WoDz3Y19Bg2BnErkZTp0en+c/i9PvgFS7MBe1+m60HjFr0hrphlAGp4yzI7pxpt4xShln4ZyYp4neJm8hmOkQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "javascript/node/selenium-webdriver/node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, "javascript/node/selenium-webdriver/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1827,6 +1806,27 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "javascript/node/selenium-webdriver/node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "javascript/node/selenium-webdriver/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "javascript/node/selenium-webdriver/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1846,28 +1846,28 @@ "dev": true }, "javascript/node/selenium-webdriver/node_modules/eslint": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.1.0.tgz", - "integrity": "sha512-1TCBecGFQtItia2o39P7Z4BK1X7ByNPxAiWJvwiyTGcOwYnTiiASgMpNA6a+beu8cFPhEDWvPf6mIlYUJv6sgA==", + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.8.0.tgz", + "integrity": "sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^3.0.2", - "@eslint/js": "9.1.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.8.0", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.2.3", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.1", + "eslint-scope": "^8.0.2", "eslint-visitor-keys": "^4.0.0", - "espree": "^10.0.1", - "esquery": "^1.4.2", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", @@ -1893,13 +1893,13 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" } }, "javascript/node/selenium-webdriver/node_modules/eslint-scope": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", - "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -1925,12 +1925,12 @@ } }, "javascript/node/selenium-webdriver/node_modules/espree": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", - "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, "dependencies": { - "acorn": "^8.11.3", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.0.0" }, @@ -1967,9 +1967,9 @@ } }, "javascript/node/selenium-webdriver/node_modules/globals": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.0.0.tgz", - "integrity": "sha512-m/C/yR4mjO6pXDTm9/R/SpYTAIyaUB4EOzcaaMEl7mds7Mshct9GfejiJNQGjHHbdMPey13Kpu4TMbYi9ex1pw==", + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", "dev": true, "engines": { "node": ">=18" @@ -1979,24 +1979,27 @@ } }, "javascript/node/selenium-webdriver/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-5.0.1.tgz", + "integrity": "sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "javascript/node/selenium-webdriver/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", + "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2506,8 +2509,7 @@ "node_modules/@bazel/runfiles": { "version": "5.8.1", "resolved": "https://registry.npmjs.org/@bazel/runfiles/-/runfiles-5.8.1.tgz", - "integrity": "sha512-NDdfpdQ6rZlylgv++iMn5FkObC/QlBQvipinGLSOguTYpRywmieOyJ29XHvUilspwTFSILWpoE9CqMGkHXug1g==", - "dev": true + "integrity": "sha512-NDdfpdQ6rZlylgv++iMn5FkObC/QlBQvipinGLSOguTYpRywmieOyJ29XHvUilspwTFSILWpoE9CqMGkHXug1g==" }, "node_modules/@emotion/babel-plugin": { "version": "11.11.0", @@ -3034,14 +3036,28 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", @@ -3080,6 +3096,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", + "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@floating-ui/core": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz", @@ -3160,9 +3194,9 @@ "dev": true }, "node_modules/@humanwhocodes/retry": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.2.3.tgz", - "integrity": "sha512-X38nUbachlb01YMlvPFojKoiXq+LzZvuSce70KPMPdeM1Rj03k4dR7lDslhbqXn3Ang4EU3+EAmwEAsbrjHW3g==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", "dev": true, "engines": { "node": ">=18.18" @@ -4171,9 +4205,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -4208,9 +4242,9 @@ } }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "engines": { "node": ">=6" @@ -4843,9 +4877,9 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4962,9 +4996,9 @@ } }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "engines": { "node": ">=0.3.1" @@ -5057,9 +5091,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", - "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -5328,9 +5362,9 @@ } }, "node_modules/eslint-plugin-mocha": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.4.3.tgz", - "integrity": "sha512-emc4TVjq5Ht0/upR+psftuz6IBG5q279p+1dSRDeHf+NS9aaerBi3lXKo1SEzwC29hFIW21gO89CEWSvRsi8IQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.5.0.tgz", + "integrity": "sha512-F2ALmQVPT1GoP27O1JTZGrV9Pqg8k79OeIuvw63UxMtQKREZtmkK1NFgkZQ2TW7L2JSSFKHFPTtHu5z8R9QNRw==", "dev": true, "dependencies": { "eslint-utils": "^3.0.0", @@ -5387,25 +5421,25 @@ } }, "node_modules/eslint-plugin-n": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.2.1.tgz", - "integrity": "sha512-uW1+df2bo06kR7ix6nB614RUlvjRPrYxlaX832O6e1MCJp4V7YozEdvMgCYuvn4ltnjPu1FVYhQ2KRrmTNoJfg==", + "version": "17.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.10.1.tgz", + "integrity": "sha512-hm/q37W6efDptJXdwirsm6A257iY6ZNtpoSG0wEzFzjJ3AhL7OhEIhdSR2e4OdYfHO5EDeqlCfFrjf9q208IPw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "enhanced-resolve": "^5.15.0", + "enhanced-resolve": "^5.17.0", "eslint-plugin-es-x": "^7.5.0", "get-tsconfig": "^4.7.0", - "globals": "^14.0.0", + "globals": "^15.8.0", "ignore": "^5.2.4", - "minimatch": "^9.0.0", + "minimatch": "^9.0.5", "semver": "^7.5.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://opencollective.com/eslint" }, "peerDependencies": { "eslint": ">=8.23.0" @@ -5421,9 +5455,9 @@ } }, "node_modules/eslint-plugin-n/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", "dev": true, "engines": { "node": ">=18" @@ -5445,9 +5479,9 @@ } }, "node_modules/eslint-plugin-n/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -5490,13 +5524,13 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", "dev": true, "dependencies": { "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" + "synckit": "^0.9.1" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -7762,31 +7796,31 @@ } }, "node_modules/mocha": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", - "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.0.tgz", + "integrity": "sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -7831,9 +7865,9 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -7914,9 +7948,9 @@ } }, "node_modules/nise": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", - "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-6.0.0.tgz", + "integrity": "sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.0", @@ -7927,9 +7961,9 @@ } }, "node_modules/nise/node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", "dev": true }, "node_modules/no-case": { @@ -8264,9 +8298,9 @@ } }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -8864,9 +8898,9 @@ "dev": true }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" @@ -9073,32 +9107,23 @@ } }, "node_modules/sinon": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", - "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-18.0.0.tgz", + "integrity": "sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==", "dev": true, "dependencies": { - "@sinonjs/commons": "^3.0.0", + "@sinonjs/commons": "^3.0.1", "@sinonjs/fake-timers": "^11.2.2", "@sinonjs/samsam": "^8.0.0", - "diff": "^5.1.0", - "nise": "^5.1.5", - "supports-color": "^7.2.0" + "diff": "^5.2.0", + "nise": "^6.0.0", + "supports-color": "^7" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/sinon" } }, - "node_modules/sinon/node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/sinon/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -9302,9 +9327,9 @@ } }, "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", "dev": true, "dependencies": { "@pkgr/core": "^0.1.0", @@ -9639,9 +9664,9 @@ } }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, "node_modules/wrap-ansi": { @@ -9696,9 +9721,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { "node": ">=10.0.0" }, @@ -9776,9 +9801,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "engines": { "node": ">=10" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9c08071ac2135..24ba616517dff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,63 +108,63 @@ importers: specifier: ^0.2.3 version: 0.2.3 ws: - specifier: ^8.17.1 - version: 8.17.1 + specifier: ^8.18.0 + version: 8.18.0 devDependencies: '@eslint/js': - specifier: ^9.5.0 - version: 9.5.0 + specifier: ^9.8.0 + version: 9.8.0 clean-jsdoc-theme: specifier: ^4.3.0 version: 4.3.0(jsdoc@4.0.3) eslint: - specifier: ^9.5.0 - version: 9.5.0(supports-color@9.4.0) + specifier: ^9.8.0 + version: 9.8.0(supports-color@9.4.0) eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@9.5.0) + version: 9.1.0(eslint@9.8.0) eslint-plugin-mocha: - specifier: ^10.4.3 - version: 10.4.3(eslint@9.5.0) + specifier: ^10.5.0 + version: 10.5.0(eslint@9.8.0) eslint-plugin-n: - specifier: ^17.9.0 - version: 17.9.0(eslint@9.5.0) + specifier: ^17.10.1 + version: 17.10.1(eslint@9.8.0) eslint-plugin-no-only-tests: specifier: ^3.1.0 version: 3.1.0 eslint-plugin-prettier: - specifier: ^5.1.3 - version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.5.0)(prettier@3.3.2) + specifier: ^5.2.1 + version: 5.2.1(eslint-config-prettier@9.1.0)(eslint@9.8.0)(prettier@3.3.3) express: specifier: ^4.19.2 version: 4.19.2(supports-color@9.4.0) globals: - specifier: ^15.6.0 - version: 15.6.0 + specifier: ^15.9.0 + version: 15.9.0 has-flag: - specifier: ^4.0.0 - version: 4.0.0 + specifier: ^5.0.1 + version: 5.0.1 jsdoc: specifier: ^4.0.3 version: 4.0.3 mocha: - specifier: ^10.5.1 - version: 10.5.1 + specifier: ^10.7.0 + version: 10.7.0 mocha-junit-reporter: specifier: ^2.2.1 - version: 2.2.1(mocha@10.5.1)(supports-color@9.4.0) + version: 2.2.1(mocha@10.7.0)(supports-color@9.4.0) multer: specifier: 1.4.5-lts.1 version: 1.4.5-lts.1 prettier: - specifier: ^3.3.2 - version: 3.3.2 + specifier: ^3.3.3 + version: 3.3.3 serve-index: specifier: ^1.9.1 version: 1.9.1(supports-color@9.4.0) sinon: - specifier: ^17.0.1 - version: 17.0.1 + specifier: ^18.0.0 + version: 18.0.0 supports-color: specifier: ^9.4.0 version: 9.4.0 @@ -247,7 +247,7 @@ packages: '@babel/traverse': 7.24.7 '@babel/types': 7.24.7 convert-source-map: 2.0.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -480,7 +480,7 @@ packages: '@babel/helper-split-export-declaration': 7.24.7 '@babel/parser': 7.24.7 '@babel/types': 7.24.7 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -622,6 +622,8 @@ packages: /@esbuild/aix-ppc64@0.19.12: resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] requiresBuild: true dev: true optional: true @@ -629,6 +631,8 @@ packages: /@esbuild/android-arm64@0.19.12: resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} engines: {node: '>=12'} + cpu: [arm64] + os: [android] requiresBuild: true dev: true optional: true @@ -636,6 +640,8 @@ packages: /@esbuild/android-arm@0.19.12: resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} engines: {node: '>=12'} + cpu: [arm] + os: [android] requiresBuild: true dev: true optional: true @@ -643,6 +649,8 @@ packages: /@esbuild/android-x64@0.19.12: resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} engines: {node: '>=12'} + cpu: [x64] + os: [android] requiresBuild: true dev: true optional: true @@ -650,6 +658,8 @@ packages: /@esbuild/darwin-arm64@0.19.12: resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] requiresBuild: true dev: true optional: true @@ -657,6 +667,8 @@ packages: /@esbuild/darwin-x64@0.19.12: resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} engines: {node: '>=12'} + cpu: [x64] + os: [darwin] requiresBuild: true dev: true optional: true @@ -664,6 +676,8 @@ packages: /@esbuild/freebsd-arm64@0.19.12: resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] requiresBuild: true dev: true optional: true @@ -671,6 +685,8 @@ packages: /@esbuild/freebsd-x64@0.19.12: resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] requiresBuild: true dev: true optional: true @@ -678,6 +694,8 @@ packages: /@esbuild/linux-arm64@0.19.12: resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} engines: {node: '>=12'} + cpu: [arm64] + os: [linux] requiresBuild: true dev: true optional: true @@ -685,6 +703,8 @@ packages: /@esbuild/linux-arm@0.19.12: resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} engines: {node: '>=12'} + cpu: [arm] + os: [linux] requiresBuild: true dev: true optional: true @@ -692,6 +712,8 @@ packages: /@esbuild/linux-ia32@0.19.12: resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} engines: {node: '>=12'} + cpu: [ia32] + os: [linux] requiresBuild: true dev: true optional: true @@ -699,6 +721,8 @@ packages: /@esbuild/linux-loong64@0.19.12: resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} engines: {node: '>=12'} + cpu: [loong64] + os: [linux] requiresBuild: true dev: true optional: true @@ -706,6 +730,8 @@ packages: /@esbuild/linux-mips64el@0.19.12: resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] requiresBuild: true dev: true optional: true @@ -713,6 +739,8 @@ packages: /@esbuild/linux-ppc64@0.19.12: resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] requiresBuild: true dev: true optional: true @@ -720,6 +748,8 @@ packages: /@esbuild/linux-riscv64@0.19.12: resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] requiresBuild: true dev: true optional: true @@ -727,6 +757,8 @@ packages: /@esbuild/linux-s390x@0.19.12: resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} engines: {node: '>=12'} + cpu: [s390x] + os: [linux] requiresBuild: true dev: true optional: true @@ -734,6 +766,8 @@ packages: /@esbuild/linux-x64@0.19.12: resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} engines: {node: '>=12'} + cpu: [x64] + os: [linux] requiresBuild: true dev: true optional: true @@ -741,6 +775,8 @@ packages: /@esbuild/netbsd-x64@0.19.12: resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] requiresBuild: true dev: true optional: true @@ -748,6 +784,8 @@ packages: /@esbuild/openbsd-x64@0.19.12: resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] requiresBuild: true dev: true optional: true @@ -755,6 +793,8 @@ packages: /@esbuild/sunos-x64@0.19.12: resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} engines: {node: '>=12'} + cpu: [x64] + os: [sunos] requiresBuild: true dev: true optional: true @@ -762,6 +802,8 @@ packages: /@esbuild/win32-arm64@0.19.12: resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} engines: {node: '>=12'} + cpu: [arm64] + os: [win32] requiresBuild: true dev: true optional: true @@ -769,6 +811,8 @@ packages: /@esbuild/win32-ia32@0.19.12: resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} engines: {node: '>=12'} + cpu: [ia32] + os: [win32] requiresBuild: true dev: true optional: true @@ -776,6 +820,8 @@ packages: /@esbuild/win32-x64@0.19.12: resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} engines: {node: '>=12'} + cpu: [x64] + os: [win32] requiresBuild: true dev: true optional: true @@ -790,13 +836,13 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@9.5.0): + /@eslint-community/eslint-utils@4.4.0(eslint@9.8.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 9.5.0(supports-color@9.4.0) + eslint: 9.8.0(supports-color@9.4.0) eslint-visitor-keys: 3.4.3 dev: true @@ -805,8 +851,13 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint/config-array@0.16.0(supports-color@9.4.0): - resolution: {integrity: sha512-/jmuSd74i4Czf1XXn7wGRWZCuyaUZ330NH1Bek0Pplatt4Sy1S5haN21SCLLdbeKslQ+S0wEJ+++v5YibSi+Lg==} + /@eslint-community/regexpp@4.11.0: + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/config-array@0.17.1(supports-color@9.4.0): + resolution: {integrity: sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: '@eslint/object-schema': 2.1.4 @@ -821,7 +872,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 @@ -855,8 +906,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@eslint/js@9.5.0: - resolution: {integrity: sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==} + /@eslint/js@9.8.0: + resolution: {integrity: sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true @@ -907,7 +958,7 @@ packages: deprecated: Use @eslint/config-array instead dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -1454,7 +1505,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -1479,7 +1530,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 eslint: 8.57.0 typescript: 5.4.5 transitivePeerDependencies: @@ -1506,7 +1557,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 eslint: 8.57.0 tsutils: 3.21.0(typescript@5.4.5) typescript: 5.4.5 @@ -1530,7 +1581,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 @@ -1638,8 +1689,8 @@ packages: uri-js: 4.4.1 dev: true - /ansi-colors@4.1.1: - resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} dev: true @@ -2217,8 +2268,19 @@ packages: ms: 2.1.3 dev: true - /debug@4.3.4(supports-color@8.1.1): - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + /debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + + /debug@4.3.5(supports-color@8.1.1): + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -2241,6 +2303,7 @@ packages: dependencies: ms: 2.1.2 supports-color: 9.4.0 + dev: true /decamelize@4.0.0: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} @@ -2317,11 +2380,6 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - /diff@5.0.0: - resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} - engines: {node: '>=0.3.1'} - dev: true - /diff@5.2.0: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} @@ -2594,23 +2652,23 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - /eslint-compat-utils@0.5.1(eslint@9.5.0): + /eslint-compat-utils@0.5.1(eslint@9.8.0): resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' dependencies: - eslint: 9.5.0(supports-color@9.4.0) + eslint: 9.8.0(supports-color@9.4.0) semver: 7.6.2 dev: true - /eslint-config-prettier@9.1.0(eslint@9.5.0): + /eslint-config-prettier@9.1.0(eslint@9.8.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 9.5.0(supports-color@9.4.0) + eslint: 9.8.0(supports-color@9.4.0) dev: true /eslint-config-standard-jsx@11.0.0(eslint-plugin-react@7.34.3)(eslint@8.57.0): @@ -2699,16 +2757,16 @@ packages: - supports-color dev: true - /eslint-plugin-es-x@7.7.0(eslint@9.5.0): + /eslint-plugin-es-x@7.7.0(eslint@9.8.0): resolution: {integrity: sha512-aP3qj8BwiEDPttxQkZdI221DLKq9sI/qHolE2YSQL1/9+xk7dTV+tB1Fz8/IaCA+lnLA1bDEnvaS2LKs0k2Uig==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0) '@eslint-community/regexpp': 4.10.1 - eslint: 9.5.0(supports-color@9.4.0) - eslint-compat-utils: 0.5.1(eslint@9.5.0) + eslint: 9.8.0(supports-color@9.4.0) + eslint-compat-utils: 0.5.1(eslint@9.8.0) dev: true /eslint-plugin-es@4.1.0(eslint@8.57.0): @@ -2757,14 +2815,14 @@ packages: - supports-color dev: true - /eslint-plugin-mocha@10.4.3(eslint@9.5.0): - resolution: {integrity: sha512-emc4TVjq5Ht0/upR+psftuz6IBG5q279p+1dSRDeHf+NS9aaerBi3lXKo1SEzwC29hFIW21gO89CEWSvRsi8IQ==} + /eslint-plugin-mocha@10.5.0(eslint@9.8.0): + resolution: {integrity: sha512-F2ALmQVPT1GoP27O1JTZGrV9Pqg8k79OeIuvw63UxMtQKREZtmkK1NFgkZQ2TW7L2JSSFKHFPTtHu5z8R9QNRw==} engines: {node: '>=14.0.0'} peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 9.5.0(supports-color@9.4.0) - eslint-utils: 3.0.0(eslint@9.5.0) + eslint: 9.8.0(supports-color@9.4.0) + eslint-utils: 3.0.0(eslint@9.8.0) globals: 13.24.0 rambda: 7.5.0 dev: true @@ -2786,18 +2844,18 @@ packages: semver: 7.6.2 dev: true - /eslint-plugin-n@17.9.0(eslint@9.5.0): - resolution: {integrity: sha512-CPSaXDXdrT4nsrOrO4mT4VB6FMUkoySRkHWuuJJHVqsIEjIeZgMY1H7AzSwPbDScikBmLN82KeM1u7ixV7PzGg==} + /eslint-plugin-n@17.10.1(eslint@9.8.0): + resolution: {integrity: sha512-hm/q37W6efDptJXdwirsm6A257iY6ZNtpoSG0wEzFzjJ3AhL7OhEIhdSR2e4OdYfHO5EDeqlCfFrjf9q208IPw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=8.23.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0) enhanced-resolve: 5.17.0 - eslint: 9.5.0(supports-color@9.4.0) - eslint-plugin-es-x: 7.7.0(eslint@9.5.0) + eslint: 9.8.0(supports-color@9.4.0) + eslint-plugin-es-x: 7.7.0(eslint@9.8.0) get-tsconfig: 4.7.5 - globals: 15.6.0 + globals: 15.9.0 ignore: 5.3.1 minimatch: 9.0.5 semver: 7.6.2 @@ -2808,8 +2866,8 @@ packages: engines: {node: '>=5.0.0'} dev: true - /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@9.5.0)(prettier@3.3.2): - resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + /eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0)(eslint@9.8.0)(prettier@3.3.3): + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' @@ -2822,11 +2880,11 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 9.5.0(supports-color@9.4.0) - eslint-config-prettier: 9.1.0(eslint@9.5.0) - prettier: 3.3.2 + eslint: 9.8.0(supports-color@9.4.0) + eslint-config-prettier: 9.1.0(eslint@9.8.0) + prettier: 3.3.3 prettier-linter-helpers: 1.0.0 - synckit: 0.8.8 + synckit: 0.9.1 dev: true /eslint-plugin-promise@6.2.0(eslint@8.57.0): @@ -2881,8 +2939,8 @@ packages: estraverse: 5.3.0 dev: true - /eslint-scope@8.0.1: - resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==} + /eslint-scope@8.0.2: + resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: esrecurse: 4.3.0 @@ -2906,13 +2964,13 @@ packages: eslint-visitor-keys: 2.1.0 dev: true - /eslint-utils@3.0.0(eslint@9.5.0): + /eslint-utils@3.0.0(eslint@9.8.0): resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 9.5.0(supports-color@9.4.0) + eslint: 9.8.0(supports-color@9.4.0) eslint-visitor-keys: 2.1.0 dev: true @@ -2952,7 +3010,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -2983,16 +3041,16 @@ packages: - supports-color dev: true - /eslint@9.5.0(supports-color@9.4.0): - resolution: {integrity: sha512-+NAOZFrW/jFTS3dASCGBxX1pkFD0/fsO+hfAkJ4TyYKwgsXZbqzrw+seCYFCcPCYXvnD67tAnglU7GQTz6kcVw==} + /eslint@9.8.0(supports-color@9.4.0): + resolution: {integrity: sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) - '@eslint-community/regexpp': 4.10.1 - '@eslint/config-array': 0.16.0(supports-color@9.4.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0) + '@eslint-community/regexpp': 4.11.0 + '@eslint/config-array': 0.17.1(supports-color@9.4.0) '@eslint/eslintrc': 3.1.0(supports-color@9.4.0) - '@eslint/js': 9.5.0 + '@eslint/js': 9.8.0 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.3.0 '@nodelib/fs.walk': 1.2.8 @@ -3001,7 +3059,7 @@ packages: cross-spawn: 7.0.3 debug: 4.3.5(supports-color@9.4.0) escape-string-regexp: 4.0.0 - eslint-scope: 8.0.1 + eslint-scope: 8.0.2 eslint-visitor-keys: 4.0.0 espree: 10.1.0 esquery: 1.5.0 @@ -3383,7 +3441,7 @@ packages: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.0.1 + minimatch: 5.1.6 once: 1.4.0 dev: true @@ -3403,8 +3461,8 @@ packages: engines: {node: '>=18'} dev: true - /globals@15.6.0: - resolution: {integrity: sha512-UzcJi88Hw//CurUIRa9Jxb0vgOCcuD/MNjwmXp633cyaRKkCWACkoqHCtfZv43b1kqXGg/fpOa8bwgacCeXsVg==} + /globals@15.9.0: + resolution: {integrity: sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==} engines: {node: '>=18'} dev: true @@ -3488,6 +3546,11 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + /has-flag@5.0.1: + resolution: {integrity: sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==} + engines: {node: '>=12'} + dev: true + /has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: @@ -4238,19 +4301,11 @@ packages: dependencies: brace-expansion: 1.1.11 - /minimatch@5.0.1: - resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true - /minimatch@5.1.6: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 - dev: false /minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} @@ -4280,7 +4335,7 @@ packages: hasBin: true dev: true - /mocha-junit-reporter@2.2.1(mocha@10.5.1)(supports-color@9.4.0): + /mocha-junit-reporter@2.2.1(mocha@10.7.0)(supports-color@9.4.0): resolution: {integrity: sha512-iDn2tlKHn8Vh8o4nCzcUVW4q7iXp7cC4EB78N0cDHIobLymyHNwe0XG8HEHHjc3hJlXm0Vy6zcrxaIhnI2fWmw==} peerDependencies: mocha: '>=2.2.5' @@ -4288,37 +4343,37 @@ packages: debug: 4.3.5(supports-color@9.4.0) md5: 2.3.0 mkdirp: 3.0.1 - mocha: 10.5.1 + mocha: 10.7.0 strip-ansi: 6.0.1 xml: 1.0.1 transitivePeerDependencies: - supports-color dev: true - /mocha@10.5.1: - resolution: {integrity: sha512-eq5tEnaz2kM9ade8cuGJBMh5fBb9Ih/TB+ddlmPR+wLQmwLhUwa0ovqDlg7OTfKquW0BI7NUcNWX7DH8sC+3gw==} + /mocha@10.7.0: + resolution: {integrity: sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA==} engines: {node: '>= 14.0.0'} hasBin: true dependencies: - ansi-colors: 4.1.1 + ansi-colors: 4.1.3 browser-stdout: 1.3.1 chokidar: 3.6.0 - debug: 4.3.4(supports-color@8.1.1) - diff: 5.0.0 + debug: 4.3.5(supports-color@8.1.1) + diff: 5.2.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 glob: 8.1.0 he: 1.2.0 js-yaml: 4.1.0 log-symbols: 4.1.0 - minimatch: 5.0.1 + minimatch: 5.1.6 ms: 2.1.3 - serialize-javascript: 6.0.0 + serialize-javascript: 6.0.2 strip-json-comments: 3.1.1 supports-color: 8.1.1 - workerpool: 6.2.1 + workerpool: 6.5.1 yargs: 16.2.0 - yargs-parser: 20.2.4 + yargs-parser: 20.2.9 yargs-unparser: 2.0.0 dev: true @@ -4359,8 +4414,8 @@ packages: engines: {node: '>= 0.6'} dev: true - /nise@5.1.9: - resolution: {integrity: sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==} + /nise@6.0.0: + resolution: {integrity: sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==} dependencies: '@sinonjs/commons': 3.0.1 '@sinonjs/fake-timers': 11.2.2 @@ -4690,8 +4745,8 @@ packages: fast-diff: 1.3.0 dev: true - /prettier@3.3.2: - resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} + /prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} hasBin: true dev: true @@ -5075,8 +5130,8 @@ packages: - supports-color dev: true - /serialize-javascript@6.0.0: - resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + /serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} dependencies: randombytes: 2.1.0 dev: true @@ -5171,14 +5226,14 @@ packages: object-inspect: 1.13.2 dev: true - /sinon@17.0.1: - resolution: {integrity: sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==} + /sinon@18.0.0: + resolution: {integrity: sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==} dependencies: '@sinonjs/commons': 3.0.1 '@sinonjs/fake-timers': 11.2.2 '@sinonjs/samsam': 8.0.0 diff: 5.2.0 - nise: 5.1.9 + nise: 6.0.0 supports-color: 7.2.0 dev: true @@ -5372,6 +5427,7 @@ packages: /supports-color@9.4.0: resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} engines: {node: '>=12'} + dev: true /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -5382,8 +5438,8 @@ packages: engines: {node: '>=0.10'} dev: false - /synckit@0.8.8: - resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + /synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} dependencies: '@pkgr/core': 0.1.1 @@ -5708,8 +5764,8 @@ packages: engines: {node: '>=0.10.0'} dev: true - /workerpool@6.2.1: - resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} + /workerpool@6.5.1: + resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} dev: true /wrap-ansi@7.0.0: @@ -5723,8 +5779,8 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - /ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + /ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -5766,11 +5822,6 @@ packages: engines: {node: '>= 6'} dev: false - /yargs-parser@20.2.4: - resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} - engines: {node: '>=10'} - dev: true - /yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 413050bc649c2..0cb2fbe21c10e 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -62,7 +62,7 @@ compile_pip_requirements( ], ) -SE_VERSION = "4.24.0.dev202407241614" +SE_VERSION = "4.24.0.dev202407312116" BROWSER_VERSIONS = [ "v85", diff --git a/py/conftest.py b/py/conftest.py index b7edd49884bd2..f2189b6fa5dd8 100644 --- a/py/conftest.py +++ b/py/conftest.py @@ -320,7 +320,7 @@ def wait_for_server(url, timeout): @pytest.fixture(autouse=True, scope="session") def webserver(request): - host = get_lan_ip() if request.config.getoption("use_lan_ip") else "0.0.0.0" + host = get_lan_ip() if request.config.getoption("use_lan_ip") else None webserver = SimpleWebServer(host=host) webserver.start() diff --git a/py/docs/source/conf.py b/py/docs/source/conf.py index 09e676e44c93c..493229e91ad6e 100644 --- a/py/docs/source/conf.py +++ b/py/docs/source/conf.py @@ -58,7 +58,7 @@ # The short X.Y version. version = '4.24' # The full version, including alpha/beta/rc tags. -release = '4.24.0.dev202407241614' +release = '4.24.0.dev202407312116' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/py/selenium/webdriver/__init__.py b/py/selenium/webdriver/__init__.py index c1d5659aac33e..cab256e5ff17e 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.24.0.dev202407241614" +__version__ = "4.24.0.dev202407312116" # We need an explicit __all__ because the above won't otherwise be exported. __all__ = [ diff --git a/py/selenium/webdriver/common/print_page_options.py b/py/selenium/webdriver/common/print_page_options.py index 8673f58610f04..1ffde95c88e67 100644 --- a/py/selenium/webdriver/common/print_page_options.py +++ b/py/selenium/webdriver/common/print_page_options.py @@ -19,6 +19,7 @@ from typing import TYPE_CHECKING from typing import List from typing import Optional +from typing import Type if TYPE_CHECKING: from typing import Literal @@ -125,10 +126,9 @@ def __set__(self, obj, value) -> None: class _ValidateTypeDescriptor: """Base Class Descriptor which validates type of any subclass attribute.""" - expected_type = None - - def __init__(self, name, expected_type): + def __init__(self, name, expected_type: Type): self.name = name + self.expected_type = expected_type def __get__(self, obj, cls): return obj._print_options.get(self.name, None) @@ -142,19 +142,22 @@ def __set__(self, obj, value) -> None: class _ValidateBackGround(_ValidateTypeDescriptor): """Expected type of background attribute.""" - expected_type = bool + def __init__(self, name): + super().__init__(name, bool) class _ValidateShrinkToFit(_ValidateTypeDescriptor): - """Expected type of shirnk to fit attribute.""" + """Expected type of shrink to fit attribute.""" - expected_type = bool + def __init__(self, name): + super().__init__(name, bool) class _ValidatePageRanges(_ValidateTypeDescriptor): - """Excepted type of page ranges attribute.""" + """Expected type of page ranges attribute.""" - expected_type = list + def __init__(self, name): + super().__init__(name, list) class PrintOptions: @@ -190,7 +193,7 @@ class PrintOptions: - Set - `self.page_width` = `value` - Patameters + Parameters ---------- `value`: `float` @@ -210,7 +213,7 @@ class PrintOptions: - Get - `self.margin_top` - Set - - `slef.margin_top` = `value` + - `self.margin_top` = `value` Parameters ---------- @@ -253,7 +256,7 @@ class PrintOptions: ----- - Get - `self.margin_left` - -Set + - Set - `self.margin_left` = `value` Parameters @@ -334,13 +337,13 @@ class PrintOptions: - `None` """ - background = _ValidateBackGround("background", bool) + background = _ValidateBackGround("background") """Gets and Sets background: Usage ----- - Get - - `self.backgorund` + - `self.background` - Set - `self.background` = `value` @@ -356,7 +359,7 @@ class PrintOptions: - `None` """ - shrink_to_fit = _ValidateShrinkToFit("shrinkToFit", bool) + shrink_to_fit = _ValidateShrinkToFit("shrinkToFit") """Gets and Sets shrink_to_fit: Usage @@ -378,7 +381,7 @@ class PrintOptions: - `None` """ - page_ranges = _ValidatePageRanges("pageRanges", list) + page_ranges = _ValidatePageRanges("pageRanges") """Gets and Sets page_ranges: Usage @@ -415,4 +418,4 @@ def _validate_num_property(self, property_name: str, value: float) -> None: raise ValueError(f"{property_name} should be an integer or a float") if value < 0: - raise ValueError(f"{property_name} cannot be less then 0") + raise ValueError(f"{property_name} cannot be less than 0") diff --git a/py/selenium/webdriver/common/timeouts.py b/py/selenium/webdriver/common/timeouts.py index 10423ad3cb19c..adaa9507bef08 100644 --- a/py/selenium/webdriver/common/timeouts.py +++ b/py/selenium/webdriver/common/timeouts.py @@ -68,9 +68,9 @@ def __init__(self, implicit_wait: float = 0, page_load: float = 0, script: float before throwing an error. """ - self.implicit_wait = implicit_wait - self.page_load = page_load - self.script = script + self._implicit_wait = self._convert(implicit_wait) + self._page_load = self._convert(page_load) + self._script = self._convert(script) # Creating descriptor objects implicit_wait = _TimeoutsDescriptor("_implicit_wait") diff --git a/py/selenium/webdriver/remote/remote_connection.py b/py/selenium/webdriver/remote/remote_connection.py index eab43d4693a6c..f09937945b90f 100644 --- a/py/selenium/webdriver/remote/remote_connection.py +++ b/py/selenium/webdriver/remote/remote_connection.py @@ -136,7 +136,11 @@ class RemoteConnection: """ browser_name = None - _timeout = socket._GLOBAL_DEFAULT_TIMEOUT + _timeout = ( + float(os.getenv("GLOBAL_DEFAULT_TIMEOUT")) + if "GLOBAL_DEFAULT_TIMEOUT" in os.environ + else socket._GLOBAL_DEFAULT_TIMEOUT + ) _ca_certs = os.getenv("REQUESTS_CA_BUNDLE") if "REQUESTS_CA_BUNDLE" in os.environ else certifi.where() @classmethod diff --git a/py/setup.py b/py/setup.py index 717dadb9952b2..b8e6a9866f271 100755 --- a/py/setup.py +++ b/py/setup.py @@ -28,7 +28,7 @@ setup_args = { 'cmdclass': {'install': install}, 'name': 'selenium', - 'version': "4.24.0.dev202407241614", + 'version': "4.24.0.dev202407312116", 'license': 'Apache 2.0', 'description': 'Official Python bindings for Selenium WebDriver.', 'long_description': open(join(abspath(dirname(__file__)), "README.rst")).read(), diff --git a/py/test/selenium/webdriver/common/webserver.py b/py/test/selenium/webdriver/common/webserver.py index 2c68b5ec8285f..5a227c1722f6c 100644 --- a/py/test/selenium/webdriver/common/webserver.py +++ b/py/test/selenium/webdriver/common/webserver.py @@ -138,7 +138,7 @@ class SimpleWebServer: def __init__(self, host=DEFAULT_HOST_IP, port=DEFAULT_PORT): self.stop_serving = False - host = host + host = host if host else DEFAULT_HOST_IP port = port while True: try: @@ -171,7 +171,8 @@ def stop(self): def where_is(self, path, localhost=False) -> str: # True force serve the page from localhost - if localhost: + # 0.0.0.0 shouldn't be used as a destination address, so fallback to localhost + if localhost or self.host == "0.0.0.0": return f"http://{DEFAULT_HOST}:{self.port}/{path}" return f"http://{self.host}:{self.port}/{path}" diff --git a/rb/Gemfile.lock b/rb/Gemfile.lock index d99af4f3dd4bb..dadfd59708695 100644 --- a/rb/Gemfile.lock +++ b/rb/Gemfile.lock @@ -3,7 +3,7 @@ PATH specs: selenium-devtools (0.127.0) selenium-webdriver (~> 4.2) - selenium-webdriver (4.23.0) + selenium-webdriver (4.24.0.nightly) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) @@ -41,6 +41,8 @@ GEM diff-lcs (1.5.1) drb (2.2.1) ffi (1.17.0) + ffi (1.17.0-java) + ffi (1.17.0-x86_64-darwin) fileutils (1.7.2) git (1.19.1) addressable (~> 2.8) @@ -49,9 +51,11 @@ GEM i18n (1.14.5) concurrent-ruby (~> 1.0) io-console (0.7.2) + io-console (0.7.2-java) irb (1.14.0) rdoc (>= 4.0.0) reline (>= 0.4.2) + jar-dependencies (0.4.1) json (2.7.2) json (2.7.2-java) language_server-protocol (3.17.0.3) @@ -67,9 +71,11 @@ GEM racc psych (5.1.2) stringio - public_suffix (6.0.0) - racc (1.8.0) - racc (1.8.0-java) + psych (5.1.2-java) + jar-dependencies (>= 0.1.7) + public_suffix (6.0.1) + racc (1.8.1) + racc (1.8.1-java) rack (2.2.9) rainbow (3.1.1) rake (13.2.1) @@ -189,4 +195,4 @@ DEPENDENCIES yard (~> 0.9.11, >= 0.9.36) BUNDLED WITH - 2.2.33 + 2.5.14 diff --git a/rb/lib/selenium/webdriver/version.rb b/rb/lib/selenium/webdriver/version.rb index 0d5f30b465640..44e68c127c214 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.23.0' + VERSION = '4.24.0.nightly' end # WebDriver end # Selenium diff --git a/rust/BUILD.bazel b/rust/BUILD.bazel index 12b51c6e582a2..e8efae2dc457e 100644 --- a/rust/BUILD.bazel +++ b/rust/BUILD.bazel @@ -1,5 +1,5 @@ load("@crates//:defs.bzl", "all_crate_deps") -load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_test", "rust_test_suite", "rustfmt_config") +load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_test", "rustfmt_config") rustfmt_config( name = "enable-rustfmt", @@ -92,6 +92,7 @@ rust_library( exclude = ["main.rs"], ), edition = "2021", + visibility = ["//rust:__subpackages__"], deps = all_crate_deps(normal = True), ) @@ -117,22 +118,3 @@ rust_test( edition = "2021", tags = ["no-sandbox"], ) - -rust_test_suite( - name = "integration", - size = "small", - srcs = glob(["tests/**/*_tests.rs"]), - data = [ - "tests/common.rs", - ":selenium-manager", - ], - edition = "2021", - tags = [ - "no-sandbox", - "requires-network", - ], - deps = [":selenium_manager"] + all_crate_deps( - normal = True, - normal_dev = True, - ), -) diff --git a/rust/tests/BUILD.bazel b/rust/tests/BUILD.bazel new file mode 100644 index 0000000000000..a037d96041f43 --- /dev/null +++ b/rust/tests/BUILD.bazel @@ -0,0 +1,26 @@ +load("@crates//:defs.bzl", "all_crate_deps") +load("//rust:defs.bzl", "rust_test_suite", "rustfmt_config") + +rustfmt_config( + name = "enable-rustfmt", +) + +rust_test_suite( + name = "integration", + size = "small", + srcs = glob(["**/*_tests.rs"]), + data = [ + "common.rs", + "//rust:selenium-manager", + ], + edition = "2021", + tags = [ + "no-sandbox", + "requires-network", + ], + deps = ["//rust:selenium_manager"] + all_crate_deps( + package_name = "rust", + normal = True, + normal_dev = True, + ), +) diff --git a/scripts/github-actions/ci-build.sh b/scripts/github-actions/ci-build.sh index 8f9a2e574415d..e64cbcf62cde8 100755 --- a/scripts/github-actions/ci-build.sh +++ b/scripts/github-actions/ci-build.sh @@ -4,25 +4,13 @@ set -eufo pipefail # We want to see what's going on set -x -# The NPM repository rule wants to write to the HOME directory -# but that's configured for the remote build machines, so run -# that repository rule first so that the subsequent remote -# build runs successfully. We don't care what the output is. -bazel query @npm//:all >/dev/null - # Now run the tests. The engflow build uses pinned browsers # so this should be fine # shellcheck disable=SC2046 bazel test --config=remote-ci --build_tests_only \ --test_tag_filters=-exclusive-if-local,-skip-remote \ --keep_going --flaky_test_attempts=2 \ - //dotnet/... \ - //java/... \ - //javascript/atoms/... \ - //javascript/node/selenium-webdriver/... \ - //javascript/webdriver/... \ - //py/... \ - //rb/spec/... -- $(cat .skipped-tests | tr '\n' ' ') + //... -- $(cat .skipped-tests | tr '\n' ' ') # Build the packages we want to ship to users bazel build --config=remote-ci \