From ddfcd94f123081a5d7029155b02d6b6753c6a8a6 Mon Sep 17 00:00:00 2001 From: Simon Mavi Stewart Date: Mon, 27 Sep 2021 21:59:59 +0100 Subject: [PATCH] [cdp] Handle the case when the first window closes This means that we need to make the remote webdriver aware of the CDP protocol, and that makes me very sad indeed. --- Rakefile | 1 - java/CHANGELOG | 1 + .../org/openqa/selenium/chrome/BUILD.bazel | 2 - .../org/openqa/selenium/chromium/BUILD.bazel | 3 +- .../selenium/chromium/ChromiumDriver.java | 4 +- .../org/openqa/selenium/devtools/BUILD.bazel | 34 +++++++++++------ .../openqa/selenium/devtools/DevTools.java | 4 ++ .../selenium/devtools/DevToolsProvider.java | 2 +- .../openqa/selenium/devtools/HasDevTools.java | 8 +++- .../devtools/idealized/target/Target.java | 3 ++ .../openqa/selenium/devtools/v85/BUILD.bazel | 5 +-- .../selenium/devtools/v85/V85Target.java | 13 +++++++ .../openqa/selenium/devtools/v93/BUILD.bazel | 5 +-- .../selenium/devtools/v93/V93Target.java | 14 +++++++ .../openqa/selenium/devtools/v94/BUILD.bazel | 5 +-- .../selenium/devtools/v94/V94Target.java | 13 +++++++ .../org/openqa/selenium/firefox/BUILD.bazel | 1 - .../selenium/firefox/FirefoxDriver.java | 37 +++++++++++++------ .../org/openqa/selenium/grid/node/BUILD.bazel | 1 - .../selenium/grid/node/config/BUILD.bazel | 1 - .../org/openqa/selenium/remote/BUILD.bazel | 25 ++++++++++--- .../selenium/remote/RemoteWebDriver.java | 12 ++++++ .../org/openqa/selenium/devtools/BUILD.bazel | 3 +- .../selenium/devtools/DevToolsTestBase.java | 13 ++++++- .../devtools/WindowSwitchingTest.java | 36 ++++++++++++++++++ .../openqa/selenium/grid/router/BUILD.bazel | 1 - 26 files changed, 194 insertions(+), 53 deletions(-) create mode 100644 java/test/org/openqa/selenium/devtools/WindowSwitchingTest.java diff --git a/Rakefile b/Rakefile index f3aff6ac6c604..9b56864cb85cc 100644 --- a/Rakefile +++ b/Rakefile @@ -106,7 +106,6 @@ JAVA_RELEASE_TARGETS = %w[ //java/src/org/openqa/selenium/devtools/v85:v85.publish //java/src/org/openqa/selenium/devtools/v93:v93.publish //java/src/org/openqa/selenium/devtools/v94:v94.publish - //java/src/org/openqa/selenium/devtools:devtools.publish //java/src/org/openqa/selenium/edge:edge.publish //java/src/org/openqa/selenium/firefox/xpi:xpi.publish //java/src/org/openqa/selenium/firefox:firefox.publish diff --git a/java/CHANGELOG b/java/CHANGELOG index b6a3c8991d2a6..fc07c4e8488b2 100644 --- a/java/CHANGELOG +++ b/java/CHANGELOG @@ -14,6 +14,7 @@ v4.0.0-rc-2 * Add strongly-typed methods for setting timeouts and other w3c capabilities on the base options class. * Enable live view for Dynamic Grid +* Merged devtools maven artifact into the main remote driver v4.0.0-rc-1 =========== diff --git a/java/src/org/openqa/selenium/chrome/BUILD.bazel b/java/src/org/openqa/selenium/chrome/BUILD.bazel index 606fa7c860773..99e4010c08eb6 100644 --- a/java/src/org/openqa/selenium/chrome/BUILD.bazel +++ b/java/src/org/openqa/selenium/chrome/BUILD.bazel @@ -15,10 +15,8 @@ java_export( "//java:auto-service", "//java/src/org/openqa/selenium:core", "//java/src/org/openqa/selenium/chromium", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/json", "//java/src/org/openqa/selenium/remote", - "//java/src/org/openqa/selenium/remote/http", artifact("com.google.guava:guava"), ], ) diff --git a/java/src/org/openqa/selenium/chromium/BUILD.bazel b/java/src/org/openqa/selenium/chromium/BUILD.bazel index 3f318cfb81b64..17b3dec4f12f0 100644 --- a/java/src/org/openqa/selenium/chromium/BUILD.bazel +++ b/java/src/org/openqa/selenium/chromium/BUILD.bazel @@ -11,11 +11,10 @@ java_export( "//visibility:public", ], exports = [ - "//java/src/org/openqa/selenium/devtools", + "//java/src/org/openqa/selenium/remote", ], deps = [ "//java:auto-service", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/json", "//java/src/org/openqa/selenium/remote", artifact("com.google.guava:guava"), diff --git a/java/src/org/openqa/selenium/chromium/ChromiumDriver.java b/java/src/org/openqa/selenium/chromium/ChromiumDriver.java index 956780ab00626..75d4652815b93 100644 --- a/java/src/org/openqa/selenium/chromium/ChromiumDriver.java +++ b/java/src/org/openqa/selenium/chromium/ChromiumDriver.java @@ -217,8 +217,8 @@ public Map executeCdpCommand(String commandName, Map new WebDriverException("Unable to create DevTools connection")); + public Optional maybeGetDevTools() { + return devTools; } public String getCastSinks() { diff --git a/java/src/org/openqa/selenium/devtools/BUILD.bazel b/java/src/org/openqa/selenium/devtools/BUILD.bazel index 389c063521c35..00c78fcf1a962 100644 --- a/java/src/org/openqa/selenium/devtools/BUILD.bazel +++ b/java/src/org/openqa/selenium/devtools/BUILD.bazel @@ -1,7 +1,6 @@ load("@rules_jvm_external//:defs.bzl", "artifact") load("//common:defs.bzl", "copy_file") -load("//java:defs.bzl", "java_binary", "java_export", "java_library") -load("//java:version.bzl", "SE_VERSION") +load("//java:defs.bzl", "java_binary", "java_library") GENERATOR_SOURCES = [ "CdpClientGenerator.java", @@ -33,7 +32,25 @@ copy_file( out = "mutation-listener.js", ) -java_export( +AUGMENTER_SRCS = [ + "DevToolsProvider.java", +] + +java_library( + name = "augmenter", + srcs = AUGMENTER_SRCS, + visibility = [ + "//java/src/org/openqa/selenium/remote:__pkg__", + ], + deps = [ + ":devtools", + "//java:auto-service", + "//java/src/org/openqa/selenium:core", + "//java/src/org/openqa/selenium/remote:api", + ], +) + +java_library( name = "devtools", srcs = glob( [ @@ -42,18 +59,13 @@ java_export( "idealized/**/*.java", "noop/*.java", ], - exclude = PROTOTYPE_SOURCES + GENERATOR_SOURCES, + exclude = AUGMENTER_SRCS + GENERATOR_SOURCES + PROTOTYPE_SOURCES, ), - maven_coordinates = "org.seleniumhq.selenium:selenium-devtools:%s" % SE_VERSION, - opens_to = [ - "org.openqa.selenium.json", - ], - pom_template = "//java/src/org/openqa/selenium:template-pom", resources = [ ":mutation-listener", ], visibility = [ - "//visibility:public", + "//java/src/org/openqa/selenium/remote:__pkg__", ], exports = [ ":devtools-prototypes", @@ -63,7 +75,7 @@ java_export( "//java:auto-service", "//java/src/org/openqa/selenium:core", "//java/src/org/openqa/selenium/json", - "//java/src/org/openqa/selenium/remote", + "//java/src/org/openqa/selenium/remote/http", artifact("com.google.guava:guava"), ], ) diff --git a/java/src/org/openqa/selenium/devtools/DevTools.java b/java/src/org/openqa/selenium/devtools/DevTools.java index 3eaf65b787de6..4e8a331ffcc11 100644 --- a/java/src/org/openqa/selenium/devtools/DevTools.java +++ b/java/src/org/openqa/selenium/devtools/DevTools.java @@ -53,6 +53,10 @@ public Domains getDomains() { @Override public void close() { + disconnectSession(); + } + + public void disconnectSession() { if (cdpSession != null) { SessionID id = cdpSession; cdpSession = null; diff --git a/java/src/org/openqa/selenium/devtools/DevToolsProvider.java b/java/src/org/openqa/selenium/devtools/DevToolsProvider.java index 1641b1ca1cd44..1316b95914d4d 100644 --- a/java/src/org/openqa/selenium/devtools/DevToolsProvider.java +++ b/java/src/org/openqa/selenium/devtools/DevToolsProvider.java @@ -47,7 +47,7 @@ public HasDevTools getImplementation(Capabilities caps, ExecuteMethod executeMet CdpInfo info = new CdpVersionFinder().match(version).orElseGet(NoOpCdpInfo::new); Optional devTools = SeleniumCdpConnection.create(caps).map(conn -> new DevTools(info::getDomains, conn)); - return () -> devTools.orElseThrow(() -> new IllegalStateException("Unable to create connection to " + caps)); + return () -> devTools; } private String getCdpUrl(Capabilities caps) { diff --git a/java/src/org/openqa/selenium/devtools/HasDevTools.java b/java/src/org/openqa/selenium/devtools/HasDevTools.java index b049d7dcca202..475d074554e5c 100644 --- a/java/src/org/openqa/selenium/devtools/HasDevTools.java +++ b/java/src/org/openqa/selenium/devtools/HasDevTools.java @@ -17,8 +17,14 @@ package org.openqa.selenium.devtools; +import java.util.Optional; + public interface HasDevTools { - DevTools getDevTools(); + default DevTools getDevTools() { + return maybeGetDevTools().orElseThrow(() -> new DevToolsException("Unable to create DevTools connection")); + } + + Optional maybeGetDevTools(); } diff --git a/java/src/org/openqa/selenium/devtools/idealized/target/Target.java b/java/src/org/openqa/selenium/devtools/idealized/target/Target.java index 6b93d1be2e30b..419500c58eb3c 100644 --- a/java/src/org/openqa/selenium/devtools/idealized/target/Target.java +++ b/java/src/org/openqa/selenium/devtools/idealized/target/Target.java @@ -18,6 +18,7 @@ package org.openqa.selenium.devtools.idealized.target; import org.openqa.selenium.devtools.Command; +import org.openqa.selenium.devtools.Event; import org.openqa.selenium.devtools.idealized.target.model.SessionID; import org.openqa.selenium.devtools.idealized.target.model.TargetID; import org.openqa.selenium.devtools.idealized.target.model.TargetInfo; @@ -37,4 +38,6 @@ public interface Target { Command attachToTarget(TargetID targetId); Command setAutoAttach(); + + Event detached(); } diff --git a/java/src/org/openqa/selenium/devtools/v85/BUILD.bazel b/java/src/org/openqa/selenium/devtools/v85/BUILD.bazel index d4ca47b593906..d854666d01efd 100644 --- a/java/src/org/openqa/selenium/devtools/v85/BUILD.bazel +++ b/java/src/org/openqa/selenium/devtools/v85/BUILD.bazel @@ -21,9 +21,8 @@ java_export( ":cdp", "//java:auto-service", "//java/src/org/openqa/selenium:core", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/json", - "//java/src/org/openqa/selenium/remote/http", + "//java/src/org/openqa/selenium/remote", artifact("com.google.guava:guava"), ], ) @@ -38,8 +37,8 @@ java_library( ], deps = [ "//java/src/org/openqa/selenium:core", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/json", + "//java/src/org/openqa/selenium/remote", artifact("com.google.guava:guava"), ], ) diff --git a/java/src/org/openqa/selenium/devtools/v85/V85Target.java b/java/src/org/openqa/selenium/devtools/v85/V85Target.java index 9255ab3f23fb5..65f13a7cc41b2 100644 --- a/java/src/org/openqa/selenium/devtools/v85/V85Target.java +++ b/java/src/org/openqa/selenium/devtools/v85/V85Target.java @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap; import org.openqa.selenium.devtools.Command; import org.openqa.selenium.devtools.ConverterFunctions; +import org.openqa.selenium.devtools.Event; import org.openqa.selenium.devtools.idealized.browser.model.BrowserContextID; import org.openqa.selenium.devtools.idealized.target.model.SessionID; import org.openqa.selenium.devtools.idealized.target.model.TargetID; @@ -86,4 +87,16 @@ public Command attachToTarget(TargetID targetId) { public Command setAutoAttach() { return Target.setAutoAttach(true, false, Optional.of(true)); } + + @Override + public Event detached() { + return new Event<>( + "Target.detachedFromTarget", + input -> { + Function converter = + ConverterFunctions.map("targetId", org.openqa.selenium.devtools.v85.target.model.TargetID.class); + return new TargetID(converter.apply(input).toString()); + } + ); + } } diff --git a/java/src/org/openqa/selenium/devtools/v93/BUILD.bazel b/java/src/org/openqa/selenium/devtools/v93/BUILD.bazel index 08d1df510f42d..cee25c8120fee 100644 --- a/java/src/org/openqa/selenium/devtools/v93/BUILD.bazel +++ b/java/src/org/openqa/selenium/devtools/v93/BUILD.bazel @@ -23,9 +23,8 @@ java_export( ":cdp", "//java:auto-service", "//java/src/org/openqa/selenium:core", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/json", - "//java/src/org/openqa/selenium/remote/http", + "//java/src/org/openqa/selenium/remote", artifact("com.google.guava:guava"), ], ) @@ -40,8 +39,8 @@ java_library( ], deps = [ "//java/src/org/openqa/selenium:core", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/json", + "//java/src/org/openqa/selenium/remote", artifact("com.google.guava:guava"), ], ) diff --git a/java/src/org/openqa/selenium/devtools/v93/V93Target.java b/java/src/org/openqa/selenium/devtools/v93/V93Target.java index 883245b00b8e5..3bb2fe5958f13 100644 --- a/java/src/org/openqa/selenium/devtools/v93/V93Target.java +++ b/java/src/org/openqa/selenium/devtools/v93/V93Target.java @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap; import org.openqa.selenium.devtools.Command; import org.openqa.selenium.devtools.ConverterFunctions; +import org.openqa.selenium.devtools.Event; import org.openqa.selenium.devtools.idealized.browser.model.BrowserContextID; import org.openqa.selenium.devtools.idealized.target.model.SessionID; import org.openqa.selenium.devtools.idealized.target.model.TargetID; @@ -86,4 +87,17 @@ public Command attachToTarget(TargetID targetId) { public Command setAutoAttach() { return Target.setAutoAttach(true, false, Optional.of(true)); } + + @Override + public Event detached() { + return new Event<>( + "Target.detachedFromTarget", + input -> { + Function converter = + ConverterFunctions.map("targetId", org.openqa.selenium.devtools.v93.target.model.TargetID.class); + return new TargetID(converter.apply(input).toString()); + } + ); + } + } diff --git a/java/src/org/openqa/selenium/devtools/v94/BUILD.bazel b/java/src/org/openqa/selenium/devtools/v94/BUILD.bazel index 37ebad445c84e..816bf12408223 100644 --- a/java/src/org/openqa/selenium/devtools/v94/BUILD.bazel +++ b/java/src/org/openqa/selenium/devtools/v94/BUILD.bazel @@ -23,9 +23,8 @@ java_export( ":cdp", "//java:auto-service", "//java/src/org/openqa/selenium:core", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/json", - "//java/src/org/openqa/selenium/remote/http", + "//java/src/org/openqa/selenium/remote", artifact("com.google.guava:guava"), ], ) @@ -40,8 +39,8 @@ java_library( ], deps = [ "//java/src/org/openqa/selenium:core", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/json", + "//java/src/org/openqa/selenium/remote", artifact("com.google.guava:guava"), ], ) diff --git a/java/src/org/openqa/selenium/devtools/v94/V94Target.java b/java/src/org/openqa/selenium/devtools/v94/V94Target.java index e594388834e84..4cb52de38d917 100644 --- a/java/src/org/openqa/selenium/devtools/v94/V94Target.java +++ b/java/src/org/openqa/selenium/devtools/v94/V94Target.java @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap; import org.openqa.selenium.devtools.Command; import org.openqa.selenium.devtools.ConverterFunctions; +import org.openqa.selenium.devtools.Event; import org.openqa.selenium.devtools.idealized.browser.model.BrowserContextID; import org.openqa.selenium.devtools.idealized.target.model.SessionID; import org.openqa.selenium.devtools.idealized.target.model.TargetID; @@ -86,4 +87,16 @@ public Command attachToTarget(TargetID targetId) { public Command setAutoAttach() { return Target.setAutoAttach(true, false, Optional.of(true)); } + + @Override + public Event detached() { + return new Event<>( + "Target.detachedFromTarget", + input -> { + Function converter = + ConverterFunctions.map("targetId", org.openqa.selenium.devtools.v94.target.model.TargetID.class); + return new TargetID(converter.apply(input).toString()); + } + ); + } } diff --git a/java/src/org/openqa/selenium/firefox/BUILD.bazel b/java/src/org/openqa/selenium/firefox/BUILD.bazel index a7b33db5972c7..9799f029d25e8 100644 --- a/java/src/org/openqa/selenium/firefox/BUILD.bazel +++ b/java/src/org/openqa/selenium/firefox/BUILD.bazel @@ -12,7 +12,6 @@ java_export( visibility = ["//visibility:public"], deps = [ "//java:auto-service", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/devtools/v85", "//java/src/org/openqa/selenium/json", "//java/src/org/openqa/selenium/remote", diff --git a/java/src/org/openqa/selenium/firefox/FirefoxDriver.java b/java/src/org/openqa/selenium/firefox/FirefoxDriver.java index 82bfe3bc429c1..11327bf4dc505 100644 --- a/java/src/org/openqa/selenium/firefox/FirefoxDriver.java +++ b/java/src/org/openqa/selenium/firefox/FirefoxDriver.java @@ -331,20 +331,35 @@ private static Capabilities dropCapabilities(Capabilities capabilities) { } @Override - public DevTools getDevTools() { - if (devTools == null) { - URI wsUri = cdpUri.orElseThrow(() -> - new DevToolsException("This version of Firefox or geckodriver does not support CDP")); + public Optional maybeGetDevTools() { + if (devTools != null) { + return Optional.of(devTools); + } + + if (!cdpUri.isPresent()) { + return Optional.empty(); + } + + URI wsUri = cdpUri.orElseThrow(() -> + new DevToolsException("This version of Firefox or geckodriver does not support CDP")); + HttpClient.Factory clientFactory = HttpClient.Factory.createDefault(); - HttpClient.Factory clientFactory = HttpClient.Factory.createDefault(); + ClientConfig wsConfig = ClientConfig.defaultConfig().baseUri(wsUri); + HttpClient wsClient = clientFactory.createClient(wsConfig); - ClientConfig wsConfig = ClientConfig.defaultConfig().baseUri(wsUri); - HttpClient wsClient = clientFactory.createClient(wsConfig); + Connection connection = new Connection(wsClient, wsUri.toString()); + CdpInfo cdpInfo = new CdpVersionFinder().match("85.0").orElseGet(NoOpCdpInfo::new); + devTools = new DevTools(cdpInfo::getDomains, connection); - Connection connection = new Connection(wsClient, wsUri.toString()); - CdpInfo cdpInfo = new CdpVersionFinder().match("85.0").orElseGet(NoOpCdpInfo::new); - devTools = new DevTools(cdpInfo::getDomains, connection); + return Optional.of(devTools); + } + + @Override + public DevTools getDevTools() { + if (!cdpUri.isPresent()) { + throw new DevToolsException("This version of Firefox or geckodriver does not support CDP"); } - return devTools; + + return maybeGetDevTools().orElseThrow(() -> new DevToolsException("Unable to initialize CDP connection")); } } diff --git a/java/src/org/openqa/selenium/grid/node/BUILD.bazel b/java/src/org/openqa/selenium/grid/node/BUILD.bazel index 26bec60efbaac..704b41b436764 100644 --- a/java/src/org/openqa/selenium/grid/node/BUILD.bazel +++ b/java/src/org/openqa/selenium/grid/node/BUILD.bazel @@ -13,7 +13,6 @@ java_library( ], deps = [ "//java/src/org/openqa/selenium:core", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/grid/component", "//java/src/org/openqa/selenium/grid/data", "//java/src/org/openqa/selenium/grid/jmx", diff --git a/java/src/org/openqa/selenium/grid/node/config/BUILD.bazel b/java/src/org/openqa/selenium/grid/node/config/BUILD.bazel index 11d34040e2d60..620d0cc0b7385 100644 --- a/java/src/org/openqa/selenium/grid/node/config/BUILD.bazel +++ b/java/src/org/openqa/selenium/grid/node/config/BUILD.bazel @@ -12,7 +12,6 @@ java_library( deps = [ "//java:auto-service", "//java/src/org/openqa/selenium/chromium", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/grid/config", "//java/src/org/openqa/selenium/grid/data", "//java/src/org/openqa/selenium/grid/node", diff --git a/java/src/org/openqa/selenium/remote/BUILD.bazel b/java/src/org/openqa/selenium/remote/BUILD.bazel index 17e27d004ffde..c18e4e2665872 100644 --- a/java/src/org/openqa/selenium/remote/BUILD.bazel +++ b/java/src/org/openqa/selenium/remote/BUILD.bazel @@ -1,11 +1,10 @@ load("@rules_jvm_external//:defs.bzl", "artifact") load("//common:defs.bzl", "copy_file") -load("//java:defs.bzl", "java_export") +load("//java:defs.bzl", "java_export", "java_library") load("//java:version.bzl", "SE_VERSION") java_export( name = "remote", - srcs = glob(["**/*.java"]), hides = [ "org.openqa.selenium.remote.internal", ], @@ -14,10 +13,6 @@ java_export( "org.openqa.selenium.json", ], pom_template = "//java/src/org/openqa/selenium:template-pom", - resources = [ - ":get-attribute", - ":is-displayed", - ], uses = [ "org.openqa.selenium.remote.AugmenterProvider", "org.openqa.selenium.remote.session.CapabilitiesFilter", @@ -26,7 +21,10 @@ java_export( ], visibility = ["//visibility:public"], exports = [ + ":api", "//java/src/org/openqa/selenium:core", + "//java/src/org/openqa/selenium/devtools", + "//java/src/org/openqa/selenium/devtools:augmenter", "//java/src/org/openqa/selenium/io", "//java/src/org/openqa/selenium/os", "//java/src/org/openqa/selenium/remote/http", @@ -34,8 +32,23 @@ java_export( "//java/src/org/openqa/selenium/remote/tracing", "//java/src/org/openqa/selenium/remote/tracing/opentelemetry", ], +) + +java_library( + name = "api", + srcs = glob(["**/*.java"]), + resources = [ + ":get-attribute", + ":is-displayed", + ], + visibility = [ + "//java/src/org/openqa/selenium/devtools:__pkg__", + ], + exports = [ + ], deps = [ "//java/src/org/openqa/selenium:core", + "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/io", "//java/src/org/openqa/selenium/json", "//java/src/org/openqa/selenium/os", diff --git a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java index 7e7651ade656c..e5dffd693e92b 100644 --- a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java +++ b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java @@ -43,6 +43,8 @@ import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; import org.openqa.selenium.WindowType; +import org.openqa.selenium.devtools.DevTools; +import org.openqa.selenium.devtools.HasDevTools; import org.openqa.selenium.interactions.HasInputDevices; import org.openqa.selenium.interactions.Interactive; import org.openqa.selenium.interactions.Keyboard; @@ -429,6 +431,16 @@ public String getPageSource() { @Override public void close() { + if (this instanceof HasDevTools) { + // This is a brute force approach to "solving" the problem of a hanging + // CDP connection. Take a look at https://github.com/aslushnikov/getting-started-with-cdp#session-hierarchy + // to get up to speed, but essentially if the page session of the + // first browser window is closed, the next CDP command will hang + // indefinitely. To prevent that from happening, we close the current + // connection. The next CDP command _should_ make us reconnect + ((HasDevTools) this).maybeGetDevTools().ifPresent(DevTools::disconnectSession); + } + execute(DriverCommand.CLOSE); } diff --git a/java/test/org/openqa/selenium/devtools/BUILD.bazel b/java/test/org/openqa/selenium/devtools/BUILD.bazel index 62b698f9bcfde..a49a4d3ffbfec 100644 --- a/java/test/org/openqa/selenium/devtools/BUILD.bazel +++ b/java/test/org/openqa/selenium/devtools/BUILD.bazel @@ -15,7 +15,6 @@ java_selenium_test_suite( ], deps = [ ":test-lib", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/grid/security", "//java/src/org/openqa/selenium/json", "//java/src/org/openqa/selenium/remote", @@ -42,12 +41,12 @@ java_library( ), deps = [ "//java/src/org/openqa/selenium/chrome", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/remote", "//java/test/org/openqa/selenium/environment", "//java/test/org/openqa/selenium/testing:test-base", "//java/test/org/openqa/selenium/testing/drivers", artifact("junit:junit"), artifact("org.assertj:assertj-core"), + artifact("org.hamcrest:hamcrest"), ], ) diff --git a/java/test/org/openqa/selenium/devtools/DevToolsTestBase.java b/java/test/org/openqa/selenium/devtools/DevToolsTestBase.java index 9ae8684c0a2bf..eb977cc98586a 100644 --- a/java/test/org/openqa/selenium/devtools/DevToolsTestBase.java +++ b/java/test/org/openqa/selenium/devtools/DevToolsTestBase.java @@ -18,8 +18,10 @@ package org.openqa.selenium.devtools; import static org.assertj.core.api.Assumptions.assumeThat; +import static org.openqa.selenium.testing.TestUtilities.isFirefox; import static org.openqa.selenium.testing.TestUtilities.isFirefoxVersionOlderThan; +import org.junit.AssumptionViolatedException; import org.junit.Before; import org.openqa.selenium.testing.JUnit4TestBase; @@ -34,6 +36,15 @@ public void setUp() { devTools = ((HasDevTools) driver).getDevTools(); devTools.createSessionIfThereIsNotOne(); - devTools.clearListeners(); + + try { + devTools.clearListeners(); + } catch (DevToolsException e) { + if (isFirefox(driver)) { + throw new AssumptionViolatedException( + "Unable to clear listeners on Firefox because Fetch domain is not implemented"); + } + throw e; + } } } diff --git a/java/test/org/openqa/selenium/devtools/WindowSwitchingTest.java b/java/test/org/openqa/selenium/devtools/WindowSwitchingTest.java new file mode 100644 index 0000000000000..2b238e7617b0a --- /dev/null +++ b/java/test/org/openqa/selenium/devtools/WindowSwitchingTest.java @@ -0,0 +1,36 @@ +package org.openqa.selenium.devtools; + +import org.junit.Test; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WindowType; +import org.openqa.selenium.devtools.idealized.target.model.TargetInfo; +import org.openqa.selenium.remote.Augmenter; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class WindowSwitchingTest extends DevToolsTestBase { + + @Test + public void shouldBeAbleToSwitchWindowsAndCloseTheOriginal() { + WebDriver driver = new Augmenter().augment(this.driver); + + driver.get("https://www.selenium.dev"); + + String originalWindow = driver.getWindowHandle(); + driver.switchTo().newWindow(WindowType.TAB); + + String newWindowHandle = driver.getWindowHandle(); + List originalTargets = devTools.send(devTools.getDomains().target().getTargets()); + + // this .close() kills the dev tools session, no chance to ever retrieve a new one for the other tab + driver.switchTo().window(originalWindow).close(); + driver.switchTo().window(newWindowHandle); + driver.get("https://www.selenium.dev/documentation/webdriver/browser_manipulation/"); + + List updatedTargets = this.devTools.send(this.devTools.getDomains().target().getTargets()); + + assertThat(updatedTargets).isNotEqualTo(originalTargets); + } +} diff --git a/java/test/org/openqa/selenium/grid/router/BUILD.bazel b/java/test/org/openqa/selenium/grid/router/BUILD.bazel index f8007fe89b5d1..6dd5c0584da05 100644 --- a/java/test/org/openqa/selenium/grid/router/BUILD.bazel +++ b/java/test/org/openqa/selenium/grid/router/BUILD.bazel @@ -48,7 +48,6 @@ java_selenium_test_suite( deps = [ ":support", "//java/src/org/openqa/selenium/chrome", - "//java/src/org/openqa/selenium/devtools", "//java/src/org/openqa/selenium/firefox", "//java/src/org/openqa/selenium/json", "//java/src/org/openqa/selenium/remote",