diff --git a/java/src/org/openqa/selenium/remote/BUILD.bazel b/java/src/org/openqa/selenium/remote/BUILD.bazel index 71bfde2e5d0b5..4fc796ddcb3d7 100644 --- a/java/src/org/openqa/selenium/remote/BUILD.bazel +++ b/java/src/org/openqa/selenium/remote/BUILD.bazel @@ -63,6 +63,7 @@ java_library( deps = [ "//java/src/org/openqa/selenium:core", "//java/src/org/openqa/selenium/bidi", + "//java/src/org/openqa/selenium/bidi/browsingcontext", "//java/src/org/openqa/selenium/bidi/log", "//java/src/org/openqa/selenium/bidi/module", "//java/src/org/openqa/selenium/bidi/network", diff --git a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java index 30d8f000adcee..1b59a405827f7 100644 --- a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java +++ b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java @@ -65,6 +65,7 @@ import org.openqa.selenium.NoSuchFrameException; import org.openqa.selenium.NoSuchWindowException; import org.openqa.selenium.OutputType; +import org.openqa.selenium.PageLoadStrategy; import org.openqa.selenium.Pdf; import org.openqa.selenium.Platform; import org.openqa.selenium.Point; @@ -78,6 +79,8 @@ import org.openqa.selenium.WindowType; import org.openqa.selenium.bidi.BiDi; import org.openqa.selenium.bidi.HasBiDi; +import org.openqa.selenium.bidi.browsingcontext.BrowsingContext; +import org.openqa.selenium.bidi.browsingcontext.ReadinessState; import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.HasDevTools; import org.openqa.selenium.federatedcredentialmanagement.FederatedCredentialManagementDialog; @@ -371,7 +374,34 @@ public Capabilities getCapabilities() { @Override public void get(String url) { - execute(DriverCommand.GET(url)); + if (isBiDiEnabled()) { + new BrowsingContext(this, getWindowHandle()).navigate(url, getReadinessState()); + } else { + execute(DriverCommand.GET(url)); + } + } + + // BiDi is active when the driver implements HasBiDi and the session returned a WebSocket URL + // (a String), not just the boolean request capability that was sent at session creation. + private boolean isBiDiEnabled() { + return this instanceof HasBiDi + && getCapabilities().getCapability("webSocketUrl") instanceof String; + } + + private ReadinessState getReadinessState() { + Object raw = getCapabilities().getCapability(CapabilityType.PAGE_LOAD_STRATEGY); + // The capability may be a PageLoadStrategy enum (set locally) or a String (deserialized from + // JSON), so normalise to the enum via toString() before comparing. + PageLoadStrategy strategy = + raw instanceof PageLoadStrategy + ? (PageLoadStrategy) raw + : PageLoadStrategy.fromString(raw == null ? null : raw.toString()); + if (PageLoadStrategy.EAGER.equals(strategy)) { + return ReadinessState.INTERACTIVE; + } else if (PageLoadStrategy.NONE.equals(strategy)) { + return ReadinessState.NONE; + } + return ReadinessState.COMPLETE; } @Override @@ -1218,12 +1248,20 @@ private class RemoteNavigation implements Navigation { @Override public void back() { - execute(DriverCommand.GO_BACK); + if (isBiDiEnabled()) { + new BrowsingContext(RemoteWebDriver.this, getWindowHandle()).back(); + } else { + execute(DriverCommand.GO_BACK); + } } @Override public void forward() { - execute(DriverCommand.GO_FORWARD); + if (isBiDiEnabled()) { + new BrowsingContext(RemoteWebDriver.this, getWindowHandle()).forward(); + } else { + execute(DriverCommand.GO_FORWARD); + } } @Override @@ -1238,7 +1276,11 @@ public void to(URL url) { @Override public void refresh() { - execute(DriverCommand.REFRESH); + if (isBiDiEnabled()) { + new BrowsingContext(RemoteWebDriver.this, getWindowHandle()).reload(getReadinessState()); + } else { + execute(DriverCommand.REFRESH); + } } } diff --git a/java/test/org/openqa/selenium/bidi/browsingcontext/BiDiNavigationTest.java b/java/test/org/openqa/selenium/bidi/browsingcontext/BiDiNavigationTest.java new file mode 100644 index 0000000000000..fc1febe132db1 --- /dev/null +++ b/java/test/org/openqa/selenium/bidi/browsingcontext/BiDiNavigationTest.java @@ -0,0 +1,113 @@ +// 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.bidi.browsingcontext; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs; +import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated; +import static org.openqa.selenium.testing.drivers.Browser.EDGE; + +import java.net.MalformedURLException; +import java.net.URL; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.testing.JupiterTestBase; +import org.openqa.selenium.testing.NeedsFreshDriver; +import org.openqa.selenium.testing.NotYetImplemented; + +class BiDiNavigationTest extends JupiterTestBase { + + @Test + @NeedsFreshDriver + void driverGetNavigatesToUrlViaBiDi() { + String url = appServer.whereIs("formPage.html"); + driver.get(url); + assertThat(driver.getCurrentUrl()).contains("formPage.html"); + assertThat(driver.getTitle()).isEqualTo("We Leave From Here"); + } + + @Test + @NeedsFreshDriver + void driverGetNavigatesToSecondUrlViaBiDi() { + driver.get(pages.formPage); + String url = appServer.whereIs("simpleTest.html"); + driver.get(url); + assertThat(driver.getCurrentUrl()).contains("simpleTest.html"); + } + + @Test + @NeedsFreshDriver + @NotYetImplemented(EDGE) + void navigateToStringUrlViaNavigationTo() { + String url = appServer.whereIs("formPage.html"); + driver.navigate().to(url); + assertThat(driver.getCurrentUrl()).contains("formPage.html"); + assertThat(driver.getTitle()).isEqualTo("We Leave From Here"); + } + + @Test + @NeedsFreshDriver + @NotYetImplemented(EDGE) + void navigateToUrlObjectViaNavigationTo() throws MalformedURLException { + URL url = new URL(appServer.whereIs("formPage.html")); + driver.navigate().to(url); + assertThat(driver.getCurrentUrl()).contains("formPage.html"); + assertThat(driver.getTitle()).isEqualTo("We Leave From Here"); + } + + @Test + @NeedsFreshDriver + @NotYetImplemented(EDGE) + void navigateBackTraversesHistory() { + driver.get(pages.formPage); + wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit(); + wait.until(titleIs("We Arrive Here")); + + driver.navigate().back(); + wait.until(titleIs("We Leave From Here")); + } + + @Test + @NeedsFreshDriver + @NotYetImplemented(EDGE) + void navigateForwardTraversesHistory() { + driver.get(pages.formPage); + wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit(); + wait.until(titleIs("We Arrive Here")); + + driver.navigate().back(); + wait.until(titleIs("We Leave From Here")); + + driver.navigate().forward(); + wait.until(titleIs("We Arrive Here")); + } + + @Test + @NeedsFreshDriver + @NotYetImplemented(EDGE) + void refreshReloadsCurrentPage() { + String url = appServer.whereIs("formPage.html"); + driver.get(url); + assertThat(driver.getTitle()).isEqualTo("We Leave From Here"); + + driver.navigate().refresh(); + + assertThat(driver.getCurrentUrl()).contains("formPage.html"); + assertThat(driver.getTitle()).isEqualTo("We Leave From Here"); + } +}