From 2ca3e71d41363cabaeb0f5fcdc8ea8fe3354327a Mon Sep 17 00:00:00 2001 From: Andrei Solntsev Date: Fri, 28 Nov 2025 00:00:58 +0200 Subject: [PATCH] #16645 switch DevTools connection between tabs/windows 1. When `createSessionIfThereIsNotOne(tab1)` is called, CDP session is opened - and attached to the first tab. 2. When `createSessionIfThereIsNotOne(tab2)` is called, we detach connection from the first tab, and attach to the second tab (a new CDP session ID is created). An alternative solution would be holding map of CDP sessions for all existing tabs. --- .../openqa/selenium/devtools/DevTools.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/java/src/org/openqa/selenium/devtools/DevTools.java b/java/src/org/openqa/selenium/devtools/DevTools.java index fd3469b129c8b..076f3af07043a 100644 --- a/java/src/org/openqa/selenium/devtools/DevTools.java +++ b/java/src/org/openqa/selenium/devtools/DevTools.java @@ -22,6 +22,7 @@ import java.io.Closeable; import java.time.Duration; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -31,6 +32,8 @@ import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.openqa.selenium.WebDriver; import org.openqa.selenium.devtools.idealized.Domains; import org.openqa.selenium.devtools.idealized.target.model.SessionID; @@ -44,6 +47,7 @@ public class DevTools implements Closeable { private final Domains protocol; private final Duration timeout = Duration.ofSeconds(30); private final Connection connection; + private String windowHandle = null; private SessionID cdpSession = null; public DevTools(Function protocol, Connection connection) { @@ -73,6 +77,8 @@ public void disconnectSession() { SessionID id = cdpSession; cdpSession = null; + windowHandle = null; + try { connection.sendAndWait( cdpSession, @@ -135,9 +141,12 @@ public void createSessionIfThereIsNotOne() { createSessionIfThereIsNotOne(null); } - public void createSessionIfThereIsNotOne(String windowHandle) { + public void createSessionIfThereIsNotOne(@Nullable String windowHandle) { if (cdpSession == null) { createSession(windowHandle); + } else if (!Objects.equals(this.windowHandle, windowHandle)) { + disconnectSession(); + attachToWindow(windowHandle); } } @@ -152,12 +161,20 @@ public void createSession() { * * @param windowHandle result of {@link WebDriver#getWindowHandle()}, optional. */ - public void createSession(String windowHandle) { + public void createSession(@Nullable String windowHandle) { if (connection.isClosed()) { connection.reopen(); } + attachToWindow(windowHandle); + } + + private void attachToWindow(String windowHandle) { TargetID targetId = findTarget(windowHandle); + attachToTarget(targetId); + this.windowHandle = windowHandle; + } + private void attachToTarget(TargetID targetId) { // Starts the session // CDP creates a parent browser session when websocket connection is made // Create session that is child of parent browser session and not child of already existing @@ -193,6 +210,7 @@ public void createSession(String windowHandle) { } } + @NonNull private TargetID findTarget(String windowHandle) { // Figure out the targets. List infos =