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 "components/constrained_window/constrained_window_views.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "chrome/browser/ui/browser.h"
9 #include "chrome/browser/ui/browser_commands.h"
10 #include "chrome/browser/ui/host_desktop.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/browser/ui/views/tab_modal_confirm_dialog_views.h"
13 #include "chrome/common/url_constants.h"
14 #include "chrome/test/base/in_process_browser_test.h"
15 #include "chrome/test/base/interactive_test_utils.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "components/web_modal/web_contents_modal_dialog_host.h"
18 #include "components/web_modal/web_contents_modal_dialog_manager.h"
19 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "ui/base/accelerators/accelerator.h"
23 #include "ui/views/focus/focus_manager.h"
24 #include "ui/views/widget/widget.h"
27 #include "base/win/windows_version.h"
32 class TestDialog
: public views::DialogDelegateView
{
34 TestDialog() { SetFocusable(true); }
35 ~TestDialog() override
{}
37 views::View
* GetInitiallyFocusedView() override
{ return this; }
38 // Don't delete the delegate yet. Keep it around for inspection later.
39 void DeleteDelegate() override
{}
41 ui::ModalType
GetModalType() const override
{
43 return ui::MODAL_TYPE_CHILD
;
45 return views::WidgetDelegate::GetModalType();
50 DISALLOW_COPY_AND_ASSIGN(TestDialog
);
53 // A helper function to create and show a web contents modal dialog.
54 scoped_ptr
<TestDialog
> ShowModalDialog(content::WebContents
* web_contents
) {
55 scoped_ptr
<TestDialog
> dialog(new TestDialog());
56 constrained_window::ShowWebModalDialogViews(dialog
.get(), web_contents
);
62 typedef InProcessBrowserTest ConstrainedWindowViewTest
;
64 // Tests the intial focus of tab-modal dialogs, the restoration of focus to the
65 // browser when they close, and that queued dialogs don't register themselves as
66 // accelerator targets until they are displayed.
67 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest
, FocusTest
) {
68 content::WebContents
* web_contents
=
69 browser()->tab_strip_model()->GetActiveWebContents();
70 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
71 scoped_ptr
<TestDialog
> dialog1
= ShowModalDialog(web_contents
);
73 // |dialog1| should be active and focused.
74 EXPECT_TRUE(dialog1
->GetWidget()->IsVisible());
75 views::FocusManager
* focus_manager
= dialog1
->GetWidget()->GetFocusManager();
76 EXPECT_EQ(dialog1
->GetContentsView(), focus_manager
->GetFocusedView());
78 // Create a second dialog. This will also be modal to |web_contents|, but will
79 // remain hidden since the |dialog1| is still showing.
80 scoped_ptr
<TestDialog
> dialog2
= ShowModalDialog(web_contents
);
81 EXPECT_FALSE(dialog2
->GetWidget()->IsVisible());
82 EXPECT_TRUE(dialog1
->GetWidget()->IsVisible());
83 EXPECT_EQ(focus_manager
, dialog2
->GetWidget()->GetFocusManager());
84 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
85 EXPECT_EQ(dialog1
->GetContentsView(), focus_manager
->GetFocusedView());
87 // Pressing return should close |dialog1|.
88 EXPECT_TRUE(focus_manager
->ProcessAccelerator(
89 ui::Accelerator(ui::VKEY_RETURN
, ui::EF_NONE
)));
90 content::RunAllPendingInMessageLoop();
91 EXPECT_EQ(NULL
, dialog1
->GetWidget());
93 // |dialog2| should be visible and focused.
94 EXPECT_TRUE(dialog2
->GetWidget()->IsVisible());
95 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
96 EXPECT_EQ(dialog2
->GetContentsView(), focus_manager
->GetFocusedView());
98 // Creating a new tab should take focus away from the other tab's dialog.
99 const int tab_with_dialog
= browser()->tab_strip_model()->active_index();
100 chrome::NewTab(browser());
101 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
102 EXPECT_NE(dialog2
->GetContentsView(), focus_manager
->GetFocusedView());
104 // Activating the previous tab should bring focus to the dialog.
105 browser()->tab_strip_model()->ActivateTabAt(tab_with_dialog
, false);
106 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
107 EXPECT_EQ(dialog2
->GetContentsView(), focus_manager
->GetFocusedView());
109 // Pressing enter again should close |dialog2|.
110 EXPECT_TRUE(focus_manager
->ProcessAccelerator(
111 ui::Accelerator(ui::VKEY_RETURN
, ui::EF_NONE
)));
112 content::RunAllPendingInMessageLoop();
113 EXPECT_EQ(NULL
, dialog2
->GetWidget());
114 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER
));
117 // Tests that the tab-modal window is closed properly when its tab is closed.
118 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest
, TabCloseTest
) {
119 scoped_ptr
<TestDialog
> dialog
= ShowModalDialog(
120 browser()->tab_strip_model()->GetActiveWebContents());
121 EXPECT_TRUE(dialog
->GetWidget()->IsVisible());
122 chrome::CloseTab(browser());
123 content::RunAllPendingInMessageLoop();
124 EXPECT_EQ(NULL
, dialog
->GetWidget());
127 // Tests that the tab-modal window is hidden when an other tab is selected and
128 // shown when its tab is selected again.
129 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest
, TabSwitchTest
) {
130 scoped_ptr
<TestDialog
> dialog
= ShowModalDialog(
131 browser()->tab_strip_model()->GetActiveWebContents());
132 EXPECT_TRUE(dialog
->GetWidget()->IsVisible());
134 // Open a new tab. The tab-modal window should hide itself.
135 chrome::NewTab(browser());
136 EXPECT_FALSE(dialog
->GetWidget()->IsVisible());
138 // Close the new tab. The tab-modal window should show itself again.
139 chrome::CloseTab(browser());
140 EXPECT_TRUE(dialog
->GetWidget()->IsVisible());
142 // Close the original tab.
143 chrome::CloseTab(browser());
144 content::RunAllPendingInMessageLoop();
145 EXPECT_EQ(NULL
, dialog
->GetWidget());
148 // Tests that tab-modal dialogs follow tabs dragged between browser windows.
149 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest
, TabMoveTest
) {
150 content::WebContents
* web_contents
=
151 browser()->tab_strip_model()->GetActiveWebContents();
152 scoped_ptr
<TestDialog
> dialog
= ShowModalDialog(web_contents
);
153 EXPECT_TRUE(dialog
->GetWidget()->IsVisible());
155 // Move the tab to a second browser window; but first create another tab.
156 // That prevents the first browser window from closing when its tab is moved.
157 chrome::NewTab(browser());
158 browser()->tab_strip_model()->DetachWebContentsAt(
159 browser()->tab_strip_model()->GetIndexOfWebContents(web_contents
));
160 Browser
* browser2
= CreateBrowser(browser()->profile());
161 browser2
->tab_strip_model()->AppendWebContents(web_contents
, true);
162 EXPECT_TRUE(dialog
->GetWidget()->IsVisible());
164 // Close the first browser.
165 chrome::CloseWindow(browser());
166 content::RunAllPendingInMessageLoop();
167 EXPECT_TRUE(dialog
->GetWidget()->IsVisible());
169 // Close the dialog's browser window.
170 chrome::CloseTab(browser2
);
171 content::RunAllPendingInMessageLoop();
172 EXPECT_EQ(NULL
, dialog
->GetWidget());
175 // Tests that the web contents navigates when backspace is pressed.
176 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest
, NavigationOnBackspace
) {
177 content::WebContents
* web_contents
=
178 browser()->tab_strip_model()->GetActiveWebContents();
179 content::WaitForLoadStop(web_contents
);
180 const GURL original_url
= web_contents
->GetURL();
181 EXPECT_NE(GURL(chrome::kChromeUIVersionURL
), original_url
);
182 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIVersionURL
));
183 content::WaitForLoadStop(web_contents
);
184 EXPECT_EQ(GURL(chrome::kChromeUIVersionURL
), web_contents
->GetURL());
186 scoped_ptr
<TestDialog
> dialog
= ShowModalDialog(web_contents
);
187 EXPECT_TRUE(dialog
->GetWidget()->IsVisible());
188 EXPECT_EQ(dialog
->GetContentsView(),
189 dialog
->GetWidget()->GetFocusManager()->GetFocusedView());
191 // Pressing backspace should navigate back and close the dialog.
192 EXPECT_TRUE(chrome::CanGoBack(browser()));
193 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_BACK
,
194 false, false, false, false));
195 content::RunAllPendingInMessageLoop();
196 content::WaitForLoadStop(web_contents
);
197 EXPECT_EQ(NULL
, dialog
->GetWidget());
198 EXPECT_EQ(original_url
, web_contents
->GetURL());
201 // Tests that the dialog closes when the escape key is pressed.
202 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest
, ClosesOnEscape
) {
204 // TODO(msw): The widget is not made NULL on XP. http://crbug.com/177482
205 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
209 scoped_ptr
<TestDialog
> dialog
= ShowModalDialog(
210 browser()->tab_strip_model()->GetActiveWebContents());
211 EXPECT_TRUE(dialog
->GetWidget()->IsVisible());
212 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE
,
213 false, false, false, false));
214 content::RunAllPendingInMessageLoop();
215 EXPECT_EQ(NULL
, dialog
->GetWidget());