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 virtual void Show() OVERRIDE {
58 tracker_->SetState(NativeManagerTracker::SHOWN);
60 virtual void Hide() OVERRIDE {
62 tracker_->SetState(NativeManagerTracker::HIDDEN);
64 virtual void Close() OVERRIDE {
66 tracker_->SetState(NativeManagerTracker::CLOSED);
67 delegate_->WillClose(dialog_);
69 virtual void Focus() OVERRIDE {
71 virtual void Pulse() OVERRIDE {
73 virtual void HostChanged(WebContentsModalDialogHost* new_host) OVERRIDE {
75 virtual NativeWebContentsModalDialog dialog() OVERRIDE {
84 SingleWebContentsDialogManagerDelegate* delegate_;
85 NativeWebContentsModalDialog dialog_;
86 NativeManagerTracker* tracker_;
88 DISALLOW_COPY_AND_ASSIGN(TestNativeWebContentsModalDialogManager);
91 class WebContentsModalDialogManagerTest
92 : public content::RenderViewHostTestHarness {
94 WebContentsModalDialogManagerTest()
99 virtual void SetUp() {
100 content::RenderViewHostTestHarness::SetUp();
102 delegate.reset(new TestWebContentsModalDialogManagerDelegate);
103 WebContentsModalDialogManager::CreateForWebContents(web_contents());
104 manager = WebContentsModalDialogManager::FromWebContents(web_contents());
105 manager->SetDelegate(delegate.get());
106 test_api.reset(new WebContentsModalDialogManager::TestApi(manager));
109 virtual void TearDown() {
111 content::RenderViewHostTestHarness::TearDown();
115 NativeWebContentsModalDialog MakeFakeDialog() {
116 // WebContentsModalDialogManager treats the NativeWebContentsModalDialog as
117 // an opaque type, so creating fake NativeWebContentsModalDialogs using
118 // reinterpret_cast is valid.
119 return reinterpret_cast<NativeWebContentsModalDialog>(next_dialog_id++);
123 scoped_ptr<TestWebContentsModalDialogManagerDelegate> delegate;
124 WebContentsModalDialogManager* manager;
125 scoped_ptr<WebContentsModalDialogManager::TestApi> test_api;
127 DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerTest);
130 SingleWebContentsDialogManager*
131 WebContentsModalDialogManager::CreateNativeWebModalManager(
132 NativeWebContentsModalDialog dialog,
133 SingleWebContentsDialogManagerDelegate* native_delegate) {
135 return new TestNativeWebContentsModalDialogManager(
141 // Test that the dialog is shown immediately when the delegate indicates the web
142 // contents is visible.
143 TEST_F(WebContentsModalDialogManagerTest, WebContentsVisible) {
144 // Dialog should be shown while WebContents is visible.
145 const NativeWebContentsModalDialog dialog = MakeFakeDialog();
147 NativeManagerTracker tracker;
148 TestNativeWebContentsModalDialogManager* native_manager =
149 new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker);
150 manager->ShowDialogWithManager(dialog,
151 scoped_ptr<SingleWebContentsDialogManager>(native_manager).Pass());
153 EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_);
154 EXPECT_TRUE(manager->IsDialogActive());
155 EXPECT_TRUE(delegate->web_contents_blocked());
156 EXPECT_TRUE(tracker.was_shown_);
158 native_manager->StopTracking();
161 // Test that the dialog is not shown immediately when the delegate indicates the
162 // web contents is not visible.
163 TEST_F(WebContentsModalDialogManagerTest, WebContentsNotVisible) {
164 // Dialog should not be shown while WebContents is not visible.
165 delegate->set_web_contents_visible(false);
167 const NativeWebContentsModalDialog dialog = MakeFakeDialog();
169 NativeManagerTracker tracker;
170 TestNativeWebContentsModalDialogManager* native_manager =
171 new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker);
172 manager->ShowDialogWithManager(dialog,
173 scoped_ptr<SingleWebContentsDialogManager>(native_manager).Pass());
175 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker.state_);
176 EXPECT_TRUE(manager->IsDialogActive());
177 EXPECT_TRUE(delegate->web_contents_blocked());
178 EXPECT_FALSE(tracker.was_shown_);
180 native_manager->StopTracking();
183 // Test that only the first of multiple dialogs is shown.
184 TEST_F(WebContentsModalDialogManagerTest, ShowDialogs) {
185 const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
186 const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
187 const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
189 NativeManagerTracker tracker1;
190 NativeManagerTracker tracker2;
191 NativeManagerTracker tracker3;
192 TestNativeWebContentsModalDialogManager* native_manager1 =
193 new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1);
194 TestNativeWebContentsModalDialogManager* native_manager2 =
195 new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2);
196 TestNativeWebContentsModalDialogManager* native_manager3 =
197 new TestNativeWebContentsModalDialogManager(dialog3, manager, &tracker3);
198 manager->ShowDialogWithManager(dialog1,
199 scoped_ptr<SingleWebContentsDialogManager>(native_manager1).Pass());
200 manager->ShowDialogWithManager(dialog2,
201 scoped_ptr<SingleWebContentsDialogManager>(native_manager2).Pass());
202 manager->ShowDialogWithManager(dialog3,
203 scoped_ptr<SingleWebContentsDialogManager>(native_manager3).Pass());
205 EXPECT_TRUE(delegate->web_contents_blocked());
206 EXPECT_EQ(NativeManagerTracker::SHOWN, tracker1.state_);
207 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker2.state_);
208 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker3.state_);
210 native_manager1->StopTracking();
211 native_manager2->StopTracking();
212 native_manager3->StopTracking();
215 // Test that the dialog is shown/hidden when the WebContents is shown/hidden.
216 TEST_F(WebContentsModalDialogManagerTest, VisibilityObservation) {
217 const NativeWebContentsModalDialog dialog = MakeFakeDialog();
219 NativeManagerTracker tracker;
220 TestNativeWebContentsModalDialogManager* native_manager =
221 new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker);
222 manager->ShowDialogWithManager(dialog,
223 scoped_ptr<SingleWebContentsDialogManager>(native_manager).Pass());
225 EXPECT_TRUE(manager->IsDialogActive());
226 EXPECT_TRUE(delegate->web_contents_blocked());
227 EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_);
229 test_api->WebContentsWasHidden();
231 EXPECT_TRUE(manager->IsDialogActive());
232 EXPECT_TRUE(delegate->web_contents_blocked());
233 EXPECT_EQ(NativeManagerTracker::HIDDEN, tracker.state_);
235 test_api->WebContentsWasShown();
237 EXPECT_TRUE(manager->IsDialogActive());
238 EXPECT_TRUE(delegate->web_contents_blocked());
239 EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_);
241 native_manager->StopTracking();
244 // Test that attaching an interstitial page closes dialogs configured to close.
245 TEST_F(WebContentsModalDialogManagerTest, InterstitialPage) {
246 const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
247 const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
248 const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
250 NativeManagerTracker tracker1;
251 NativeManagerTracker tracker2;
252 NativeManagerTracker tracker3;
253 TestNativeWebContentsModalDialogManager* native_manager1 =
254 new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1);
255 TestNativeWebContentsModalDialogManager* native_manager2 =
256 new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2);
257 TestNativeWebContentsModalDialogManager* native_manager3 =
258 new TestNativeWebContentsModalDialogManager(dialog3, manager, &tracker3);
259 manager->ShowDialogWithManager(dialog1,
260 scoped_ptr<SingleWebContentsDialogManager>(native_manager1).Pass());
261 manager->ShowDialogWithManager(dialog2,
262 scoped_ptr<SingleWebContentsDialogManager>(native_manager2).Pass());
263 manager->ShowDialogWithManager(dialog3,
264 scoped_ptr<SingleWebContentsDialogManager>(native_manager3).Pass());
266 #if defined(OS_WIN) || defined(USE_AURA)
267 manager->SetCloseOnInterstitialPage(dialog2, false);
269 // TODO(wittman): Remove this section once Mac is changed to close on
270 // interstitial pages by default.
271 manager->SetCloseOnInterstitialPage(dialog1, true);
272 manager->SetCloseOnInterstitialPage(dialog3, true);
275 test_api->DidAttachInterstitialPage();
277 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
278 EXPECT_EQ(NativeManagerTracker::SHOWN, tracker2.state_);
279 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
280 EXPECT_TRUE(tracker1.was_shown_);
281 EXPECT_TRUE(tracker2.was_shown_);
282 EXPECT_FALSE(tracker3.was_shown_);
284 native_manager2->StopTracking();
288 // Test that the first dialog is always shown, regardless of the order in which
289 // dialogs are closed.
290 TEST_F(WebContentsModalDialogManagerTest, CloseDialogs) {
291 // The front dialog is always shown regardless of dialog close order.
292 const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
293 const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
294 const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
295 const NativeWebContentsModalDialog dialog4 = MakeFakeDialog();
297 NativeManagerTracker tracker1;
298 NativeManagerTracker tracker2;
299 NativeManagerTracker tracker3;
300 NativeManagerTracker tracker4;
301 TestNativeWebContentsModalDialogManager* native_manager1 =
302 new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1);
303 TestNativeWebContentsModalDialogManager* native_manager2 =
304 new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2);
305 TestNativeWebContentsModalDialogManager* native_manager3 =
306 new TestNativeWebContentsModalDialogManager(dialog3, manager, &tracker3);
307 TestNativeWebContentsModalDialogManager* native_manager4 =
308 new TestNativeWebContentsModalDialogManager(dialog4, manager, &tracker4);
309 manager->ShowDialogWithManager(dialog1,
310 scoped_ptr<SingleWebContentsDialogManager>(native_manager1).Pass());
311 manager->ShowDialogWithManager(dialog2,
312 scoped_ptr<SingleWebContentsDialogManager>(native_manager2).Pass());
313 manager->ShowDialogWithManager(dialog3,
314 scoped_ptr<SingleWebContentsDialogManager>(native_manager3).Pass());
315 manager->ShowDialogWithManager(dialog4,
316 scoped_ptr<SingleWebContentsDialogManager>(native_manager4).Pass());
318 native_manager1->Close();
320 EXPECT_TRUE(manager->IsDialogActive());
321 EXPECT_TRUE(delegate->web_contents_blocked());
322 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
323 EXPECT_EQ(NativeManagerTracker::SHOWN, tracker2.state_);
324 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker3.state_);
325 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker4.state_);
327 native_manager3->Close();
329 EXPECT_TRUE(manager->IsDialogActive());
330 EXPECT_TRUE(delegate->web_contents_blocked());
331 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
332 EXPECT_EQ(NativeManagerTracker::SHOWN, tracker2.state_);
333 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
334 EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker4.state_);
335 EXPECT_FALSE(tracker3.was_shown_);
337 native_manager2->Close();
339 EXPECT_TRUE(manager->IsDialogActive());
340 EXPECT_TRUE(delegate->web_contents_blocked());
341 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
342 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_);
343 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
344 EXPECT_EQ(NativeManagerTracker::SHOWN, tracker4.state_);
345 EXPECT_FALSE(tracker3.was_shown_);
347 native_manager4->Close();
349 EXPECT_FALSE(manager->IsDialogActive());
350 EXPECT_FALSE(delegate->web_contents_blocked());
351 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
352 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_);
353 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
354 EXPECT_EQ(NativeManagerTracker::CLOSED, tracker4.state_);
355 EXPECT_TRUE(tracker1.was_shown_);
356 EXPECT_TRUE(tracker2.was_shown_);
357 EXPECT_FALSE(tracker3.was_shown_);
358 EXPECT_TRUE(tracker4.was_shown_);
361 // Test that CloseAllDialogs does what it says.
362 TEST_F(WebContentsModalDialogManagerTest, CloseAllDialogs) {
363 const int kWindowCount = 4;
364 NativeManagerTracker trackers[kWindowCount];
365 TestNativeWebContentsModalDialogManager* native_managers[kWindowCount];
366 for (int i = 0; i < kWindowCount; i++) {
367 const NativeWebContentsModalDialog dialog = MakeFakeDialog();
369 new TestNativeWebContentsModalDialogManager(
370 dialog, manager, &(trackers[i]));
371 manager->ShowDialogWithManager(dialog,
372 scoped_ptr<SingleWebContentsDialogManager>(
373 native_managers[i]).Pass());
376 for (int i = 0; i < kWindowCount; i++)
377 EXPECT_NE(NativeManagerTracker::CLOSED, trackers[i].state_);
379 test_api->CloseAllDialogs();
381 EXPECT_FALSE(delegate->web_contents_blocked());
382 EXPECT_FALSE(manager->IsDialogActive());
383 for (int i = 0; i < kWindowCount; i++)
384 EXPECT_EQ(NativeManagerTracker::CLOSED, trackers[i].state_);
387 } // namespace web_modal