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