blob: da898af559598930b7248290e7e2c9089c23272d [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <algorithm>
#include "base/containers/to_vector.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/strcat.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ui/views/content_setting_bubble_contents.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
#include "chrome/browser/ui/views/permissions/chip/chip_controller.h"
#include "chrome/browser/ui/views/permissions/permission_prompt_chip.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/grit/generated_resources.h"
#include "components/infobars/content/content_infobar_manager.h"
#include "components/infobars/core/infobar_manager.h"
#include "components/permissions/features.h"
#include "components/permissions/permission_prompt.h"
#include "components/permissions/permission_request_enums.h"
#include "components/permissions/permission_request_manager.h"
#include "components/permissions/prediction_service/permission_ui_selector.h"
#include "components/permissions/test/enums_to_string.h"
#include "components/permissions/test/mock_permission_request.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/base_event_utils.h"
#include "ui/gfx/animation/animation_test_api.h"
#include "ui/views/test/ax_event_counter.h"
#include "ui/views/test/button_test_api.h"
namespace {
using ::content::RenderFrameHost;
using ::content::WebContents;
using QuietUiReason = ::permissions::PermissionUiSelector::QuietUiReason;
using ::base::test::ScopedFeatureList;
using ::infobars::InfoBar;
using ::infobars::InfoBarManager;
using ::testing::Combine;
using ::testing::Values;
class InfoBarObserver : public InfoBarManager::Observer {
public:
explicit InfoBarObserver(WebContents* web_contents)
: web_contents_(web_contents) {
infobars::ContentInfoBarManager* infobar_manager =
infobars::ContentInfoBarManager::FromWebContents(web_contents);
CHECK(infobar_manager != nullptr);
infobar_manager->AddObserver(this);
}
~InfoBarObserver() override {
infobars::ContentInfoBarManager* infobar_manager =
infobars::ContentInfoBarManager::FromWebContents(web_contents_);
CHECK(infobar_manager != nullptr);
infobar_manager->RemoveObserver(this);
}
void OnInfoBarAdded(InfoBar* infobar) override { info_bar_added_ = true; }
void OnInfoBarRemoved(InfoBar* infobar, bool animate) override {}
void OnInfoBarReplaced(InfoBar* old_infobar, InfoBar* new_infobar) override {}
void OnManagerWillBeDestroyed(InfoBarManager* manager) override {}
bool info_bar_added_ = false;
private:
raw_ptr<WebContents> web_contents_;
};
} // namespace
namespace test {
class MockPermissionRequestManager
: public permissions::PermissionRequestManager {
private:
explicit MockPermissionRequestManager(
const GURL& origin,
const std::vector<permissions::RequestType> request_types,
bool with_gesture,
WebContents* web_contents)
: MockPermissionRequestManager(origin,
request_types,
with_gesture,
/*quiet_ui_reason=*/std::nullopt,
web_contents) {}
explicit MockPermissionRequestManager(
const GURL& origin,
const std::vector<permissions::RequestType> request_types,
bool with_gesture,
std::optional<QuietUiReason> quiet_ui_reason,
WebContents* web_contents)
: permissions::PermissionRequestManager(web_contents),
quiet_ui_reason_(quiet_ui_reason),
web_contents_(web_contents) {
requests_ = base::ToVector(
request_types,
[&](auto request_type)
-> std::unique_ptr<permissions::PermissionRequest> {
return std::make_unique<permissions::MockPermissionRequest>(
origin, request_type,
with_gesture
? permissions::PermissionRequestGestureType::GESTURE
: permissions::PermissionRequestGestureType::NO_GESTURE);
});
raw_requests_ = base::ToVector(
requests_,
[](const auto& request)
-> raw_ptr<permissions::PermissionRequest, VectorExperimental> {
return request.get();
});
requests_[0]->set_requesting_frame_id(
web_contents->GetPrimaryMainFrame()->GetGlobalId());
ON_CALL(*this, Dismiss).WillByDefault([]() { NOTREACHED(); });
ON_CALL(*this, Deny).WillByDefault([]() { NOTREACHED(); });
ON_CALL(*this, Ignore).WillByDefault([]() { NOTREACHED(); });
ON_CALL(*this, Accept).WillByDefault([]() { NOTREACHED(); });
ON_CALL(*this, PreIgnoreQuietPrompt).WillByDefault([]() { NOTREACHED(); });
ON_CALL(*this, FinalizeCurrentRequests).WillByDefault([]() {
NOTREACHED();
});
}
public:
~MockPermissionRequestManager() override { requests_.clear(); }
static MockPermissionRequestManager* CreateForWebContents(
const GURL& origin,
const std::vector<permissions::RequestType> request_types,
bool with_gesture,
WebContents* web_contents) {
web_contents->SetUserData(
UserDataKey(),
base::WrapUnique(static_cast<PermissionRequestManager*>(
new MockPermissionRequestManager(origin, request_types,
with_gesture, web_contents))));
return static_cast<MockPermissionRequestManager*>(
permissions::PermissionRequestManager::FromWebContents(web_contents));
}
static MockPermissionRequestManager* CreateForWebContents(
const GURL& origin,
const std::vector<permissions::RequestType> request_types,
bool with_gesture,
std::optional<QuietUiReason> quiet_ui_reason,
WebContents* web_contents) {
web_contents->SetUserData(
UserDataKey(), base::WrapUnique(static_cast<PermissionRequestManager*>(
new MockPermissionRequestManager(
origin, request_types, with_gesture,
quiet_ui_reason, web_contents))));
return static_cast<MockPermissionRequestManager*>(
permissions::PermissionRequestManager::FromWebContents(web_contents));
}
const std::vector<std::unique_ptr<permissions::PermissionRequest>>& Requests()
override {
return requests_;
}
GURL GetRequestingOrigin() const override {
return raw_requests_.front()->requesting_origin();
}
GURL GetEmbeddingOrigin() const override {
return GURL("https://embedder.example.com");
}
MOCK_METHOD(void, Dismiss, (), (override));
MOCK_METHOD(void, Deny, (), (override));
MOCK_METHOD(void, Ignore, (), (override));
MOCK_METHOD(void, Accept, (), (override));
MOCK_METHOD(void, PreIgnoreQuietPrompt, (), (override));
MOCK_METHOD(void, FinalizeCurrentRequests, (), (override));
void OpenHelpCenterLink(const ui::Event& event) override {}
void SetManageClicked() override { requests_.clear(); }
void SetLearnMoreClicked() override { requests_.clear(); }
void SetHatsShownCallback(base::OnceCallback<void()> callback) override {}
bool RecreateView() override { return false; }
const permissions::PermissionPrompt* GetCurrentPrompt() const override {
return nullptr;
}
bool WasCurrentRequestAlreadyDisplayed() override {
return was_current_request_already_displayed_;
}
bool ShouldDropCurrentRequestIfCannotShowQuietly() const override {
return false;
}
bool ShouldCurrentRequestUseQuietUI() const override {
return quiet_ui_reason_.has_value();
}
std::optional<QuietUiReason> ReasonForUsingQuietUi() const override {
return quiet_ui_reason_;
}
void SetDismissOnTabClose() override {}
void SetPromptShown() override {}
void SetDecisionTime() override {}
base::WeakPtr<permissions::PermissionPrompt::Delegate> GetWeakPtr() override {
return weak_factory_.GetWeakPtr();
}
WebContents* GetAssociatedWebContents() override { return web_contents_; }
bool IsRequestInProgress() { return !requests_.empty(); }
void SetAlreadyDisplayed() { was_current_request_already_displayed_ = true; }
void ClearRequests() { requests_.clear(); }
void SetView(std::unique_ptr<permissions::PermissionPrompt> view) {
view_ = std::move(view);
}
private:
std::vector<raw_ptr<permissions::PermissionRequest, VectorExperimental>>
raw_requests_;
bool was_current_request_already_displayed_ = false;
std::optional<QuietUiReason> quiet_ui_reason_;
raw_ptr<WebContents> web_contents_;
base::WeakPtrFactory<MockPermissionRequestManager> weak_factory_{this};
};
} // namespace test
class PermissionChipUnitTest : public TestWithBrowserView {
public:
PermissionChipUnitTest()
: TestWithBrowserView(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
animation_mode_reset_(gfx::AnimationTestApi::SetRichAnimationRenderMode(
gfx::Animation::RichAnimationRenderMode::FORCE_ENABLED)) {}
PermissionChipUnitTest(const PermissionChipUnitTest&) = delete;
PermissionChipUnitTest& operator=(const PermissionChipUnitTest&) = delete;
void SetUp() override {
feature_list_->InitWithFeatures(
/*enabledabled_features=*/{},
/*disabled_features=*/{
permissions::features::kPermissionPromiseLifetimeModulation});
TestWithBrowserView::SetUp();
AddTab(browser(), GURL("http://a.com"));
web_contents_ = browser()->tab_strip_model()->GetWebContentsAt(0);
}
void ClickOnChip(ChipController* controller) {
views::test::ButtonTestApi(controller->chip())
.NotifyClick(ui::MouseEvent(ui::EventType::kMousePressed, gfx::Point(),
gfx::Point(), ui::EventTimeForNow(),
ui::EF_LEFT_MOUSE_BUTTON, 0));
base::RunLoop().RunUntilIdle();
}
void ClickOnAcceptPermissionRequestQuietChip(ChipController* controller) {
auto* bubble = controller->GetContentSettingBubbleContentsForTesting();
EXPECT_NE(bubble, nullptr);
bubble->AsDialogDelegate()->Accept();
}
raw_ptr<WebContents, DanglingUntriaged> web_contents_;
// Some of these tests rely on animation being enabled. This forces
// animation on even if it's turned off in the OS.
gfx::AnimationTestApi::RenderModeResetter animation_mode_reset_;
base::TimeDelta kChipCollapseDuration = base::Seconds(12);
base::TimeDelta kNormalChipDismissDuration = base::Seconds(6);
base::TimeDelta kQuietChipDismissDuration = base::Seconds(18);
base::TimeDelta kLongerThanAllTimersDuration = base::Seconds(50);
protected:
std::unique_ptr<ScopedFeatureList> feature_list_ =
std::make_unique<ScopedFeatureList>();
};
TEST_F(PermissionChipUnitTest, AlreadyDisplayedRequestTest) {
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {permissions::RequestType::kNotifications},
false, web_contents_);
delegate.SetAlreadyDisplayed();
EXPECT_TRUE(delegate.WasCurrentRequestAlreadyDisplayed());
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt.get_chip_controller_for_testing();
EXPECT_FALSE(chip_controller->IsBubbleShowing());
// The permission request was already displayed, but the dismiss timer will
// not be triggered directly after the chip is displayed because of the popup
// bubble.
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
// The default dismiss timer is 6 seconds. The chip should be still displayed
// after 5 seconds.
task_environment()->AdvanceClock(kNormalChipDismissDuration -
base::Seconds(1));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(delegate.IsRequestInProgress());
// Wait 2 more seconds for the dismiss timer to finish.
task_environment()->AdvanceClock(base::Seconds(2));
base::RunLoop().RunUntilIdle();
// All chips are feature auto popup bubble. They should not resolve a prompt
// automatically.
EXPECT_TRUE(delegate.IsRequestInProgress());
delegate.ClearRequests();
}
TEST_F(PermissionChipUnitTest, AccessibleName) {
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {permissions::RequestType::kNotifications},
false, web_contents_);
delegate.SetAlreadyDisplayed();
EXPECT_TRUE(delegate.WasCurrentRequestAlreadyDisplayed());
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt.get_chip_controller_for_testing();
AddTab(browser(), GURL("http://a.com"));
std::u16string tab_title = browser()->GetTitleForTab(0);
std::u16string permission_title = l10n_util::GetStringFUTF16(
IDS_TAB_AX_LABEL_PERMISSION_REQUESTED_FORMAT, tab_title);
chip_controller->ShowPermissionUi(delegate.GetWeakPtr());
chip_controller->AnimateExpand();
ui::AXNodeData data;
browser()
->GetBrowserView()
.tab_strip_view()
->GetTabAnchorViewAt(0)
->GetViewAccessibility()
.GetAccessibleNodeData(&data);
EXPECT_TRUE(chip_controller->IsPermissionPromptChipVisible());
EXPECT_EQ(permission_title,
data.GetString16Attribute(ax::mojom::StringAttribute::kName));
chip_controller->HideChip();
data = ui::AXNodeData();
browser()
->GetBrowserView()
.tab_strip_view()
->GetTabAnchorViewAt(0)
->GetViewAccessibility()
.GetAccessibleNodeData(&data);
EXPECT_FALSE(chip_controller->IsPermissionPromptChipVisible());
EXPECT_EQ(tab_title,
data.GetString16Attribute(ax::mojom::StringAttribute::kName));
delegate.ClearRequests();
}
TEST_F(PermissionChipUnitTest, ClickOnRequestChipTest) {
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {permissions::RequestType::kNotifications},
true, web_contents_);
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt.get_chip_controller_for_testing();
// Due to animation issue, the collapse timer will not be started.
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
// Animation does not work. Most probably it is unit tests limitations.
// `chip.is_fully_collapsed()` will not work as well.
EXPECT_TRUE(chip_controller->IsAnimating());
chip_controller->stop_animation_for_test();
EXPECT_FALSE(chip_controller->IsAnimating());
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
task_environment()->AdvanceClock(kLongerThanAllTimersDuration);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(delegate.IsRequestInProgress());
// Bubble is showing automatically.
EXPECT_TRUE(chip_controller->IsBubbleShowing());
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
// A click on the chip hides the popup bubble and resolves a permission
// request.
EXPECT_CALL(delegate, Dismiss()).WillOnce([&delegate]() {
delegate.ClearRequests();
});
ClickOnChip(chip_controller);
EXPECT_FALSE(chip_controller->IsBubbleShowing());
EXPECT_FALSE(delegate.IsRequestInProgress());
}
TEST_F(PermissionChipUnitTest, DisplayQuietChipNoAbusiveTest) {
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {permissions::RequestType::kNotifications},
true, QuietUiReason::kEnabledInPrefs, web_contents_);
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt.get_chip_controller_for_testing();
EXPECT_FALSE(chip_controller->IsBubbleShowing());
// Due to animation issue, the collapse timer will not be started.
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
// Animation does not work. Most probably it is unit tests limitations.
// `chip.is_fully_collapsed()` will not work as well.
EXPECT_TRUE(chip_controller->IsAnimating());
chip_controller->stop_animation_for_test();
EXPECT_FALSE(chip_controller->IsAnimating());
EXPECT_TRUE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
task_environment()->AdvanceClock(kChipCollapseDuration - base::Seconds(1));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(delegate.IsRequestInProgress());
EXPECT_TRUE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
EXPECT_TRUE(chip_controller->chip()->GetVisible());
// Wait 2 more seconds for the collapse timer to finish.
task_environment()->AdvanceClock(base::Seconds(2));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(delegate.IsRequestInProgress());
// The collapse timer is fired and the dismiss timer is started.
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_TRUE(chip_controller->is_dismiss_timer_running_for_testing());
EXPECT_TRUE(chip_controller->chip()->GetVisible());
EXPECT_CALL(delegate, Ignore()).WillOnce([&delegate]() {
delegate.ClearRequests();
});
task_environment()->AdvanceClock(kNormalChipDismissDuration +
base::Seconds(1));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(chip_controller->chip()->GetVisible());
EXPECT_FALSE(delegate.IsRequestInProgress());
}
TEST_F(PermissionChipUnitTest, ClickOnQuietChipNoAbusiveTest) {
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {permissions::RequestType::kNotifications},
true, QuietUiReason::kEnabledInPrefs, web_contents_);
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt.get_chip_controller_for_testing();
chip_controller->stop_animation_for_test();
// Open a permission popup bubble.
ClickOnChip(chip_controller);
EXPECT_TRUE(chip_controller->IsBubbleShowing());
// Collapse timer was restarted.
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
// After 30 seconds the permission prompt popup bubble should still be
// visible.
task_environment()->AdvanceClock(kLongerThanAllTimersDuration);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(chip_controller->IsBubbleShowing());
EXPECT_TRUE(delegate.IsRequestInProgress());
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
EXPECT_CALL(delegate, Dismiss()).WillOnce([&delegate]() {
delegate.ClearRequests();
});
// The seconds click on the chip hides the popup bubble.
ClickOnChip(chip_controller);
EXPECT_FALSE(chip_controller->IsBubbleShowing());
EXPECT_FALSE(delegate.IsRequestInProgress());
}
TEST_F(PermissionChipUnitTest, DisplayQuietChipAbusiveTest) {
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {permissions::RequestType::kNotifications},
true, QuietUiReason::kTriggeredDueToAbusiveRequests, web_contents_);
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt.get_chip_controller_for_testing();
EXPECT_FALSE(chip_controller->IsBubbleShowing());
// The quiet abusive chip does not have animation and will start the
// dismiss timer immediately after displaying.
EXPECT_FALSE(chip_controller->IsAnimating());
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_TRUE(chip_controller->is_dismiss_timer_running_for_testing());
// The dismiss timer is 18 seconds by default. After 17 seconds, the
// chip should be there.
task_environment()->AdvanceClock(kQuietChipDismissDuration -
base::Seconds(1));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(delegate.IsRequestInProgress());
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_TRUE(chip_controller->is_dismiss_timer_running_for_testing());
EXPECT_TRUE(chip_controller->chip()->GetVisible());
EXPECT_CALL(delegate, Ignore()).WillOnce([&delegate]() {
delegate.ClearRequests();
});
// Wait 2 more seconds for the dismiss timer to finish.
task_environment()->AdvanceClock(base::Seconds(2));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(chip_controller->chip()->GetVisible());
EXPECT_FALSE(delegate.IsRequestInProgress());
}
TEST_F(PermissionChipUnitTest, ClickOnQuietChipAbusiveTest) {
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {permissions::RequestType::kNotifications},
true, QuietUiReason::kTriggeredDueToAbusiveRequests, web_contents_);
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt.get_chip_controller_for_testing();
// Open a permission popup bubble.
ClickOnChip(chip_controller);
EXPECT_TRUE(chip_controller->IsBubbleShowing());
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
task_environment()->AdvanceClock(kLongerThanAllTimersDuration);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(chip_controller->is_collapse_timer_running_for_testing());
EXPECT_FALSE(chip_controller->is_dismiss_timer_running_for_testing());
EXPECT_TRUE(delegate.IsRequestInProgress());
EXPECT_TRUE(chip_controller->IsBubbleShowing());
EXPECT_CALL(delegate, Dismiss()).WillOnce([&delegate]() {
delegate.ClearRequests();
});
// The second click on the chip hides the prompt.
ClickOnChip(chip_controller);
EXPECT_FALSE(chip_controller->IsBubbleShowing());
EXPECT_FALSE(delegate.IsRequestInProgress());
}
class PermissionPromiseLifetimeModulationTest : public PermissionChipUnitTest {
public:
void SetUp() override {
feature_list_->InitWithFeatures(
{permissions::features::kPermissionPromiseLifetimeModulation},
/*disabled_features=*/{});
TestWithBrowserView::SetUp();
AddTab(browser(), GURL("http://a.com"));
web_contents_ = browser()->tab_strip_model()->GetWebContentsAt(0);
}
};
TEST_F(PermissionPromiseLifetimeModulationTest,
NotificationsRequestsNotPreignoredForNonQuietPrompts) {
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {permissions::RequestType::kNotifications},
true,
/*quiet_ui_reason=*/std::nullopt, web_contents_);
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
EXPECT_TRUE(delegate.IsRequestInProgress());
delegate.ClearRequests();
}
TEST_F(PermissionPromiseLifetimeModulationTest,
GeolocationRequestsNotPreignoredForNonQuietPrompts) {
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {permissions::RequestType::kGeolocation},
true, /*quiet_ui_reason=*/std::nullopt, web_contents_);
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
EXPECT_TRUE(delegate.IsRequestInProgress());
delegate.ClearRequests();
}
template <class ParamType>
std::string TestNameGenerator(const testing::TestParamInfo<ParamType>& info) {
return base::StrCat({test::ToString(std::get<0>(info.param)), "For",
test::ToString(std::get<1>(info.param))});
}
using QuietUiReasonsTestCase =
std::tuple<permissions::RequestType, QuietUiReason>;
class QuietUiPreignoreTest
: public PermissionPromiseLifetimeModulationTest,
public testing::WithParamInterface<QuietUiReasonsTestCase> {};
INSTANTIATE_TEST_SUITE_P(
TestCases,
QuietUiPreignoreTest,
Combine(Values(permissions::RequestType::kGeolocation,
permissions::RequestType::kNotifications),
Values(QuietUiReason::kEnabledInPrefs,
QuietUiReason::kTriggeredByCrowdDeny,
QuietUiReason::kTriggeredDueToAbusiveRequests,
QuietUiReason::kTriggeredDueToAbusiveContent,
QuietUiReason::kServicePredictedVeryUnlikelyGrant,
QuietUiReason::kOnDevicePredictedVeryUnlikelyGrant,
QuietUiReason::kTriggeredDueToDisruptiveBehavior)),
/*name_generator=*/
TestNameGenerator<QuietUiPreignoreTest::ParamType>);
TEST_P(QuietUiPreignoreTest,
PermissionRequestsForAllQuietUiReasonsGetPreignored) {
auto [request_type, quiet_ui_reason] = GetParam();
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {request_type}, true, quiet_ui_reason,
web_contents_);
EXPECT_CALL(delegate, PreIgnoreQuietPrompt()).WillOnce([&delegate]() {
return delegate.PermissionRequestManager::PreIgnoreQuietPrompt();
});
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
delegate.ClearRequests();
}
class QuietUiAbusiveRequestsTest
: public PermissionPromiseLifetimeModulationTest,
public testing::WithParamInterface<QuietUiReasonsTestCase> {};
INSTANTIATE_TEST_SUITE_P(
TestCases,
QuietUiAbusiveRequestsTest,
Combine(Values(permissions::RequestType::kNotifications),
Values(QuietUiReason::kTriggeredDueToAbusiveRequests,
QuietUiReason::kTriggeredDueToAbusiveContent,
QuietUiReason::kTriggeredDueToDisruptiveBehavior)),
/*name_generator=*/
TestNameGenerator<QuietUiAbusiveRequestsTest::ParamType>);
TEST_P(QuietUiAbusiveRequestsTest, GetsDenied) {
auto [request_type, quiet_ui_reason] = GetParam();
InfoBarObserver infobar_observer(web_contents_);
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {request_type}, true, quiet_ui_reason,
web_contents_);
EXPECT_CALL(delegate, PreIgnoreQuietPrompt()).WillOnce([&delegate]() {
return delegate.PermissionRequestManager::PreIgnoreQuietPrompt();
});
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt.get_chip_controller_for_testing();
// Open a permission popup bubble.
ClickOnChip(chip_controller);
ASSERT_TRUE(chip_controller->IsBubbleShowing());
EXPECT_CALL(delegate, Deny()).WillOnce([&delegate]() {
delegate.ClearRequests();
});
EXPECT_TRUE(delegate.IsRequestInProgress());
ClickOnAcceptPermissionRequestQuietChip(chip_controller);
EXPECT_FALSE(delegate.IsRequestInProgress());
}
class QuietUiNonAbusiveRequestsTest
: public PermissionPromiseLifetimeModulationTest,
public testing::WithParamInterface<QuietUiReasonsTestCase> {};
INSTANTIATE_TEST_SUITE_P(
TestCases,
QuietUiNonAbusiveRequestsTest,
Combine(Values(permissions::RequestType::kGeolocation,
permissions::RequestType::kNotifications),
Values(QuietUiReason::kEnabledInPrefs)),
/*name_generator=*/
TestNameGenerator<QuietUiNonAbusiveRequestsTest::ParamType>);
TEST_P(QuietUiNonAbusiveRequestsTest, GetsAccepted) {
auto [request_type, quiet_ui_reason] = GetParam();
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {request_type}, true, quiet_ui_reason,
web_contents_);
EXPECT_CALL(delegate, PreIgnoreQuietPrompt()).WillOnce([&delegate]() {
return delegate.PermissionRequestManager::PreIgnoreQuietPrompt();
});
PermissionPromptChip chip_prompt(browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt.get_chip_controller_for_testing();
// Open a permission popup bubble.
ClickOnChip(chip_controller);
ASSERT_TRUE(chip_controller->IsBubbleShowing());
EXPECT_CALL(delegate, Accept()).WillOnce([&delegate]() {
delegate.ClearRequests();
});
EXPECT_TRUE(delegate.IsRequestInProgress());
ClickOnAcceptPermissionRequestQuietChip(chip_controller);
EXPECT_FALSE(delegate.IsRequestInProgress());
}
class InfobarTest
: public PermissionPromiseLifetimeModulationTest,
public testing::WithParamInterface<permissions::RequestType> {};
INSTANTIATE_TEST_SUITE_P(
TestCases,
InfobarTest,
testing::ValuesIn<permissions::RequestType>({
permissions::RequestType::kNotifications,
permissions::RequestType::kGeolocation,
}),
/*name_generator=*/
[](const testing::TestParamInfo<InfobarTest::ParamType>& info) {
return std::string(test::ToString(info.param));
});
TEST_P(InfobarTest, ShowInfobarIfNecessary) {
base::HistogramTester histogram_tester;
InfoBarObserver infobar_observer(web_contents_);
auto& delegate = *test::MockPermissionRequestManager::CreateForWebContents(
GURL("https://test.origin"), {GetParam()}, true,
QuietUiReason::kEnabledInPrefs, web_contents_);
EXPECT_CALL(delegate, PreIgnoreQuietPrompt()).WillOnce([&delegate]() {
return delegate.PermissionRequestManager::PreIgnoreQuietPrompt();
});
auto chip_prompt = std::make_unique<PermissionPromptChip>(
browser(), web_contents_, &delegate);
ChipController* chip_controller =
chip_prompt->get_chip_controller_for_testing();
delegate.SetView(std::move(chip_prompt));
// Open a permission popup bubble.
ClickOnChip(chip_controller);
ASSERT_TRUE(chip_controller->IsBubbleShowing());
EXPECT_CALL(delegate, Accept()).WillOnce([&delegate]() {
delegate.PermissionRequestManager::Accept();
});
EXPECT_CALL(delegate, FinalizeCurrentRequests()).WillOnce([&delegate]() {
delegate.PermissionRequestManager::FinalizeCurrentRequests();
});
EXPECT_TRUE(delegate.IsRequestInProgress());
ClickOnAcceptPermissionRequestQuietChip(chip_controller);
EXPECT_FALSE(delegate.IsRequestInProgress());
EXPECT_EQ(infobar_observer.info_bar_added_, true);
histogram_tester.ExpectBucketCount(
"Permissions.QuietPrompt.Preignore.PageReloadInfoBar", true, 1);
histogram_tester.ExpectBucketCount(
"Permissions.QuietPrompt.Preignore.PageReloadInfoBar", false, 0);
}