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