Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / constrained_window_views_browsertest.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/memory/weak_ptr.h"
6 #include "chrome/browser/platform_util.h"
7 #include "chrome/browser/profiles/profile.h"
8 #include "chrome/browser/search/search.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/browser_commands.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/browser/ui/views/constrained_window_views.h"
13 #include "chrome/browser/ui/views/frame/browser_view.h"
14 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
15 #include "chrome/common/url_constants.h"
16 #include "chrome/test/base/in_process_browser_test.h"
17 #include "chrome/test/base/ui_test_utils.h"
18 #include "components/web_modal/web_contents_modal_dialog_host.h"
19 #include "components/web_modal/web_contents_modal_dialog_manager.h"
20 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
21 #include "content/public/browser/native_web_keyboard_event.h"
22 #include "content/public/browser/navigation_controller.h"
23 #include "content/public/browser/notification_types.h"
24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/web_contents.h"
26 #include "ipc/ipc_message.h"
27 #include "ui/base/accelerators/accelerator.h"
28 #include "ui/views/controls/textfield/textfield.h"
29 #include "ui/views/focus/focus_manager.h"
30 #include "ui/views/layout/fill_layout.h"
31 #include "ui/views/test/test_widget_observer.h"
32 #include "ui/views/window/dialog_delegate.h"
33 #include "ui/web_dialogs/test/test_web_dialog_delegate.h"
34
35 #if defined(USE_AURA) && defined(USE_X11)
36 #include <X11/Xlib.h>
37 #include "ui/events/test/events_test_utils_x11.h"
38 #endif
39
40 using web_modal::WebContentsModalDialogManager;
41 using web_modal::WebContentsModalDialogManagerDelegate;
42
43 namespace {
44
45 class TestConstrainedDialogContentsView
46     : public views::View,
47       public base::SupportsWeakPtr<TestConstrainedDialogContentsView> {
48  public:
49   TestConstrainedDialogContentsView()
50       : text_field_(new views::Textfield) {
51     SetLayoutManager(new views::FillLayout);
52     AddChildView(text_field_);
53   }
54
55   views::View* GetInitiallyFocusedView() {
56     return text_field_;
57   }
58
59  private:
60   views::Textfield* text_field_;
61   DISALLOW_COPY_AND_ASSIGN(TestConstrainedDialogContentsView);
62 };
63
64 class TestConstrainedDialog : public views::DialogDelegate {
65  public:
66   TestConstrainedDialog()
67       : contents_((new TestConstrainedDialogContentsView())->AsWeakPtr()),
68         done_(false) {
69   }
70
71   virtual ~TestConstrainedDialog() {}
72
73   virtual views::View* GetInitiallyFocusedView() OVERRIDE {
74     return contents_ ? contents_->GetInitiallyFocusedView() : NULL;
75   }
76
77   virtual views::View* GetContentsView() OVERRIDE {
78     return contents_.get();
79   }
80
81   virtual views::Widget* GetWidget() OVERRIDE {
82     return contents_ ? contents_->GetWidget() : NULL;
83   }
84
85   virtual const views::Widget* GetWidget() const OVERRIDE {
86     return contents_ ? contents_->GetWidget() : NULL;
87   }
88
89   virtual void DeleteDelegate() OVERRIDE {
90     // Don't delete the delegate yet.  We need to keep it around for inspection
91     // later.
92     EXPECT_TRUE(done_);
93   }
94
95   virtual bool Accept() OVERRIDE {
96     done_ = true;
97     return true;
98   }
99
100   virtual bool Cancel() OVERRIDE {
101     done_ = true;
102     return true;
103   }
104
105   virtual ui::ModalType GetModalType() const OVERRIDE {
106 #if defined(USE_ASH)
107     return ui::MODAL_TYPE_CHILD;
108 #else
109     return views::WidgetDelegate::GetModalType();
110 #endif
111   }
112
113   bool done() {
114     return done_;
115   }
116
117  private:
118   // contents_ will be freed when the View goes away.
119   base::WeakPtr<TestConstrainedDialogContentsView> contents_;
120   bool done_;
121
122   DISALLOW_COPY_AND_ASSIGN(TestConstrainedDialog);
123 };
124
125 } // namespace
126
127 class ConstrainedWindowViewTest : public InProcessBrowserTest {
128  public:
129   ConstrainedWindowViewTest() {
130   }
131 };
132
133 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
134 // TODO(erg): linux_aura bringup: http://crbug.com/163931
135 #define MAYBE_FocusTest DISABLED_FocusTest
136 #else
137 #define MAYBE_FocusTest FocusTest
138 #endif
139
140 // Tests the following:
141 //
142 // *) Initially focused view in a constrained dialog receives focus reliably.
143 //
144 // *) Constrained windows that are queued don't register themselves as
145 //    accelerator targets until they are displayed.
146 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, MAYBE_FocusTest) {
147   content::WebContents* web_contents =
148       browser()->tab_strip_model()->GetActiveWebContents();
149   ASSERT_TRUE(web_contents != NULL);
150   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
151       WebContentsModalDialogManager::FromWebContents(web_contents);
152   ASSERT_TRUE(web_contents_modal_dialog_manager != NULL);
153   WebContentsModalDialogManagerDelegate* modal_delegate =
154       web_contents_modal_dialog_manager->delegate();
155   ASSERT_TRUE(modal_delegate != NULL);
156
157   // Create a constrained dialog.  It will attach itself to web_contents.
158   scoped_ptr<TestConstrainedDialog> test_dialog1(new TestConstrainedDialog);
159   views::Widget* window1 = views::Widget::CreateWindowAsFramelessChild(
160       test_dialog1.get(),
161       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
162   web_contents_modal_dialog_manager->ShowModalDialog(window1->GetNativeView());
163
164   views::FocusManager* focus_manager = window1->GetFocusManager();
165   ASSERT_TRUE(focus_manager);
166
167   // test_dialog1's text field should be focused.
168   EXPECT_EQ(test_dialog1->GetInitiallyFocusedView(),
169             focus_manager->GetFocusedView());
170
171   // Now create a second constrained dialog.  This will also be attached to
172   // web_contents, but will remain hidden since the test_dialog1 is still
173   // showing.
174   scoped_ptr<TestConstrainedDialog> test_dialog2(new TestConstrainedDialog);
175   views::Widget* window2 = views::Widget::CreateWindowAsFramelessChild(
176       test_dialog2.get(),
177       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
178   web_contents_modal_dialog_manager->ShowModalDialog(window2->GetNativeView());
179   // Should be the same focus_manager.
180   ASSERT_EQ(focus_manager, window2->GetFocusManager());
181
182   // test_dialog1's text field should still be the view that has focus.
183   EXPECT_EQ(test_dialog1->GetInitiallyFocusedView(),
184             focus_manager->GetFocusedView());
185   ASSERT_TRUE(web_contents_modal_dialog_manager->IsDialogActive());
186
187   // Now send a VKEY_RETURN to the browser.  This should result in closing
188   // test_dialog1.
189   EXPECT_TRUE(focus_manager->ProcessAccelerator(
190       ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE)));
191   content::RunAllPendingInMessageLoop();
192
193   EXPECT_TRUE(test_dialog1->done());
194   EXPECT_FALSE(test_dialog2->done());
195   EXPECT_TRUE(web_contents_modal_dialog_manager->IsDialogActive());
196
197   // test_dialog2 will be shown.  Focus should be on test_dialog2's text field.
198   EXPECT_EQ(test_dialog2->GetInitiallyFocusedView(),
199             focus_manager->GetFocusedView());
200
201   int tab_with_constrained_window =
202       browser()->tab_strip_model()->active_index();
203
204   // Create a new tab.
205   chrome::NewTab(browser());
206
207   // The constrained dialog should no longer be selected.
208   EXPECT_NE(test_dialog2->GetInitiallyFocusedView(),
209             focus_manager->GetFocusedView());
210
211   browser()->tab_strip_model()->ActivateTabAt(tab_with_constrained_window,
212                                               false);
213
214   // Activating the previous tab should bring focus to the constrained window.
215   EXPECT_EQ(test_dialog2->GetInitiallyFocusedView(),
216             focus_manager->GetFocusedView());
217
218   // Send another VKEY_RETURN, closing test_dialog2
219   EXPECT_TRUE(focus_manager->ProcessAccelerator(
220       ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE)));
221   content::RunAllPendingInMessageLoop();
222   EXPECT_TRUE(test_dialog2->done());
223   EXPECT_FALSE(web_contents_modal_dialog_manager->IsDialogActive());
224 }
225
226 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
227 // TODO(erg): linux_aura bringup: http://crbug.com/163931
228 #define MAYBE_TabCloseTest DISABLED_TabCloseTest
229 #else
230 #define MAYBE_TabCloseTest TabCloseTest
231 #endif
232
233 // Tests that the constrained window is closed properly when its tab is
234 // closed.
235 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, MAYBE_TabCloseTest) {
236   content::WebContents* web_contents =
237       browser()->tab_strip_model()->GetActiveWebContents();
238   ASSERT_TRUE(web_contents != NULL);
239   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
240       WebContentsModalDialogManager::FromWebContents(web_contents);
241   ASSERT_TRUE(web_contents_modal_dialog_manager != NULL);
242   WebContentsModalDialogManagerDelegate* modal_delegate =
243       web_contents_modal_dialog_manager->delegate();
244   ASSERT_TRUE(modal_delegate != NULL);
245
246   // Create a constrained dialog.  It will attach itself to web_contents.
247   scoped_ptr<TestConstrainedDialog> test_dialog(new TestConstrainedDialog);
248   views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
249       test_dialog.get(),
250       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
251   web_contents_modal_dialog_manager->ShowModalDialog(window->GetNativeView());
252
253   bool closed =
254       browser()->tab_strip_model()->CloseWebContentsAt(
255           browser()->tab_strip_model()->active_index(),
256           TabStripModel::CLOSE_NONE);
257   EXPECT_TRUE(closed);
258   content::RunAllPendingInMessageLoop();
259   EXPECT_TRUE(test_dialog->done());
260 }
261
262 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
263 // TODO(erg): linux_aura bringup: http://crbug.com/163931
264 #define MAYBE_TabSwitchTest DISABLED_TabSwitchTest
265 #else
266 #define MAYBE_TabSwitchTest TabSwitchTest
267 #endif
268
269 // Tests that the constrained window is hidden when an other tab is selected and
270 // shown when its tab is selected again.
271 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, MAYBE_TabSwitchTest) {
272   content::WebContents* web_contents =
273       browser()->tab_strip_model()->GetActiveWebContents();
274   ASSERT_TRUE(web_contents != NULL);
275
276   // Create a constrained dialog.  It will attach itself to web_contents.
277   scoped_ptr<TestConstrainedDialog> test_dialog(new TestConstrainedDialog);
278   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
279       WebContentsModalDialogManager::FromWebContents(web_contents);
280   WebContentsModalDialogManagerDelegate* modal_delegate =
281       web_contents_modal_dialog_manager->delegate();
282   ASSERT_TRUE(modal_delegate != NULL);
283   views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
284       test_dialog.get(),
285       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
286   web_contents_modal_dialog_manager->ShowModalDialog(window->GetNativeView());
287   EXPECT_TRUE(window->IsVisible());
288
289   // Open a new tab. The constrained window should hide itself.
290   browser()->tab_strip_model()->AppendWebContents(
291       content::WebContents::Create(
292           content::WebContents::CreateParams(browser()->profile())),
293       true);
294   EXPECT_FALSE(window->IsVisible());
295
296   // Close the new tab. The constrained window should show itself again.
297   bool closed =
298       browser()->tab_strip_model()->CloseWebContentsAt(
299           browser()->tab_strip_model()->active_index(),
300           TabStripModel::CLOSE_NONE);
301   EXPECT_TRUE(closed);
302   EXPECT_TRUE(window->IsVisible());
303
304   // Close the original tab.
305   browser()->tab_strip_model()->CloseWebContentsAt(
306       browser()->tab_strip_model()->active_index(),
307       TabStripModel::CLOSE_NONE);
308   content::RunAllPendingInMessageLoop();
309   EXPECT_TRUE(test_dialog->done());
310 }
311
312 // Tests that the constrained window behaves properly when moving its tab
313 // between browser windows.
314 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabMoveTest) {
315   // Open a second browser.
316   Browser* browser2 = CreateBrowser(browser()->profile());
317
318   // Create a second WebContents in the second browser, so that moving the
319   // WebContents does not trigger the browser to close immediately. This mimics
320   // the behavior when a user drags tabs between browsers.
321   content::WebContents* web_contents = content::WebContents::Create(
322       content::WebContents::CreateParams(browser()->profile()));
323   browser2->tab_strip_model()->AppendWebContents(web_contents, true);
324   ASSERT_EQ(web_contents, browser2->tab_strip_model()->GetActiveWebContents());
325
326   // Create a constrained dialog.  It will attach itself to web_contents.
327   scoped_ptr<TestConstrainedDialog> test_dialog(new TestConstrainedDialog);
328   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
329       WebContentsModalDialogManager::FromWebContents(web_contents);
330   WebContentsModalDialogManagerDelegate* modal_delegate =
331       web_contents_modal_dialog_manager->delegate();
332   ASSERT_TRUE(modal_delegate != NULL);
333   views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
334       test_dialog.get(),
335       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
336   web_contents_modal_dialog_manager->ShowModalDialog(window->GetNativeView());
337   EXPECT_TRUE(window->IsVisible());
338
339   // Detach the web contents from the second browser's tab strip.
340   browser2->tab_strip_model()->DetachWebContentsAt(
341       browser2->tab_strip_model()->GetIndexOfWebContents(web_contents));
342
343   // Append the web contents to the first browser.
344   browser()->tab_strip_model()->AppendWebContents(web_contents, true);
345   EXPECT_TRUE(window->IsVisible());
346
347   // Close the second browser.
348   browser2->tab_strip_model()->CloseAllTabs();
349   content::RunAllPendingInMessageLoop();
350   EXPECT_TRUE(window->IsVisible());
351
352   // Close the dialog's tab.
353   bool closed =
354       browser()->tab_strip_model()->CloseWebContentsAt(
355           browser()->tab_strip_model()->GetIndexOfWebContents(web_contents),
356           TabStripModel::CLOSE_NONE);
357   EXPECT_TRUE(closed);
358   content::RunAllPendingInMessageLoop();
359   EXPECT_TRUE(test_dialog->done());
360 }
361
362 #if defined(OS_WIN) || (defined(USE_AURA) && defined(USE_X11))
363
364 // Forwards the key event which has |key_code| to the renderer.
365 void ForwardKeyEvent(content::RenderViewHost* host, ui::KeyboardCode key_code) {
366 #if defined(OS_WIN)
367   MSG native_key_event = { NULL, WM_KEYDOWN, key_code, 0 };
368 #elif defined(USE_X11)
369   ui::ScopedXI2Event x_event;
370   x_event.InitKeyEvent(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
371   XEvent* native_key_event = x_event;
372 #endif
373
374 #if defined(USE_AURA)
375   ui::KeyEvent key(native_key_event, false);
376   ui::KeyEvent* native_ui_key_event = &key;
377 #elif defined(OS_WIN)
378   MSG native_ui_key_event = native_key_event;
379 #endif
380
381   host->ForwardKeyboardEvent(
382       content::NativeWebKeyboardEvent(native_ui_key_event));
383 }
384
385 // Tests that backspace is not processed before it's sent to the web contents.
386 // Flaky on Win Aura and Linux ChromiumOS. See http://crbug.com/170331
387 #if defined(USE_AURA)
388 #define MAYBE_BackspaceSentToWebContent DISABLED_BackspaceSentToWebContent
389 #else
390 #define MAYBE_BackspaceSentToWebContent BackspaceSentToWebContent
391 #endif
392 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest,
393                        MAYBE_BackspaceSentToWebContent) {
394   content::WebContents* web_contents =
395       browser()->tab_strip_model()->GetActiveWebContents();
396   ASSERT_TRUE(web_contents != NULL);
397
398   GURL new_tab_url(chrome::kChromeUINewTabURL);
399   ui_test_utils::NavigateToURL(browser(), new_tab_url);
400   GURL about_url(chrome::kChromeUIAboutURL);
401   ui_test_utils::NavigateToURL(browser(), about_url);
402
403   ConstrainedWebDialogDelegate* cwdd = CreateConstrainedWebDialog(
404       browser()->profile(),
405       new ui::test::TestWebDialogDelegate(about_url),
406       NULL,
407       web_contents);
408
409   content::WindowedNotificationObserver back_observer(
410       content::NOTIFICATION_LOAD_STOP,
411       content::Source<content::NavigationController>(
412           &web_contents->GetController()));
413   content::RenderViewHost* render_view_host =
414       cwdd->GetWebContents()->GetRenderViewHost();
415   ForwardKeyEvent(render_view_host, ui::VKEY_BACK);
416
417   // Backspace is not processed as accelerator before it's sent to web contents.
418   EXPECT_FALSE(web_contents->GetController().GetPendingEntry());
419   EXPECT_EQ(about_url.spec(), web_contents->GetURL().spec());
420
421   // Backspace is processed as accelerator after it's sent to web contents.
422   content::RunAllPendingInMessageLoop();
423   EXPECT_TRUE(web_contents->GetController().GetPendingEntry());
424
425   // Wait for the navigation to commit, since the URL will not be visible
426   // until then.
427   back_observer.Wait();
428   EXPECT_TRUE(chrome::IsNTPURL(web_contents->GetURL(), browser()->profile()));
429 }
430
431 // Fails flakily (once per 10-20 runs) on Win Aura only. http://crbug.com/177482
432 // Also fails on CrOS.
433 // Also fails on linux_aura (http://crbug.com/163931)
434 #if defined(TOOLKIT_VIEWS)
435 #define MAYBE_EscapeCloseConstrainedWindow DISABLED_EscapeCloseConstrainedWindow
436 #else
437 #define MAYBE_EscapeCloseConstrainedWindow EscapeCloseConstrainedWindow
438 #endif
439
440 // Tests that escape closes the constrained window.
441 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest,
442                        MAYBE_EscapeCloseConstrainedWindow) {
443   content::WebContents* web_contents =
444       browser()->tab_strip_model()->GetActiveWebContents();
445   ASSERT_TRUE(web_contents != NULL);
446
447   GURL new_tab_url(chrome::kChromeUINewTabURL);
448   ui_test_utils::NavigateToURL(browser(), new_tab_url);
449   ConstrainedWebDialogDelegate* cwdd = CreateConstrainedWebDialog(
450       browser()->profile(),
451       new ui::test::TestWebDialogDelegate(new_tab_url),
452       NULL,
453       web_contents);
454
455   views::Widget* widget =
456       views::Widget::GetWidgetForNativeView(cwdd->GetNativeDialog());
457   views::test::TestWidgetObserver observer(widget);
458
459   content::RenderViewHost* render_view_host =
460       cwdd->GetWebContents()->GetRenderViewHost();
461   ForwardKeyEvent(render_view_host, ui::VKEY_ESCAPE);
462
463   // Escape is not processed as accelerator before it's sent to web contents.
464   EXPECT_FALSE(observer.widget_closed());
465
466   content::RunAllPendingInMessageLoop();
467
468   // Escape is processed as accelerator after it's sent to web contents.
469   EXPECT_TRUE(observer.widget_closed());
470 }
471
472 #endif  // defined(OS_WIN) || (defined(USE_AURA) && defined(USE_X11))