1// Copyright 2017 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#import "ios/chrome/browser/web/blocked_popup_tab_helper.h" 6 7#include "base/memory/ptr_util.h" 8#include "base/test/metrics/histogram_tester.h" 9#include "components/content_settings/core/browser/host_content_settings_map.h" 10#include "components/infobars/core/confirm_infobar_delegate.h" 11#include "components/infobars/core/infobar.h" 12#include "components/infobars/core/infobar_manager.h" 13#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" 14#include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" 15#include "ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h" 16#include "ios/chrome/browser/infobars/infobar_manager_impl.h" 17#import "ios/chrome/browser/web/chrome_web_test.h" 18#import "ios/web/public/test/fakes/test_navigation_manager.h" 19#import "ios/web/public/test/fakes/test_web_state.h" 20#import "ios/web/public/test/fakes/test_web_state_delegate.h" 21#include "testing/gtest/include/gtest/gtest.h" 22#include "url/gurl.h" 23 24#if !defined(__has_feature) || !__has_feature(objc_arc) 25#error "This file requires ARC support." 26#endif 27 28using web::WebState; 29 30// Test fixture for BlockedPopupTabHelper class. 31class BlockedPopupTabHelperTest : public ChromeWebTest { 32 protected: 33 void SetUp() override { 34 ChromeWebTest::SetUp(); 35 web_state()->SetDelegate(&web_state_delegate_); 36 BlockedPopupTabHelper::CreateForWebState(web_state()); 37 InfoBarManagerImpl::CreateForWebState(web_state()); 38 } 39 40 // Returns true if InfoBarManager is being observed. 41 bool IsObservingSources() { 42 return GetBlockedPopupTabHelper()->scoped_observer_.IsObservingSources(); 43 } 44 45 // Returns BlockedPopupTabHelper that is being tested. 46 BlockedPopupTabHelper* GetBlockedPopupTabHelper() { 47 return BlockedPopupTabHelper::FromWebState(web_state()); 48 } 49 50 // Returns InfoBarManager attached to |web_state()|. 51 infobars::InfoBarManager* GetInfobarManager() { 52 return InfoBarManagerImpl::FromWebState(web_state()); 53 } 54 55 web::TestWebStateDelegate web_state_delegate_; 56}; 57 58// Tests ShouldBlockPopup method. This test changes content settings without 59// restoring them back, which is fine because changes do not persist across test 60// runs. 61TEST_F(BlockedPopupTabHelperTest, ShouldBlockPopup) { 62 const GURL source_url1("https://source-url1"); 63 EXPECT_TRUE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url1)); 64 65 // Allow popups for |source_url1|. 66 scoped_refptr<HostContentSettingsMap> settings_map( 67 ios::HostContentSettingsMapFactory::GetForBrowserState( 68 chrome_browser_state_.get())); 69 settings_map->SetContentSettingCustomScope( 70 ContentSettingsPattern::FromURL(source_url1), 71 ContentSettingsPattern::Wildcard(), ContentSettingsType::POPUPS, 72 CONTENT_SETTING_ALLOW); 73 74 EXPECT_FALSE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url1)); 75 const GURL source_url2("https://source-url2"); 76 EXPECT_TRUE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url2)); 77 78 // Allow all popups. 79 settings_map->SetDefaultContentSetting(ContentSettingsType::POPUPS, 80 CONTENT_SETTING_ALLOW); 81 82 EXPECT_FALSE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url1)); 83 EXPECT_FALSE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url2)); 84} 85 86// Tests that allowing blocked popup opens a child window and allows future 87// popups for the source url. 88TEST_F(BlockedPopupTabHelperTest, AllowBlockedPopup) { 89 const GURL source_url("https://source-url"); 90 ASSERT_TRUE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url)); 91 92 // Block popup. 93 const GURL target_url("https://target-url"); 94 web::Referrer referrer(source_url, web::ReferrerPolicyDefault); 95 GetBlockedPopupTabHelper()->HandlePopup(target_url, referrer); 96 97 // Allow blocked popup. 98 ASSERT_EQ(1U, GetInfobarManager()->infobar_count()); 99 infobars::InfoBar* infobar = GetInfobarManager()->infobar_at(0); 100 auto* delegate = infobar->delegate()->AsConfirmInfoBarDelegate(); 101 ASSERT_TRUE(delegate); 102 ASSERT_FALSE(web_state_delegate_.last_open_url_request()); 103 delegate->Accept(); 104 105 // Verify that popups are allowed for |test_url|. 106 EXPECT_FALSE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url)); 107 108 // Verify that child window was open. 109 auto* open_url_request = web_state_delegate_.last_open_url_request(); 110 ASSERT_TRUE(open_url_request); 111 EXPECT_EQ(web_state(), open_url_request->web_state); 112 WebState::OpenURLParams params = open_url_request->params; 113 EXPECT_EQ(target_url, params.url); 114 EXPECT_EQ(source_url, params.referrer.url); 115 EXPECT_EQ(web::ReferrerPolicyDefault, params.referrer.policy); 116 EXPECT_EQ(WindowOpenDisposition::NEW_POPUP, params.disposition); 117 EXPECT_TRUE( 118 PageTransitionCoreTypeIs(params.transition, ui::PAGE_TRANSITION_LINK)); 119 EXPECT_TRUE(params.is_renderer_initiated); 120} 121 122// Tests that destroying WebState while Infobar is presented does not crash. 123TEST_F(BlockedPopupTabHelperTest, DestroyWebState) { 124 const GURL source_url("https://source-url"); 125 ASSERT_TRUE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url)); 126 127 // Block popup. 128 const GURL target_url("https://target-url"); 129 web::Referrer referrer(source_url, web::ReferrerPolicyDefault); 130 GetBlockedPopupTabHelper()->HandlePopup(target_url, referrer); 131 132 // Verify that destroying WebState does not crash. 133 DestroyWebState(); 134} 135 136// Tests that an infobar is added to the infobar manager when 137// BlockedPopupTabHelper::HandlePopup() is called. 138TEST_F(BlockedPopupTabHelperTest, ShowAndDismissInfoBar) { 139 // Check that there are no infobars showing and no registered observers. 140 EXPECT_EQ(0U, GetInfobarManager()->infobar_count()); 141 EXPECT_FALSE(IsObservingSources()); 142 143 // Call |HandlePopup| to show an infobar. 144 const GURL test_url("https://popups.example.com"); 145 GetBlockedPopupTabHelper()->HandlePopup(test_url, web::Referrer()); 146 ASSERT_EQ(1U, GetInfobarManager()->infobar_count()); 147 EXPECT_TRUE(IsObservingSources()); 148 149 // Dismiss the infobar and check that the tab helper no longer has any 150 // registered observers. 151 GetInfobarManager()->infobar_at(0)->RemoveSelf(); 152 EXPECT_EQ(0U, GetInfobarManager()->infobar_count()); 153 EXPECT_FALSE(IsObservingSources()); 154} 155 156// Tests that the Infobar presentation and dismissal histograms are recorded 157// correctly. 158TEST_F(BlockedPopupTabHelperTest, RecordDismissMetrics) { 159 base::HistogramTester histogram_tester; 160 161 // Call |HandlePopup| to show an infobar and check that the Presented 162 // histogram was recorded correctly. 163 const GURL test_url("https://popups.example.com"); 164 GetBlockedPopupTabHelper()->HandlePopup(test_url, web::Referrer()); 165 ASSERT_EQ(1U, GetInfobarManager()->infobar_count()); 166 histogram_tester.ExpectUniqueSample( 167 "Mobile.Messages.Confirm.Event.ConfirmInfobarTypeBlockPopups", 168 static_cast<base::HistogramBase::Sample>( 169 MobileMessagesConfirmInfobarEvents::Presented), 170 1); 171 172 // Dismiss the infobar and check that the Dismiss histogram was recorded 173 // correctly. 174 GetInfobarManager()->infobar_at(0)->delegate()->InfoBarDismissed(); 175 histogram_tester.ExpectBucketCount( 176 kInfobarTypeBlockPopupsEventHistogram, 177 static_cast<base::HistogramBase::Sample>( 178 MobileMessagesConfirmInfobarEvents::Dismissed), 179 1); 180} 181 182// Tests that the Infobar accept histogram is recorded correctly. 183TEST_F(BlockedPopupTabHelperTest, RecordAcceptMetrics) { 184 base::HistogramTester histogram_tester; 185 const GURL source_url("https://source-url"); 186 ASSERT_TRUE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url)); 187 188 // Block popup. 189 const GURL target_url("https://target-url"); 190 web::Referrer referrer(source_url, web::ReferrerPolicyDefault); 191 GetBlockedPopupTabHelper()->HandlePopup(target_url, referrer); 192 193 // Accept the infobar and check that the Accepted histogram was recorded 194 // correctly. 195 ASSERT_EQ(1U, GetInfobarManager()->infobar_count()); 196 auto* delegate = GetInfobarManager() 197 ->infobar_at(0) 198 ->delegate() 199 ->AsConfirmInfoBarDelegate(); 200 delegate->Accept(); 201 histogram_tester.ExpectBucketCount( 202 kInfobarTypeBlockPopupsEventHistogram, 203 static_cast<base::HistogramBase::Sample>( 204 MobileMessagesConfirmInfobarEvents::Accepted), 205 1); 206} 207