1 // Copyright (c) 2011 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 "build/build_config.h" 6 7 #include "base/file_util.h" 8 #include "base/format_macros.h" 9 #include "base/message_loop.h" 10 #include "base/path_service.h" 11 #include "base/string_number_conversions.h" 12 #include "base/string_util.h" 13 #include "base/utf_string_conversions.h" 14 #include "chrome/browser/tabs/tab_strip_model.h" 15 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/browser_window.h" 17 #include "chrome/browser/ui/view_ids.h" 18 #include "chrome/common/chrome_paths.h" 19 #include "chrome/common/url_constants.h" 20 #include "chrome/test/in_process_browser_test.h" 21 #include "chrome/test/ui_test_utils.h" 22 #include "content/browser/renderer_host/render_view_host.h" 23 #include "content/browser/renderer_host/render_widget_host_view.h" 24 #include "content/browser/tab_contents/interstitial_page.h" 25 #include "content/browser/tab_contents/tab_contents.h" 26 #include "content/browser/tab_contents/tab_contents_view.h" 27 #include "net/test/test_server.h" 28 29 #if defined(TOOLKIT_VIEWS) || defined(OS_WIN) 30 #include "views/focus/focus_manager.h" 31 #include "views/view.h" 32 #include "views/window/window.h" 33 #endif 34 35 #if defined(TOOLKIT_VIEWS) 36 #include "chrome/browser/ui/views/frame/browser_view.h" 37 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" 38 #include "chrome/browser/ui/views/tab_contents/tab_contents_container.h" 39 #endif 40 41 #if defined(TOOLKIT_USES_GTK) 42 #include "chrome/browser/ui/gtk/view_id_util.h" 43 #endif 44 45 #if defined(OS_WIN) 46 #include <Psapi.h> 47 #include <windows.h> 48 #endif 49 50 #if defined(OS_LINUX) 51 #define MAYBE_FocusTraversal FocusTraversal 52 #define MAYBE_FocusTraversalOnInterstitial FocusTraversalOnInterstitial 53 // TODO(jcampan): http://crbug.com/23683 54 #define MAYBE_TabsRememberFocusFindInPage FAILS_TabsRememberFocusFindInPage 55 #elif defined(OS_MACOSX) 56 // TODO(suzhe): http://crbug.com/60973 (following two tests) 57 #define MAYBE_FocusTraversal DISABLED_FocusTraversal 58 #define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial 59 // TODO(suzhe): http://crbug.com/49737 60 #define MAYBE_TabsRememberFocusFindInPage FAILS_TabsRememberFocusFindInPage 61 #elif defined(OS_WIN) 62 // Disabled, http://crbug.com/62543. 63 #define MAYBE_FocusTraversal DISABLED_FocusTraversal 64 // Disabled, http://crbug.com/62544. 65 #define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial 66 // Flaky, http://crbug.com/62537. 67 #define MAYBE_TabsRememberFocusFindInPage FLAKY_TabsRememberFocusFindInPage 68 #endif 69 70 namespace { 71 72 // The delay waited in some cases where we don't have a notifications for an 73 // action we take. 74 const int kActionDelayMs = 500; 75 76 const char kSimplePage[] = "files/focus/page_with_focus.html"; 77 const char kStealFocusPage[] = "files/focus/page_steals_focus.html"; 78 const char kTypicalPage[] = "files/focus/typical_page.html"; 79 const char kTypicalPageName[] = "typical_page.html"; 80 81 // Test to make sure Chrome is in the foreground as we start testing. This is 82 // required for tests that synthesize input to the Chrome window. 83 bool ChromeInForeground() { 84 #if defined(OS_WIN) 85 HWND window = ::GetForegroundWindow(); 86 std::wstring caption; 87 std::wstring filename; 88 int len = ::GetWindowTextLength(window) + 1; 89 ::GetWindowText(window, WriteInto(&caption, len), len); 90 bool chrome_window_in_foreground = 91 EndsWith(caption, L" - Google Chrome", true) || 92 EndsWith(caption, L" - Chromium", true); 93 if (!chrome_window_in_foreground) { 94 DWORD process_id; 95 int thread_id = ::GetWindowThreadProcessId(window, &process_id); 96 97 base::ProcessHandle process; 98 if (base::OpenProcessHandleWithAccess(process_id, 99 PROCESS_QUERY_LIMITED_INFORMATION, 100 &process)) { 101 len = MAX_PATH; 102 if (!GetProcessImageFileName(process, WriteInto(&filename, len), len)) { 103 int error = GetLastError(); 104 filename = std::wstring(L"Unable to read filename for process id '" + 105 base::IntToString16(process_id) + 106 L"' (error ") + 107 base::IntToString16(error) + L")"; 108 } 109 base::CloseProcessHandle(process); 110 } 111 } 112 EXPECT_TRUE(chrome_window_in_foreground) 113 << "Chrome must be in the foreground when running interactive tests\n" 114 << "Process in foreground: " << filename.c_str() << "\n" 115 << "Window: " << window << "\n" 116 << "Caption: " << caption.c_str(); 117 return chrome_window_in_foreground; 118 #else 119 // Windows only at the moment. 120 return true; 121 #endif 122 } 123 124 class BrowserFocusTest : public InProcessBrowserTest { 125 public: 126 BrowserFocusTest() { 127 set_show_window(true); 128 EnableDOMAutomation(); 129 } 130 131 bool IsViewFocused(ViewID vid) { 132 return ui_test_utils::IsViewFocused(browser(), vid); 133 } 134 135 void ClickOnView(ViewID vid) { 136 ui_test_utils::ClickOnView(browser(), vid); 137 } 138 }; 139 140 class TestInterstitialPage : public InterstitialPage { 141 public: 142 TestInterstitialPage(TabContents* tab, bool new_navigation, const GURL& url) 143 : InterstitialPage(tab, new_navigation, url) { 144 FilePath file_path; 145 bool r = PathService::Get(chrome::DIR_TEST_DATA, &file_path); 146 EXPECT_TRUE(r); 147 file_path = file_path.AppendASCII("focus"); 148 file_path = file_path.AppendASCII(kTypicalPageName); 149 r = file_util::ReadFileToString(file_path, &html_contents_); 150 EXPECT_TRUE(r); 151 } 152 153 virtual std::string GetHTMLContents() { 154 return html_contents_; 155 } 156 157 // Exposing render_view_host() and tab() to be public; they are declared as 158 // protected in the superclass. 159 virtual RenderViewHost* render_view_host() { 160 return InterstitialPage::render_view_host(); 161 } 162 163 virtual TabContents* tab() { 164 return InterstitialPage::tab(); 165 } 166 167 bool HasFocus() { 168 return render_view_host()->view()->HasFocus(); 169 } 170 171 protected: 172 virtual void FocusedNodeChanged(bool is_editable_node) { 173 NotificationService::current()->Notify( 174 NotificationType::FOCUS_CHANGED_IN_PAGE, 175 Source<TabContents>(tab()), 176 Details<const bool>(&is_editable_node)); 177 } 178 179 private: 180 std::string html_contents_; 181 }; 182 183 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, 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 MessageLoop::current()->PostDelayedTask(FROM_HERE, 189 new MessageLoop::QuitTask(), 190 kActionDelayMs); 191 ui_test_utils::RunMessageLoop(); 192 #endif // defined(OS_POSIX) 193 194 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 195 196 ClickOnView(VIEW_ID_TAB_CONTAINER); 197 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 198 199 ClickOnView(VIEW_ID_LOCATION_BAR); 200 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 201 } 202 203 // Flaky, http://crbug.com/69034. 204 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FLAKY_BrowsersRememberFocus) { 205 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 206 ASSERT_TRUE(test_server()->Start()); 207 208 // First we navigate to our test page. 209 GURL url = test_server()->GetURL(kSimplePage); 210 ui_test_utils::NavigateToURL(browser(), url); 211 212 gfx::NativeWindow window = browser()->window()->GetNativeHandle(); 213 214 // The focus should be on the Tab contents. 215 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 216 // Now hide the window, show it again, the focus should not have changed. 217 ui_test_utils::HideNativeWindow(window); 218 ui_test_utils::ShowAndFocusNativeWindow(window); 219 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 220 221 browser()->FocusLocationBar(); 222 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 223 // Hide the window, show it again, the focus should not have changed. 224 ui_test_utils::HideNativeWindow(window); 225 ui_test_utils::ShowAndFocusNativeWindow(window); 226 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 227 228 // The rest of this test does not make sense on Linux because the behavior 229 // of Activate() is not well defined and can vary by window manager. 230 #if defined(OS_WIN) 231 // Open a new browser window. 232 Browser* browser2 = Browser::Create(browser()->profile()); 233 ASSERT_TRUE(browser2); 234 browser2->tabstrip_model()->delegate()->AddBlankTab(true); 235 browser2->window()->Show(); 236 ui_test_utils::NavigateToURL(browser2, url); 237 238 HWND hwnd2 = reinterpret_cast<HWND>(browser2->window()->GetNativeHandle()); 239 BrowserView* browser_view2 = 240 BrowserView::GetBrowserViewForNativeWindow(hwnd2); 241 ASSERT_TRUE(browser_view2); 242 views::FocusManager* focus_manager2 = 243 views::FocusManager::GetFocusManagerForNativeView(hwnd2); 244 ASSERT_TRUE(focus_manager2); 245 EXPECT_EQ(browser_view2->GetTabContentsContainerView(), 246 focus_manager2->GetFocusedView()); 247 248 // Switch to the 1st browser window, focus should still be on the location 249 // bar and the second browser should have nothing focused. 250 browser()->window()->Activate(); 251 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 252 EXPECT_EQ(NULL, focus_manager2->GetFocusedView()); 253 254 // Switch back to the second browser, focus should still be on the page. 255 browser2->window()->Activate(); 256 EXPECT_EQ(NULL, 257 views::FocusManager::GetFocusManagerForNativeView( 258 browser()->window()->GetNativeHandle())->GetFocusedView()); 259 EXPECT_EQ(browser_view2->GetTabContentsContainerView(), 260 focus_manager2->GetFocusedView()); 261 262 // Close the 2nd browser to avoid a DCHECK(). 263 browser_view2->Close(); 264 #endif 265 } 266 267 // Tabs remember focus. 268 // Disabled, http://crbug.com/62542. 269 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_TabsRememberFocus) { 270 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 271 ASSERT_TRUE(test_server()->Start()); 272 273 // First we navigate to our test page. 274 GURL url = test_server()->GetURL(kSimplePage); 275 ui_test_utils::NavigateToURL(browser(), url); 276 277 // Create several tabs. 278 for (int i = 0; i < 4; ++i) 279 browser()->AddSelectedTabWithURL(url, PageTransition::TYPED); 280 281 // Alternate focus for the tab. 282 const bool kFocusPage[3][5] = { 283 { true, true, true, true, false }, 284 { false, false, false, false, false }, 285 { false, true, false, true, false } 286 }; 287 288 for (int i = 1; i < 3; i++) { 289 for (int j = 0; j < 5; j++) { 290 // Activate the tab. 291 browser()->ActivateTabAt(j, true); 292 293 // Activate the location bar or the page. 294 if (kFocusPage[i][j]) { 295 browser()->GetTabContentsAt(j)->view()->Focus(); 296 } else { 297 browser()->FocusLocationBar(); 298 } 299 } 300 301 // Now come back to the tab and check the right view is focused. 302 for (int j = 0; j < 5; j++) { 303 // Activate the tab. 304 browser()->ActivateTabAt(j, true); 305 306 ViewID vid = kFocusPage[i][j] ? VIEW_ID_TAB_CONTAINER_FOCUS_VIEW : 307 VIEW_ID_LOCATION_BAR; 308 ASSERT_TRUE(IsViewFocused(vid)); 309 } 310 311 browser()->ActivateTabAt(0, true); 312 // Try the above, but with ctrl+tab. Since tab normally changes focus, 313 // this has regressed in the past. Loop through several times to be sure. 314 for (int j = 0; j < 15; j++) { 315 ViewID vid = kFocusPage[i][j % 5] ? VIEW_ID_TAB_CONTAINER_FOCUS_VIEW : 316 VIEW_ID_LOCATION_BAR; 317 ASSERT_TRUE(IsViewFocused(vid)); 318 319 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 320 browser(), ui::VKEY_TAB, true, false, false, false)); 321 } 322 323 // As above, but with ctrl+shift+tab. 324 browser()->ActivateTabAt(4, true); 325 for (int j = 14; j >= 0; --j) { 326 ViewID vid = kFocusPage[i][j % 5] ? VIEW_ID_TAB_CONTAINER_FOCUS_VIEW : 327 VIEW_ID_LOCATION_BAR; 328 ASSERT_TRUE(IsViewFocused(vid)); 329 330 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 331 browser(), ui::VKEY_TAB, true, true, false, false)); 332 } 333 } 334 } 335 336 // Tabs remember focus with find-in-page box. 337 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_TabsRememberFocusFindInPage) { 338 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 339 ASSERT_TRUE(test_server()->Start()); 340 341 // First we navigate to our test page. 342 GURL url = test_server()->GetURL(kSimplePage); 343 ui_test_utils::NavigateToURL(browser(), url); 344 345 browser()->Find(); 346 ui_test_utils::FindInPage(browser()->GetSelectedTabContentsWrapper(), 347 ASCIIToUTF16("a"), true, false, NULL); 348 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 349 350 // Focus the location bar. 351 browser()->FocusLocationBar(); 352 353 // Create a 2nd tab. 354 browser()->AddSelectedTabWithURL(url, PageTransition::TYPED); 355 356 // Focus should be on the recently opened tab page. 357 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 358 359 // Select 1st tab, focus should still be on the location-bar. 360 // (bug http://crbug.com/23296) 361 browser()->ActivateTabAt(0, true); 362 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 363 364 // Now open the find box again, switch to another tab and come back, the focus 365 // should return to the find box. 366 browser()->Find(); 367 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 368 browser()->ActivateTabAt(1, true); 369 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 370 browser()->ActivateTabAt(0, true); 371 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 372 } 373 374 // Background window does not steal focus. 375 // Flaky, http://crbug.com/62538. 376 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, 377 FLAKY_BackgroundBrowserDontStealFocus) { 378 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 379 ASSERT_TRUE(test_server()->Start()); 380 381 // Open a new browser window. 382 Browser* browser2 = Browser::Create(browser()->profile()); 383 ASSERT_TRUE(browser2); 384 browser2->tabstrip_model()->delegate()->AddBlankTab(true); 385 browser2->window()->Show(); 386 387 Browser* focused_browser = NULL; 388 Browser* unfocused_browser = NULL; 389 #if defined(USE_X11) 390 // On X11, calling Activate() is not guaranteed to move focus, so we have 391 // to figure out which browser does have focus. 392 if (browser2->window()->IsActive()) { 393 focused_browser = browser2; 394 unfocused_browser = browser(); 395 } else if (browser()->window()->IsActive()) { 396 focused_browser = browser(); 397 unfocused_browser = browser2; 398 } else { 399 FAIL() << "Could not determine which browser has focus"; 400 } 401 #elif defined(OS_WIN) 402 focused_browser = browser(); 403 unfocused_browser = browser2; 404 #elif defined(OS_MACOSX) 405 // On Mac, the newly created window always gets the focus. 406 focused_browser = browser2; 407 unfocused_browser = browser(); 408 #endif 409 410 GURL steal_focus_url = test_server()->GetURL(kStealFocusPage); 411 ui_test_utils::NavigateToURL(unfocused_browser, steal_focus_url); 412 413 // Activate the first browser. 414 focused_browser->window()->Activate(); 415 416 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript( 417 unfocused_browser->GetSelectedTabContents()->render_view_host(), L"", 418 L"stealFocus();")); 419 420 // Make sure the first browser is still active. 421 EXPECT_TRUE(focused_browser->window()->IsActive()); 422 } 423 424 // Page cannot steal focus when focus is on location bar. 425 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) { 426 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 427 ASSERT_TRUE(test_server()->Start()); 428 429 // Open the page that steals focus. 430 GURL url = test_server()->GetURL(kStealFocusPage); 431 ui_test_utils::NavigateToURL(browser(), url); 432 433 browser()->FocusLocationBar(); 434 435 ASSERT_TRUE(ui_test_utils::ExecuteJavaScript( 436 browser()->GetSelectedTabContents()->render_view_host(), L"", 437 L"stealFocus();")); 438 439 // Make sure the location bar is still focused. 440 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 441 } 442 443 // Focus traversal on a regular page. 444 // Note that this test relies on a notification from the renderer that the 445 // focus has changed in the page. The notification in the renderer may change 446 // at which point this test would fail (see comment in 447 // RenderWidget::didFocus()). 448 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) { 449 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 450 ASSERT_TRUE(test_server()->Start()); 451 452 // First we navigate to our test page. 453 GURL url = test_server()->GetURL(kTypicalPage); 454 ui_test_utils::NavigateToURL(browser(), url); 455 456 browser()->FocusLocationBar(); 457 458 const char* kTextElementID = "textEdit"; 459 const char* kExpElementIDs[] = { 460 "", // Initially no element in the page should be focused 461 // (the location bar is focused). 462 kTextElementID, "searchButton", "luckyButton", "googleLink", "gmailLink", 463 "gmapLink" 464 }; 465 466 // Test forward focus traversal. 467 for (int i = 0; i < 3; ++i) { 468 SCOPED_TRACE(StringPrintf("outer loop: %d", i)); 469 // Location bar should be focused. 470 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 471 472 // Move the caret to the end, otherwise the next Tab key may not move focus. 473 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 474 browser(), ui::VKEY_END, false, false, false, false)); 475 476 // Now let's press tab to move the focus. 477 for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) { 478 SCOPED_TRACE(StringPrintf("inner loop %" PRIuS, j)); 479 // Let's make sure the focus is on the expected element in the page. 480 std::string actual; 481 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( 482 browser()->GetSelectedTabContents()->render_view_host(), 483 L"", 484 L"window.domAutomationController.send(getFocusedElement());", 485 &actual)); 486 ASSERT_STREQ(kExpElementIDs[j], actual.c_str()); 487 488 if (j < arraysize(kExpElementIDs) - 1) { 489 // If the next element is the kTextElementID, we expect to be 490 // notified we have switched to an editable node. 491 bool is_editable_node = 492 (strcmp(kTextElementID, kExpElementIDs[j + 1]) == 0); 493 Details<bool> details(&is_editable_node); 494 495 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWaitWithDetails( 496 browser(), ui::VKEY_TAB, false, false, false, false, 497 NotificationType::FOCUS_CHANGED_IN_PAGE, 498 NotificationSource(Source<TabContents>( 499 browser()->GetSelectedTabContents())), 500 details)); 501 } else { 502 // On the last tab key press, the focus returns to the browser. 503 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( 504 browser(), ui::VKEY_TAB, false, false, false, false, 505 NotificationType::FOCUS_RETURNED_TO_BROWSER, 506 NotificationSource(Source<Browser>(browser())))); 507 } 508 } 509 510 // At this point the renderer has sent us a message asking to advance the 511 // focus (as the end of the focus loop was reached in the renderer). 512 // We need to run the message loop to process it. 513 ui_test_utils::RunAllPendingInMessageLoop(); 514 } 515 516 // Now let's try reverse focus traversal. 517 for (int i = 0; i < 3; ++i) { 518 SCOPED_TRACE(StringPrintf("outer loop: %d", i)); 519 // Location bar should be focused. 520 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 521 522 // Move the caret to the end, otherwise the next Tab key may not move focus. 523 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 524 browser(), ui::VKEY_END, false, false, false, false)); 525 526 // Now let's press shift-tab to move the focus in reverse. 527 for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) { 528 SCOPED_TRACE(StringPrintf("inner loop: %" PRIuS, j)); 529 const char* next_element = 530 kExpElementIDs[arraysize(kExpElementIDs) - 1 - j]; 531 532 if (j < arraysize(kExpElementIDs) - 1) { 533 // If the next element is the kTextElementID, we expect to be 534 // notified we have switched to an editable node. 535 bool is_editable_node = (strcmp(kTextElementID, next_element) == 0); 536 Details<bool> details(&is_editable_node); 537 538 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWaitWithDetails( 539 browser(), ui::VKEY_TAB, false, true, false, false, 540 NotificationType::FOCUS_CHANGED_IN_PAGE, 541 NotificationSource(Source<TabContents>( 542 browser()->GetSelectedTabContents())), 543 details)); 544 } else { 545 // On the last tab key press, the focus returns to the browser. 546 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( 547 browser(), ui::VKEY_TAB, false, true, false, false, 548 NotificationType::FOCUS_RETURNED_TO_BROWSER, 549 NotificationSource(Source<Browser>(browser())))); 550 } 551 552 // Let's make sure the focus is on the expected element in the page. 553 std::string actual; 554 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( 555 browser()->GetSelectedTabContents()->render_view_host(), 556 L"", 557 L"window.domAutomationController.send(getFocusedElement());", 558 &actual)); 559 ASSERT_STREQ(next_element, actual.c_str()); 560 } 561 562 // At this point the renderer has sent us a message asking to advance the 563 // focus (as the end of the focus loop was reached in the renderer). 564 // We need to run the message loop to process it. 565 ui_test_utils::RunAllPendingInMessageLoop(); 566 } 567 } 568 569 // Focus traversal while an interstitial is showing. 570 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) { 571 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 572 ASSERT_TRUE(test_server()->Start()); 573 574 // First we navigate to our test page. 575 GURL url = test_server()->GetURL(kSimplePage); 576 ui_test_utils::NavigateToURL(browser(), url); 577 578 // Focus should be on the page. 579 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 580 581 // Let's show an interstitial. 582 TestInterstitialPage* interstitial_page = 583 new TestInterstitialPage(browser()->GetSelectedTabContents(), 584 true, GURL("http://interstitial.com")); 585 interstitial_page->Show(); 586 // Give some time for the interstitial to show. 587 MessageLoop::current()->PostDelayedTask(FROM_HERE, 588 new MessageLoop::QuitTask(), 589 1000); 590 ui_test_utils::RunMessageLoop(); 591 592 browser()->FocusLocationBar(); 593 594 const char* kExpElementIDs[] = { 595 "", // Initially no element in the page should be focused 596 // (the location bar is focused). 597 "textEdit", "searchButton", "luckyButton", "googleLink", "gmailLink", 598 "gmapLink" 599 }; 600 601 // Test forward focus traversal. 602 for (int i = 0; i < 2; ++i) { 603 // Location bar should be focused. 604 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 605 606 // Move the caret to the end, otherwise the next Tab key may not move focus. 607 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 608 browser(), ui::VKEY_END, false, false, false, false)); 609 610 // Now let's press tab to move the focus. 611 for (size_t j = 0; j < 7; ++j) { 612 // Let's make sure the focus is on the expected element in the page. 613 std::string actual; 614 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( 615 interstitial_page->render_view_host(), L"", 616 L"window.domAutomationController.send(getFocusedElement());", 617 &actual)); 618 ASSERT_STREQ(kExpElementIDs[j], actual.c_str()); 619 620 NotificationType::Type notification_type; 621 NotificationSource notification_source = 622 NotificationService::AllSources(); 623 if (j < arraysize(kExpElementIDs) - 1) { 624 notification_type = NotificationType::FOCUS_CHANGED_IN_PAGE; 625 notification_source = Source<TabContents>( 626 interstitial_page->tab()); 627 } else { 628 // On the last tab key press, the focus returns to the browser. 629 notification_type = NotificationType::FOCUS_RETURNED_TO_BROWSER; 630 notification_source = Source<Browser>(browser()); 631 } 632 633 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( 634 browser(), ui::VKEY_TAB, false, false, false, false, 635 notification_type, notification_source)); 636 } 637 638 // At this point the renderer has sent us a message asking to advance the 639 // focus (as the end of the focus loop was reached in the renderer). 640 // We need to run the message loop to process it. 641 ui_test_utils::RunAllPendingInMessageLoop(); 642 } 643 644 // Now let's try reverse focus traversal. 645 for (int i = 0; i < 2; ++i) { 646 // Location bar should be focused. 647 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 648 649 // Move the caret to the end, otherwise the next Tab key may not move focus. 650 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 651 browser(), ui::VKEY_END, false, false, false, false)); 652 653 // Now let's press shift-tab to move the focus in reverse. 654 for (size_t j = 0; j < 7; ++j) { 655 NotificationType::Type notification_type; 656 NotificationSource notification_source = 657 NotificationService::AllSources(); 658 if (j < arraysize(kExpElementIDs) - 1) { 659 notification_type = NotificationType::FOCUS_CHANGED_IN_PAGE; 660 notification_source = Source<TabContents>( 661 interstitial_page->tab()); 662 } else { 663 // On the last tab key press, the focus returns to the browser. 664 notification_type = NotificationType::FOCUS_RETURNED_TO_BROWSER; 665 notification_source = Source<Browser>(browser()); 666 } 667 668 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( 669 browser(), ui::VKEY_TAB, false, true, false, false, 670 notification_type, notification_source)); 671 672 // Let's make sure the focus is on the expected element in the page. 673 std::string actual; 674 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( 675 interstitial_page->render_view_host(), L"", 676 L"window.domAutomationController.send(getFocusedElement());", 677 &actual)); 678 ASSERT_STREQ(kExpElementIDs[6 - j], actual.c_str()); 679 } 680 681 // At this point the renderer has sent us a message asking to advance the 682 // focus (as the end of the focus loop was reached in the renderer). 683 // We need to run the message loop to process it. 684 ui_test_utils::RunAllPendingInMessageLoop(); 685 } 686 } 687 688 // Focus stays on page with interstitials. 689 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, InterstitialFocus) { 690 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 691 ASSERT_TRUE(test_server()->Start()); 692 693 // First we navigate to our test page. 694 GURL url = test_server()->GetURL(kSimplePage); 695 ui_test_utils::NavigateToURL(browser(), url); 696 697 // Page should have focus. 698 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 699 EXPECT_TRUE(browser()->GetSelectedTabContents()->render_view_host()->view()-> 700 HasFocus()); 701 702 // Let's show an interstitial. 703 TestInterstitialPage* interstitial_page = 704 new TestInterstitialPage(browser()->GetSelectedTabContents(), 705 true, GURL("http://interstitial.com")); 706 interstitial_page->Show(); 707 // Give some time for the interstitial to show. 708 MessageLoop::current()->PostDelayedTask(FROM_HERE, 709 new MessageLoop::QuitTask(), 710 1000); 711 ui_test_utils::RunMessageLoop(); 712 713 // The interstitial should have focus now. 714 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 715 EXPECT_TRUE(interstitial_page->HasFocus()); 716 717 // Hide the interstitial. 718 interstitial_page->DontProceed(); 719 720 // Focus should be back on the original page. 721 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 722 } 723 724 // Make sure Find box can request focus, even when it is already open. 725 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) { 726 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 727 ASSERT_TRUE(test_server()->Start()); 728 729 // Open some page (any page that doesn't steal focus). 730 GURL url = test_server()->GetURL(kTypicalPage); 731 ui_test_utils::NavigateToURL(browser(), url); 732 733 EXPECT_TRUE(ChromeInForeground()); 734 735 #if defined(OS_MACOSX) 736 // Press Cmd+F, which will make the Find box open and request focus. 737 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 738 browser(), ui::VKEY_F, false, false, false, true)); 739 #else 740 // Press Ctrl+F, which will make the Find box open and request focus. 741 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 742 browser(), ui::VKEY_F, true, false, false, false)); 743 #endif 744 745 // Ideally, we wouldn't sleep here and instead would intercept the 746 // RenderViewHostDelegate::HandleKeyboardEvent() callback. To do that, we 747 // could create a RenderViewHostDelegate wrapper and hook-it up by either: 748 // - creating a factory used to create the delegate 749 // - making the test a private and overwriting the delegate member directly. 750 MessageLoop::current()->PostDelayedTask( 751 FROM_HERE, new MessageLoop::QuitTask(), kActionDelayMs); 752 ui_test_utils::RunMessageLoop(); 753 754 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 755 756 browser()->FocusLocationBar(); 757 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 758 759 // Now press Ctrl+F again and focus should move to the Find box. 760 #if defined(OS_MACOSX) 761 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 762 browser(), ui::VKEY_F, false, false, false, true)); 763 #else 764 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 765 browser(), ui::VKEY_F, true, false, false, false)); 766 #endif 767 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 768 769 // Set focus to the page. 770 ClickOnView(VIEW_ID_TAB_CONTAINER); 771 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 772 773 // Now press Ctrl+F again and focus should move to the Find box. 774 #if defined(OS_MACOSX) 775 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 776 browser(), ui::VKEY_F, false, false, false, true)); 777 #else 778 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 779 browser(), ui::VKEY_F, true, false, false, false)); 780 #endif 781 782 // See remark above on why we wait. 783 MessageLoop::current()->PostDelayedTask( 784 FROM_HERE, new MessageLoop::QuitTask(), kActionDelayMs); 785 ui_test_utils::RunMessageLoop(); 786 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 787 } 788 789 // Makes sure the focus is in the right location when opening the different 790 // types of tabs. 791 // Flaky, http://crbug.com/62539. 792 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FLAKY_TabInitialFocus) { 793 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 794 795 // Open the history tab, focus should be on the tab contents. 796 browser()->ShowHistoryTab(); 797 ASSERT_NO_FATAL_FAILURE(ui_test_utils::WaitForLoadStop( 798 browser()->GetSelectedTabContents())); 799 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 800 801 // Open the new tab, focus should be on the location bar. 802 browser()->NewTab(); 803 ASSERT_NO_FATAL_FAILURE(ui_test_utils::WaitForLoadStop( 804 browser()->GetSelectedTabContents())); 805 EXPECT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 806 807 // Open the download tab, focus should be on the tab contents. 808 browser()->ShowDownloadsTab(); 809 ASSERT_NO_FATAL_FAILURE(ui_test_utils::WaitForLoadStop( 810 browser()->GetSelectedTabContents())); 811 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 812 813 // Open about:blank, focus should be on the location bar. 814 browser()->AddSelectedTabWithURL(GURL(chrome::kAboutBlankURL), 815 PageTransition::LINK); 816 ASSERT_NO_FATAL_FAILURE(ui_test_utils::WaitForLoadStop( 817 browser()->GetSelectedTabContents())); 818 EXPECT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 819 } 820 821 // Tests that focus goes where expected when using reload. 822 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) { 823 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 824 ASSERT_TRUE(test_server()->Start()); 825 826 // Open the new tab, reload. 827 browser()->NewTab(); 828 ui_test_utils::RunAllPendingInMessageLoop(); 829 830 browser()->Reload(CURRENT_TAB); 831 ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser())); 832 // Focus should stay on the location bar. 833 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 834 835 // Open a regular page, focus the location bar, reload. 836 ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(kSimplePage)); 837 browser()->FocusLocationBar(); 838 ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); 839 browser()->Reload(CURRENT_TAB); 840 ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser())); 841 842 // Focus should now be on the tab contents. 843 browser()->ShowDownloadsTab(); 844 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 845 } 846 847 // Tests that focus goes where expected when using reload on a crashed tab. 848 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FocusOnReloadCrashedTab) { 849 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 850 ASSERT_TRUE(test_server()->Start()); 851 852 // Open a regular page, crash, reload. 853 ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(kSimplePage)); 854 ui_test_utils::CrashTab(browser()->GetSelectedTabContents()); 855 browser()->Reload(CURRENT_TAB); 856 ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser())); 857 858 // Focus should now be on the tab contents. 859 browser()->ShowDownloadsTab(); 860 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); 861 } 862 863 } // namespace 864