blob: ad886e77c08e6854fb41431025e5690583633c32 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_TEST_BASE_BROWSER_WITH_TEST_WINDOW_TEST_H_
#define CHROME_TEST_BASE_BROWSER_WITH_TEST_WINDOW_TEST_H_
#include <memory>
#include <optional>
#include <vector>
#include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "chrome/browser/performance_manager/test_support/test_user_performance_tuning_manager_environment.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/test_browser_window.h"
#include "chrome/test/base/testing_profile.h"
#include "components/variations/scoped_variations_ids_provider.h"
#include "components/variations/variations_client.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_renderer_host.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(TOOLKIT_VIEWS)
#include "chrome/test/views/chrome_test_views_delegate.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/test/ash_test_helper.h"
#include "ash/test/ash_test_views_delegate.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ash/app_mode/kiosk_chrome_app_manager.h"
#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#else
#include "ui/views/test/scoped_views_test_helper.h"
#endif
#endif
#if BUILDFLAG(IS_WIN)
#include "ui/base/win/scoped_ole_initializer.h"
#endif
class GURL;
class GaiaId;
namespace content {
class NavigationController;
}
#if BUILDFLAG(IS_CHROMEOS)
namespace crosapi {
class CrosapiManager;
}
#endif
class TestingProfileManager;
// WARNING WARNING WARNING WARNING
// Do not use this class. See docs/chrome_browser_design_principles.md for
// details. Either write a browser test which provides both a "class Browser"
// and a "class BrowserView" or a unit test which requires neither.
// Historically, features were written that take a "class Browser" as an input
// parameter. "class Browser" cannot be stubbed/faked/mocked, and this class was
// written as a workaround to create a "class Browser" without a "class
// BrowserView". This cannot happen in production code and thus results in test
// logic leaking into production code. New features should not take "class
// Browser" as input, and should instead perform dependency injection.
//
// Base class for browser based unit tests. BrowserWithTestWindowTest creates a
// Browser with a TestingProfile and TestBrowserWindow. To add a tab use
// AddTab. For example, the following adds a tab and navigates to two URLs:
//
// // Add a new tab and navigate it. This will be at index 0.
// // WARNING: this creates a real WebContents. If you want to add a test
// // WebContents create it directly and insert it into the TabStripModel.
// AddTab(browser(), GURL("http://foo/1"));
// WebContents* contents = browser()->tab_strip_model()->GetWebContentsAt(0);
//
// // Navigate somewhere else.
// GURL url2("http://foo/2");
// NavigateAndCommit(contents, url2);
//
// // This is equivalent to the above, and lets you test pending navigations.
// browser()->OpenURL(OpenURLParams(
// GURL("http://foo/2"), GURL(), WindowOpenDisposition::CURRENT_TAB,
// ui::PAGE_TRANSITION_TYPED, false), /*navigation_handle_callback=*/{});
// CommitPendingLoad(&contents->GetController());
//
// Subclasses must invoke BrowserWithTestWindowTest::SetUp as it is responsible
// for creating the various objects of this class.
class BrowserWithTestWindowTest : public testing::Test, public ProfileObserver {
public:
// Trait which requests construction of a hosted app.
struct HostedApp {};
struct ValidTraits {
explicit ValidTraits(content::BrowserTaskEnvironment::ValidTraits);
explicit ValidTraits(HostedApp);
explicit ValidTraits(Browser::Type);
// TODO(alexclarke): Make content::BrowserTaskEnvironment::ValidTraits
// imply this.
explicit ValidTraits(base::test::TaskEnvironment::ValidTraits);
};
// Creates a BrowserWithTestWindowTest with zero or more traits. By default
// the initial window will be a tabbed browser created on the native desktop,
// which is not a hosted app.
template <typename... TaskEnvironmentTraits>
requires base::trait_helpers::AreValidTraits<ValidTraits,
TaskEnvironmentTraits...>
NOINLINE explicit BrowserWithTestWindowTest(TaskEnvironmentTraits... traits)
: BrowserWithTestWindowTest(
std::make_unique<content::BrowserTaskEnvironment>(
base::trait_helpers::Exclude<HostedApp, Browser::Type>::Filter(
traits)...),
base::trait_helpers::GetEnum<Browser::Type, Browser::TYPE_NORMAL>(
traits...),
base::trait_helpers::HasTrait<HostedApp,
TaskEnvironmentTraits...>()) {}
BrowserWithTestWindowTest(const BrowserWithTestWindowTest&) = delete;
BrowserWithTestWindowTest& operator=(const BrowserWithTestWindowTest&) =
delete;
~BrowserWithTestWindowTest() override;
void SetUp() override;
void TearDown() override;
// Set up process for `profile_manager_`. If a `profile_manager` is supplied,
// it will be set as the underlying profile manager that `profile_manager_`
// uses, aka `profile_manager_->profile_manager()`. This can only be called
// before ::SetUp().
void SetUpProfileManager(
const base::FilePath& profiles_path = base::FilePath(),
std::unique_ptr<ProfileManager> profile_manager = nullptr);
protected:
BrowserWindow* window() const { return window_.get(); }
Browser* browser() const { return browser_.get(); }
void set_browser(Browser* browser) { browser_.reset(browser); }
std::unique_ptr<Browser> release_browser() { return std::move(browser_); }
TestingProfile* profile() const { return profile_; }
TestingProfile* GetProfile() { return profile_; }
TestingProfileManager* profile_manager() { return profile_manager_.get(); }
content::BrowserTaskEnvironment* task_environment() {
return task_environment_.get();
}
network::TestURLLoaderFactory* test_url_loader_factory() {
return &test_url_loader_factory_;
}
std::unique_ptr<BrowserWindow> release_browser_window() {
return std::move(window_);
}
#if BUILDFLAG(IS_CHROMEOS)
ash::AshTestHelper* ash_test_helper() { return &ash_test_helper_; }
user_manager::FakeUserManager* user_manager() { return user_manager_.Get(); }
#endif
// The context to help determine desktop type when creating new Widgets.
gfx::NativeWindow GetContext();
// Adds a tab to |browser| with the given URL and commits the load.
// This is a convenience function. The new tab will be added at index 0.
// WARNING: this creates a real WebContents. If you want to add a test
// WebContents create it directly and insert it into the TabStripModel.
void AddTab(Browser* browser, const GURL& url);
// Commits the pending load on the given controller. It will keep the
// URL of the pending load. If there is no pending load, this does nothing.
void CommitPendingLoad(content::NavigationController* controller);
// Creates a pending navigation on the given WebContents to the given URL with
// the default parameters and the commits the load with a page ID one larger
// than any seen. This emulates what happens on a new navigation.
void NavigateAndCommit(content::WebContents* web_contents, const GURL& url);
// Navigates the current tab. This is a wrapper around NavigateAndCommit.
void NavigateAndCommitActiveTab(const GURL& url);
// Set the |title| of the current tab.
void NavigateAndCommitActiveTabWithTitle(Browser* browser,
const GURL& url,
const std::u16string& title);
// Sets the focused frame to the main frame of the active WebContents, for
// tests that rely on the focused frame not being null.
void FocusMainFrameOfActiveWebContents();
// Returns the profile name used for the profile created in SetUp() by
// default. Subclasses can override to change the profile name. If it returns
// std::nullopt, this will skip creating profile and browser window.
virtual std::optional<std::string> GetDefaultProfileName();
// Creates the profile used by this test. The caller doesn't own the return
// value.
virtual TestingProfile* CreateProfile(const std::string& profile_name);
// Deletes the specified profile.
// If `profile_name` is the one returned from GetDefaultProfileName(),
// because this instance creates Browser for the profile in SetUp() and keeps
// it in a member, the Browser instance will also be destroyed to avoid leak.
virtual void DeleteProfile(const std::string& profile_name);
// Returns a vector of testing factories to be used when creating the profile.
// This is only used by CreateProfile(), and will be irrelevant if that
// method is overridden.
virtual TestingProfile::TestingFactories GetTestingFactories();
// Creates the BrowserWindow used by this test. Subclasses can provide their
// own test BrowserWindow. If the provided BrowserWindow is null then Browser
// will create a production BrowserWindow and the subclass is responsible for
// cleaning it up (usually by NativeWidget destruction).
virtual std::unique_ptr<BrowserWindow> CreateBrowserWindow();
// Creates the browser given |profile|, |browser_type|, |hosted_app|, and
// |browser_window|.
virtual std::unique_ptr<Browser> CreateBrowser(Profile* profile,
Browser::Type browser_type,
bool hosted_app,
BrowserWindow* browser_window);
#if defined(TOOLKIT_VIEWS)
views::TestViewsDelegate* test_views_delegate() {
#if BUILDFLAG(IS_CHROMEOS)
return test_views_delegate_.get();
#else
return views_test_helper_->test_views_delegate();
#endif
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
// Logs in an User as `email`.
virtual void LogIn(std::string_view email, const GaiaId& gaia_id);
// Handles the post-process for the newly created Profile.
// Expected to be called on customizing CreateProfile for ash.
virtual void OnUserProfileCreated(const std::string& email, Profile* profile);
// Switches the active user to the one specified by the email.
virtual void SwitchActiveUser(const std::string& email);
// ProfileObserver:
void OnProfileWillBeDestroyed(Profile* profile) override;
ash::ScopedCrosSettingsTestHelper* GetCrosSettingsHelper();
ash::StubInstallAttributes* GetInstallAttributes();
#endif
private:
// The template constructor has to be in the header but it delegates to this
// constructor to initialize all other members out-of-line.
BrowserWithTestWindowTest(
std::unique_ptr<content::BrowserTaskEnvironment> task_environment,
Browser::Type browser_type,
bool hosted_app);
// We need to create a MessageLoop, otherwise a bunch of things fails.
std::unique_ptr<content::BrowserTaskEnvironment> task_environment_;
#if BUILDFLAG(IS_CHROMEOS)
ash::TestSessionControllerClient* GetSessionControllerClient();
// A template method (in Design Pattern) that execute post profile creation
// steps.
void PostUserProfileCreation(const std::string& email, Profile* profile);
ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
user_manager::TypedScopedUserManager<user_manager::FakeUserManager>
user_manager_;
std::vector<
std::unique_ptr<base::ScopedObservation<Profile, ProfileObserver>>>
profile_observations_;
std::unique_ptr<crosapi::CrosapiManager> manager_;
std::unique_ptr<ash::KioskChromeAppManager> kiosk_chrome_app_manager_;
#endif
raw_ptr<TestingProfile, AcrossTasksDanglingUntriaged> profile_ = nullptr;
// test_url_loader_factory_ is declared before profile_manager_
// to guarantee it outlives any profiles that might use it.
network::TestURLLoaderFactory test_url_loader_factory_;
std::unique_ptr<TestingProfileManager> profile_manager_;
std::unique_ptr<BrowserWindow> window_; // Usually a TestBrowserWindow.
std::unique_ptr<Browser> browser_;
#if BUILDFLAG(IS_CHROMEOS)
ash::AshTestHelper ash_test_helper_;
std::unique_ptr<views::TestViewsDelegate> test_views_delegate_ =
std::make_unique<ChromeTestViewsDelegate<ash::AshTestViewsDelegate>>();
#elif defined(TOOLKIT_VIEWS)
std::unique_ptr<views::ScopedViewsTestHelper> views_test_helper_ =
std::make_unique<views::ScopedViewsTestHelper>(
std::make_unique<ChromeTestViewsDelegate<>>());
#endif
// The existence of this object enables tests via RenderViewHostTester.
std::unique_ptr<content::RenderViewHostTestEnabler> rvh_test_enabler_;
#if BUILDFLAG(IS_WIN)
ui::ScopedOleInitializer ole_initializer_;
#endif
// The type of browser to create (tabbed or popup).
const Browser::Type browser_type_;
// Whether the browser is part of a hosted app.
const bool hosted_app_;
// Initialize the variations provider.
variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
variations::VariationsIdsProvider::Mode::kUseSignedInState};
// Some of the UI elements in top chrome need to observe the
// UserPerformanceTuningManager, so create and install a fake.
performance_manager::user_tuning::TestUserPerformanceTuningManagerEnvironment
user_performance_tuning_manager_environment_;
};
#endif // CHROME_TEST_BASE_BROWSER_WITH_TEST_WINDOW_TEST_H_