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