blob: 5d47f7d999244c0bbb18fbc6a75495d2f39b02d6 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/profiles/profile_picker_view.h"
#include "base/check.h"
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/lifetime/browser_shutdown.h"
#include "chrome/browser/ui/profile_picker.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/profiles/profile_picker_test_base.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "content/public/browser/notification_source.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "google_apis/gaia/gaia_urls.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/views/view.h"
#include "ui/views/view_observer.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
namespace {
// Waits until the widget bounds change.
class WidgetBoundsChangeWaiter : public views::WidgetObserver {
public:
explicit WidgetBoundsChangeWaiter(views::Widget* widget) {
DCHECK(widget);
observation_.Observe(widget);
}
// Waits until the widget bounds change.
void Wait() { run_loop_.Run(); }
private:
// WidgetObserver:
void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) override {
run_loop_.Quit();
}
base::RunLoop run_loop_;
base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{
this};
};
} // namespace
class ProfilePickerInteractiveUiTest : public ProfilePickerTestBase {
public:
ProfilePickerInteractiveUiTest()
: feature_list_(features::kSignInProfileCreation) {}
~ProfilePickerInteractiveUiTest() override = default;
void ShowAndFocusPicker(ProfilePicker::EntryPoint entry_point) {
ProfilePicker::Show(entry_point);
WaitForLayoutWithoutToolbar();
EXPECT_TRUE(
ui_test_utils::ShowAndFocusNativeWindow(widget()->GetNativeWindow()));
}
void SendCloseWindowKeyboardCommand() {
// Close window using keyboard.
#if defined(OS_MAC)
// Use Cmd-W on Mac.
bool control = false;
bool shift = false;
bool command = true;
// Mac needs the widget to get focused (once again) for
// SendKeyPressToWindowSync to work. A test-only particularity, pressing the
// keybinding manually right in the run of the test actually replaces the
// need of this call.
ASSERT_TRUE(
ui_test_utils::ShowAndFocusNativeWindow(widget()->GetNativeWindow()));
#else
// Use Ctrl-Shift-W on other platforms.
bool control = true;
bool shift = true;
bool command = false;
#endif
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
widget()->GetNativeWindow(), ui::VKEY_W, control, shift, /*alt=*/false,
command));
}
void SendBackKeyboardCommand() {
// Close window using keyboard.
#if defined(OS_MAC)
// Use Cmd-[ on Mac.
bool alt = false;
bool command = true;
ui::KeyboardCode key = ui::VKEY_OEM_4;
// Mac needs the widget to get focused (once again) for
// SendKeyPressToWindowSync to work. A test-only particularity, pressing the
// keybinding manually right in the run of the test actually replaces the
// need of this call.
ASSERT_TRUE(
ui_test_utils::ShowAndFocusNativeWindow(widget()->GetNativeWindow()));
#else
// Use Ctrl-left on other platforms.
bool alt = true;
bool command = false;
ui::KeyboardCode key = ui::VKEY_LEFT;
#endif
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
widget()->GetNativeWindow(), key, /*control=*/false,
/*shift=*/false, alt, command));
}
base::test::ScopedFeatureList feature_list_;
};
// Checks that the main picker view can be closed with keyboard shortcut.
IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, CloseWithKeyboard) {
// Open a new picker.
ShowAndFocusPicker(ProfilePicker::EntryPoint::kProfileMenuManageProfiles);
WaitForLoadStop(web_contents(), GURL("chrome://profile-picker"));
EXPECT_TRUE(ProfilePicker::IsOpen());
SendCloseWindowKeyboardCommand();
WaitForPickerClosed();
// Closing the picker does not exit Chrome.
EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
}
#if defined(OS_MAC)
// Checks that Chrome be closed with keyboard shortcut. Only MacOS has a
// keyboard shortcut to exit Chrome.
IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, ExitWithKeyboard) {
// Open a new picker.
ShowAndFocusPicker(ProfilePicker::EntryPoint::kProfileMenuManageProfiles);
WaitForLoadStop(web_contents(), GURL("chrome://profile-picker"));
EXPECT_TRUE(ProfilePicker::IsOpen());
content::WindowedNotificationObserver terminate_observer(
chrome::NOTIFICATION_APP_TERMINATING,
content::NotificationService::AllSources());
// Send Cmd-Q.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
widget()->GetNativeWindow(), ui::VKEY_Q, /*control=*/false,
/*shift=*/false, /*alt=*/false, /*command=*/true));
// Check that Chrome is quitting.
terminate_observer.Wait();
WaitForPickerClosed();
EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
}
#endif
// Flaky on Mac, see https://crbug.com/1216134
#if defined(OS_MAC)
#define MAYBE_FullscreenWithKeyboard DISABLED_FullscreenWithKeyboard
#else
#define MAYBE_FullscreenWithKeyboard FullscreenWithKeyboard
#endif
// Checks that the main picker view can switch to full screen.
IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest,
MAYBE_FullscreenWithKeyboard) {
// Open a new picker.
ShowAndFocusPicker(ProfilePicker::EntryPoint::kProfileMenuManageProfiles);
WaitForLoadStop(web_contents(), GURL("chrome://profile-picker"));
EXPECT_TRUE(ProfilePicker::IsOpen());
EXPECT_FALSE(widget()->IsFullscreen());
WidgetBoundsChangeWaiter bounds_waiter(widget());
// Toggle fullscreen with keyboard.
#if defined(OS_MAC)
// Use Cmd-Ctrl-F on Mac.
bool control = true;
bool command = true;
ui::KeyboardCode key_code = ui::VKEY_F;
#else
// Use F11 on other platforms.
bool control = false;
bool command = false;
ui::KeyboardCode key_code = ui::VKEY_F11;
#endif
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
widget()->GetNativeWindow(), key_code, control, /*shift=*/false,
/*alt=*/false, command));
// Fullscreen causes the bounds of the widget to change.
bounds_waiter.Wait();
EXPECT_TRUE(widget()->IsFullscreen());
}
// Checks that the signin web view is able to process keyboard events.
IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest,
CloseSigninWithKeyboard) {
ShowAndFocusPicker(ProfilePicker::EntryPoint::kProfileMenuAddNewProfile);
// Simulate a click on the signin button.
base::MockCallback<base::OnceCallback<void(bool)>> switch_finished_callback;
EXPECT_CALL(switch_finished_callback, Run(true));
ProfilePicker::SwitchToSignIn(SK_ColorRED, switch_finished_callback.Get());
// Switch to the signin webview.
WaitForLayoutWithToolbar();
WaitForLoadStop(web_contents(),
GaiaUrls::GetInstance()->signin_chrome_sync_dice());
// Close the picker with the keyboard.
EXPECT_TRUE(ProfilePicker::IsOpen());
SendCloseWindowKeyboardCommand();
WaitForPickerClosed();
}
// Checks that both the signin web view and the main picker view are able to
// process a back keyboard event.
IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest,
NavigateBackWithKeyboard) {
#if defined(USE_OZONE)
// Fails with ozone (https://crbug.com/1173544).
if (features::IsUsingOzonePlatform())
GTEST_SKIP();
#endif
// Simulate walking through the flow starting at the picker so that navigating
// back to the picker makes sense.
ShowAndFocusPicker(ProfilePicker::EntryPoint::kProfileMenuManageProfiles);
WaitForLoadStop(web_contents(), GURL("chrome://profile-picker"));
web_contents()->GetController().LoadURL(
GURL("chrome://profile-picker/new-profile"), content::Referrer(),
ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
WaitForLoadStop(web_contents(), GURL("chrome://profile-picker/new-profile"));
// Simulate a click on the signin button.
base::MockCallback<base::OnceCallback<void(bool)>> switch_finished_callback;
EXPECT_CALL(switch_finished_callback, Run(true));
ProfilePicker::SwitchToSignIn(SK_ColorRED, switch_finished_callback.Get());
// Switch to the signin webview.
WaitForLayoutWithToolbar();
WaitForLoadStop(web_contents(),
GaiaUrls::GetInstance()->signin_chrome_sync_dice());
// Navigate back with the keyboard.
SendBackKeyboardCommand();
WaitForLayoutWithoutToolbar();
WaitForLoadStop(web_contents(), GURL("chrome://profile-picker/new-profile"));
// Navigate again back with the keyboard.
SendBackKeyboardCommand();
WaitForLoadStop(web_contents(), GURL("chrome://profile-picker"));
// Navigating back once again does nothing.
SendBackKeyboardCommand();
EXPECT_EQ(web_contents()->GetController().GetPendingEntry(), nullptr);
}