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