Home | History | Annotate | Download | only in web_modal
      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.
      4 
      5 #include "components/web_modal/web_contents_modal_dialog_manager.h"
      6 
      7 #include <map>
      8 
      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"
     14 
     15 namespace web_modal {
     16 
     17 // Tracks persistent state changes of the native WC-modal dialog manager.
     18 class NativeManagerTracker {
     19  public:
     20   enum DialogState {
     21     UNKNOWN,
     22     NOT_SHOWN,
     23     SHOWN,
     24     HIDDEN,
     25     CLOSED
     26   };
     27 
     28   NativeManagerTracker() : state_(UNKNOWN), was_shown_(false) {}
     29 
     30   void SetState(DialogState state) {
     31     state_ = state;
     32     if (state_ == SHOWN)
     33       was_shown_ = true;
     34   }
     35 
     36   DialogState state_;
     37   bool was_shown_;
     38 };
     39 
     40 NativeManagerTracker unused_tracker;
     41 
     42 class TestNativeWebContentsModalDialogManager
     43     : public SingleWebContentsDialogManager {
     44  public:
     45   TestNativeWebContentsModalDialogManager(
     46       NativeWebContentsModalDialog dialog,
     47       SingleWebContentsDialogManagerDelegate* delegate,
     48       NativeManagerTracker* tracker)
     49       : delegate_(delegate),
     50         dialog_(dialog),
     51         tracker_(tracker) {
     52     if (tracker_)
     53       tracker_->SetState(NativeManagerTracker::NOT_SHOWN);
     54   }
     55 
     56   virtual void Show() OVERRIDE {
     57     if (tracker_)
     58       tracker_->SetState(NativeManagerTracker::SHOWN);
     59   }
     60   virtual void Hide() OVERRIDE {
     61     if (tracker_)
     62       tracker_->SetState(NativeManagerTracker::HIDDEN);
     63   }
     64   virtual void Close() OVERRIDE {
     65     if (tracker_)
     66       tracker_->SetState(NativeManagerTracker::CLOSED);
     67     delegate_->WillClose(dialog_);
     68   }
     69   virtual void Focus() OVERRIDE {
     70   }
     71   virtual void Pulse() OVERRIDE {
     72   }
     73   virtual void HostChanged(WebContentsModalDialogHost* new_host) OVERRIDE {
     74   }
     75   virtual NativeWebContentsModalDialog dialog() OVERRIDE {
     76       return dialog_;
     77   }
     78 
     79   void StopTracking() {
     80     tracker_ = NULL;
     81   }
     82 
     83  private:
     84   SingleWebContentsDialogManagerDelegate* delegate_;
     85   NativeWebContentsModalDialog dialog_;
     86   NativeManagerTracker* tracker_;
     87 
     88   DISALLOW_COPY_AND_ASSIGN(TestNativeWebContentsModalDialogManager);
     89 };
     90 
     91 class WebContentsModalDialogManagerTest
     92     : public content::RenderViewHostTestHarness {
     93  public:
     94   WebContentsModalDialogManagerTest()
     95       : next_dialog_id(1),
     96         manager(NULL) {
     97   }
     98 
     99   virtual void SetUp() {
    100     content::RenderViewHostTestHarness::SetUp();
    101 
    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));
    107   }
    108 
    109   virtual void TearDown() {
    110     test_api.reset();
    111     content::RenderViewHostTestHarness::TearDown();
    112   }
    113 
    114  protected:
    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++);
    120   }
    121 
    122   int next_dialog_id;
    123   scoped_ptr<TestWebContentsModalDialogManagerDelegate> delegate;
    124   WebContentsModalDialogManager* manager;
    125   scoped_ptr<WebContentsModalDialogManager::TestApi> test_api;
    126 
    127   DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerTest);
    128 };
    129 
    130 SingleWebContentsDialogManager*
    131 WebContentsModalDialogManager::CreateNativeWebModalManager(
    132     NativeWebContentsModalDialog dialog,
    133     SingleWebContentsDialogManagerDelegate* native_delegate) {
    134   NOTREACHED();
    135   return new TestNativeWebContentsModalDialogManager(
    136       dialog,
    137       native_delegate,
    138       &unused_tracker);
    139 }
    140 
    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();
    146 
    147   NativeManagerTracker tracker;
    148   TestNativeWebContentsModalDialogManager* native_manager =
    149       new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker);
    150   manager->ShowDialogWithManager(dialog,
    151       scoped_ptr<SingleWebContentsDialogManager>(native_manager).Pass());
    152 
    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_);
    157 
    158   native_manager->StopTracking();
    159 }
    160 
    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);
    166 
    167   const NativeWebContentsModalDialog dialog = MakeFakeDialog();
    168 
    169   NativeManagerTracker tracker;
    170   TestNativeWebContentsModalDialogManager* native_manager =
    171       new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker);
    172   manager->ShowDialogWithManager(dialog,
    173       scoped_ptr<SingleWebContentsDialogManager>(native_manager).Pass());
    174 
    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_);
    179 
    180   native_manager->StopTracking();
    181 }
    182 
    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();
    188 
    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());
    204 
    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_);
    209 
    210   native_manager1->StopTracking();
    211   native_manager2->StopTracking();
    212   native_manager3->StopTracking();
    213 }
    214 
    215 // Test that the dialog is shown/hidden when the WebContents is shown/hidden.
    216 TEST_F(WebContentsModalDialogManagerTest, VisibilityObservation) {
    217   const NativeWebContentsModalDialog dialog = MakeFakeDialog();
    218 
    219   NativeManagerTracker tracker;
    220   TestNativeWebContentsModalDialogManager* native_manager =
    221       new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker);
    222   manager->ShowDialogWithManager(dialog,
    223       scoped_ptr<SingleWebContentsDialogManager>(native_manager).Pass());
    224 
    225   EXPECT_TRUE(manager->IsDialogActive());
    226   EXPECT_TRUE(delegate->web_contents_blocked());
    227   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_);
    228 
    229   test_api->WebContentsWasHidden();
    230 
    231   EXPECT_TRUE(manager->IsDialogActive());
    232   EXPECT_TRUE(delegate->web_contents_blocked());
    233   EXPECT_EQ(NativeManagerTracker::HIDDEN, tracker.state_);
    234 
    235   test_api->WebContentsWasShown();
    236 
    237   EXPECT_TRUE(manager->IsDialogActive());
    238   EXPECT_TRUE(delegate->web_contents_blocked());
    239   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_);
    240 
    241   native_manager->StopTracking();
    242 }
    243 
    244 // Test that attaching an interstitial page closes all dialogs.
    245 TEST_F(WebContentsModalDialogManagerTest, InterstitialPage) {
    246   const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
    247   const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
    248 
    249   NativeManagerTracker tracker1;
    250   NativeManagerTracker tracker2;
    251   TestNativeWebContentsModalDialogManager* native_manager1 =
    252       new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1);
    253   TestNativeWebContentsModalDialogManager* native_manager2 =
    254       new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2);
    255   manager->ShowDialogWithManager(dialog1,
    256       scoped_ptr<SingleWebContentsDialogManager>(native_manager1).Pass());
    257   manager->ShowDialogWithManager(dialog2,
    258       scoped_ptr<SingleWebContentsDialogManager>(native_manager2).Pass());
    259 
    260   test_api->DidAttachInterstitialPage();
    261 
    262 #if defined(USE_AURA)
    263   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
    264   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_);
    265 #else
    266   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker1.state_);
    267   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker2.state_);
    268 #endif
    269 
    270   EXPECT_TRUE(tracker1.was_shown_);
    271   EXPECT_FALSE(tracker2.was_shown_);
    272 
    273 #if !defined(USE_AURA)
    274   native_manager1->StopTracking();
    275   native_manager2->StopTracking();
    276 #endif
    277 }
    278 
    279 
    280 // Test that the first dialog is always shown, regardless of the order in which
    281 // dialogs are closed.
    282 TEST_F(WebContentsModalDialogManagerTest, CloseDialogs) {
    283   // The front dialog is always shown regardless of dialog close order.
    284   const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
    285   const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
    286   const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
    287   const NativeWebContentsModalDialog dialog4 = MakeFakeDialog();
    288 
    289   NativeManagerTracker tracker1;
    290   NativeManagerTracker tracker2;
    291   NativeManagerTracker tracker3;
    292   NativeManagerTracker tracker4;
    293   TestNativeWebContentsModalDialogManager* native_manager1 =
    294       new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1);
    295   TestNativeWebContentsModalDialogManager* native_manager2 =
    296       new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2);
    297   TestNativeWebContentsModalDialogManager* native_manager3 =
    298       new TestNativeWebContentsModalDialogManager(dialog3, manager, &tracker3);
    299   TestNativeWebContentsModalDialogManager* native_manager4 =
    300       new TestNativeWebContentsModalDialogManager(dialog4, manager, &tracker4);
    301   manager->ShowDialogWithManager(dialog1,
    302       scoped_ptr<SingleWebContentsDialogManager>(native_manager1).Pass());
    303   manager->ShowDialogWithManager(dialog2,
    304       scoped_ptr<SingleWebContentsDialogManager>(native_manager2).Pass());
    305   manager->ShowDialogWithManager(dialog3,
    306       scoped_ptr<SingleWebContentsDialogManager>(native_manager3).Pass());
    307   manager->ShowDialogWithManager(dialog4,
    308       scoped_ptr<SingleWebContentsDialogManager>(native_manager4).Pass());
    309 
    310   native_manager1->Close();
    311 
    312   EXPECT_TRUE(manager->IsDialogActive());
    313   EXPECT_TRUE(delegate->web_contents_blocked());
    314   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
    315   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker2.state_);
    316   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker3.state_);
    317   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker4.state_);
    318 
    319   native_manager3->Close();
    320 
    321   EXPECT_TRUE(manager->IsDialogActive());
    322   EXPECT_TRUE(delegate->web_contents_blocked());
    323   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
    324   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker2.state_);
    325   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
    326   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker4.state_);
    327   EXPECT_FALSE(tracker3.was_shown_);
    328 
    329   native_manager2->Close();
    330 
    331   EXPECT_TRUE(manager->IsDialogActive());
    332   EXPECT_TRUE(delegate->web_contents_blocked());
    333   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
    334   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_);
    335   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
    336   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker4.state_);
    337   EXPECT_FALSE(tracker3.was_shown_);
    338 
    339   native_manager4->Close();
    340 
    341   EXPECT_FALSE(manager->IsDialogActive());
    342   EXPECT_FALSE(delegate->web_contents_blocked());
    343   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
    344   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_);
    345   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
    346   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker4.state_);
    347   EXPECT_TRUE(tracker1.was_shown_);
    348   EXPECT_TRUE(tracker2.was_shown_);
    349   EXPECT_FALSE(tracker3.was_shown_);
    350   EXPECT_TRUE(tracker4.was_shown_);
    351 }
    352 
    353 // Test that CloseAllDialogs does what it says.
    354 TEST_F(WebContentsModalDialogManagerTest, CloseAllDialogs) {
    355   const int kWindowCount = 4;
    356   NativeManagerTracker trackers[kWindowCount];
    357   TestNativeWebContentsModalDialogManager* native_managers[kWindowCount];
    358   for (int i = 0; i < kWindowCount; i++) {
    359     const NativeWebContentsModalDialog dialog = MakeFakeDialog();
    360     native_managers[i] =
    361         new TestNativeWebContentsModalDialogManager(
    362             dialog, manager, &(trackers[i]));
    363     manager->ShowDialogWithManager(dialog,
    364     scoped_ptr<SingleWebContentsDialogManager>(
    365         native_managers[i]).Pass());
    366   }
    367 
    368   for (int i = 0; i < kWindowCount; i++)
    369     EXPECT_NE(NativeManagerTracker::CLOSED, trackers[i].state_);
    370 
    371   test_api->CloseAllDialogs();
    372 
    373   EXPECT_FALSE(delegate->web_contents_blocked());
    374   EXPECT_FALSE(manager->IsDialogActive());
    375   for (int i = 0; i < kWindowCount; i++)
    376     EXPECT_EQ(NativeManagerTracker::CLOSED, trackers[i].state_);
    377 }
    378 
    379 }  // namespace web_modal
    380