Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(741)

Side by Side Diff: chrome/browser/ui/browser_command_controller_interactive_browsertest.cc

Issue 2922773002: Add BrowserCommandController Interactive Test (Closed)
Patch Set: Resolve review comments Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/test/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <memory>
6 #include <string>
7
8 #include "base/macros.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/strings/string_util.h"
11 #include "build/build_config.h"
12 #include "chrome/app/chrome_command_ids.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_commands.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "chrome/test/base/interactive_test_utils.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "content/public/test/test_utils.h"
23 #include "ui/events/keycodes/dom/keycode_converter.h"
24 #include "ui/events/keycodes/keyboard_code_conversion.h"
25 #include "ui/events/keycodes/keyboard_codes.h"
26 #include "url/gurl.h"
27 #include "url/url_constants.h"
28
29 #if defined(OS_MACOSX)
30 #include "base/mac/mac_util.h"
31 #endif
32
33 namespace {
34 // The html file to receive key events, prevent defaults and export all the
35 // events with "getKeyEventReport()" function. It has two magic keys: pressing
36 // "S" to enter fullscreen mode; pressing "X" to indicate the end of all the
37 // keys (see FinishTestAndVerifyResult() function).
38 constexpr char kFullscreenKeyboardLockHTML[] = "/fullscreen_keyboardlock.html";
39
40 // On MacOSX command key is used for most of the shortcuts, so replace it with
41 // control to reduce the complexity of comparison of the results.
42 void NormalizeMetaKeyForMacOS(std::string* output) {
43 #if defined(OS_MACOSX)
44 base::ReplaceSubstringsAfterOffset(output, 0, "MetaLeft", "ControlLeft");
45 #endif
46 }
47
48 } // namespace
49
50 class BrowserCommandControllerInteractiveTest : public InProcessBrowserTest {
51 public:
52 BrowserCommandControllerInteractiveTest() = default;
53 ~BrowserCommandControllerInteractiveTest() override = default;
54
55 protected:
56 // Starts the test page and waits for it to be loaded.
57 void StartTestPage();
58
59 // Sends a control or command + |key| shortcut to the focused window. Shift
60 // modifier will be added if |shift| is true.
61 void SendShortcut(ui::KeyboardCode key, bool shift = false);
62
63 // Sends a control or command + shift + |key| shortcut to the focused window.
64 void SendShiftShortcut(ui::KeyboardCode key);
65
66 // Sends a fullscreen shortcut to the focused window and wait for the
67 // operation to take effect.
68 void SendFullscreenShortcutAndWait();
69
70 // Sends a KeyS to the focused window to trigger JavaScript fullscreen and
71 // wait for the operation to take effect.
72 void SendJsFullscreenShortcutAndWait();
73
74 // Sends an ESC to the focused window.
75 void SendEscape();
76
77 // Sends an ESC to the focused window to exit JavaScript fullscreen and wait
78 // for the operation to take effect.
79 void SendEscapeAndWaitForExitingFullscreen();
80
81 // Sends a set of preventable shortcuts to the web page.
82 void SendShortcutsInFullscreen();
83
84 // Sends a magic KeyX to the focused window to stop the test case, receives
85 // the result and verifies if it is equal to |expected_result_|.
86 void FinishTestAndVerifyResult();
87
88 private:
89 void SetUpOnMainThread() override;
90
91 // The expected output from the web page. This string is generated by
92 // appending key presses from Send* functions above.
93 std::string expected_result_;
94
95 DISALLOW_COPY_AND_ASSIGN(BrowserCommandControllerInteractiveTest);
96 };
97
98 void BrowserCommandControllerInteractiveTest::StartTestPage() {
99 ASSERT_TRUE(embedded_test_server()->Start());
100 // Ensures the initial states.
101 ASSERT_EQ(1, browser()->tab_strip_model()->count());
102 ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
103 ASSERT_EQ(1U, BrowserList::GetInstance()->size());
104 // Add a second tab for counting and focus purposes.
105 AddTabAtIndex(1, GURL(url::kAboutBlankURL), ui::PAGE_TRANSITION_LINK);
106 ASSERT_EQ(2, browser()->tab_strip_model()->count());
107 ASSERT_EQ(1U, BrowserList::GetInstance()->size());
108
109 ui_test_utils::NavigateToURLWithDisposition(
110 browser(), embedded_test_server()->GetURL(kFullscreenKeyboardLockHTML),
111 WindowOpenDisposition::CURRENT_TAB,
112 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
113 }
114
115 void BrowserCommandControllerInteractiveTest::SendShortcut(
116 ui::KeyboardCode key,
117 bool shift /* = false */) {
118 #if defined(OS_MACOSX)
119 const bool control_modifier = false;
120 const bool command_modifier = true;
121 #else
122 const bool control_modifier = true;
123 const bool command_modifier = false;
124 #endif
125 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), key, control_modifier,
126 shift, false, command_modifier));
127
128 expected_result_ += ui::KeycodeConverter::DomCodeToCodeString(
129 ui::UsLayoutKeyboardCodeToDomCode(key));
130 expected_result_ += " ctrl:";
131 expected_result_ += control_modifier ? "true" : "false";
132 expected_result_ += " shift:";
133 expected_result_ += shift ? "true" : "false";
134 expected_result_ += " alt:false";
135 expected_result_ += " meta:";
136 expected_result_ += command_modifier ? "true" : "false";
137 expected_result_ += '\n';
138 }
139
140 void BrowserCommandControllerInteractiveTest::SendShiftShortcut(
141 ui::KeyboardCode key) {
142 ASSERT_NO_FATAL_FAILURE(SendShortcut(key, true));
143 }
144
145 void BrowserCommandControllerInteractiveTest::SendFullscreenShortcutAndWait() {
146 // On MacOSX, entering and exiting fullscreen are not synchronous. So we wait
147 // for the observer to notice the change of fullscreen state.
148 content::WindowedNotificationObserver observer(
149 chrome::NOTIFICATION_FULLSCREEN_CHANGED,
150 content::NotificationService::AllSources());
151 // Enter fullscreen.
152 #if defined(OS_MACOSX)
153 // On MACOSX, Command + Control + F is used.
154 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_F, true,
155 false, false, true));
156 #elif defined(OS_CHROMEOS)
157 // A dedicated fullscreen key is used on Chrome OS, so send a fullscreen
158 // command directly instead, to avoid constructing the key press.
159 ASSERT_TRUE(chrome::ExecuteCommand(browser(), IDC_FULLSCREEN));
160 #else
161 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_F11, false,
162 false, false, false));
163 #endif
164
165 observer.Wait();
166 }
167
168 void BrowserCommandControllerInteractiveTest::
169 SendJsFullscreenShortcutAndWait() {
170 content::WindowedNotificationObserver observer(
171 chrome::NOTIFICATION_FULLSCREEN_CHANGED,
172 content::NotificationService::AllSources());
173 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_S, false,
174 false, false, false));
175 expected_result_ += "KeyS ctrl:false shift:false alt:false meta:false\n";
176 observer.Wait();
177 }
178
179 void BrowserCommandControllerInteractiveTest::SendEscape() {
180 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE, false,
181 false, false, false));
182 expected_result_ += "Escape ctrl:false shift:false alt:false meta:false\n";
183 }
184
185 void BrowserCommandControllerInteractiveTest ::
186 SendEscapeAndWaitForExitingFullscreen() {
187 content::WindowedNotificationObserver observer(
188 chrome::NOTIFICATION_FULLSCREEN_CHANGED,
189 content::NotificationService::AllSources());
190 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE, false,
191 false, false, false));
192 observer.Wait();
193 }
194
195 void BrowserCommandControllerInteractiveTest::SendShortcutsInFullscreen() {
196 const int initial_active_index = browser()->tab_strip_model()->active_index();
197 const int initial_tab_count = browser()->tab_strip_model()->count();
198 const size_t initial_browser_count = BrowserList::GetInstance()->size();
199 // The tab should not be closed.
200 ASSERT_NO_FATAL_FAILURE(SendShortcut(ui::VKEY_W));
201 ASSERT_EQ(initial_tab_count, browser()->tab_strip_model()->count());
202 // The window should not be closed.
203 ASSERT_NO_FATAL_FAILURE(SendShiftShortcut(ui::VKEY_W));
204 ASSERT_EQ(initial_browser_count, BrowserList::GetInstance()->size());
205 // TODO(zijiehe): ChromeOS incorrectly handles these;
206 // see http://crbug.com/737307.
207 #if !defined(OS_CHROMEOS)
208 // A new tab should not be created.
209 ASSERT_NO_FATAL_FAILURE(SendShortcut(ui::VKEY_T));
210 ASSERT_EQ(initial_tab_count, browser()->tab_strip_model()->count());
211 // A new window should not be created.
212 ASSERT_NO_FATAL_FAILURE(SendShortcut(ui::VKEY_N));
213 ASSERT_EQ(initial_browser_count, BrowserList::GetInstance()->size());
214 // A new incognito window should not be created.
215 ASSERT_NO_FATAL_FAILURE(SendShiftShortcut(ui::VKEY_N));
216 ASSERT_EQ(initial_browser_count, BrowserList::GetInstance()->size());
217 // Last closed tab should not be restored.
218 ASSERT_NO_FATAL_FAILURE(SendShiftShortcut(ui::VKEY_T));
219 ASSERT_EQ(initial_tab_count, browser()->tab_strip_model()->count());
220 #endif
221 // Browser should not switch to the next tab.
222 ASSERT_NO_FATAL_FAILURE(SendShortcut(ui::VKEY_TAB));
223 ASSERT_EQ(initial_active_index, browser()->tab_strip_model()->active_index());
224 // Browser should not switch to the previous tab.
225 ASSERT_NO_FATAL_FAILURE(SendShiftShortcut(ui::VKEY_TAB));
226 ASSERT_EQ(initial_active_index, browser()->tab_strip_model()->active_index());
227 }
228
229 void BrowserCommandControllerInteractiveTest::FinishTestAndVerifyResult() {
230 // The renderer process receives key events through IPC channel,
231 // SendKeyPressSync() cannot guarantee the JS has processed the key event it
232 // sent. So we sent a KeyX to the webpage to indicate the end of the test
233 // case. After processing this key event, web page is safe to send the record
234 // back through window.domAutomationController.
235 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_X, false,
236 false, false, false));
237 expected_result_ += "KeyX ctrl:false shift:false alt:false meta:false";
238 std::string result;
239 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
240 browser()->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(),
241 "getKeyEventReport();", &result));
242 NormalizeMetaKeyForMacOS(&result);
243 NormalizeMetaKeyForMacOS(&expected_result_);
244 base::TrimWhitespaceASCII(result, base::TRIM_ALL, &result);
245 ASSERT_EQ(expected_result_, result);
246 }
247
248 void BrowserCommandControllerInteractiveTest::SetUpOnMainThread() {
249 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
250 }
251
252 IN_PROC_BROWSER_TEST_F(BrowserCommandControllerInteractiveTest,
253 ShortcutsShouldTakeEffectInWindowMode) {
254 ASSERT_EQ(1, browser()->tab_strip_model()->count());
255 ASSERT_NO_FATAL_FAILURE(SendShortcut(ui::VKEY_T));
256 ASSERT_EQ(2, browser()->tab_strip_model()->count());
257 ASSERT_NO_FATAL_FAILURE(SendShortcut(ui::VKEY_T));
258 ASSERT_EQ(3, browser()->tab_strip_model()->count());
259 ASSERT_NO_FATAL_FAILURE(SendShortcut(ui::VKEY_W));
260 ASSERT_EQ(2, browser()->tab_strip_model()->count());
261 ASSERT_NO_FATAL_FAILURE(SendShortcut(ui::VKEY_W));
262 ASSERT_EQ(1, browser()->tab_strip_model()->count());
263 ASSERT_NO_FATAL_FAILURE(SendFullscreenShortcutAndWait());
264 ASSERT_TRUE(browser()
265 ->exclusive_access_manager()
266 ->fullscreen_controller()
267 ->IsFullscreenForBrowser());
268 }
269
270 IN_PROC_BROWSER_TEST_F(BrowserCommandControllerInteractiveTest,
271 UnpreservedShortcutsShouldBePreventable) {
272 ASSERT_NO_FATAL_FAILURE(StartTestPage());
273
274 // The browser print function should be blocked by the web page.
275 ASSERT_NO_FATAL_FAILURE(SendShortcut(ui::VKEY_P));
276 // The system print function should be blocked by the web page.
277 ASSERT_NO_FATAL_FAILURE(SendShiftShortcut(ui::VKEY_P));
278 ASSERT_NO_FATAL_FAILURE(FinishTestAndVerifyResult());
279 }
280
281 #if defined(OS_MACOSX)
282 // TODO(zijiehe): Figure out why this test crashes on Mac OSX. The suspicious
283 // command is "SendFullscreenShortcutAndWait()". See, http://crbug.com/738949.
284 #define MAYBE_KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen \
285 DISABLED_KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen
286 #else
287 #define MAYBE_KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen \
288 KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen
289 #endif
290 IN_PROC_BROWSER_TEST_F(
291 BrowserCommandControllerInteractiveTest,
292 MAYBE_KeyEventsShouldBeConsumedByWebPageInBrowserFullscreen) {
293 ASSERT_NO_FATAL_FAILURE(StartTestPage());
294
295 ASSERT_NO_FATAL_FAILURE(SendFullscreenShortcutAndWait());
296 ASSERT_NO_FATAL_FAILURE(SendShortcutsInFullscreen());
297 // Current page should not exit browser fullscreen mode.
298 ASSERT_NO_FATAL_FAILURE(SendEscape());
299
300 ASSERT_NO_FATAL_FAILURE(FinishTestAndVerifyResult());
301 }
302
303 IN_PROC_BROWSER_TEST_F(
304 BrowserCommandControllerInteractiveTest,
305 KeyEventsShouldBeConsumedByWebPageInJsFullscreenExceptForEsc) {
306 ASSERT_NO_FATAL_FAILURE(StartTestPage());
307
308 ASSERT_NO_FATAL_FAILURE(SendJsFullscreenShortcutAndWait());
309 ASSERT_NO_FATAL_FAILURE(SendShortcutsInFullscreen());
310 // Current page should exit HTML fullscreen mode.
311 ASSERT_NO_FATAL_FAILURE(SendEscapeAndWaitForExitingFullscreen());
312
313 ASSERT_NO_FATAL_FAILURE(FinishTestAndVerifyResult());
314 }
315
316 IN_PROC_BROWSER_TEST_F(
317 BrowserCommandControllerInteractiveTest,
318 KeyEventsShouldBeConsumedByWebPageInJsFullscreenExceptForF11) {
319 ASSERT_NO_FATAL_FAILURE(StartTestPage());
320
321 ASSERT_NO_FATAL_FAILURE(SendJsFullscreenShortcutAndWait());
322 ASSERT_NO_FATAL_FAILURE(SendShortcutsInFullscreen());
323 #if defined(OS_MACOSX)
324 // On 10.9 or earlier, sending the exit fullscreen shortcut will crash the
325 // binary. See http://crbug.com/740250.
326 if (base::mac::IsAtLeastOS10_10()) {
327 // Current page should exit browser fullscreen mode.
328 ASSERT_NO_FATAL_FAILURE(SendFullscreenShortcutAndWait());
329 }
330 #else
331 // Current page should exit browser fullscreen mode.
332 ASSERT_NO_FATAL_FAILURE(SendFullscreenShortcutAndWait());
333 #endif
334
335 ASSERT_NO_FATAL_FAILURE(FinishTestAndVerifyResult());
336 }
OLDNEW
« no previous file with comments | « no previous file | chrome/test/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698