[WebEngine] Add NavigationController instrumentation tests
Bug: 1404980
Change-Id: I66fe9a0431e89fd4114fd7f1ff561803e588e565
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4136718
Reviewed-by: Rayan Kanso <rayankans@chromium.org>
Commit-Queue: Susanne Westphal <swestphal@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1091284}
diff --git a/weblayer/browser/android/javatests/BUILD.gn b/weblayer/browser/android/javatests/BUILD.gn
index de6b25e..b6e37947 100644
--- a/weblayer/browser/android/javatests/BUILD.gn
+++ b/weblayer/browser/android/javatests/BUILD.gn
@@ -12,6 +12,7 @@
"src/org/chromium/webengine/test/CookieManagerTest.java",
"src/org/chromium/webengine/test/ExecuteScriptTest.java",
"src/org/chromium/webengine/test/TabManagerTest.java",
+ "src/org/chromium/webengine/test/TabNavigationControllerTest.java",
"src/org/chromium/webengine/test/TabPrerenderTest.java",
"src/org/chromium/webengine/test/WebEngineTest.java",
"src/org/chromium/webengine/test/WebFragmentTest.java",
diff --git a/weblayer/browser/android/javatests/src/org/chromium/webengine/test/TabNavigationControllerTest.java b/weblayer/browser/android/javatests/src/org/chromium/webengine/test/TabNavigationControllerTest.java
new file mode 100644
index 0000000..47d8d6a0
--- /dev/null
+++ b/weblayer/browser/android/javatests/src/org/chromium/webengine/test/TabNavigationControllerTest.java
@@ -0,0 +1,208 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.webengine.test;
+
+import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.DoNotBatch;
+import org.chromium.net.test.EmbeddedTestServer;
+import org.chromium.net.test.EmbeddedTestServerRule;
+import org.chromium.webengine.Navigation;
+import org.chromium.webengine.NavigationObserver;
+import org.chromium.webengine.Tab;
+import org.chromium.webengine.TabNavigationController;
+import org.chromium.webengine.WebEngine;
+import org.chromium.webengine.WebSandbox;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Tests various aspects of Navigations and NavigationObservers.
+ */
+@DoNotBatch(reason = "Tests need separate Activities and WebFragments")
+@RunWith(WebEngineJUnit4ClassRunner.class)
+public class TabNavigationControllerTest {
+ @Rule
+ public EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
+
+ @Rule
+ public InstrumentationActivityTestRule mActivityTestRule =
+ new InstrumentationActivityTestRule();
+
+ private EmbeddedTestServer mServer;
+
+ private WebSandbox mSandbox;
+
+ private TabNavigationController mNavigationController;
+ private Tab mActiveTab;
+
+ @Before
+ public void setUp() throws Exception {
+ mActivityTestRule.launchShell();
+ mServer = mTestServerRule.getServer();
+
+ mSandbox = mActivityTestRule.getWebSandbox();
+ WebEngine webEngine = runOnUiThreadBlocking(() -> mSandbox.createWebEngine()).get();
+
+ mActiveTab = webEngine.getTabManager().getActiveTab();
+ mNavigationController = mActiveTab.getNavigationController();
+ }
+
+ @After
+ public void shutdown() throws Exception {
+ if (mSandbox != null) {
+ runOnUiThreadBlocking(() -> mSandbox.shutdown());
+ }
+ mActivityTestRule.finish();
+ }
+
+ private String getTestDataURL(String path) {
+ return mServer.getURL("/weblayer/test/data/" + path);
+ }
+
+ private void navigateSync(String url) throws InterruptedException {
+ CountDownLatch navigationCompleted = new CountDownLatch(1);
+
+ runOnUiThreadBlocking(() -> {
+ mNavigationController.registerNavigationObserver(new NavigationObserver() {
+ @Override
+ public void onNavigationCompleted(@NonNull Navigation navigation) {
+ navigationCompleted.countDown();
+ }
+ });
+ mNavigationController.navigate(url);
+ });
+ navigationCompleted.await();
+ }
+
+ @Test
+ @SmallTest
+ public void cannotGoBackOnFirstLoadedUrl() throws Exception {
+ Assert.assertFalse((runOnUiThreadBlocking(() -> mNavigationController.canGoBack())).get());
+ navigateSync(getTestDataURL("simple_page.html"));
+ Assert.assertFalse((runOnUiThreadBlocking(() -> mNavigationController.canGoBack())).get());
+ }
+
+ @Test
+ @SmallTest
+ public void canGoBackOnSecondLoadedUrl() throws Exception {
+ navigateSync(getTestDataURL("simple_page.html"));
+ navigateSync(getTestDataURL("simple_page2.html"));
+ Assert.assertTrue((runOnUiThreadBlocking(() -> mNavigationController.canGoBack())).get());
+ }
+
+ @Test
+ @SmallTest
+ public void cannotGoForwardWhenNotNavigatedBackBefore() throws Exception {
+ navigateSync(getTestDataURL("simple_page.html"));
+ Assert.assertFalse(
+ (runOnUiThreadBlocking(() -> mNavigationController.canGoForward())).get());
+ }
+
+ @Test
+ @SmallTest
+ public void backNavigationToFirstPage() throws Exception {
+ navigateSync(getTestDataURL("simple_page.html"));
+ navigateSync(getTestDataURL("simple_page2.html"));
+
+ // Synchronously go back.
+ CountDownLatch navigationCompleted = new CountDownLatch(1);
+ runOnUiThreadBlocking(() -> {
+ mNavigationController.registerNavigationObserver(new NavigationObserver() {
+ @Override
+ public void onNavigationCompleted(@NonNull Navigation navigation) {
+ navigationCompleted.countDown();
+ }
+ });
+ mNavigationController.goBack();
+ });
+ navigationCompleted.await();
+
+ Assert.assertEquals(
+ getTestDataURL("simple_page.html"), mActiveTab.getDisplayUri().toString());
+ Assert.assertFalse((runOnUiThreadBlocking(() -> mNavigationController.canGoBack())).get());
+ Assert.assertTrue(
+ (runOnUiThreadBlocking(() -> mNavigationController.canGoForward())).get());
+ }
+
+ @Test
+ @SmallTest
+ public void forwardNavigationAfterBackNavigation() throws Exception {
+ navigateSync(getTestDataURL("simple_page.html"));
+ navigateSync(getTestDataURL("simple_page2.html"));
+
+ // Synchronously go back.
+ CountDownLatch backNavigationCompleted = new CountDownLatch(1);
+ runOnUiThreadBlocking(() -> {
+ mNavigationController.registerNavigationObserver(new NavigationObserver() {
+ @Override
+ public void onNavigationCompleted(@NonNull Navigation navigation) {
+ backNavigationCompleted.countDown();
+ }
+ });
+ mNavigationController.goBack();
+ });
+ backNavigationCompleted.await();
+ Assert.assertEquals(
+ getTestDataURL("simple_page.html"), mActiveTab.getDisplayUri().toString());
+
+ // Synchronously go forward
+ CountDownLatch forwardNavigationCompleted = new CountDownLatch(1);
+ runOnUiThreadBlocking(() -> {
+ mNavigationController.registerNavigationObserver(new NavigationObserver() {
+ @Override
+ public void onNavigationCompleted(@NonNull Navigation navigation) {
+ forwardNavigationCompleted.countDown();
+ }
+ });
+ mNavigationController.goForward();
+ });
+ forwardNavigationCompleted.await();
+ Assert.assertEquals(
+ getTestDataURL("simple_page2.html"), mActiveTab.getDisplayUri().toString());
+ }
+
+ @Test
+ @SmallTest
+ public void testAllNavigationEventsAreReceivedOnNavigate() throws Exception {
+ CountDownLatch navigationCompleted = new CountDownLatch(1);
+ CountDownLatch navigationStarted = new CountDownLatch(1);
+ CountDownLatch finishedLoadProgress = new CountDownLatch(1);
+
+ runOnUiThreadBlocking(() -> {
+ mNavigationController.registerNavigationObserver(new NavigationObserver() {
+ @Override
+ public void onNavigationStarted(@NonNull Navigation navigation) {
+ navigationStarted.countDown();
+ }
+ @Override
+ public void onNavigationCompleted(@NonNull Navigation navigation) {
+ navigationCompleted.countDown();
+ }
+ @Override
+ public void onLoadProgressChanged(double progress) {
+ if (progress == 1.0) {
+ finishedLoadProgress.countDown();
+ }
+ }
+ });
+
+ mNavigationController.navigate(getTestDataURL("simple_page.html"));
+ });
+ navigationStarted.await();
+ navigationCompleted.await();
+ finishedLoadProgress.await();
+ }
+}
\ No newline at end of file