1 // Copyright (c) 2012 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 <stddef.h>
6
7 #include "base/bind.h"
8 #include "base/files/file_util.h"
9 #include "base/format_macros.h"
10 #include "base/location.h"
11 #include "base/path_service.h"
12 #include "base/run_loop.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/stl_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/threading/thread_restrictions.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "build/build_config.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_commands.h"
22 #include "chrome/browser/ui/browser_navigator_params.h"
23 #include "chrome/browser/ui/browser_tabstrip.h"
24 #include "chrome/browser/ui/browser_window.h"
25 #include "chrome/browser/ui/chrome_pages.h"
26 #include "chrome/browser/ui/find_bar/find_bar_host_unittest_util.h"
27 #include "chrome/browser/ui/location_bar/location_bar.h"
28 #include "chrome/browser/ui/tabs/tab_strip_model.h"
29 #include "chrome/browser/ui/view_ids.h"
30 #include "chrome/common/chrome_paths.h"
31 #include "chrome/common/url_constants.h"
32 #include "chrome/test/base/chrome_test_utils.h"
33 #include "chrome/test/base/in_process_browser_test.h"
34 #include "chrome/test/base/interactive_test_utils.h"
35 #include "chrome/test/base/ui_test_utils.h"
36 #include "components/omnibox/browser/autocomplete_match_type.h"
37 #include "components/omnibox/browser/omnibox_edit_controller.h"
38 #include "components/omnibox/browser/omnibox_edit_model.h"
39 #include "components/omnibox/browser/omnibox_view.h"
40 #include "content/public/browser/notification_service.h"
41 #include "content/public/browser/notification_types.h"
42 #include "content/public/browser/render_frame_host.h"
43 #include "content/public/browser/render_view_host.h"
44 #include "content/public/browser/render_widget_host.h"
45 #include "content/public/browser/render_widget_host_view.h"
46 #include "content/public/browser/web_contents.h"
47 #include "content/public/test/browser_test.h"
48 #include "content/public/test/browser_test_utils.h"
49 #include "content/public/test/test_navigation_observer.h"
50 #include "net/test/embedded_test_server/embedded_test_server.h"
51 #include "ui/base/test/ui_controls.h"
52
53 namespace {
54
55 using content::RenderViewHost;
56 using content::WebContents;
57
58 #if defined(OS_POSIX)
59 // The delay waited in some cases where we don't have a notifications for an
60 // action we take.
61 const int kActionDelayMs = 500;
62 #endif
63
64 const char kSimplePage[] = "/focus/page_with_focus.html";
65 const char kStealFocusPage[] = "/focus/page_steals_focus.html";
66 const char kTypicalPage[] = "/focus/typical_page.html";
67
68 class BrowserFocusTest : public InProcessBrowserTest {
69 public:
70 // InProcessBrowserTest overrides:
SetUpOnMainThread()71 void SetUpOnMainThread() override {
72 ASSERT_TRUE(embedded_test_server()->Start());
73 }
74
IsViewFocused(ViewID vid)75 bool IsViewFocused(ViewID vid) {
76 return ui_test_utils::IsViewFocused(browser(), vid);
77 }
78
ClickOnView(ViewID vid)79 void ClickOnView(ViewID vid) { ui_test_utils::ClickOnView(browser(), vid); }
80
TestFocusTraversal(RenderViewHost * render_view_host,bool reverse)81 void TestFocusTraversal(RenderViewHost* render_view_host, bool reverse) {
82 const char kGetFocusedElementJS[] =
83 "window.domAutomationController.send(getFocusedElement());";
84 const char* kExpectedIDs[] = {"textEdit", "searchButton", "luckyButton",
85 "googleLink", "gmailLink", "gmapLink"};
86 SCOPED_TRACE(base::StringPrintf("TestFocusTraversal: reverse=%d", reverse));
87 ui::KeyboardCode key = ui::VKEY_TAB;
88 #if defined(OS_MAC)
89 // TODO(msw): Mac requires ui::VKEY_BACKTAB for reverse cycling. Sigh...
90 key = reverse ? ui::VKEY_BACKTAB : ui::VKEY_TAB;
91 #endif
92
93 // Loop through the focus chain twice for good measure.
94 for (size_t i = 0; i < 2; ++i) {
95 SCOPED_TRACE(base::StringPrintf("focus outer loop: %" PRIuS, i));
96 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
97
98 // Mac requires an extra Tab key press to traverse the app menu button
99 // iff "Full Keyboard Access" is enabled. In reverse, four Tab key presses
100 // are required to traverse the back/forward buttons and the tab strip.
101 #if defined(OS_MAC)
102 constexpr int kFocusableElementsBeforeOmnibox = 4;
103 constexpr int kFocusableElementsAfterOmnibox = 1;
104 if (ui_controls::IsFullKeyboardAccessEnabled()) {
105 for (int j = 0; j < (reverse ? kFocusableElementsBeforeOmnibox
106 : kFocusableElementsAfterOmnibox);
107 ++j) {
108 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), key, false,
109 reverse, false, false));
110 }
111 }
112 #endif
113
114 if (reverse) {
115 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), key, false,
116 reverse, false, false));
117 }
118
119 for (size_t j = 0; j < base::size(kExpectedIDs); ++j) {
120 SCOPED_TRACE(base::StringPrintf("focus inner loop %" PRIuS, j));
121 const size_t index = reverse ? base::size(kExpectedIDs) - 1 - j : j;
122 // The details are the node's editable state, i.e. true for "textEdit".
123 bool is_editable_node = index == 0;
124
125 // Press Tab (or Shift+Tab) and check the focused element id.
126 auto source = content::Source<RenderViewHost>(render_view_host);
127 ui_test_utils::WindowedNotificationObserverWithDetails<bool> observer(
128 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE, source);
129 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), key, false,
130 reverse, false, false));
131 observer.Wait();
132 bool observed_editable_node;
133 ASSERT_TRUE(
134 observer.GetDetailsFor(source.map_key(), &observed_editable_node));
135 EXPECT_EQ(is_editable_node, observed_editable_node);
136
137 std::string focused_id;
138 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
139 WebContents::FromRenderViewHost(render_view_host),
140 kGetFocusedElementJS, &focused_id));
141 EXPECT_STREQ(kExpectedIDs[index], focused_id.c_str());
142 }
143
144 // On the last Tab key press, focus returns to the browser.
145 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), key, false,
146 reverse, false, false));
147
148 // Except on Mac, where extra tabs are once again required to traverse the
149 // other top chrome elements.
150 #if defined(OS_MAC)
151 if (ui_controls::IsFullKeyboardAccessEnabled()) {
152 for (int j = 0; j < (reverse ? kFocusableElementsAfterOmnibox
153 : kFocusableElementsBeforeOmnibox);
154 ++j) {
155 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), key, false,
156 reverse, false, false));
157 }
158 }
159 #endif
160
161 ui_test_utils::WaitForViewFocus(
162 browser(), reverse ? VIEW_ID_OMNIBOX : VIEW_ID_LOCATION_ICON, true);
163
164 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), key, false,
165 reverse, false, false));
166 ui_test_utils::WaitForViewFocus(
167 browser(), reverse ? VIEW_ID_LOCATION_ICON : VIEW_ID_OMNIBOX, true);
168 if (reverse) {
169 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), key, false,
170 false, false, false));
171 }
172 }
173 }
174 };
175
176 // Flaky on Mac (http://crbug.com/67301).
177 #if defined(OS_MAC)
178 #define MAYBE_ClickingMovesFocus DISABLED_ClickingMovesFocus
179 #else
180 // If this flakes, disable and log details in http://crbug.com/523255.
181 #define MAYBE_ClickingMovesFocus ClickingMovesFocus
182 #endif
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,MAYBE_ClickingMovesFocus)183 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_ClickingMovesFocus) {
184 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
185 #if defined(OS_POSIX)
186 // It seems we have to wait a little bit for the widgets to spin up before
187 // we can start clicking on them.
188 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
189 FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
190 base::TimeDelta::FromMilliseconds(kActionDelayMs));
191 content::RunMessageLoop();
192 #endif // defined(OS_POSIX)
193
194 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
195
196 ClickOnView(VIEW_ID_TAB_CONTAINER);
197 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
198
199 ClickOnView(VIEW_ID_OMNIBOX);
200 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
201 }
202
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,BrowsersRememberFocus)203 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) {
204 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
205 const GURL url = embedded_test_server()->GetURL(kSimplePage);
206 ui_test_utils::NavigateToURL(browser(), url);
207
208 gfx::NativeWindow window = browser()->window()->GetNativeWindow();
209
210 // The focus should be on the Tab contents.
211 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
212 // Now hide the window, show it again, the focus should not have changed.
213 ui_test_utils::HideNativeWindow(window);
214 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(window));
215 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
216
217 chrome::FocusLocationBar(browser());
218 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
219 // Hide the window, show it again, the focus should not have changed.
220 ui_test_utils::HideNativeWindow(window);
221 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(window));
222 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
223 }
224
225 // Tabs remember focus.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,TabsRememberFocus)226 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocus) {
227 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
228 const GURL url = embedded_test_server()->GetURL(kSimplePage);
229 ui_test_utils::NavigateToURL(browser(), url);
230
231 // Create several tabs.
232 for (int i = 0; i < 4; ++i) {
233 chrome::AddSelectedTabWithURL(browser(), url, ui::PAGE_TRANSITION_TYPED);
234 }
235
236 // Alternate focus for the tab.
237 const bool kFocusPage[3][5] = {{true, true, true, true, false},
238 {false, false, false, false, false},
239 {false, true, false, true, false}};
240
241 for (int i = 0; i < 3; i++) {
242 for (int j = 0; j < 5; j++) {
243 // Activate the tab.
244 browser()->tab_strip_model()->ActivateTabAt(
245 j, {TabStripModel::GestureType::kOther});
246
247 // Activate the location bar or the page.
248 if (kFocusPage[i][j]) {
249 browser()->tab_strip_model()->GetWebContentsAt(j)->Focus();
250 } else {
251 chrome::FocusLocationBar(browser());
252 }
253 }
254
255 // Now come back to the tab and check the right view is focused.
256 for (int j = 0; j < 5; j++) {
257 // Activate the tab.
258 browser()->tab_strip_model()->ActivateTabAt(
259 j, {TabStripModel::GestureType::kOther});
260
261 ViewID vid = kFocusPage[i][j] ? VIEW_ID_TAB_CONTAINER : VIEW_ID_OMNIBOX;
262 ASSERT_TRUE(IsViewFocused(vid));
263 }
264
265 browser()->tab_strip_model()->ActivateTabAt(
266 0, {TabStripModel::GestureType::kOther});
267 // Try the above, but with ctrl+tab. Since tab normally changes focus,
268 // this has regressed in the past. Loop through several times to be sure.
269 for (int j = 0; j < 15; j++) {
270 ViewID vid =
271 kFocusPage[i][j % 5] ? VIEW_ID_TAB_CONTAINER : VIEW_ID_OMNIBOX;
272 ASSERT_TRUE(IsViewFocused(vid));
273
274 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_TAB, true,
275 false, false, false));
276 }
277
278 // As above, but with ctrl+shift+tab.
279 browser()->tab_strip_model()->ActivateTabAt(
280 4, {TabStripModel::GestureType::kOther});
281 for (int j = 14; j >= 0; --j) {
282 ViewID vid =
283 kFocusPage[i][j % 5] ? VIEW_ID_TAB_CONTAINER : VIEW_ID_OMNIBOX;
284 ASSERT_TRUE(IsViewFocused(vid));
285
286 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_TAB, true,
287 true, false, false));
288 }
289 }
290 }
291
292 // Tabs remember focus with find-in-page box.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,TabsRememberFocusFindInPage)293 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocusFindInPage) {
294 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
295 const GURL url = embedded_test_server()->GetURL(kSimplePage);
296 ui_test_utils::NavigateToURL(browser(), url);
297
298 chrome::Find(browser());
299 ui_test_utils::FindInPage(
300 browser()->tab_strip_model()->GetActiveWebContents(),
301 base::ASCIIToUTF16("a"), true, false, NULL, NULL);
302 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
303
304 // Focus the location bar.
305 chrome::FocusLocationBar(browser());
306
307 // Create a 2nd tab.
308 chrome::AddSelectedTabWithURL(browser(), url, ui::PAGE_TRANSITION_TYPED);
309
310 // Focus should be on the recently opened tab page.
311 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
312
313 // Select 1st tab, focus should still be on the location-bar.
314 // (bug http://crbug.com/23296)
315 browser()->tab_strip_model()->ActivateTabAt(
316 0, {TabStripModel::GestureType::kOther});
317 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
318
319 // Now open the find box again, switch to another tab and come back, the focus
320 // should return to the find box.
321 chrome::Find(browser());
322 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
323 browser()->tab_strip_model()->ActivateTabAt(
324 1, {TabStripModel::GestureType::kOther});
325 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
326 browser()->tab_strip_model()->ActivateTabAt(
327 0, {TabStripModel::GestureType::kOther});
328 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
329 }
330
331 // Background window does not steal focus.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,BackgroundBrowserDontStealFocus)332 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) {
333 // Ensure the browser process state is in sync with the WindowServer process.
334 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
335
336 // Open a new browser window.
337 Browser* background_browser =
338 Browser::Create(Browser::CreateParams(browser()->profile(), true));
339 chrome::AddTabAt(background_browser, GURL(), -1, true);
340 background_browser->window()->Show();
341
342 const GURL steal_focus_url = embedded_test_server()->GetURL(kStealFocusPage);
343 ui_test_utils::NavigateToURL(background_browser, steal_focus_url);
344
345 // The navigation will activate |background_browser|. Except, on some
346 // platforms, that may be asynchronous. Ensure the activation is properly
347 // reflected in the browser process by activating again.
348 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(background_browser));
349 EXPECT_TRUE(background_browser->window()->IsActive());
350
351 // Activate the first browser (again). Note BringBrowserWindowToFront() does
352 // Show() and Focus(), but not Activate(), which is needed for Desktop Linux.
353 browser()->window()->Activate();
354 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
355 EXPECT_TRUE(browser()->window()->IsActive());
356 ASSERT_TRUE(content::ExecuteScript(
357 background_browser->tab_strip_model()->GetActiveWebContents(),
358 "stealFocus();"));
359
360 // Try flushing tasks. Note that on Mac and Desktop Linux, window activation
361 // is asynchronous. There's no way to guarantee that the WindowServer process
362 // has actually activated a window without waiting for the activation event.
363 // But this test is checking that _no_ activation event occurs. So there is
364 // nothing to wait for. So, assuming the test fails and |unfocused_browser|
365 // _did_ activate, the expectation below still isn't guaranteed to fail after
366 // flushing run loops.
367 content::RunAllTasksUntilIdle();
368
369 // Make sure the first browser is still active.
370 EXPECT_TRUE(browser()->window()->IsActive());
371 }
372
373 // Page cannot steal focus when focus is on location bar.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,LocationBarLockFocus)374 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) {
375 // Open the page that steals focus.
376 const GURL url = embedded_test_server()->GetURL(kStealFocusPage);
377 ui_test_utils::NavigateToURL(browser(), url);
378
379 chrome::FocusLocationBar(browser());
380
381 ASSERT_TRUE(content::ExecuteScript(
382 browser()->tab_strip_model()->GetActiveWebContents(), "stealFocus();"));
383
384 // Make sure the location bar is still focused.
385 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
386 }
387
388 // Test forward and reverse focus traversal on a typical page.
389 // Disabled for Mac because it is flaky on "Mac10.9 Tests (dbg)",
390 // see https://crbug.com/60973.
391 #if defined(OS_MAC)
392 #define MAYBE_FocusTraversal DISABLED_FocusTraversal
393 #else
394 #define MAYBE_FocusTraversal FocusTraversal
395 #endif
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,MAYBE_FocusTraversal)396 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) {
397 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
398 const GURL url = embedded_test_server()->GetURL(kTypicalPage);
399 ui_test_utils::NavigateToURL(browser(), url);
400 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
401 chrome::FocusLocationBar(browser());
402
403 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
404 EXPECT_NO_FATAL_FAILURE(
405 TestFocusTraversal(tab->GetMainFrame()->GetRenderViewHost(), false));
406 EXPECT_NO_FATAL_FAILURE(
407 TestFocusTraversal(tab->GetMainFrame()->GetRenderViewHost(), true));
408 }
409
410 // Test that find-in-page UI can request focus, even when it is already open.
411 #if defined(OS_MAC)
412 #define MAYBE_FindFocusTest DISABLED_FindFocusTest
413 #else
414 // If this flakes, disable and log details in http://crbug.com/523255.
415 #define MAYBE_FindFocusTest FindFocusTest
416 #endif
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,MAYBE_FindFocusTest)417 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FindFocusTest) {
418 chrome::DisableFindBarAnimationsDuringTesting(true);
419 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
420 const GURL url = embedded_test_server()->GetURL(kTypicalPage);
421 ui_test_utils::NavigateToURL(browser(), url);
422 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
423
424 chrome::Find(browser());
425 EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
426
427 chrome::FocusLocationBar(browser());
428 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
429
430 chrome::Find(browser());
431 EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
432
433 ClickOnView(VIEW_ID_TAB_CONTAINER);
434 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
435
436 chrome::Find(browser());
437 EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
438 }
439
440 // Makes sure the focus is in the right location when opening the different
441 // types of tabs.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,TabInitialFocus)442 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabInitialFocus) {
443 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
444
445 // Open the history tab, focus should be on the tab contents.
446 chrome::ShowHistory(browser());
447 ASSERT_NO_FATAL_FAILURE(EXPECT_TRUE(content::WaitForLoadStop(
448 browser()->tab_strip_model()->GetActiveWebContents())));
449 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
450
451 // Open the new tab, focus should be on the location bar.
452 chrome::NewTab(browser());
453 ASSERT_NO_FATAL_FAILURE(EXPECT_TRUE(content::WaitForLoadStop(
454 browser()->tab_strip_model()->GetActiveWebContents())));
455 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
456
457 // Open the download tab, focus should be on the tab contents.
458 chrome::ShowDownloads(browser());
459 ASSERT_NO_FATAL_FAILURE(EXPECT_TRUE(content::WaitForLoadStop(
460 browser()->tab_strip_model()->GetActiveWebContents())));
461 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
462
463 // Open about:blank, focus should be on the location bar.
464 chrome::AddSelectedTabWithURL(browser(), GURL(url::kAboutBlankURL),
465 ui::PAGE_TRANSITION_LINK);
466 ASSERT_NO_FATAL_FAILURE(EXPECT_TRUE(content::WaitForLoadStop(
467 browser()->tab_strip_model()->GetActiveWebContents())));
468 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
469 }
470
471 // Tests that focus goes where expected when using reload.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,FocusOnReload)472 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) {
473 // Open the new tab, reload.
474 {
475 content::WindowedNotificationObserver observer(
476 content::NOTIFICATION_LOAD_STOP,
477 content::NotificationService::AllSources());
478 chrome::NewTab(browser());
479 observer.Wait();
480 }
481 content::RunAllPendingInMessageLoop();
482
483 {
484 content::WindowedNotificationObserver observer(
485 content::NOTIFICATION_LOAD_STOP,
486 content::Source<content::NavigationController>(
487 &browser()
488 ->tab_strip_model()
489 ->GetActiveWebContents()
490 ->GetController()));
491 chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
492 observer.Wait();
493 }
494 // Focus should stay on the location bar.
495 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
496
497 // Open a regular page, focus the location bar, reload.
498 ui_test_utils::NavigateToURL(browser(),
499 embedded_test_server()->GetURL(kSimplePage));
500 chrome::FocusLocationBar(browser());
501 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
502 {
503 content::WindowedNotificationObserver observer(
504 content::NOTIFICATION_LOAD_STOP,
505 content::Source<content::NavigationController>(
506 &browser()
507 ->tab_strip_model()
508 ->GetActiveWebContents()
509 ->GetController()));
510 chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
511 observer.Wait();
512 }
513
514 // Focus should now be on the tab contents.
515 chrome::ShowDownloads(browser());
516 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
517 }
518
519 // Tests that focus goes where expected when using reload on a crashed tab.
520 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
521 // Hangy, http://crbug.com/50025.
522 #define MAYBE_FocusOnReloadCrashedTab DISABLED_FocusOnReloadCrashedTab
523 #else
524 #define MAYBE_FocusOnReloadCrashedTab FocusOnReloadCrashedTab
525 #endif
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,MAYBE_FocusOnReloadCrashedTab)526 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusOnReloadCrashedTab) {
527 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
528
529 // Open a regular page, crash, reload.
530 ui_test_utils::NavigateToURL(browser(),
531 embedded_test_server()->GetURL(kSimplePage));
532 content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
533 {
534 content::WindowedNotificationObserver observer(
535 content::NOTIFICATION_LOAD_STOP,
536 content::Source<content::NavigationController>(
537 &browser()
538 ->tab_strip_model()
539 ->GetActiveWebContents()
540 ->GetController()));
541 chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
542 observer.Wait();
543 }
544
545 // Focus should now be on the tab contents.
546 chrome::ShowDownloads(browser());
547 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
548 }
549
550 // Tests that focus goes to frame after crashed tab.
551 // TODO(shrikant): Find out where the focus should be deterministically.
552 // Currently focused_view after crash seem to be non null in debug mode
553 // (invalidated pointer 0xcccccc).
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,DISABLED_FocusAfterCrashedTab)554 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FocusAfterCrashedTab) {
555 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
556
557 content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
558
559 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
560 }
561
562 // Tests that when omnibox triggers a navigation, then the focus is moved into
563 // the current tab.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,NavigateFromOmnibox)564 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, NavigateFromOmnibox) {
565 const GURL url = embedded_test_server()->GetURL("/title1.html");
566
567 // Focus the Omnibox.
568 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
569 chrome::FocusLocationBar(browser());
570 OmniboxView* view = browser()->window()->GetLocationBar()->GetOmniboxView();
571
572 // Simulate typing a URL into the omnibox.
573 view->SetUserText(base::UTF8ToUTF16(url.spec()));
574 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
575 EXPECT_FALSE(view->IsSelectAll());
576
577 // Simulate pressing Enter and wait until the navigation starts.
578 content::WebContents* web_contents =
579 chrome_test_utils::GetActiveWebContents(this);
580 content::TestNavigationManager nav_manager(web_contents, url);
581 ASSERT_TRUE(ui_controls::SendKeyPress(browser()->window()->GetNativeWindow(),
582 ui::VKEY_RETURN, false, false, false,
583 false));
584 ASSERT_TRUE(nav_manager.WaitForRequestStart());
585
586 // Verify that a navigation has started.
587 EXPECT_TRUE(web_contents->GetController().GetPendingEntry());
588 // Verify that the Omnibox text is not selected - this is a regression test
589 // for https://crbug.com/1048742.
590 EXPECT_FALSE(view->IsSelectAll());
591 // Intentionally not asserting anything about IsViewFocused in this
592 // _intermediate_ state.
593
594 // Wait for the navigation to finish and verify final, steady state.
595 nav_manager.WaitForNavigationFinished();
596 EXPECT_TRUE(nav_manager.was_successful());
597 EXPECT_EQ(url, web_contents->GetLastCommittedURL());
598 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
599 EXPECT_FALSE(view->IsSelectAll());
600 }
601
602 // Tests that when a new tab is opened from the omnibox, the focus is moved from
603 // the omnibox for the current tab.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,NavigateFromOmniboxIntoNewTab)604 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, NavigateFromOmniboxIntoNewTab) {
605 GURL url("http://www.google.com/");
606 GURL url2("http://maps.google.com/");
607
608 // Navigate to url.
609 NavigateParams p(browser(), url, ui::PAGE_TRANSITION_LINK);
610 p.window_action = NavigateParams::SHOW_WINDOW;
611 p.disposition = WindowOpenDisposition::CURRENT_TAB;
612 Navigate(&p);
613
614 // Focus the omnibox.
615 chrome::FocusLocationBar(browser());
616
617 OmniboxEditController* controller = browser()
618 ->window()
619 ->GetLocationBar()
620 ->GetOmniboxView()
621 ->model()
622 ->controller();
623
624 // Simulate an alt-enter.
625 controller->OnAutocompleteAccept(
626 url2, nullptr, WindowOpenDisposition::NEW_FOREGROUND_TAB,
627 ui::PAGE_TRANSITION_TYPED, AutocompleteMatchType::URL_WHAT_YOU_TYPED,
628 base::TimeTicks());
629
630 // Make sure the second tab is selected.
631 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
632
633 // The tab contents should have the focus in the second tab.
634 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
635
636 // Go back to the first tab. The focus should not be in the omnibox.
637 chrome::SelectPreviousTab(browser());
638 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
639 EXPECT_FALSE(IsViewFocused(VIEW_ID_OMNIBOX));
640 }
641
642 // Flaky on all platforms (http://crbug.com/665296).
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,DISABLED_FocusOnNavigate)643 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FocusOnNavigate) {
644 // Needed on Mac.
645 // TODO(warx): check why it is needed on Mac.
646 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
647 // Load the NTP.
648 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
649 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
650
651 // Navigate to another page.
652 const base::FilePath::CharType* kEmptyFile = FILE_PATH_LITERAL("empty.html");
653 GURL file_url(ui_test_utils::GetTestUrl(
654 base::FilePath(base::FilePath::kCurrentDirectory),
655 base::FilePath(kEmptyFile)));
656 ui_test_utils::NavigateToURL(browser(), file_url);
657
658 ClickOnView(VIEW_ID_TAB_CONTAINER);
659
660 // Navigate back. Should focus the location bar.
661 {
662 content::WindowedNotificationObserver back_nav_observer(
663 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
664 content::NotificationService::AllSources());
665 chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
666 back_nav_observer.Wait();
667 }
668
669 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
670
671 // Navigate forward. Shouldn't focus the location bar.
672 ClickOnView(VIEW_ID_TAB_CONTAINER);
673 {
674 content::WindowedNotificationObserver forward_nav_observer(
675 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
676 content::NotificationService::AllSources());
677 chrome::GoForward(browser(), WindowOpenDisposition::CURRENT_TAB);
678 forward_nav_observer.Wait();
679 }
680
681 EXPECT_FALSE(IsViewFocused(VIEW_ID_OMNIBOX));
682 }
683
684 // Ensure that crbug.com/567445 does not regress. This test checks that the
685 // Omnibox does not get focused when loading about:blank in a case where it's
686 // not the startup URL, e.g. when a page opens a popup to about:blank, with a
687 // null opener, and then navigates it. This is a potential security issue; see
688 // comments in |WebContentsImpl::FocusLocationBarByDefault|.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,AboutBlankNavigationLocationTest)689 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, AboutBlankNavigationLocationTest) {
690 const GURL url1 = embedded_test_server()->GetURL("/title1.html");
691 ui_test_utils::NavigateToURL(browser(), url1);
692
693 TabStripModel* tab_strip = browser()->tab_strip_model();
694 WebContents* web_contents = tab_strip->GetActiveWebContents();
695
696 const GURL url2 = embedded_test_server()->GetURL("/title2.html");
697 const std::string spoof =
698 "var w = window.open('about:blank'); w.opener = null;"
699 "w.document.location = '" +
700 url2.spec() + "';";
701
702 ASSERT_TRUE(content::ExecuteScript(web_contents, spoof));
703 EXPECT_EQ(url1, web_contents->GetVisibleURL());
704 // After running the spoof code, |GetActiveWebContents| returns the new tab,
705 // not the same as |web_contents|.
706 ASSERT_NO_FATAL_FAILURE(EXPECT_TRUE(content::WaitForLoadStop(
707 browser()->tab_strip_model()->GetActiveWebContents())));
708 EXPECT_FALSE(IsViewFocused(VIEW_ID_OMNIBOX));
709 }
710
711 // Regression test for https://crbug.com/677716. This ensures that the omnibox
712 // does not get focused if another tab in the same window navigates to the New
713 // Tab Page, since that can scroll the origin of the selected tab out of view.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,NoFocusForBackgroundNTP)714 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, NoFocusForBackgroundNTP) {
715 // Start at the NTP and navigate to a test page. We will later go back to the
716 // NTP, which gives the omnibox focus in some cases.
717 chrome::NewTab(browser());
718 ui_test_utils::NavigateToURL(browser(),
719 embedded_test_server()->GetURL("/title1.html"));
720
721 TabStripModel* tab_strip = browser()->tab_strip_model();
722 WebContents* opener_web_contents = tab_strip->GetActiveWebContents();
723
724 // Open a second tab from the test page.
725 const GURL new_url = embedded_test_server()->GetURL("/title2.html");
726 const std::string open_script = "window.open('" + new_url.spec() + "');";
727 content::WebContentsAddedObserver open_observer;
728 ASSERT_TRUE(content::ExecuteScript(opener_web_contents, open_script));
729 WebContents* new_web_contents = open_observer.GetWebContents();
730
731 // Tell the first (non-selected) tab to go back. This should not give the
732 // omnibox focus, since the navigation occurred in a different tab. Otherwise
733 // the focus may scroll the origin out of view, making a spoof possible.
734 const std::string go_back_script = "window.opener.history.back();";
735 content::TestNavigationObserver back_observer(opener_web_contents);
736 ASSERT_TRUE(content::ExecuteScript(new_web_contents, go_back_script));
737 back_observer.Wait();
738 EXPECT_FALSE(IsViewFocused(VIEW_ID_OMNIBOX));
739 }
740
741 // Tests that the location bar is focusable when showing, which is the case in
742 // popup windows.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,PopupLocationBar)743 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, PopupLocationBar) {
744 Browser* popup_browser = CreateBrowserForPopup(browser()->profile());
745
746 // Make sure the popup is in the front. Otherwise the test is flaky.
747 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(popup_browser));
748
749 ui_test_utils::FocusView(popup_browser, VIEW_ID_TAB_CONTAINER);
750 EXPECT_TRUE(
751 ui_test_utils::IsViewFocused(popup_browser, VIEW_ID_TAB_CONTAINER));
752
753 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(popup_browser, ui::VKEY_TAB,
754 false, false, false, false));
755 ui_test_utils::WaitForViewFocus(popup_browser, VIEW_ID_LOCATION_ICON, true);
756
757 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(popup_browser, ui::VKEY_TAB,
758 false, false, false, false));
759 ui_test_utils::WaitForViewFocus(popup_browser, VIEW_ID_OMNIBOX, true);
760
761 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(popup_browser, ui::VKEY_TAB,
762 false, false, false, false));
763 ui_test_utils::WaitForViewFocus(popup_browser, VIEW_ID_TAB_CONTAINER, true);
764 }
765
766 // Tests that the location bar is not focusable when hidden, which is the case
767 // in app windows.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,AppLocationBar)768 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, AppLocationBar) {
769 Browser* app_browser = CreateBrowserForApp("foo", browser()->profile());
770
771 // Make sure the app window is in the front. Otherwise the test is flaky.
772 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(app_browser));
773
774 ui_test_utils::FocusView(app_browser, VIEW_ID_TAB_CONTAINER);
775 EXPECT_TRUE(ui_test_utils::IsViewFocused(app_browser, VIEW_ID_TAB_CONTAINER));
776
777 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(app_browser, ui::VKEY_TAB, false,
778 false, false, false));
779 base::RunLoop().RunUntilIdle();
780 ui_test_utils::WaitForViewFocus(app_browser, VIEW_ID_TAB_CONTAINER, true);
781 }
782
783 } // namespace
784