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/web_modal/web_contents_modal_dialog_manager.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "components/web_modal/single_web_contents_dialog_manager.h"
11 #include "components/web_modal/test_web_contents_modal_dialog_manager_delegate.h"
12 #include "content/public/test/test_renderer_host.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 // Tracks persistent state changes of the native WC-modal dialog manager.
18 class NativeManagerTracker
{
28 NativeManagerTracker() : state_(UNKNOWN
), was_shown_(false) {}
30 void SetState(DialogState state
) {
40 NativeManagerTracker unused_tracker
;
42 class TestNativeWebContentsModalDialogManager
43 : public SingleWebContentsDialogManager
{
45 TestNativeWebContentsModalDialogManager(
46 NativeWebContentsModalDialog dialog
,
47 SingleWebContentsDialogManagerDelegate
* delegate
,
48 NativeManagerTracker
* tracker
)
49 : delegate_(delegate
),
53 tracker_
->SetState(NativeManagerTracker::NOT_SHOWN
);
56 void Show() override
{
58 tracker_
->SetState(NativeManagerTracker::SHOWN
);
60 void Hide() override
{
62 tracker_
->SetState(NativeManagerTracker::HIDDEN
);
64 void Close() override
{
66 tracker_
->SetState(NativeManagerTracker::CLOSED
);
67 delegate_
->WillClose(dialog_
);
69 void Focus() override
{}
70 void Pulse() override
{}
71 void HostChanged(WebContentsModalDialogHost
* new_host
) override
{}
72 NativeWebContentsModalDialog
dialog() override
{ return dialog_
; }
79 SingleWebContentsDialogManagerDelegate
* delegate_
;
80 NativeWebContentsModalDialog dialog_
;
81 NativeManagerTracker
* tracker_
;
83 DISALLOW_COPY_AND_ASSIGN(TestNativeWebContentsModalDialogManager
);
86 class WebContentsModalDialogManagerTest
87 : public content::RenderViewHostTestHarness
{
89 WebContentsModalDialogManagerTest()
94 void SetUp() override
{
95 content::RenderViewHostTestHarness::SetUp();
97 delegate
.reset(new TestWebContentsModalDialogManagerDelegate
);
98 WebContentsModalDialogManager::CreateForWebContents(web_contents());
99 manager
= WebContentsModalDialogManager::FromWebContents(web_contents());
100 manager
->SetDelegate(delegate
.get());
101 test_api
.reset(new WebContentsModalDialogManager::TestApi(manager
));
104 void TearDown() override
{
106 content::RenderViewHostTestHarness::TearDown();
110 NativeWebContentsModalDialog
MakeFakeDialog() {
111 // WebContentsModalDialogManager treats the NativeWebContentsModalDialog as
112 // an opaque type, so creating fake NativeWebContentsModalDialogs using
113 // reinterpret_cast is valid.
114 return reinterpret_cast<NativeWebContentsModalDialog
>(next_dialog_id
++);
118 scoped_ptr
<TestWebContentsModalDialogManagerDelegate
> delegate
;
119 WebContentsModalDialogManager
* manager
;
120 scoped_ptr
<WebContentsModalDialogManager::TestApi
> test_api
;
122 DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerTest
);
125 SingleWebContentsDialogManager
*
126 WebContentsModalDialogManager::CreateNativeWebModalManager(
127 NativeWebContentsModalDialog dialog
,
128 SingleWebContentsDialogManagerDelegate
* native_delegate
) {
130 return new TestNativeWebContentsModalDialogManager(
136 // Test that the dialog is shown immediately when the delegate indicates the web
137 // contents is visible.
138 TEST_F(WebContentsModalDialogManagerTest
, WebContentsVisible
) {
139 // Dialog should be shown while WebContents is visible.
140 const NativeWebContentsModalDialog dialog
= MakeFakeDialog();
142 NativeManagerTracker tracker
;
143 TestNativeWebContentsModalDialogManager
* native_manager
=
144 new TestNativeWebContentsModalDialogManager(dialog
, manager
, &tracker
);
145 manager
->ShowDialogWithManager(dialog
,
146 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager
).Pass());
148 EXPECT_EQ(NativeManagerTracker::SHOWN
, tracker
.state_
);
149 EXPECT_TRUE(manager
->IsDialogActive());
150 EXPECT_TRUE(delegate
->web_contents_blocked());
151 EXPECT_TRUE(tracker
.was_shown_
);
153 native_manager
->StopTracking();
156 // Test that the dialog is not shown immediately when the delegate indicates the
157 // web contents is not visible.
158 TEST_F(WebContentsModalDialogManagerTest
, WebContentsNotVisible
) {
159 // Dialog should not be shown while WebContents is not visible.
160 delegate
->set_web_contents_visible(false);
162 const NativeWebContentsModalDialog dialog
= MakeFakeDialog();
164 NativeManagerTracker tracker
;
165 TestNativeWebContentsModalDialogManager
* native_manager
=
166 new TestNativeWebContentsModalDialogManager(dialog
, manager
, &tracker
);
167 manager
->ShowDialogWithManager(dialog
,
168 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager
).Pass());
170 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN
, tracker
.state_
);
171 EXPECT_TRUE(manager
->IsDialogActive());
172 EXPECT_TRUE(delegate
->web_contents_blocked());
173 EXPECT_FALSE(tracker
.was_shown_
);
175 native_manager
->StopTracking();
178 // Test that only the first of multiple dialogs is shown.
179 TEST_F(WebContentsModalDialogManagerTest
, ShowDialogs
) {
180 const NativeWebContentsModalDialog dialog1
= MakeFakeDialog();
181 const NativeWebContentsModalDialog dialog2
= MakeFakeDialog();
182 const NativeWebContentsModalDialog dialog3
= MakeFakeDialog();
184 NativeManagerTracker tracker1
;
185 NativeManagerTracker tracker2
;
186 NativeManagerTracker tracker3
;
187 TestNativeWebContentsModalDialogManager
* native_manager1
=
188 new TestNativeWebContentsModalDialogManager(dialog1
, manager
, &tracker1
);
189 TestNativeWebContentsModalDialogManager
* native_manager2
=
190 new TestNativeWebContentsModalDialogManager(dialog2
, manager
, &tracker2
);
191 TestNativeWebContentsModalDialogManager
* native_manager3
=
192 new TestNativeWebContentsModalDialogManager(dialog3
, manager
, &tracker3
);
193 manager
->ShowDialogWithManager(dialog1
,
194 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager1
).Pass());
195 manager
->ShowDialogWithManager(dialog2
,
196 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager2
).Pass());
197 manager
->ShowDialogWithManager(dialog3
,
198 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager3
).Pass());
200 EXPECT_TRUE(delegate
->web_contents_blocked());
201 EXPECT_EQ(NativeManagerTracker::SHOWN
, tracker1
.state_
);
202 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN
, tracker2
.state_
);
203 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN
, tracker3
.state_
);
205 native_manager1
->StopTracking();
206 native_manager2
->StopTracking();
207 native_manager3
->StopTracking();
210 // Test that the dialog is shown/hidden when the WebContents is shown/hidden.
211 TEST_F(WebContentsModalDialogManagerTest
, VisibilityObservation
) {
212 const NativeWebContentsModalDialog dialog
= MakeFakeDialog();
214 NativeManagerTracker tracker
;
215 TestNativeWebContentsModalDialogManager
* native_manager
=
216 new TestNativeWebContentsModalDialogManager(dialog
, manager
, &tracker
);
217 manager
->ShowDialogWithManager(dialog
,
218 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager
).Pass());
220 EXPECT_TRUE(manager
->IsDialogActive());
221 EXPECT_TRUE(delegate
->web_contents_blocked());
222 EXPECT_EQ(NativeManagerTracker::SHOWN
, tracker
.state_
);
224 test_api
->WebContentsWasHidden();
226 EXPECT_TRUE(manager
->IsDialogActive());
227 EXPECT_TRUE(delegate
->web_contents_blocked());
228 EXPECT_EQ(NativeManagerTracker::HIDDEN
, tracker
.state_
);
230 test_api
->WebContentsWasShown();
232 EXPECT_TRUE(manager
->IsDialogActive());
233 EXPECT_TRUE(delegate
->web_contents_blocked());
234 EXPECT_EQ(NativeManagerTracker::SHOWN
, tracker
.state_
);
236 native_manager
->StopTracking();
239 // Test that attaching an interstitial page closes all dialogs.
240 TEST_F(WebContentsModalDialogManagerTest
, InterstitialPage
) {
241 const NativeWebContentsModalDialog dialog1
= MakeFakeDialog();
242 const NativeWebContentsModalDialog dialog2
= MakeFakeDialog();
244 NativeManagerTracker tracker1
;
245 NativeManagerTracker tracker2
;
246 TestNativeWebContentsModalDialogManager
* native_manager1
=
247 new TestNativeWebContentsModalDialogManager(dialog1
, manager
, &tracker1
);
248 TestNativeWebContentsModalDialogManager
* native_manager2
=
249 new TestNativeWebContentsModalDialogManager(dialog2
, manager
, &tracker2
);
250 manager
->ShowDialogWithManager(dialog1
,
251 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager1
).Pass());
252 manager
->ShowDialogWithManager(dialog2
,
253 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager2
).Pass());
255 test_api
->DidAttachInterstitialPage();
257 #if defined(USE_AURA)
258 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker1
.state_
);
259 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker2
.state_
);
261 EXPECT_EQ(NativeManagerTracker::SHOWN
, tracker1
.state_
);
262 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN
, tracker2
.state_
);
265 EXPECT_TRUE(tracker1
.was_shown_
);
266 EXPECT_FALSE(tracker2
.was_shown_
);
268 #if !defined(USE_AURA)
269 native_manager1
->StopTracking();
270 native_manager2
->StopTracking();
275 // Test that the first dialog is always shown, regardless of the order in which
276 // dialogs are closed.
277 TEST_F(WebContentsModalDialogManagerTest
, CloseDialogs
) {
278 // The front dialog is always shown regardless of dialog close order.
279 const NativeWebContentsModalDialog dialog1
= MakeFakeDialog();
280 const NativeWebContentsModalDialog dialog2
= MakeFakeDialog();
281 const NativeWebContentsModalDialog dialog3
= MakeFakeDialog();
282 const NativeWebContentsModalDialog dialog4
= MakeFakeDialog();
284 NativeManagerTracker tracker1
;
285 NativeManagerTracker tracker2
;
286 NativeManagerTracker tracker3
;
287 NativeManagerTracker tracker4
;
288 TestNativeWebContentsModalDialogManager
* native_manager1
=
289 new TestNativeWebContentsModalDialogManager(dialog1
, manager
, &tracker1
);
290 TestNativeWebContentsModalDialogManager
* native_manager2
=
291 new TestNativeWebContentsModalDialogManager(dialog2
, manager
, &tracker2
);
292 TestNativeWebContentsModalDialogManager
* native_manager3
=
293 new TestNativeWebContentsModalDialogManager(dialog3
, manager
, &tracker3
);
294 TestNativeWebContentsModalDialogManager
* native_manager4
=
295 new TestNativeWebContentsModalDialogManager(dialog4
, manager
, &tracker4
);
296 manager
->ShowDialogWithManager(dialog1
,
297 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager1
).Pass());
298 manager
->ShowDialogWithManager(dialog2
,
299 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager2
).Pass());
300 manager
->ShowDialogWithManager(dialog3
,
301 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager3
).Pass());
302 manager
->ShowDialogWithManager(dialog4
,
303 scoped_ptr
<SingleWebContentsDialogManager
>(native_manager4
).Pass());
305 native_manager1
->Close();
307 EXPECT_TRUE(manager
->IsDialogActive());
308 EXPECT_TRUE(delegate
->web_contents_blocked());
309 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker1
.state_
);
310 EXPECT_EQ(NativeManagerTracker::SHOWN
, tracker2
.state_
);
311 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN
, tracker3
.state_
);
312 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN
, tracker4
.state_
);
314 native_manager3
->Close();
316 EXPECT_TRUE(manager
->IsDialogActive());
317 EXPECT_TRUE(delegate
->web_contents_blocked());
318 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker1
.state_
);
319 EXPECT_EQ(NativeManagerTracker::SHOWN
, tracker2
.state_
);
320 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker3
.state_
);
321 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN
, tracker4
.state_
);
322 EXPECT_FALSE(tracker3
.was_shown_
);
324 native_manager2
->Close();
326 EXPECT_TRUE(manager
->IsDialogActive());
327 EXPECT_TRUE(delegate
->web_contents_blocked());
328 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker1
.state_
);
329 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker2
.state_
);
330 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker3
.state_
);
331 EXPECT_EQ(NativeManagerTracker::SHOWN
, tracker4
.state_
);
332 EXPECT_FALSE(tracker3
.was_shown_
);
334 native_manager4
->Close();
336 EXPECT_FALSE(manager
->IsDialogActive());
337 EXPECT_FALSE(delegate
->web_contents_blocked());
338 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker1
.state_
);
339 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker2
.state_
);
340 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker3
.state_
);
341 EXPECT_EQ(NativeManagerTracker::CLOSED
, tracker4
.state_
);
342 EXPECT_TRUE(tracker1
.was_shown_
);
343 EXPECT_TRUE(tracker2
.was_shown_
);
344 EXPECT_FALSE(tracker3
.was_shown_
);
345 EXPECT_TRUE(tracker4
.was_shown_
);
348 // Test that CloseAllDialogs does what it says.
349 TEST_F(WebContentsModalDialogManagerTest
, CloseAllDialogs
) {
350 const int kWindowCount
= 4;
351 NativeManagerTracker trackers
[kWindowCount
];
352 TestNativeWebContentsModalDialogManager
* native_managers
[kWindowCount
];
353 for (int i
= 0; i
< kWindowCount
; i
++) {
354 const NativeWebContentsModalDialog dialog
= MakeFakeDialog();
356 new TestNativeWebContentsModalDialogManager(
357 dialog
, manager
, &(trackers
[i
]));
358 manager
->ShowDialogWithManager(dialog
,
359 scoped_ptr
<SingleWebContentsDialogManager
>(
360 native_managers
[i
]).Pass());
363 for (int i
= 0; i
< kWindowCount
; i
++)
364 EXPECT_NE(NativeManagerTracker::CLOSED
, trackers
[i
].state_
);
366 test_api
->CloseAllDialogs();
368 EXPECT_FALSE(delegate
->web_contents_blocked());
369 EXPECT_FALSE(manager
->IsDialogActive());
370 for (int i
= 0; i
< kWindowCount
; i
++)
371 EXPECT_EQ(NativeManagerTracker::CLOSED
, trackers
[i
].state_
);
374 } // namespace web_modal