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 "base/bind.h" 6 #include "base/file_util.h" 7 #include "base/format_macros.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/path_service.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/strings/utf_string_conversions.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/browser_tabstrip.h" 17 #include "chrome/browser/ui/browser_window.h" 18 #include "chrome/browser/ui/chrome_pages.h" 19 #include "chrome/browser/ui/omnibox/location_bar.h" 20 #include "chrome/browser/ui/omnibox/omnibox_edit_controller.h" 21 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" 22 #include "chrome/browser/ui/omnibox/omnibox_view.h" 23 #include "chrome/browser/ui/tabs/tab_strip_model.h" 24 #include "chrome/browser/ui/view_ids.h" 25 #include "chrome/common/chrome_paths.h" 26 #include "chrome/common/url_constants.h" 27 #include "chrome/test/base/in_process_browser_test.h" 28 #include "chrome/test/base/interactive_test_utils.h" 29 #include "chrome/test/base/ui_test_utils.h" 30 #include "content/public/browser/interstitial_page.h" 31 #include "content/public/browser/interstitial_page_delegate.h" 32 #include "content/public/browser/notification_service.h" 33 #include "content/public/browser/render_view_host.h" 34 #include "content/public/browser/render_widget_host_view.h" 35 #include "content/public/browser/web_contents.h" 36 #include "content/public/browser/web_contents_view.h" 37 #include "content/public/test/browser_test_utils.h" 38 #include "net/test/embedded_test_server/embedded_test_server.h" 39 40 #if defined(OS_WIN) 41 #include <windows.h> 42 #include <Psapi.h> 43 #include "base/strings/string_util.h" 44 #endif 45 46 using content::InterstitialPage; 47 using content::NavigationController; 48 using content::RenderViewHost; 49 using content::WebContents; 50 51 #if defined(OS_MACOSX) 52 // TODO(suzhe): http://crbug.com/60973 53 #define MAYBE_FocusTraversal DISABLED_FocusTraversal 54 #define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial 55 #elif defined(OS_WIN) || defined(OS_CHROMEOS) 56 // http://crbug.com/109770 and http://crbug.com/62544 57 #define MAYBE_FocusTraversal FocusTraversal 58 #define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial 59 #else 60 #define MAYBE_FocusTraversal FocusTraversal 61 #define MAYBE_FocusTraversalOnInterstitial FocusTraversalOnInterstitial 62 #endif 63 64 #if defined(OS_LINUX) || defined(OS_MACOSX) 65 // TODO(jcampan): http://crbug.com/23683 for linux. 66 // TODO(suzhe): http://crbug.com/49737 for mac. 67 #define MAYBE_TabsRememberFocusFindInPage DISABLED_TabsRememberFocusFindInPage 68 #elif defined(OS_WIN) 69 // Flaky, http://crbug.com/62537. 70 #define MAYBE_TabsRememberFocusFindInPage DISABLED_TabsRememberFocusFindInPage 71 #endif 72 73 namespace { 74 75 // The delay waited in some cases where we don't have a notifications for an 76 // action we take. 77 const int kActionDelayMs = 500; 78 79 // Maxiumum time to wait until the focus is moved to expected view. 80 const int kFocusChangeTimeoutMs = 500; 81 82 const char kSimplePage[] = "/focus/page_with_focus.html"; 83 const char kStealFocusPage[] = "/focus/page_steals_focus.html"; 84 const char kTypicalPage[] = "/focus/typical_page.html"; 85 const char kTypicalPageName[] = "typical_page.html"; 86 87 // Test to make sure Chrome is in the foreground as we start testing. This is 88 // required for tests that synthesize input to the Chrome window. 89 bool ChromeInForeground() { 90 #if defined(OS_WIN) 91 HWND window = ::GetForegroundWindow(); 92 std::wstring caption; 93 std::wstring filename; 94 int len = ::GetWindowTextLength(window) + 1; 95 if (len > 1) 96 ::GetWindowText(window, WriteInto(&caption, len), len); 97 bool chrome_window_in_foreground = 98 EndsWith(caption, L" - Google Chrome", true) || 99 EndsWith(caption, L" - Chromium", true); 100 if (!chrome_window_in_foreground) { 101 DWORD process_id; 102 int thread_id = ::GetWindowThreadProcessId(window, &process_id); 103 104 base::ProcessHandle process; 105 if (base::OpenProcessHandleWithAccess(process_id, 106 PROCESS_QUERY_LIMITED_INFORMATION, 107 &process)) { 108 if (!GetProcessImageFileName(process, WriteInto(&filename, MAX_PATH), 109 MAX_PATH)) { 110 int error = GetLastError(); 111 filename = std::wstring(L"Unable to read filename for process id '" + 112 base::IntToString16(process_id) + 113 L"' (error ") + 114 base::IntToString16(error) + L")"; 115 } 116 base::CloseProcessHandle(process); 117 } 118 } 119 EXPECT_TRUE(chrome_window_in_foreground) 120 << "Chrome must be in the foreground when running interactive tests\n" 121 << "Process in foreground: " << filename.c_str() << "\n" 122 << "Window: " << window << "\n" 123 << "Caption: " << caption.c_str(); 124 return chrome_window_in_foreground; 125 #else 126 // Windows only at the moment. 127 return true; 128 #endif 129 } 130 131 // Wait the focus change in message loop. 132 void CheckFocus(Browser* browser, ViewID id, const base::Time& timeout) { 133 if (ui_test_utils::IsViewFocused(browser, id) || 134 base::Time::Now() > timeout) { 135 base::MessageLoop::current()->PostTask(FROM_HERE, 136 base::MessageLoop::QuitClosure()); 137 } else { 138 base::MessageLoop::current()->PostDelayedTask( 139 FROM_HERE, 140 base::Bind(&CheckFocus, browser, id, timeout), 141 base::TimeDelta::FromMilliseconds(10)); 142 } 143 }; 144 145 class BrowserFocusTest : public InProcessBrowserTest { 146 public: 147 bool IsViewFocused(ViewID vid) { 148 return ui_test_utils::IsViewFocused(browser(), vid); 149 } 150 151 void ClickOnView(ViewID vid) { 152 ui_test_utils::ClickOnView(browser(), vid); 153 } 154 155 bool WaitForFocusChange(ViewID vid) { 156 const base::Time timeout = base::Time::Now() + 157 base::TimeDelta::FromMilliseconds(kFocusChangeTimeoutMs); 158 base::MessageLoop::current()->PostDelayedTask( 159 FROM_HERE, 160 base::Bind(&CheckFocus, browser(), vid, timeout), 161 base::TimeDelta::FromMilliseconds(100)); 162 content::RunMessageLoop(); 163 return IsViewFocused(vid); 164 } 165 }; 166 167 class TestInterstitialPage : public content::InterstitialPageDelegate { 168 public: 169 TestInterstitialPage(WebContents* tab, bool new_navigation, const GURL& url) { 170 base::FilePath file_path; 171 bool r = PathService::Get(chrome::DIR_TEST_DATA, &file_path); 172 EXPECT_TRUE(r); 173 file_path = file_path.AppendASCII("focus"); 174 file_path = file_path.AppendASCII(kTypicalPageName); 175 r = file_util::ReadFileToString(file_path, &html_contents_); 176 EXPECT_TRUE(r); 177 interstitial_page_ = InterstitialPage::Create( 178 tab, new_navigation, url , this); 179 interstitial_page_->Show(); 180 } 181 182 virtual std::string GetHTMLContents() OVERRIDE { 183 return html_contents_; 184 } 185 186 RenderViewHost* render_view_host() { 187 return interstitial_page_->GetRenderViewHostForTesting(); 188 } 189 190 void DontProceed() { 191 interstitial_page_->DontProceed(); 192 } 193 194 bool HasFocus() { 195 return render_view_host()->GetView()->HasFocus(); 196 } 197 198 private: 199 std::string html_contents_; 200 InterstitialPage* interstitial_page_; // Owns us. 201 }; 202 203 // Flaky on mac. http://crbug.com/67301. 204 #if defined(OS_MACOSX) 205 #define MAYBE_ClickingMovesFocus DISABLED_ClickingMovesFocus 206 #else 207 #define MAYBE_ClickingMovesFocus ClickingMovesFocus 208 #endif 209 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_ClickingMovesFocus) { 210 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 211 #if defined(OS_POSIX) 212 // It seems we have to wait a little bit for the widgets to spin up before 213 // we can start clicking on them. 214 base::MessageLoop::current()->PostDelayedTask( 215 FROM_HERE, 216 base::MessageLoop::QuitClosure(), 217 base::TimeDelta::FromMilliseconds(kActionDelayMs)); 218 content::RunMessageLoop(); 219 #endif // defined(OS_POSIX) 220 221 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 222 223 ClickOnView(VIEW_ID_TAB_CONTAINER); 224 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 225 226 ClickOnView(VIEW_ID_OMNIBOX); 227 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 228 } 229 230 // Flaky, http://crbug.com/69034. 231 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_BrowsersRememberFocus) { 232 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 233 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 234 235 // First we navigate to our test page. 236 GURL url = embedded_test_server()->GetURL(kSimplePage); 237 ui_test_utils::NavigateToURL(browser(), url); 238 239 gfx::NativeWindow window = browser()->window()->GetNativeWindow(); 240 241 // The focus should be on the Tab contents. 242 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 243 // Now hide the window, show it again, the focus should not have changed. 244 ui_test_utils::HideNativeWindow(window); 245 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(window)); 246 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 247 248 chrome::FocusLocationBar(browser()); 249 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 250 // Hide the window, show it again, the focus should not have changed. 251 ui_test_utils::HideNativeWindow(window); 252 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(window)); 253 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 254 } 255 256 // Tabs remember focus. 257 // Disabled, http://crbug.com/62542. 258 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_TabsRememberFocus) { 259 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 260 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 261 262 // First we navigate to our test page. 263 GURL url = embedded_test_server()->GetURL(kSimplePage); 264 ui_test_utils::NavigateToURL(browser(), url); 265 266 // Create several tabs. 267 for (int i = 0; i < 4; ++i) { 268 chrome::AddSelectedTabWithURL(browser(), url, 269 content::PAGE_TRANSITION_TYPED); 270 } 271 272 // Alternate focus for the tab. 273 const bool kFocusPage[3][5] = { 274 { true, true, true, true, false }, 275 { false, false, false, false, false }, 276 { false, true, false, true, false } 277 }; 278 279 for (int i = 1; i < 3; i++) { 280 for (int j = 0; j < 5; j++) { 281 // Activate the tab. 282 browser()->tab_strip_model()->ActivateTabAt(j, true); 283 284 // Activate the location bar or the page. 285 if (kFocusPage[i][j]) { 286 browser()->tab_strip_model()->GetWebContentsAt(j)->GetView()->Focus(); 287 } else { 288 chrome::FocusLocationBar(browser()); 289 } 290 } 291 292 // Now come back to the tab and check the right view is focused. 293 for (int j = 0; j < 5; j++) { 294 // Activate the tab. 295 browser()->tab_strip_model()->ActivateTabAt(j, true); 296 297 ViewID vid = kFocusPage[i][j] ? VIEW_ID_TAB_CONTAINER : VIEW_ID_OMNIBOX; 298 ASSERT_TRUE(IsViewFocused(vid)); 299 } 300 301 browser()->tab_strip_model()->ActivateTabAt(0, true); 302 // Try the above, but with ctrl+tab. Since tab normally changes focus, 303 // this has regressed in the past. Loop through several times to be sure. 304 for (int j = 0; j < 15; j++) { 305 ViewID vid = kFocusPage[i][j % 5] ? VIEW_ID_TAB_CONTAINER : 306 VIEW_ID_OMNIBOX; 307 ASSERT_TRUE(IsViewFocused(vid)); 308 309 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 310 browser(), ui::VKEY_TAB, true, false, false, false)); 311 } 312 313 // As above, but with ctrl+shift+tab. 314 browser()->tab_strip_model()->ActivateTabAt(4, true); 315 for (int j = 14; j >= 0; --j) { 316 ViewID vid = kFocusPage[i][j % 5] ? VIEW_ID_TAB_CONTAINER : 317 VIEW_ID_OMNIBOX; 318 ASSERT_TRUE(IsViewFocused(vid)); 319 320 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 321 browser(), ui::VKEY_TAB, true, true, false, false)); 322 } 323 } 324 } 325 326 // Tabs remember focus with find-in-page box. 327 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_TabsRememberFocusFindInPage) { 328 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 329 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 330 331 // First we navigate to our test page. 332 GURL url = embedded_test_server()->GetURL(kSimplePage); 333 ui_test_utils::NavigateToURL(browser(), url); 334 335 chrome::Find(browser()); 336 ui_test_utils::FindInPage( 337 browser()->tab_strip_model()->GetActiveWebContents(), 338 ASCIIToUTF16("a"), true, false, NULL, NULL); 339 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 340 341 // Focus the location bar. 342 chrome::FocusLocationBar(browser()); 343 344 // Create a 2nd tab. 345 chrome::AddSelectedTabWithURL(browser(), url, content::PAGE_TRANSITION_TYPED); 346 347 // Focus should be on the recently opened tab page. 348 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 349 350 // Select 1st tab, focus should still be on the location-bar. 351 // (bug http://crbug.com/23296) 352 browser()->tab_strip_model()->ActivateTabAt(0, true); 353 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 354 355 // Now open the find box again, switch to another tab and come back, the focus 356 // should return to the find box. 357 chrome::Find(browser()); 358 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 359 browser()->tab_strip_model()->ActivateTabAt(1, true); 360 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 361 browser()->tab_strip_model()->ActivateTabAt(0, true); 362 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 363 } 364 365 // Background window does not steal focus. 366 // Flaky, http://crbug.com/62538. 367 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, 368 DISABLED_BackgroundBrowserDontStealFocus) { 369 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 370 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 371 372 // Open a new browser window. 373 Browser* browser2 = 374 new Browser(Browser::CreateParams(browser()->profile(), 375 browser()->host_desktop_type())); 376 ASSERT_TRUE(browser2); 377 chrome::AddBlankTabAt(browser2, -1, true); 378 browser2->window()->Show(); 379 380 Browser* focused_browser = NULL; 381 Browser* unfocused_browser = NULL; 382 #if defined(USE_X11) 383 // On X11, calling Activate() is not guaranteed to move focus, so we have 384 // to figure out which browser does have focus. 385 if (browser2->window()->IsActive()) { 386 focused_browser = browser2; 387 unfocused_browser = browser(); 388 } else if (browser()->window()->IsActive()) { 389 focused_browser = browser(); 390 unfocused_browser = browser2; 391 } else { 392 FAIL() << "Could not determine which browser has focus"; 393 } 394 #elif defined(OS_WIN) 395 focused_browser = browser(); 396 unfocused_browser = browser2; 397 #elif defined(OS_MACOSX) 398 // On Mac, the newly created window always gets the focus. 399 focused_browser = browser2; 400 unfocused_browser = browser(); 401 #endif 402 403 GURL steal_focus_url = embedded_test_server()->GetURL(kStealFocusPage); 404 ui_test_utils::NavigateToURL(unfocused_browser, steal_focus_url); 405 406 // Activate the first browser. 407 focused_browser->window()->Activate(); 408 409 ASSERT_TRUE(content::ExecuteScript( 410 unfocused_browser->tab_strip_model()->GetActiveWebContents(), 411 "stealFocus();")); 412 413 // Make sure the first browser is still active. 414 EXPECT_TRUE(focused_browser->window()->IsActive()); 415 } 416 417 // Page cannot steal focus when focus is on location bar. 418 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) { 419 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 420 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 421 422 // Open the page that steals focus. 423 GURL url = embedded_test_server()->GetURL(kStealFocusPage); 424 ui_test_utils::NavigateToURL(browser(), url); 425 426 chrome::FocusLocationBar(browser()); 427 428 ASSERT_TRUE(content::ExecuteScript( 429 browser()->tab_strip_model()->GetActiveWebContents(), 430 "stealFocus();")); 431 432 // Make sure the location bar is still focused. 433 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 434 } 435 436 // Focus traversal on a regular page. 437 // Note that this test relies on a notification from the renderer that the 438 // focus has changed in the page. The notification in the renderer may change 439 // at which point this test would fail (see comment in 440 // RenderWidget::didFocus()). 441 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) { 442 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 443 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 444 445 // First we navigate to our test page. 446 GURL url = embedded_test_server()->GetURL(kTypicalPage); 447 ui_test_utils::NavigateToURL(browser(), url); 448 449 chrome::FocusLocationBar(browser()); 450 451 const char* kTextElementID = "textEdit"; 452 const char* kExpElementIDs[] = { 453 "", // Initially no element in the page should be focused 454 // (the location bar is focused). 455 kTextElementID, "searchButton", "luckyButton", "googleLink", "gmailLink", 456 "gmapLink" 457 }; 458 459 // Test forward focus traversal. 460 for (int i = 0; i < 3; ++i) { 461 SCOPED_TRACE(base::StringPrintf("outer loop: %d", i)); 462 // Location bar should be focused. 463 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 464 465 // Move the caret to the end, otherwise the next Tab key may not move focus. 466 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 467 browser(), ui::VKEY_END, false, false, false, false)); 468 469 // Now let's press tab to move the focus. 470 for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) { 471 SCOPED_TRACE(base::StringPrintf("inner loop %" PRIuS, j)); 472 // Let's make sure the focus is on the expected element in the page. 473 std::string actual; 474 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 475 browser()->tab_strip_model()->GetActiveWebContents(), 476 "window.domAutomationController.send(getFocusedElement());", 477 &actual)); 478 ASSERT_STREQ(kExpElementIDs[j], actual.c_str()); 479 480 if (j < arraysize(kExpElementIDs) - 1) { 481 // If the next element is the kTextElementID, we expect to be 482 // notified we have switched to an editable node. 483 bool is_editable_node = 484 (strcmp(kTextElementID, kExpElementIDs[j + 1]) == 0); 485 content::Details<bool> details(&is_editable_node); 486 487 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWaitWithDetails( 488 browser(), ui::VKEY_TAB, false, false, false, false, 489 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE, 490 content::NotificationSource(content::Source<RenderViewHost>( 491 browser()->tab_strip_model()->GetActiveWebContents()-> 492 GetRenderViewHost())), 493 details)); 494 } else { 495 // On the last tab key press, the focus returns to the browser. 496 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( 497 browser(), ui::VKEY_TAB, false, false, false, false, 498 chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER, 499 content::NotificationSource(content::Source<Browser>(browser())))); 500 } 501 } 502 503 // At this point the renderer has sent us a message asking to advance the 504 // focus (as the end of the focus loop was reached in the renderer). 505 // We need to run the message loop to process it. 506 content::RunAllPendingInMessageLoop(); 507 } 508 509 // Now let's try reverse focus traversal. 510 for (int i = 0; i < 3; ++i) { 511 SCOPED_TRACE(base::StringPrintf("outer loop: %d", i)); 512 // Location bar should be focused. 513 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 514 515 // Move the caret to the end, otherwise the next Tab key may not move focus. 516 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 517 browser(), ui::VKEY_END, false, false, false, false)); 518 519 // Now let's press shift-tab to move the focus in reverse. 520 for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) { 521 SCOPED_TRACE(base::StringPrintf("inner loop: %" PRIuS, j)); 522 const char* next_element = 523 kExpElementIDs[arraysize(kExpElementIDs) - 1 - j]; 524 525 if (j < arraysize(kExpElementIDs) - 1) { 526 // If the next element is the kTextElementID, we expect to be 527 // notified we have switched to an editable node. 528 bool is_editable_node = (strcmp(kTextElementID, next_element) == 0); 529 content::Details<bool> details(&is_editable_node); 530 531 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWaitWithDetails( 532 browser(), ui::VKEY_TAB, false, true, false, false, 533 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE, 534 content::NotificationSource(content::Source<RenderViewHost>( 535 browser()->tab_strip_model()->GetActiveWebContents()-> 536 GetRenderViewHost())), 537 details)); 538 } else { 539 // On the last tab key press, the focus returns to the browser. 540 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( 541 browser(), ui::VKEY_TAB, false, true, false, false, 542 chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER, 543 content::NotificationSource(content::Source<Browser>(browser())))); 544 } 545 546 // Let's make sure the focus is on the expected element in the page. 547 std::string actual; 548 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 549 browser()->tab_strip_model()->GetActiveWebContents(), 550 "window.domAutomationController.send(getFocusedElement());", 551 &actual)); 552 ASSERT_STREQ(next_element, actual.c_str()); 553 } 554 555 // At this point the renderer has sent us a message asking to advance the 556 // focus (as the end of the focus loop was reached in the renderer). 557 // We need to run the message loop to process it. 558 content::RunAllPendingInMessageLoop(); 559 } 560 } 561 562 // Focus traversal while an interstitial is showing. 563 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) { 564 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 565 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 566 567 // First we navigate to our test page. 568 GURL url = embedded_test_server()->GetURL(kSimplePage); 569 ui_test_utils::NavigateToURL(browser(), url); 570 571 // Focus should be on the page. 572 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 573 574 // Let's show an interstitial. 575 TestInterstitialPage* interstitial_page = new TestInterstitialPage( 576 browser()->tab_strip_model()->GetActiveWebContents(), 577 true, GURL("http://interstitial.com")); 578 // Give some time for the interstitial to show. 579 base::MessageLoop::current()->PostDelayedTask( 580 FROM_HERE, 581 base::MessageLoop::QuitClosure(), 582 base::TimeDelta::FromSeconds(1)); 583 content::RunMessageLoop(); 584 585 chrome::FocusLocationBar(browser()); 586 587 const char* kExpElementIDs[] = { 588 "", // Initially no element in the page should be focused 589 // (the location bar is focused). 590 "textEdit", "searchButton", "luckyButton", "googleLink", "gmailLink", 591 "gmapLink" 592 }; 593 594 // Test forward focus traversal. 595 for (int i = 0; i < 2; ++i) { 596 // Location bar should be focused. 597 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 598 599 // Move the caret to the end, otherwise the next Tab key may not move focus. 600 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 601 browser(), ui::VKEY_END, false, false, false, false)); 602 603 // Now let's press tab to move the focus. 604 for (size_t j = 0; j < 7; ++j) { 605 // Let's make sure the focus is on the expected element in the page. 606 std::string actual; 607 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 608 interstitial_page->render_view_host(), 609 "window.domAutomationController.send(getFocusedElement());", 610 &actual)); 611 ASSERT_STREQ(kExpElementIDs[j], actual.c_str()); 612 613 int notification_type; 614 content::NotificationSource notification_source = 615 content::NotificationService::AllSources(); 616 if (j < arraysize(kExpElementIDs) - 1) { 617 notification_type = content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE; 618 notification_source = content::Source<RenderViewHost>( 619 interstitial_page->render_view_host()); 620 } else { 621 // On the last tab key press, the focus returns to the browser. 622 notification_type = chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER; 623 notification_source = content::Source<Browser>(browser()); 624 } 625 626 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( 627 browser(), ui::VKEY_TAB, false, false, false, false, 628 notification_type, notification_source)); 629 } 630 631 // At this point the renderer has sent us a message asking to advance the 632 // focus (as the end of the focus loop was reached in the renderer). 633 // We need to run the message loop to process it. 634 content::RunAllPendingInMessageLoop(); 635 } 636 637 // Now let's try reverse focus traversal. 638 for (int i = 0; i < 2; ++i) { 639 // Location bar should be focused. 640 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 641 642 // Move the caret to the end, otherwise the next Tab key may not move focus. 643 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 644 browser(), ui::VKEY_END, false, false, false, false)); 645 646 // Now let's press shift-tab to move the focus in reverse. 647 for (size_t j = 0; j < 7; ++j) { 648 int notification_type; 649 content::NotificationSource notification_source = 650 content::NotificationService::AllSources(); 651 if (j < arraysize(kExpElementIDs) - 1) { 652 notification_type = content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE; 653 notification_source = content::Source<RenderViewHost>( 654 interstitial_page->render_view_host()); 655 } else { 656 // On the last tab key press, the focus returns to the browser. 657 notification_type = chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER; 658 notification_source = content::Source<Browser>(browser()); 659 } 660 661 ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait( 662 browser(), ui::VKEY_TAB, false, true, false, false, 663 notification_type, notification_source)); 664 665 // Let's make sure the focus is on the expected element in the page. 666 std::string actual; 667 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 668 interstitial_page->render_view_host(), 669 "window.domAutomationController.send(getFocusedElement());", 670 &actual)); 671 ASSERT_STREQ(kExpElementIDs[6 - j], actual.c_str()); 672 } 673 674 // At this point the renderer has sent us a message asking to advance the 675 // focus (as the end of the focus loop was reached in the renderer). 676 // We need to run the message loop to process it. 677 content::RunAllPendingInMessageLoop(); 678 } 679 } 680 681 // Focus stays on page with interstitials. 682 // http://crbug.com/81451 683 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_InterstitialFocus) { 684 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 685 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 686 687 // First we navigate to our test page. 688 GURL url = embedded_test_server()->GetURL(kSimplePage); 689 ui_test_utils::NavigateToURL(browser(), url); 690 691 // Page should have focus. 692 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 693 EXPECT_TRUE(browser()->tab_strip_model()->GetActiveWebContents()-> 694 GetRenderViewHost()->GetView()->HasFocus()); 695 696 // Let's show an interstitial. 697 TestInterstitialPage* interstitial_page = new TestInterstitialPage( 698 browser()->tab_strip_model()->GetActiveWebContents(), 699 true, GURL("http://interstitial.com")); 700 // Give some time for the interstitial to show. 701 base::MessageLoop::current()->PostDelayedTask( 702 FROM_HERE, 703 base::MessageLoop::QuitClosure(), 704 base::TimeDelta::FromSeconds(1)); 705 content::RunMessageLoop(); 706 707 // The interstitial should have focus now. 708 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 709 EXPECT_TRUE(interstitial_page->HasFocus()); 710 711 // Hide the interstitial. 712 interstitial_page->DontProceed(); 713 714 // Focus should be back on the original page. 715 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 716 } 717 718 // Make sure Find box can request focus, even when it is already open. 719 // Disabled due to flakiness. http://crbug.com/67301. 720 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FindFocusTest) { 721 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 722 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 723 724 // Open some page (any page that doesn't steal focus). 725 GURL url = embedded_test_server()->GetURL(kTypicalPage); 726 ui_test_utils::NavigateToURL(browser(), url); 727 728 EXPECT_TRUE(ChromeInForeground()); 729 730 #if defined(OS_MACOSX) 731 // Press Cmd+F, which will make the Find box open and request focus. 732 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 733 browser(), ui::VKEY_F, false, false, false, true)); 734 #else 735 // Press Ctrl+F, which will make the Find box open and request focus. 736 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 737 browser(), ui::VKEY_F, true, false, false, false)); 738 #endif 739 740 ASSERT_TRUE(WaitForFocusChange(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 741 742 chrome::FocusLocationBar(browser()); 743 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 744 745 // Now press Ctrl+F again and focus should move to the Find box. 746 #if defined(OS_MACOSX) 747 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 748 browser(), ui::VKEY_F, false, false, false, true)); 749 #else 750 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 751 browser(), ui::VKEY_F, true, false, false, false)); 752 #endif 753 ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 754 755 // Set focus to the page. 756 ClickOnView(VIEW_ID_TAB_CONTAINER); 757 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 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 768 ASSERT_TRUE(WaitForFocusChange(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); 769 } 770 771 // Makes sure the focus is in the right location when opening the different 772 // types of tabs. 773 // Flaky, http://crbug.com/62539. 774 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_TabInitialFocus) { 775 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 776 777 // Open the history tab, focus should be on the tab contents. 778 chrome::ShowHistory(browser()); 779 ASSERT_NO_FATAL_FAILURE(content::WaitForLoadStop( 780 browser()->tab_strip_model()->GetActiveWebContents())); 781 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 782 783 // Open the new tab, focus should be on the location bar. 784 chrome::NewTab(browser()); 785 ASSERT_NO_FATAL_FAILURE(content::WaitForLoadStop( 786 browser()->tab_strip_model()->GetActiveWebContents())); 787 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 788 789 // Open the download tab, focus should be on the tab contents. 790 chrome::ShowDownloads(browser()); 791 ASSERT_NO_FATAL_FAILURE(content::WaitForLoadStop( 792 browser()->tab_strip_model()->GetActiveWebContents())); 793 EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 794 795 // Open about:blank, focus should be on the location bar. 796 chrome::AddSelectedTabWithURL(browser(), GURL(content::kAboutBlankURL), 797 content::PAGE_TRANSITION_LINK); 798 ASSERT_NO_FATAL_FAILURE(content::WaitForLoadStop( 799 browser()->tab_strip_model()->GetActiveWebContents())); 800 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 801 } 802 803 // Tests that focus goes where expected when using reload. 804 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) { 805 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 806 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 807 808 // Open the new tab, reload. 809 { 810 content::WindowedNotificationObserver observer( 811 content::NOTIFICATION_LOAD_STOP, 812 content::NotificationService::AllSources()); 813 chrome::NewTab(browser()); 814 observer.Wait(); 815 } 816 content::RunAllPendingInMessageLoop(); 817 818 { 819 content::WindowedNotificationObserver observer( 820 content::NOTIFICATION_LOAD_STOP, 821 content::Source<NavigationController>( 822 &browser()->tab_strip_model()->GetActiveWebContents()-> 823 GetController())); 824 chrome::Reload(browser(), CURRENT_TAB); 825 observer.Wait(); 826 } 827 // Focus should stay on the location bar. 828 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 829 830 // Open a regular page, focus the location bar, reload. 831 ui_test_utils::NavigateToURL(browser(), 832 embedded_test_server()->GetURL(kSimplePage)); 833 chrome::FocusLocationBar(browser()); 834 ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 835 { 836 content::WindowedNotificationObserver observer( 837 content::NOTIFICATION_LOAD_STOP, 838 content::Source<NavigationController>( 839 &browser()->tab_strip_model()->GetActiveWebContents()-> 840 GetController())); 841 chrome::Reload(browser(), CURRENT_TAB); 842 observer.Wait(); 843 } 844 845 // Focus should now be on the tab contents. 846 chrome::ShowDownloads(browser()); 847 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 848 } 849 850 // Tests that focus goes where expected when using reload on a crashed tab. 851 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FocusOnReloadCrashedTab) { 852 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 853 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 854 855 // Open a regular page, crash, reload. 856 ui_test_utils::NavigateToURL(browser(), 857 embedded_test_server()->GetURL(kSimplePage)); 858 content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents()); 859 { 860 content::WindowedNotificationObserver observer( 861 content::NOTIFICATION_LOAD_STOP, 862 content::Source<NavigationController>( 863 &browser()->tab_strip_model()->GetActiveWebContents()-> 864 GetController())); 865 chrome::Reload(browser(), CURRENT_TAB); 866 observer.Wait(); 867 } 868 869 // Focus should now be on the tab contents. 870 chrome::ShowDownloads(browser()); 871 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER)); 872 } 873 874 // Tests that when a new tab is opened from the omnibox, the focus is moved from 875 // the omnibox for the current tab. 876 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, 877 NavigateFromOmniboxIntoNewTab) { 878 GURL url("http://www.google.com/"); 879 GURL url2("http://maps.google.com/"); 880 881 // Navigate to url. 882 chrome::NavigateParams p(browser(), url, content::PAGE_TRANSITION_LINK); 883 p.window_action = chrome::NavigateParams::SHOW_WINDOW; 884 p.disposition = CURRENT_TAB; 885 chrome::Navigate(&p); 886 887 // Focus the omnibox. 888 chrome::FocusLocationBar(browser()); 889 890 OmniboxEditController* controller = 891 browser()->window()->GetLocationBar()->GetLocationEntry()->model()-> 892 controller(); 893 894 // Simulate an alt-enter. 895 controller->OnAutocompleteAccept(url2, NEW_FOREGROUND_TAB, 896 content::PAGE_TRANSITION_TYPED, GURL()); 897 898 // Make sure the second tab is selected. 899 EXPECT_EQ(1, browser()->tab_strip_model()->active_index()); 900 901 // The tab contents should have the focus in the second tab. 902 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); 903 904 // Go back to the first tab. The focus should not be in the omnibox. 905 chrome::SelectPreviousTab(browser()); 906 EXPECT_EQ(0, browser()->tab_strip_model()->active_index()); 907 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); 908 } 909 910 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnNavigate) { 911 // Needed on Mac. 912 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 913 // Load the NTP. 914 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL)); 915 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 916 917 // Navigate to another page. 918 const base::FilePath::CharType* kEmptyFile = FILE_PATH_LITERAL("empty.html"); 919 GURL file_url(ui_test_utils::GetTestUrl(base::FilePath( 920 base::FilePath::kCurrentDirectory), base::FilePath(kEmptyFile))); 921 ui_test_utils::NavigateToURL(browser(), file_url); 922 923 ClickOnView(VIEW_ID_TAB_CONTAINER); 924 925 // Navigate back. Should focus the location bar. 926 { 927 content::WindowedNotificationObserver back_nav_observer( 928 content::NOTIFICATION_NAV_ENTRY_COMMITTED, 929 content::NotificationService::AllSources()); 930 chrome::GoBack(browser(), CURRENT_TAB); 931 back_nav_observer.Wait(); 932 } 933 934 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX)); 935 936 // Navigate forward. Shouldn't focus the location bar. 937 ClickOnView(VIEW_ID_TAB_CONTAINER); 938 { 939 content::WindowedNotificationObserver forward_nav_observer( 940 content::NOTIFICATION_NAV_ENTRY_COMMITTED, 941 content::NotificationService::AllSources()); 942 chrome::GoForward(browser(), CURRENT_TAB); 943 forward_nav_observer.Wait(); 944 } 945 946 EXPECT_FALSE(IsViewFocused(VIEW_ID_OMNIBOX)); 947 } 948 949 } // namespace 950