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