blob: 92ef5cc85be9d51774d1c1ff80ef9f559e807d35 [file] [log] [blame]
// Copyright 2025 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 "base/scoped_observation.h"
#include "base/test/run_until.h"
#include "base/test/test_future.h"
#include "chrome/browser/background/glic/glic_background_mode_manager.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/glic/glic_pref_names.h"
#include "chrome/browser/glic/host/glic.mojom.h"
#include "chrome/browser/glic/public/glic_keyed_service.h"
#include "chrome/browser/glic/public/glic_keyed_service_factory.h"
#include "chrome/browser/glic/test_support/glic_test_environment.h"
#include "chrome/browser/glic/test_support/glic_test_util.h"
#include "chrome/browser/glic/test_support/interactive_glic_test.h"
#include "chrome/browser/glic/widget/glic_window_controller.h"
#include "chrome/browser/global_features.h"
#include "chrome/browser/policy/policy_test_utils.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/policy/profile_policy_connector_builder.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_test_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
#include "chrome/browser/ui/views/tabs/glic_button.h"
#include "chrome/browser/ui/views/tabs/tab_strip_action_container.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
using glic::prefs::SettingsPolicyState;
using ::prefs::kGeminiSettings;
using policy::PolicyTest;
namespace glic {
class GlicButton;
namespace {
// An observer of the GlicWindowController's panel state. Fires the given
// callback when the state changes to the given kind.
class PanelStateObserver : public GlicWindowController::StateObserver {
public:
PanelStateObserver(mojom::PanelState::Kind kind, base::OnceClosure callback)
: kind_(kind), callback_(std::move(callback)) {}
void PanelStateChanged(const mojom::PanelState& panel_state,
Browser* attached_browser) override {
if (panel_state.kind == kind_) {
std::move(callback_).Run();
}
}
private:
mojom::PanelState::Kind kind_;
base::OnceClosure callback_;
};
class GlicAppStateObserver : public Host::Observer {
public:
explicit GlicAppStateObserver(Host* host)
: GlicAppStateObserver(host, host->GetPrimaryWebUiState()) {}
explicit GlicAppStateObserver(Host* host, mojom::WebUiState initial_state) {
observation_.Observe(host);
state_ = initial_state;
}
~GlicAppStateObserver() override { observation_.Reset(); }
void Wait(mojom::WebUiState state) {
waiting_for_state_ = state;
if (state_ == waiting_for_state_) {
return;
}
// Run run_loop until the state_ == waiting_for_state_.
run_loop_.Run();
}
void WebUiStateChanged(mojom::WebUiState state) override {
state_ = state;
if (state_ != waiting_for_state_) {
return;
}
run_loop_.Quit();
observation_.Reset();
}
private:
base::ScopedObservation<Host, Host::Observer> observation_{this};
mojom::WebUiState state_ = mojom::WebUiState::kUninitialized;
mojom::WebUiState waiting_for_state_ = mojom::WebUiState::kUninitialized;
base::RunLoop run_loop_;
};
class GlicPolicyTest : public PolicyTest {
public:
GlicPolicyTest() {
scoped_feature_list_.InitWithFeaturesAndParameters(
{{features::kGlic,
{
// This test currently loads about:blank instead of a client which
// could ever reach the kReady state. To speed that up, cut down
// the time we wait for it.
{features::kGlicMaxLoadingTimeMs.name, "500"},
}}},
{});
}
GlicPolicyTest(const GlicPolicyTest&) = delete;
GlicPolicyTest& operator=(const GlicPolicyTest&) = delete;
~GlicPolicyTest() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
PolicyTest::SetUpCommandLine(command_line);
// Load blank page in glic guest view
command_line->AppendSwitchASCII(::switches::kGlicGuestURL, "about:blank");
}
void SetUpOnMainThread() override {
PolicyTest::SetUpOnMainThread();
g_browser_process->local_state()->SetBoolean(
glic::prefs::kGlicLauncherEnabled, true);
profile_1_ = browser()->profile();
// "policy_for_profile_1_" is provider_, setup in PolicyTest.
{
// The policy configuration here causes signin::WaitForRefreshTokensLoaded
// to hang when run from GlicTestEnvironmentFactory, so disable it here
// and run ForceSigninAndModelExecutionCapability() directly afterward.
glic_test_environment_.SetForceSigninAndModelExecutionCapability(false);
policy_for_profile_2_.SetDefaultReturns(
/*is_initialization_complete_return=*/true,
/*is_first_policy_load_complete_return=*/true);
policy::PushProfilePolicyConnectorProviderForTesting(
&policy_for_profile_2_);
ProfileManager* profile_manager = g_browser_process->profile_manager();
base::FilePath new_path =
profile_manager->GenerateNextProfileDirectoryPath();
profile_2_ =
&profiles::testing::CreateProfileSync(profile_manager, new_path);
ForceSigninAndModelExecutionCapability(profile_2_);
}
}
void TearDownOnMainThread() override {
PolicyTest::TearDownOnMainThread();
if (GlicBackgroundModeManager* background_mode_manager =
g_browser_process->GetFeatures()->glic_background_mode_manager()) {
background_mode_manager->ExitBackgroundMode();
}
profile_1_ = nullptr;
profile_2_ = nullptr;
}
GlicButton* GetGlicButtonForBrowser(Browser* browser) {
TabStripActionContainer* container =
BrowserView::GetBrowserViewForBrowser(browser)
->tab_strip_region_view()
->GetTabStripActionContainer();
CHECK(container);
return container->GetGlicButton();
}
void SetGlicPolicy(
testing::NiceMock<policy::MockConfigurationPolicyProvider>& provider,
SettingsPolicyState value) {
using policy::POLICY_LEVEL_MANDATORY;
using policy::POLICY_SCOPE_USER;
using policy::POLICY_SOURCE_ENTERPRISE_DEFAULT;
using policy::PolicyMap;
using policy::key::kGeminiSettings;
PolicyMap policies;
policies.Set(kGeminiSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT,
base::Value(static_cast<int>(value)), nullptr);
provider.UpdateChromePolicy(policies);
}
// Simulates a click on an element with the given |id|.
void ClickElementWithId(content::WebContents* web_contents,
const std::string& id) {
// Get the center coordinates of the DOM element.
const int x =
EvalJs(web_contents,
content::JsReplace("const bounds = "
"document.getElementById($1)."
"getBoundingClientRect();"
"Math.floor(bounds.left + bounds.width / 2)",
id))
.ExtractInt();
const int y =
EvalJs(web_contents,
content::JsReplace("const bounds = "
"document.getElementById($1)."
"getBoundingClientRect();"
"Math.floor(bounds.top + bounds.height / 2)",
id))
.ExtractInt();
SimulateMouseClickAt(web_contents, 0, blink::WebMouseEvent::Button::kLeft,
gfx::Point(x, y));
}
testing::NiceMock<policy::MockConfigurationPolicyProvider>&
policy_for_profile_1() {
// This comes from the PolicyTest base class.
return provider_;
}
testing::NiceMock<policy::MockConfigurationPolicyProvider>&
policy_for_profile_2() {
return policy_for_profile_2_;
}
protected:
// The first profile.
raw_ptr<Profile> profile_1_;
// The second profile.
raw_ptr<Profile> profile_2_;
static constexpr int kEnabledValue =
static_cast<int>(SettingsPolicyState::kEnabled);
static constexpr int kDisabledValue =
static_cast<int>(SettingsPolicyState::kDisabled);
private:
GlicTestEnvironment glic_test_environment_;
testing::NiceMock<policy::MockConfigurationPolicyProvider>
policy_for_profile_2_;
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(GlicPolicyTest, PrefDefaultsToEnabled) {
// The pref defaults to enabled.
EXPECT_EQ(kEnabledValue, profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
EXPECT_EQ(kEnabledValue, profile_2_->GetPrefs()->GetInteger(kGeminiSettings));
}
IN_PROC_BROWSER_TEST_F(GlicPolicyTest, PrefDisabledByPolicy) {
// By default the pref should start off unmanaged and defaulted to enabled.
PrefService* prefs = browser()->profile()->GetPrefs();
EXPECT_FALSE(prefs->IsManagedPreference(kGeminiSettings));
EXPECT_EQ(kEnabledValue, prefs->GetInteger(kGeminiSettings));
// Verify that policy can force-disable Glic.
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kDisabled);
EXPECT_TRUE(prefs->IsManagedPreference(kGeminiSettings));
EXPECT_EQ(kDisabledValue, prefs->GetInteger(kGeminiSettings));
// Verify the policy value cannot be overridden.
prefs->SetInteger(kGeminiSettings, kEnabledValue);
EXPECT_EQ(kDisabledValue, prefs->GetInteger(kGeminiSettings));
}
// Ensure that when policy disables Glic, a browser window doesn't show the Glic
// button.
IN_PROC_BROWSER_TEST_F(GlicPolicyTest, PolicyAffectsGlicButtonInNewWindows) {
ASSERT_EQ(browser()->profile(), profile_1_);
ASSERT_NE(profile_1_, profile_2_);
// Disable the policy in the default profile.
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kDisabled);
ASSERT_EQ(kDisabledValue,
profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
{
// A new window in profile 1 shouldn't have the Glic button.
Browser* new_window_profile_1 = CreateBrowser(profile_1_);
EXPECT_FALSE(GetGlicButtonForBrowser(new_window_profile_1)->GetVisible());
// A new window in profile 2 should continue to have the Glic button since
// only profile 1 disabled Glic.
Browser* new_window_profile_2 = CreateBrowser(profile_2_);
EXPECT_TRUE(GetGlicButtonForBrowser(new_window_profile_2)->GetVisible());
}
// Re-enable the policy. Ensure the button is recreated.
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kEnabled);
ASSERT_EQ(kEnabledValue, profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
{
// A new window in profile 1 should again get the Glic button now that the
// policy is re-enabled.
Browser* new_window_profile_1 = CreateBrowser(profile_1_);
EXPECT_TRUE(GetGlicButtonForBrowser(new_window_profile_1)->GetVisible());
}
}
// Ensure that when policy disables Glic, a browser window doesn't show the Glic
// button.
IN_PROC_BROWSER_TEST_F(GlicPolicyTest, GlicButtonInExistingWindows) {
ASSERT_EQ(browser()->profile(), profile_1_);
ASSERT_NE(profile_1_, profile_2_);
// Create two windows in each profile.
Browser* profile_1_window_1 = browser();
Browser* profile_1_window_2 = CreateBrowser(profile_1_);
Browser* profile_2_window_1 = CreateBrowser(profile_2_);
Browser* profile_2_window_2 = CreateBrowser(profile_2_);
// Ensure the button was created in each window.
EXPECT_TRUE(GetGlicButtonForBrowser(profile_1_window_1)->GetVisible());
EXPECT_TRUE(GetGlicButtonForBrowser(profile_1_window_2)->GetVisible());
EXPECT_TRUE(GetGlicButtonForBrowser(profile_2_window_1)->GetVisible());
EXPECT_TRUE(GetGlicButtonForBrowser(profile_2_window_2)->GetVisible());
// Disable the policy in the first profile.
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kDisabled);
ASSERT_EQ(kDisabledValue,
profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
{
// The windows in profile 1 should have lost their Glic button.
EXPECT_FALSE(GetGlicButtonForBrowser(profile_1_window_1)->GetVisible());
EXPECT_FALSE(GetGlicButtonForBrowser(profile_1_window_2)->GetVisible());
// The windows in profile 2 should have kept their Glic button.
EXPECT_TRUE(GetGlicButtonForBrowser(profile_2_window_1)->GetVisible());
EXPECT_TRUE(GetGlicButtonForBrowser(profile_2_window_2)->GetVisible());
}
// Re-enable the policy. Ensure the button is recreated.
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kEnabled);
ASSERT_EQ(kEnabledValue, profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
{
// The windows in profile 1 should get back their Glic button.
EXPECT_TRUE(GetGlicButtonForBrowser(profile_1_window_1)->GetVisible());
EXPECT_TRUE(GetGlicButtonForBrowser(profile_1_window_2)->GetVisible());
// The windows in profile 2 still have their Glic button.
EXPECT_TRUE(GetGlicButtonForBrowser(profile_2_window_1)->GetVisible());
EXPECT_TRUE(GetGlicButtonForBrowser(profile_2_window_2)->GetVisible());
}
}
// Ensure that background mode is entered if and only if a profile with the
// policy enabled is loaded.
IN_PROC_BROWSER_TEST_F(GlicPolicyTest, PolicyDisablesBackgroundMode) {
ASSERT_EQ(browser()->profile(), profile_1_);
ASSERT_NE(profile_1_, profile_2_);
Browser* new_window_profile_2 = CreateBrowser(profile_2_);
ASSERT_TRUE(new_window_profile_2);
GlicBackgroundModeManager* background_mode_manager =
g_browser_process->GetFeatures()->glic_background_mode_manager();
EXPECT_TRUE(background_mode_manager->IsInBackgroundModeForTesting());
// Disable the policy in the default profile.
{
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kDisabled);
ASSERT_EQ(kDisabledValue,
profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
ASSERT_EQ(kEnabledValue,
profile_2_->GetPrefs()->GetInteger(kGeminiSettings));
}
// Background mode should remain active since profile_2_ still has it enabled.
EXPECT_TRUE(background_mode_manager->IsInBackgroundModeForTesting());
// Disable the policy in the second profile.
{
SetGlicPolicy(policy_for_profile_2(), SettingsPolicyState::kDisabled);
ASSERT_EQ(kDisabledValue,
profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
ASSERT_EQ(kDisabledValue,
profile_2_->GetPrefs()->GetInteger(kGeminiSettings));
}
// Background mode should be exited since none of the loaded profiles enable
// Glic.
EXPECT_FALSE(background_mode_manager->IsInBackgroundModeForTesting());
// Enable the policy in the default profile again.
{
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kEnabled);
ASSERT_EQ(kEnabledValue,
profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
ASSERT_EQ(kDisabledValue,
profile_2_->GetPrefs()->GetInteger(kGeminiSettings));
}
// Background mode should be reentered since the first profile is enabled.
EXPECT_TRUE(background_mode_manager->IsInBackgroundModeForTesting());
}
// Ensure navigating to chrome://glic is enabled only if the policy is enabled.
IN_PROC_BROWSER_TEST_F(GlicPolicyTest, PolicyDisablesWebUi) {
GURL glic_url = GURL(chrome::kChromeUIGlicURL);
GlicKeyedService* service =
GlicKeyedServiceFactory::GetGlicKeyedService(profile_1_);
// Navigating to chrome://glic should succeed.
{
GlicAppStateObserver app_observer(&service->host());
content::TestNavigationObserver observer(glic_url);
observer.WatchExistingWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), glic_url));
observer.WaitForNavigationFinished();
ASSERT_EQ(observer.last_navigation_url(), glic_url);
ASSERT_TRUE(observer.last_navigation_succeeded());
// WebUi will be in an error state since the mock web client is not setup.
app_observer.Wait(mojom::WebUiState::kError);
}
// Disable the policy.
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kDisabled);
ASSERT_EQ(kDisabledValue,
browser()->profile()->GetPrefs()->GetInteger(kGeminiSettings));
// Navigate to chrome://glic. The glic page should be unavailable.
{
GlicAppStateObserver app_observer(&service->host());
content::TestNavigationObserver observer(glic_url);
observer.WatchExistingWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), glic_url));
observer.WaitForNavigationFinished();
ASSERT_EQ(observer.last_navigation_url(), glic_url);
ASSERT_TRUE(observer.last_navigation_succeeded());
app_observer.Wait(mojom::WebUiState::kDisabledByAdmin);
}
// Re-enable the policy.
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kEnabled);
ASSERT_EQ(kEnabledValue, profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
// Navigating to chrome://glic should now succeed again.
{
GlicAppStateObserver app_observer(&service->host());
content::TestNavigationObserver observer(glic_url);
observer.WatchExistingWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), glic_url));
observer.WaitForNavigationFinished();
ASSERT_EQ(observer.last_navigation_url(), glic_url);
ASSERT_TRUE(observer.last_navigation_succeeded());
// WebUi will be in an error state since the mock web client is not setup.
app_observer.Wait(mojom::WebUiState::kError);
}
}
// Same as GlicPolicyTest but starts Chrome with the Glic policy disabled.
class GlicPolicyDisabledTest : public GlicPolicyTest {
public:
void SetUpInProcessBrowserTestFixture() override {
GlicPolicyTest::SetUpInProcessBrowserTestFixture();
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kDisabled);
}
};
// Test that navigations to chrome://glic when the policy is disabled from
// startup shows glic as unavailable.
IN_PROC_BROWSER_TEST_F(GlicPolicyDisabledTest, WebUiDisabledAtLoad) {
GURL glic_url = GURL(chrome::kChromeUIGlicURL);
GlicKeyedService* service =
GlicKeyedServiceFactory::GetGlicKeyedService(profile_1_);
// Glic shouldn't load since it's disabled by policy from startup.
{
GlicAppStateObserver app_observer(&service->host());
content::TestNavigationObserver observer(glic_url);
observer.WatchExistingWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), glic_url));
observer.WaitForNavigationFinished();
ASSERT_EQ(observer.last_navigation_url(), glic_url);
ASSERT_TRUE(observer.last_navigation_succeeded());
app_observer.Wait(mojom::WebUiState::kDisabledByAdmin);
}
// Enable the policy at runtime
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kEnabled);
ASSERT_EQ(kEnabledValue, profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
// Navigating to chrome://glic should now load the webview.
{
GlicAppStateObserver app_observer(&service->host());
content::TestNavigationObserver observer(glic_url);
observer.WatchExistingWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), glic_url));
observer.WaitForNavigationFinished();
ASSERT_EQ(observer.last_navigation_url(), glic_url);
ASSERT_TRUE(observer.last_navigation_succeeded());
// WebUi will be in an error state since the mock web client is not setup.
app_observer.Wait(mojom::WebUiState::kError);
}
}
// Ensure that if the policy changes to disabled at runtime, and the user has an
// an open Glic window, that window should show the unavailable page.
IN_PROC_BROWSER_TEST_F(GlicPolicyTest, DisableGlicWhenIsOpen) {
// The pref defaults to enabled.
ASSERT_EQ(kEnabledValue, profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
GlicKeyedService* service =
GlicKeyedServiceFactory::GetGlicKeyedService(profile_1_);
ASSERT_FALSE(service->window_controller().IsShowing());
// Show the panel as if the glic button was clicked.
{
base::test::TestFuture<void> wait_for_panel;
PanelStateObserver panel_state_observer(
mojom::PanelState::Kind::kDetached,
wait_for_panel.GetCallback());
service->window_controller().AddStateObserver(&panel_state_observer);
service->ToggleUI(/*bwi=*/browser(), /*prevent_close=*/false,
/*source=*/mojom::InvocationSource::kOsButton);
EXPECT_TRUE(wait_for_panel.Wait());
service->window_controller().RemoveStateObserver(&panel_state_observer);
}
ASSERT_TRUE(service->window_controller().IsShowing());
GlicAppStateObserver app_observer(&service->host());
app_observer.Wait(mojom::WebUiState::kError);
// Disable the policy.
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kDisabled);
ASSERT_EQ(kDisabledValue,
profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
ASSERT_TRUE(base::test::RunUntil([&]() {
return service->host().GetPrimaryWebUiState() ==
mojom::WebUiState::kDisabledByAdmin;
})) << "Timed out waiting for unavailable state. Current state: "
<< service->host().GetPrimaryWebUiState();
ASSERT_TRUE(service->window_controller().IsShowing());
// Flakiness on linux.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
// TODO(crbug.com/426583248) Wait for animation to finish instead of using the
// arbitrary 1000ms wait.
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), base::Milliseconds(1000));
run_loop.Run();
ClickElementWithId(
service->window_controller().GetGlicView()->GetWebContents(),
"disabledByAdminCloseButton");
ASSERT_TRUE(base::test::RunUntil([&]() {
return !service->window_controller().IsShowing();
})) << "Timed out waiting for glic to close";
#endif
}
// Ensure the chrome://settings page for Glic is available when the feature is
// disabled by policy (but the profile is otherwise eligible, completed FRE
// etc).
IN_PROC_BROWSER_TEST_F(GlicPolicyTest,
SettingsPageAvailableWithPolicyDisabled) {
// Disable the policy.
SetGlicPolicy(policy_for_profile_1(), SettingsPolicyState::kDisabled);
ASSERT_EQ(kDisabledValue,
profile_1_->GetPrefs()->GetInteger(kGeminiSettings));
// Navigate to the Glic settings page URL.
const GURL kGlicSettingsUrl =
chrome::GetSettingsUrl(chrome::kGlicSettingsSubpage);
content::TestNavigationObserver observer(kGlicSettingsUrl);
observer.WatchExistingWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kGlicSettingsUrl));
observer.WaitForNavigationFinished();
ASSERT_TRUE(observer.last_navigation_succeeded());
// If the settings page wasn't registered, the navigation will redirect to
// chrome://settings.
EXPECT_EQ(kGlicSettingsUrl,
browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
}
} // namespace
} // namespace glic