| Index: chrome/browser/ui/browser_command_controller_interactive_browsertest.cc
|
| diff --git a/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc b/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..99ca713a39342b97aa239bd051bcb2241a939f71
|
| --- /dev/null
|
| +++ b/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc
|
| @@ -0,0 +1,405 @@
|
| +// Copyright 2017 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 <memory>
|
| +#include <string>
|
| +
|
| +#include "base/macros.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "build/build_config.h"
|
| +#include "chrome/app/chrome_command_ids.h"
|
| +#include "chrome/browser/chrome_notification_types.h"
|
| +#include "chrome/browser/ui/browser.h"
|
| +#include "chrome/browser/ui/browser_commands.h"
|
| +#include "chrome/browser/ui/tabs/tab_strip_model.h"
|
| +#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
|
| +#include "chrome/test/base/in_process_browser_test.h"
|
| +#include "chrome/test/base/interactive_test_utils.h"
|
| +#include "content/public/browser/notification_service.h"
|
| +#include "content/public/test/browser_test_utils.h"
|
| +#include "content/public/test/test_utils.h"
|
| +#include "ui/events/keycodes/keyboard_codes.h"
|
| +#include "ui/events/keycodes/keyboard_code_conversion.h"
|
| +#include "ui/events/keycodes/dom/keycode_converter.h"
|
| +#include "url/gurl.h"
|
| +
|
| +namespace {
|
| +// The html file to receive key events, prevent defaults and export all the
|
| +// events with "getKeyEventReport()" function. It has two magic keys: pressing
|
| +// "S" to enter fullscreen mode; pressing "X" to indicate the end of all the
|
| +// keys.
|
| +constexpr char kFullscreenKeyboardLockHTML[] = "/fullscreen_keyboardlock.html";
|
| +
|
| +class TabCountObserver : public TabStripModelObserver {
|
| + public:
|
| + TabCountObserver(Browser* browser, int expected);
|
| + ~TabCountObserver() override;
|
| +
|
| + private:
|
| + // TabStripModelObserver implementations.
|
| + void TabInsertedAt(TabStripModel* tab_strip_model,
|
| + content::WebContents* contents,
|
| + int index,
|
| + bool foreground) override;
|
| +
|
| + const int expected_;
|
| + bool seen_ = false;
|
| +};
|
| +
|
| +TabCountObserver::TabCountObserver(Browser* browser, int expected)
|
| + : expected_(expected) {
|
| + DCHECK(browser);
|
| + seen_ = (browser->tab_strip_model()->count() == expected_);
|
| + if (!seen_) {
|
| + browser->tab_strip_model()->AddObserver(this);
|
| + }
|
| +}
|
| +TabCountObserver::~TabCountObserver() {
|
| + while (!seen_) {
|
| + content::RunAllPendingInMessageLoop();
|
| + }
|
| +}
|
| +
|
| +void TabCountObserver::TabInsertedAt(TabStripModel* tab_strip_model,
|
| + content::WebContents* contents,
|
| + int index,
|
| + bool foreground) {
|
| + if (tab_strip_model->count() == expected_) {
|
| + seen_ = true;
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class BrowserCommandControllerInteractiveTest : public InProcessBrowserTest {
|
| + public:
|
| + BrowserCommandControllerInteractiveTest() = default;
|
| + ~BrowserCommandControllerInteractiveTest() override = default;
|
| +
|
| + protected:
|
| + // Starts the test page and waits for it to be loaded.
|
| + void StartTestPage();
|
| +
|
| + // Wait for the browser to have the expected tab count or timeout.
|
| + void WaitForTabCount(int tab_count) const;
|
| +
|
| + // Sends a control or command + |key| shortcut to the focused window. Shift
|
| + // modifier will be added if |shift| is true.
|
| + void SendShortcut(ui::KeyboardCode key, bool shift = false);
|
| +
|
| + // Sends a control or command + shift + |key| shortcut to the focused window.
|
| + void SendShiftShortcut(ui::KeyboardCode key);
|
| +
|
| + // Sends a fullscreen shortcut to the focused window and wait for the
|
| + // operation to take effect.
|
| + void SendFullscreenShortcutAndWait();
|
| +
|
| + // Sends a KeyS to the focused window to trigger JavaScript fullscreen and
|
| + // wait for the operation to take effect.
|
| + void SendJsFullscreenShortcutAndWait();
|
| +
|
| + // Sends an ESC to the focused window.
|
| + void SendEscape();
|
| +
|
| + // Sends an ESC to the focused window to exit JavaScript fullscreen and wait
|
| + // for the operation to take effect.
|
| + void SendEscapeAndWaitForExitingFullscreen();
|
| +
|
| + // Sends a magic KeyX to the focused window to stop the test case, receives
|
| + // the result and verifies if it equals to |expected_result_|.
|
| + void FinishTestAndVerifyResult();
|
| +
|
| + private:
|
| + std::string expected_result_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BrowserCommandControllerInteractiveTest);
|
| +};
|
| +
|
| +void BrowserCommandControllerInteractiveTest::StartTestPage() {
|
| + ASSERT_TRUE(embedded_test_server()->Start());
|
| + ui_test_utils::NavigateToURLWithDisposition(
|
| + browser(),
|
| + embedded_test_server()->GetURL(kFullscreenKeyboardLockHTML),
|
| + WindowOpenDisposition::CURRENT_TAB,
|
| + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
|
| + ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
|
| +}
|
| +
|
| +void BrowserCommandControllerInteractiveTest::WaitForTabCount(
|
| + int tab_count) const {
|
| + while (browser()->tab_strip_model()->count() != tab_count)
|
| + content::RunAllPendingInMessageLoop();
|
| +}
|
| +
|
| +void BrowserCommandControllerInteractiveTest::SendShortcut(
|
| + ui::KeyboardCode key,
|
| + bool shift /* = false */) {
|
| +#if defined(OS_MACOSX)
|
| + const bool control_modifier = false;
|
| + const bool command_modifier = true;
|
| +#else
|
| + const bool control_modifier = true;
|
| + const bool command_modifier = false;
|
| +#endif
|
| + ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(),
|
| + key, control_modifier, shift, false, command_modifier));
|
| +
|
| + // TODO(zijiehe): Investigate why inconsistente key event sequence is
|
| + // generated by Mac OSX.
|
| + std::string code_string = ui::KeycodeConverter::DomCodeToCodeString(
|
| + ui::UsLayoutKeyboardCodeToDomCode(key));
|
| +#if defined(OS_MACOSX)
|
| + if (shift) {
|
| + expected_result_ += "keydown ShiftLeft\n";
|
| + }
|
| + expected_result_ += "keydown ControlLeft\n";
|
| + expected_result_ += "keydown ";
|
| + expected_result_ += code_string;
|
| + expected_result_ += "\n";
|
| + expected_result_ += "keyup ControlLeft\n";
|
| + if (shift) {
|
| + expected_result_ += "keyup ShiftLeft\n";
|
| + }
|
| +#else
|
| + expected_result_ += "keydown ControlLeft\n";
|
| + if (shift) {
|
| + expected_result_ += "keydown ShiftLeft\n";
|
| + }
|
| + expected_result_ += "keydown ";
|
| + expected_result_ += code_string;
|
| + expected_result_ += "\n";
|
| + expected_result_ += "keyup ";
|
| + expected_result_ += code_string;
|
| + expected_result_ += "\n";
|
| + if (shift) {
|
| + expected_result_ += "keyup ShiftLeft\n";
|
| + }
|
| + expected_result_ += "keyup ControlLeft\n";
|
| +#endif
|
| +}
|
| +
|
| +void BrowserCommandControllerInteractiveTest::SendShiftShortcut(
|
| + ui::KeyboardCode key) {
|
| + SendShortcut(key, true);
|
| +}
|
| +
|
| +void BrowserCommandControllerInteractiveTest::SendFullscreenShortcutAndWait() {
|
| + content::WindowedNotificationObserver observer(
|
| + chrome::NOTIFICATION_FULLSCREEN_CHANGED,
|
| + content::NotificationService::AllSources());
|
| + // Enter fullscreen.
|
| +#if defined(OS_MACOSX)
|
| + // Command + Shift + F shortcut is not registered to interactive_ui_tests, so
|
| + // send directly a fullscreen command instead.
|
| + ASSERT_TRUE(chrome::ExecuteCommand(browser(), IDC_FULLSCREEN));
|
| +#elif defined(OS_CHROMEOS)
|
| + // A dedicated fullscreen key is used on Chrome OS, so send a fullscreen
|
| + // command directly instead, to avoid constructing the key press.
|
| + ASSERT_TRUE(chrome::ExecuteCommand(browser(), IDC_FULLSCREEN));
|
| +#else
|
| + ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
|
| + browser(), ui::VKEY_F11, false, false, false, false));
|
| +#endif
|
| + observer.Wait();
|
| +}
|
| +
|
| +void
|
| +BrowserCommandControllerInteractiveTest::SendJsFullscreenShortcutAndWait() {
|
| + content::WindowedNotificationObserver observer(
|
| + chrome::NOTIFICATION_FULLSCREEN_CHANGED,
|
| + content::NotificationService::AllSources());
|
| + ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
|
| + browser(), ui::VKEY_S, false, false, false, false));
|
| + expected_result_ += "keydown KeyS\n";
|
| + expected_result_ += "keyup KeyS\n";
|
| + observer.Wait();
|
| +}
|
| +
|
| +void BrowserCommandControllerInteractiveTest::SendEscape() {
|
| + ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
|
| + browser(), ui::VKEY_ESCAPE, false, false, false, false));
|
| + expected_result_ += "keydown Escape\n";
|
| + expected_result_ += "keyup Escape\n";
|
| +}
|
| +
|
| +void BrowserCommandControllerInteractiveTest
|
| + ::SendEscapeAndWaitForExitingFullscreen() {
|
| + content::WindowedNotificationObserver observer(
|
| + chrome::NOTIFICATION_FULLSCREEN_CHANGED,
|
| + content::NotificationService::AllSources());
|
| + ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
|
| + browser(), ui::VKEY_ESCAPE, false, false, false, false));
|
| + observer.Wait();
|
| +}
|
| +
|
| +void BrowserCommandControllerInteractiveTest::FinishTestAndVerifyResult() {
|
| + // Magic KeyX to stop the test.
|
| + EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(),
|
| + ui::VKEY_X, false, false, false, false));
|
| + expected_result_ += "keydown KeyX\n";
|
| + expected_result_ += "keyup KeyX";
|
| + std::string result;
|
| + EXPECT_TRUE(content::ExecuteScriptAndExtractString(
|
| + browser()->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(),
|
| + "getKeyEventReport();",
|
| + &result));
|
| +#if defined(OS_MACOSX)
|
| + // On MacOSX command key is used for most of the shortcuts, so replace it with
|
| + // control to reduce the complexity of comparison of the results.
|
| + base::ReplaceSubstringsAfterOffset(&result, 0, "MetaLeft", "ControlLeft");
|
| +#endif
|
| + base::TrimWhitespaceASCII(result, base::TRIM_ALL, &result);
|
| + ASSERT_EQ(result, expected_result_);
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(BrowserCommandControllerInteractiveTest,
|
| + ShortcutsShouldTakeEffectInWindowMode) {
|
| + ASSERT_EQ(browser()->tab_strip_model()->count(), 1);
|
| + SendShortcut(ui::VKEY_T);
|
| + WaitForTabCount(2);
|
| + // { TabCountObserver observer(browser(), 2); }
|
| + ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
|
| + SendShortcut(ui::VKEY_T);
|
| + WaitForTabCount(3);
|
| + // { TabCountObserver observer(browser(), 3); }
|
| + ASSERT_EQ(browser()->tab_strip_model()->count(), 3);
|
| +#if !defined(OS_MACOSX)
|
| + // Command + W is not registered to interactive_ui_tests. So the following
|
| + // test cases won't work on Mac OSX.
|
| + SendShortcut(ui::VKEY_W);
|
| + WaitForTabCount(2);
|
| + // { TabCountObserver observer(browser(), 2); }
|
| + ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
|
| + SendShortcut(ui::VKEY_W);
|
| + WaitForTabCount(1);
|
| + // { TabCountObserver observer(browser(), 1); }
|
| + ASSERT_EQ(browser()->tab_strip_model()->count(), 1);
|
| +#endif
|
| + SendFullscreenShortcutAndWait();
|
| + ASSERT_TRUE(browser()->
|
| + exclusive_access_manager()->
|
| + fullscreen_controller()->
|
| + IsFullscreenForBrowser());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(BrowserCommandControllerInteractiveTest,
|
| + UnpreservedShortcutsShouldBePreventable) {
|
| + ASSERT_EQ(browser()->tab_strip_model()->count(), 1);
|
| + StartTestPage();
|
| +
|
| + // Print.
|
| + SendShortcut(ui::VKEY_P);
|
| + // Print by using system function.
|
| + SendShiftShortcut(ui::VKEY_P);
|
| + FinishTestAndVerifyResult();
|
| +}
|
| +
|
| +#if defined(OS_MACOSX)
|
| +// TODO(zijiehe): Figure out why this test crashes on Mac OSX. The suspicious
|
| +// command is "SendFullscreenShortcutAndWait()".
|
| +#define MAYBE_KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen \
|
| + DISABLED_KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen
|
| +#else
|
| +#define MAYBE_KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen \
|
| + KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen
|
| +#endif
|
| +IN_PROC_BROWSER_TEST_F(
|
| + BrowserCommandControllerInteractiveTest,
|
| + MAYBE_KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen) {
|
| + ASSERT_EQ(browser()->tab_strip_model()->count(), 1);
|
| + StartTestPage();
|
| +
|
| + SendFullscreenShortcutAndWait();
|
| + // The tab should not be closed.
|
| + SendShortcut(ui::VKEY_W);
|
| + // The window should not be closed.
|
| + SendShiftShortcut(ui::VKEY_W);
|
| + // TODO(zijiehe): ChromeOS incorrectly handles these;
|
| + // see http://crbug.com/737307.
|
| +#if !defined(OS_CHROMEOS)
|
| + // A new tab should not be created.
|
| + SendShortcut(ui::VKEY_T);
|
| + // A new window should not be created.
|
| + SendShortcut(ui::VKEY_N);
|
| + // A new incognito window should not be created.
|
| + SendShiftShortcut(ui::VKEY_N);
|
| + // Last closed tab should not be restored.
|
| + SendShiftShortcut(ui::VKEY_T);
|
| +#endif
|
| + // Browser should not switch to the next tab.
|
| + SendShortcut(ui::VKEY_TAB);
|
| + // Browser should not switch to the previous tab.
|
| + SendShiftShortcut(ui::VKEY_TAB);
|
| + // Current page should not exit browser fullscreen mode.
|
| + SendEscape();
|
| +
|
| + FinishTestAndVerifyResult();
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(
|
| + BrowserCommandControllerInteractiveTest,
|
| + KeyEventsShouldBeConsumedByWebPageInJsFullscreenExceptForEsc) {
|
| + ASSERT_EQ(browser()->tab_strip_model()->count(), 1);
|
| + StartTestPage();
|
| +
|
| + SendJsFullscreenShortcutAndWait();
|
| + // The tab should not be closed.
|
| + SendShortcut(ui::VKEY_W);
|
| + // The window should not be closed.
|
| + SendShiftShortcut(ui::VKEY_W);
|
| + // TODO(zijiehe): ChromeOS incorrectly handles these;
|
| + // see http://crbug.com/737307.
|
| +#if !defined(OS_CHROMEOS)
|
| + // A new tab should not be created.
|
| + SendShortcut(ui::VKEY_T);
|
| + // A new window should not be created.
|
| + SendShortcut(ui::VKEY_N);
|
| + // A new incognito window should not be created.
|
| + SendShiftShortcut(ui::VKEY_N);
|
| + // Last closed tab should not be restored.
|
| + SendShiftShortcut(ui::VKEY_T);
|
| +#endif
|
| + // Browser should not switch to the next tab.
|
| + SendShortcut(ui::VKEY_TAB);
|
| + // Browser should not switch to the previous tab.
|
| + SendShiftShortcut(ui::VKEY_TAB);
|
| + // Current page should exit HTML fullscreen mode.
|
| + SendEscapeAndWaitForExitingFullscreen();
|
| +
|
| + FinishTestAndVerifyResult();
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(
|
| + BrowserCommandControllerInteractiveTest,
|
| + KeyEventsShouldBeConsumedByWebPageInJsFullscreenExceptForF11) {
|
| + ASSERT_EQ(browser()->tab_strip_model()->count(), 1);
|
| + StartTestPage();
|
| +
|
| + SendJsFullscreenShortcutAndWait();
|
| + // The tab should not be closed.
|
| + SendShortcut(ui::VKEY_W);
|
| + // The window should not be closed.
|
| + SendShiftShortcut(ui::VKEY_W);
|
| + // TODO(zijiehe): ChromeOS incorrectly handles these;
|
| + // see http://crbug.com/737307.
|
| +#if !defined(OS_CHROMEOS)
|
| + // A new tab should not be created.
|
| + SendShortcut(ui::VKEY_T);
|
| + // A new window should not be created.
|
| + SendShortcut(ui::VKEY_N);
|
| + // A new incognito window should not be created.
|
| + SendShiftShortcut(ui::VKEY_N);
|
| + // Last closed tab should not be restored.
|
| + SendShiftShortcut(ui::VKEY_T);
|
| +#endif
|
| + // Browser should not switch to the next tab.
|
| + SendShortcut(ui::VKEY_TAB);
|
| + // Browser should not switch to the previous tab.
|
| + SendShiftShortcut(ui::VKEY_TAB);
|
| + // Current page should exit browser fullscreen mode.
|
| + SendFullscreenShortcutAndWait();
|
| +
|
| + FinishTestAndVerifyResult();
|
| +}
|
|
|