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.
6 #include "base/bind_helpers.h"
7 #include "base/message_loop/message_loop.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/browser_window.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
13 #include "chrome/common/url_constants.h"
14 #include "chrome/test/base/in_process_browser_test.h"
15 #include "chrome/test/base/ui_test_utils.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/render_widget_host_view.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/test/test_utils.h"
20 #include "ui/views/controls/webview/web_dialog_view.h"
21 #include "ui/views/widget/widget.h"
22 #include "ui/web_dialogs/test/test_web_dialog_delegate.h"
26 // Initial size of WebDialog for SizeWindow test case. Note the height must be
27 // at least 59 on Windows.
28 const int kInitialWidth
= 60;
29 const int kInitialHeight
= 60;
31 class TestWebDialogView
: public views::WebDialogView
{
33 TestWebDialogView(content::BrowserContext
* context
,
34 ui::WebDialogDelegate
* delegate
,
35 bool* observed_destroy
)
36 : views::WebDialogView(context
, delegate
, new ChromeWebContentsHandler
),
37 should_quit_on_size_change_(false),
38 observed_destroy_(observed_destroy
) {
39 EXPECT_FALSE(*observed_destroy_
);
40 delegate
->GetDialogSize(&last_size_
);
43 ~TestWebDialogView() override
{ *observed_destroy_
= true; }
45 void set_should_quit_on_size_change(bool should_quit
) {
46 should_quit_on_size_change_
= should_quit
;
50 // TODO(xiyuan): Update this when WidgetDelegate has bounds change hook.
51 void SaveWindowPlacement(const gfx::Rect
& bounds
,
52 ui::WindowShowState show_state
) override
{
53 if (should_quit_on_size_change_
&& last_size_
!= bounds
.size()) {
54 // Schedule message loop quit because we could be called while
55 // the bounds change call is on the stack and not in the nested message
57 base::MessageLoop::current()->PostTask(
59 base::Bind(&base::MessageLoop::Quit
,
60 base::Unretained(base::MessageLoop::current())));
63 last_size_
= bounds
.size();
66 void OnDialogClosed(const std::string
& json_retval
) override
{
67 should_quit_on_size_change_
= false; // No quit when we are closing.
68 views::WebDialogView::OnDialogClosed(json_retval
); // Deletes this.
71 // Whether we should quit message loop when size change is detected.
72 bool should_quit_on_size_change_
;
74 bool* observed_destroy_
;
76 DISALLOW_COPY_AND_ASSIGN(TestWebDialogView
);
79 class WebDialogBrowserTest
: public InProcessBrowserTest
{
81 WebDialogBrowserTest() {}
83 // content::BrowserTestBase:
84 void SetUpOnMainThread() override
;
87 TestWebDialogView
* view_
= nullptr;
88 bool web_dialog_delegate_destroyed_
= false;
89 bool web_dialog_view_destroyed_
= false;
92 DISALLOW_COPY_AND_ASSIGN(WebDialogBrowserTest
);
95 void WebDialogBrowserTest::SetUpOnMainThread() {
96 ui::test::TestWebDialogDelegate
* delegate
=
97 new ui::test::TestWebDialogDelegate(GURL(chrome::kChromeUIChromeURLsURL
));
98 delegate
->set_size(kInitialWidth
, kInitialHeight
);
99 delegate
->SetDeleteOnClosedAndObserve(&web_dialog_delegate_destroyed_
);
101 view_
= new TestWebDialogView(browser()->profile(), delegate
,
102 &web_dialog_view_destroyed_
);
103 gfx::NativeView parent_view
=
104 browser()->tab_strip_model()->GetActiveWebContents()->GetNativeView();
105 views::Widget::CreateWindowWithParent(view_
, parent_view
);
106 view_
->GetWidget()->Show();
111 // Windows has some issues resizing windows. An off by one problem, and a
112 // minimum size that seems too big. See http://crbug.com/52602.
114 #define MAYBE_SizeWindow DISABLED_SizeWindow
116 #define MAYBE_SizeWindow SizeWindow
118 IN_PROC_BROWSER_TEST_F(WebDialogBrowserTest
, MAYBE_SizeWindow
) {
119 // TestWebDialogView should quit current message loop on size change.
120 view_
->set_should_quit_on_size_change(true);
122 gfx::Rect set_bounds
= view_
->GetWidget()->GetClientAreaBoundsInScreen();
123 gfx::Rect actual_bounds
, rwhv_bounds
;
125 // Bigger than the default in both dimensions.
126 set_bounds
.set_width(400);
127 set_bounds
.set_height(300);
129 // WebDialogView ignores the WebContents* |source| argument to MoveContents.
130 // We could pass view_->web_contents(), but it's not relevant for the test.
131 view_
->MoveContents(nullptr, set_bounds
);
132 content::RunMessageLoop(); // TestWebDialogView will quit.
133 actual_bounds
= view_
->GetWidget()->GetClientAreaBoundsInScreen();
134 EXPECT_EQ(set_bounds
, actual_bounds
);
137 view_
->web_contents()->GetRenderWidgetHostView()->GetViewBounds();
138 EXPECT_LT(0, rwhv_bounds
.width());
139 EXPECT_LT(0, rwhv_bounds
.height());
140 EXPECT_GE(set_bounds
.width(), rwhv_bounds
.width());
141 EXPECT_GE(set_bounds
.height(), rwhv_bounds
.height());
143 // Larger in one dimension and smaller in the other.
144 set_bounds
.set_width(550);
145 set_bounds
.set_height(250);
147 view_
->MoveContents(nullptr, set_bounds
);
148 content::RunMessageLoop(); // TestWebDialogView will quit.
149 actual_bounds
= view_
->GetWidget()->GetClientAreaBoundsInScreen();
150 EXPECT_EQ(set_bounds
, actual_bounds
);
153 view_
->web_contents()->GetRenderWidgetHostView()->GetViewBounds();
154 EXPECT_LT(0, rwhv_bounds
.width());
155 EXPECT_LT(0, rwhv_bounds
.height());
156 EXPECT_GE(set_bounds
.width(), rwhv_bounds
.width());
157 EXPECT_GE(set_bounds
.height(), rwhv_bounds
.height());
160 const gfx::Size min_size
= view_
->GetWidget()->GetMinimumSize();
161 EXPECT_LT(0, min_size
.width());
162 EXPECT_LT(0, min_size
.height());
164 set_bounds
.set_size(min_size
);
166 view_
->MoveContents(nullptr, set_bounds
);
167 content::RunMessageLoop(); // TestWebDialogView will quit.
168 actual_bounds
= view_
->GetWidget()->GetClientAreaBoundsInScreen();
169 EXPECT_EQ(set_bounds
, actual_bounds
);
172 view_
->web_contents()->GetRenderWidgetHostView()->GetViewBounds();
173 EXPECT_LT(0, rwhv_bounds
.width());
174 EXPECT_LT(0, rwhv_bounds
.height());
175 EXPECT_GE(set_bounds
.width(), rwhv_bounds
.width());
176 EXPECT_GE(set_bounds
.height(), rwhv_bounds
.height());
178 // Check to make sure we can't get to 0x0. First expand beyond the minimum
179 // size that was set above so that TestWebDialogView has a change to pick up.
180 set_bounds
.set_height(250);
181 view_
->MoveContents(nullptr, set_bounds
);
182 content::RunMessageLoop(); // TestWebDialogView will quit.
183 actual_bounds
= view_
->GetWidget()->GetClientAreaBoundsInScreen();
184 EXPECT_EQ(set_bounds
, actual_bounds
);
186 // Now verify that attempts to re-size to 0x0 enforces the minimum size.
187 set_bounds
.set_width(0);
188 set_bounds
.set_height(0);
190 view_
->MoveContents(nullptr, set_bounds
);
191 content::RunMessageLoop(); // TestWebDialogView will quit.
192 actual_bounds
= view_
->GetWidget()->GetClientAreaBoundsInScreen();
193 EXPECT_EQ(min_size
, actual_bounds
.size());
195 // And that the render view is also non-zero.
197 view_
->web_contents()->GetRenderWidgetHostView()->GetViewBounds();
198 EXPECT_LT(0, rwhv_bounds
.width());
199 EXPECT_LT(0, rwhv_bounds
.height());
201 // WebDialogView::CanClose() returns true only after before-unload handlers
202 // have run (or the dialog has none and gets fast-closed via
203 // RenderViewHostImpl::ClosePageIgnoringUnloadEvents which is the case here).
204 // Close via WebContents for more authentic coverage (vs Widget::CloseNow()).
205 EXPECT_FALSE(web_dialog_delegate_destroyed_
);
206 view_
->web_contents()->Close();
207 EXPECT_TRUE(web_dialog_delegate_destroyed_
);
209 // The close of the actual widget should happen asynchronously.
210 EXPECT_FALSE(web_dialog_view_destroyed_
);
211 content::RunAllPendingInMessageLoop();
212 EXPECT_TRUE(web_dialog_view_destroyed_
);
215 // Test that closing the parent of a window-modal web dialog properly destroys
216 // the dialog and delegate.
217 IN_PROC_BROWSER_TEST_F(WebDialogBrowserTest
, CloseParentWindow
) {
218 // Open a second browser window so we don't trigger shutdown.
219 ui_test_utils::NavigateToURLWithDisposition(
220 browser(), GURL(url::kAboutBlankURL
), NEW_WINDOW
,
221 ui_test_utils::BROWSER_TEST_NONE
);
223 // TestWebDialogDelegate defaults to window-modal, so closing the browser
224 // Window (as opposed to closing merely the tab) should close the dialog.
225 EXPECT_EQ(ui::MODAL_TYPE_WINDOW
,
226 view_
->GetWidget()->widget_delegate()->GetModalType());
228 // Close the parent window. Tear down may happen asynchronously.
229 EXPECT_FALSE(web_dialog_delegate_destroyed_
);
230 EXPECT_FALSE(web_dialog_view_destroyed_
);
231 browser()->window()->Close();
232 content::RunAllPendingInMessageLoop();
233 EXPECT_TRUE(web_dialog_delegate_destroyed_
);
234 EXPECT_TRUE(web_dialog_view_destroyed_
);