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