chromium/chrome/browser/ash/app_mode/kiosk_guest_view_browsertest.cc

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

#include "apps/test/app_window_waiter.h"
#include "base/check_deref.h"
#include "chrome/browser/ash/app_mode/kiosk_controller.h"
#include "chrome/browser/ash/login/app_mode/test/kiosk_base_test.h"
#include "chrome/browser/ash/login/app_mode/test/web_kiosk_base_test.h"
#include "chrome/browser/ash/login/test/device_state_mixin.h"
#include "chrome/browser/ash/login/test/login_manager_mixin.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/guest_view/browser/guest_view_base.h"
#include "components/guest_view/browser/guest_view_manager_delegate.h"
#include "components/guest_view/browser/test_guest_view_manager.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/window_open_disposition.h"

namespace ash {

namespace {

void NotifyKioskGuestAdded(content::WebContents* guest_web_contents) {
  KioskController::Get().OnGuestAdded(guest_web_contents);
}

Profile& GetProfile() {
  return CHECK_DEREF(ProfileManager::GetPrimaryUserProfile());
}

void OpenWebUiWithGuestView() {
  // Enable troubleshooting tools to access a Web Ui page with `<webview>` tag.
  // Note: `<webview>` is a restricted tag and triggers guest view creation only
  // for Chrome apps and allowlisted WebUi pages.
  GetProfile().GetPrefs()->SetBoolean(prefs::kKioskTroubleshootingToolsEnabled,
                                      true);

  // Navigate to the WebUi page allowlisted here
  // extensions/common/api/_api_features.json.
  GURL signin_url{"chrome://chrome-signin/?reason=5"};
  Browser::CreateParams params =
      Browser::CreateParams(Browser::Type::TYPE_NORMAL,
                            /*profile=*/&GetProfile(),
                            /*user_gesture=*/true);
  auto& new_browser = CHECK_DEREF(Browser::Create(params));
  new_browser.window()->Show();
  ui_test_utils::NavigateToURLWithDisposition(
      &new_browser, signin_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
}

guest_view::TestGuestViewManager& GetGuestViewManager(
    guest_view::TestGuestViewManagerFactory& factory) {
  return CHECK_DEREF(factory.GetOrCreateTestGuestViewManager(
      &GetProfile(), extensions::ExtensionsAPIClient::Get()
                         ->CreateGuestViewManagerDelegate()));
}

}  // namespace

class WebKioskGuestViewBrowserTest : public WebKioskBaseTest {
 public:
  WebKioskGuestViewBrowserTest() = default;
  WebKioskGuestViewBrowserTest(const WebKioskGuestViewBrowserTest&) = delete;
  WebKioskGuestViewBrowserTest& operator=(const WebKioskGuestViewBrowserTest&) =
      delete;

  ~WebKioskGuestViewBrowserTest() override = default;

 protected:
  void SetUpOnMainThread() override {
    WebKioskBaseTest::SetUpOnMainThread();
    InitializeRegularOnlineKiosk();
  }

  guest_view::TestGuestViewManagerFactory& factory() { return factory_; }

 private:
  guest_view::TestGuestViewManagerFactory factory_;
};

IN_PROC_BROWSER_TEST_F(WebKioskGuestViewBrowserTest,
                       AddingGuestViewDoesNotCrash) {
  EXPECT_EQ(0ULL, GetGuestViewManager(factory()).GetCurrentGuestCount());
  OpenWebUiWithGuestView();

  auto* guest_view =
      GetGuestViewManager(factory()).WaitForSingleGuestViewCreated();
  ASSERT_NE(guest_view, nullptr);
  ASSERT_NE(guest_view->web_contents(), nullptr);
  EXPECT_NO_FATAL_FAILURE(NotifyKioskGuestAdded(guest_view->web_contents()));
}

class ChromeAppKioskGuestViewBrowserTest : public KioskBaseTest {
 public:
  ChromeAppKioskGuestViewBrowserTest() = default;
  ChromeAppKioskGuestViewBrowserTest(
      const ChromeAppKioskGuestViewBrowserTest&) = delete;
  ChromeAppKioskGuestViewBrowserTest& operator=(
      const ChromeAppKioskGuestViewBrowserTest&) = delete;

  ~ChromeAppKioskGuestViewBrowserTest() override = default;

 protected:
  void LaunchApp() {
    StartAppLaunchFromLoginScreen(NetworkStatus::kOnline);
    WaitForAppLaunchWithOptions(/*check_launch_data=*/true,
                                /*terminate_app=*/false,
                                /*keep_app_open=*/true);
  }

  content::WebContents* WaitForAppWindowWebContents() {
    extensions::AppWindowRegistry* app_window_registry =
        extensions::AppWindowRegistry::Get(&GetProfile());
    extensions::AppWindow& window = CHECK_DEREF(
        apps::AppWindowWaiter(app_window_registry, test_app_id()).Wait());
    return window.web_contents();
  }

  guest_view::TestGuestViewManagerFactory& factory() { return factory_; }

 private:
  ash::DeviceStateMixin device_state_{
      &mixin_host_,
      ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
  LoginManagerMixin login_manager_{
      &mixin_host_,
      {{LoginManagerMixin::TestUserInfo{test_owner_account_id_}}}};

  guest_view::TestGuestViewManagerFactory factory_;
};

IN_PROC_BROWSER_TEST_F(ChromeAppKioskGuestViewBrowserTest,
                       AddingGuestViewDoesNotCrash) {
  LaunchApp();
  EXPECT_EQ(0ULL, GetGuestViewManager(factory()).GetCurrentGuestCount());
  OpenWebUiWithGuestView();
  auto* guest_view =
      GetGuestViewManager(factory()).WaitForSingleGuestViewCreated();
  ASSERT_NE(guest_view, nullptr);
  ASSERT_NE(guest_view->web_contents(), nullptr);
  EXPECT_NO_FATAL_FAILURE(NotifyKioskGuestAdded(guest_view->web_contents()));
}

}  // namespace ash