chromium/chrome/browser/lacros/web_contents_can_go_back_observer_browsertest.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/run_loop.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/lacros/browser_test_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/lacros/window_utility.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/crosapi/mojom/clipboard.mojom.h"
#include "chromeos/crosapi/mojom/test_controller.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
#include "ui/aura/window.h"

class WebContentsCanGoBackObserverTest : public InProcessBrowserTest {
 protected:
  WebContentsCanGoBackObserverTest() = default;

  WebContentsCanGoBackObserverTest(const WebContentsCanGoBackObserverTest&) =
      delete;
  WebContentsCanGoBackObserverTest& operator=(
      const WebContentsCanGoBackObserverTest&) = delete;

  void CheckCanGoBackOnServer(const std::string& window_id,
                              bool expected_value) {
    base::RunLoop outer_loop;
    auto look_for_property_value = base::BindRepeating(
        [](base::RunLoop* outer_loop, const std::string& window_id,
           bool expected_value) {
          auto* lacros_service = chromeos::LacrosService::Get();

          base::RunLoop inner_loop(base::RunLoop::Type::kNestableTasksAllowed);
          crosapi::mojom::OptionalBoolean out_value;
          lacros_service->GetRemote<crosapi::mojom::TestController>()
              ->GetMinimizeOnBackKeyWindowProperty(
                  window_id, base::BindOnce(
                                 [](base::RunLoop* loop,
                                    crosapi::mojom::OptionalBoolean* out_value,
                                    crosapi::mojom::OptionalBoolean value) {
                                   *out_value = value;
                                   loop->Quit();
                                 },
                                 &inner_loop, &out_value));
          inner_loop.Run();

          // can-go-back and minimize-on-back-gesture are always contrary.
          if ((expected_value &&
               out_value == crosapi::mojom::OptionalBoolean::kFalse) ||
              (!expected_value &&
               out_value == crosapi::mojom::OptionalBoolean::kTrue))
            outer_loop->Quit();
        },
        &outer_loop, window_id, expected_value);
    base::RepeatingTimer timer;
    timer.Start(FROM_HERE, base::Milliseconds(1),
                std::move(look_for_property_value));
    outer_loop.Run();
  }

  ~WebContentsCanGoBackObserverTest() override = default;
};

IN_PROC_BROWSER_TEST_F(WebContentsCanGoBackObserverTest, CanGoBack_ServerSide) {
  auto* lacros_service = chromeos::LacrosService::Get();
  ASSERT_TRUE(lacros_service);
  ASSERT_TRUE(lacros_service->IsAvailable<crosapi::mojom::TestController>());

  EXPECT_FALSE(chrome::CanGoBack(browser()));
  EXPECT_FALSE(chrome::CanGoForward(browser()));

  // Navigate away to any valid URL, so the back/forward list changes.
  NavigateToURLWithDisposition(browser(), GURL(chrome::kChromeUIAboutURL),
                               WindowOpenDisposition::CURRENT_TAB,
                               ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);

  std::string window_id = lacros_window_utility::GetRootWindowUniqueId(
      browser()->window()->GetNativeWindow()->GetRootWindow());

  EXPECT_TRUE(chrome::CanGoBack(browser()));
  EXPECT_FALSE(chrome::CanGoForward(browser()));
  CheckCanGoBackOnServer(window_id, true /* expected_value */);

  // Tweak the back/forward list.
  chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
  content::WaitForLoadStop(
      browser()->tab_strip_model()->GetActiveWebContents());

  EXPECT_FALSE(chrome::CanGoBack(browser()));
  EXPECT_TRUE(chrome::CanGoForward(browser()));
  CheckCanGoBackOnServer(window_id, false /* expected_value */);
}

IN_PROC_BROWSER_TEST_F(WebContentsCanGoBackObserverTest,
                       CanGoBackMultipleTabs_ServerSide) {
  auto* lacros_service = chromeos::LacrosService::Get();
  ASSERT_TRUE(lacros_service);
  ASSERT_TRUE(lacros_service->IsAvailable<crosapi::mojom::TestController>());

  EXPECT_FALSE(chrome::CanGoBack(browser()));
  EXPECT_FALSE(chrome::CanGoForward(browser()));

  // Navigate away to any valid URL, so the back/forward list changes.
  NavigateToURLWithDisposition(browser(), GURL(chrome::kChromeUIAboutURL),
                               WindowOpenDisposition::CURRENT_TAB,
                               ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);

  std::string window_id = lacros_window_utility::GetRootWindowUniqueId(
      browser()->window()->GetNativeWindow()->GetRootWindow());

  EXPECT_TRUE(chrome::CanGoBack(browser()));
  EXPECT_FALSE(chrome::CanGoForward(browser()));
  CheckCanGoBackOnServer(window_id, true /* expected_value */);

  NavigateToURLWithDisposition(browser(), GURL(chrome::kChromeUIVersionURL),
                               WindowOpenDisposition::NEW_FOREGROUND_TAB,
                               ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);

  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
  EXPECT_FALSE(chrome::CanGoBack(browser()));
  EXPECT_FALSE(chrome::CanGoForward(browser()));
  CheckCanGoBackOnServer(window_id, false /* expected_value */);

  // Navigate the current (second) tab to a different URL, so we can test
  // back/forward later.
  NavigateToURLWithDisposition(browser(), GURL(chrome::kChromeUIFlagsURL),
                               WindowOpenDisposition::CURRENT_TAB,
                               ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
  EXPECT_TRUE(chrome::CanGoBack(browser()));
  EXPECT_FALSE(chrome::CanGoForward(browser()));
  CheckCanGoBackOnServer(window_id, true /* expected_value */);

  // Tweak the back/forward list of the 2nd tab, and verify.
  chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
  content::WaitForLoadStop(
      browser()->tab_strip_model()->GetActiveWebContents());

  EXPECT_FALSE(chrome::CanGoBack(browser()));
  EXPECT_TRUE(chrome::CanGoForward(browser()));
  CheckCanGoBackOnServer(window_id, false /* expected_value */);

  // Switch to a different tab, and verify whether the `can go back` property
  // updates accordingly.
  browser()->tab_strip_model()->ActivateTabAt(
      0, TabStripUserGestureDetails(
             TabStripUserGestureDetails::GestureType::kOther));
  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());

  EXPECT_TRUE(chrome::CanGoBack(browser()));
  EXPECT_FALSE(chrome::CanGoForward(browser()));
  CheckCanGoBackOnServer(window_id, true /* expected_value */);
}