blob: e4a808911f9e8554d286ba64979482a1f7bc5636 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/omnibox/omnibox_view.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/infobars/confirm_infobar.h"
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "chrome/browser/ui/views/permissions/chip/permission_chip_view.h"
#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h"
#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/interaction/interactive_browser_test.h"
#include "chrome/test/permissions/permission_request_manager_test_api.h"
#include "components/infobars/content/content_infobar_manager.h"
#include "components/infobars/core/infobar.h"
#include "components/infobars/core/infobar_manager.h"
#include "components/omnibox/browser/test_location_bar_model.h"
#include "components/permissions/features.h"
#include "components/permissions/permission_actions_history.h"
#include "components/permissions/permission_uma_util.h"
#include "components/permissions/permission_util.h"
#include "components/permissions/permissions_client.h"
#include "components/permissions/request_type.h"
#include "components/permissions/test/mock_permission_ui_selector.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/interaction/interactive_test.h"
#include "ui/views/window/dialog_client_view.h"
#include "url/gurl.h"
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kWebContentsElementId);
const char kLocationBarView[] = "LocationBarView";
const auto QuietChipElementId = PermissionChipView::kElementIdForTesting;
const auto QuietBubbleAllowElementId =
views::DialogClientView::kOkButtonElementId;
const auto QuietBubbleElementId = ContentSettingBubbleContents::kMainElementId;
const auto InfobarElementId = ConfirmInfoBar::kInfoBarElementId;
using ::base::test::ScopedFeatureList;
using ::testing::ValuesIn;
class QuietPromptInteractiveUITest : public InteractiveBrowserTest {
public:
QuietPromptInteractiveUITest() {
https_server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::TYPE_HTTPS);
}
~QuietPromptInteractiveUITest() override = default;
void SetUpOnMainThread() override {
https_server()->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
https_server()->ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server()->InitializeAndListen());
host_resolver()->AddRule("*", "127.0.0.1");
content::SetupCrossSiteRedirector(https_server());
https_server()->StartAcceptingConnections();
test_api_ =
std::make_unique<test::PermissionRequestManagerTestApi>(browser());
// Override url in the omnibox to avoid test flakiness due to different port
// in the original url.
std::u16string url_override(u"https://www.test.com/");
OverrideVisibleUrlInLocationBar(url_override);
InteractiveBrowserTest::SetUpOnMainThread();
}
net::EmbeddedTestServer* https_server() { return https_server_.get(); }
GURL GetURL() {
return https_server()->GetURL("a.test", "/permissions/requests.html");
}
void SetUpCommandLine(base::CommandLine* command_line) override {
// Set a window's size to avoid pixel tests flakiness due to different
// widths of the omnibox.
command_line->AppendSwitchASCII(switches::kWindowSize,
base::StringPrintf("%d,%d", 800, 600));
InteractiveBrowserTest::SetUpCommandLine(command_line);
}
LocationBarView* GetLocationBarView() {
return BrowserView::GetBrowserViewForBrowser(browser())
->toolbar()
->location_bar();
}
void OverrideVisibleUrlInLocationBar(const std::u16string& text) {
OmniboxView* omnibox_view = GetLocationBarView()->GetOmniboxView();
raw_ptr<TestLocationBarModel> test_location_bar_model_ =
new TestLocationBarModel;
std::unique_ptr<LocationBarModel> location_bar_model(
test_location_bar_model_);
browser()->GetFeatures().swap_location_bar_models(&location_bar_model);
test_location_bar_model_->set_formatted_full_url(text);
// Normally the URL for display has portions elided. We aren't doing that in
// this case, because that is irrevelant for these tests.
test_location_bar_model_->set_url_for_display(text);
omnibox_view->Update();
}
using QuietUiReason = permissions::PermissionUiSelector::QuietUiReason;
using WarningReason = permissions::PermissionUiSelector::WarningReason;
void SetCannedUiDecision(std::optional<QuietUiReason> quiet_ui_reason,
std::optional<WarningReason> warning_reason) {
test_api_->manager()->set_permission_ui_selector_for_testing(
std::make_unique<MockPermissionUiSelector>(
permissions::PermissionUiSelector::Decision(quiet_ui_reason,
warning_reason)));
}
// Checks that the permission chip is visible and in the given mode.
// If `is_request` is false, should be in indicator mode instead.
auto CheckChipIsRequest(bool is_request) {
return CheckViewProperty(QuietChipElementId,
&PermissionChipView::GetIsRequestForTesting,
is_request);
}
auto CheckChipText(int id_string) {
return CheckViewProperty(QuietChipElementId, &PermissionChipView::GetText,
l10n_util::GetStringUTF16(id_string));
}
auto CheckQuietPromptMessage(int id_string) {
return CheckViewProperty(
QuietBubbleElementId,
&ContentSettingBubbleContents::get_message_for_test,
l10n_util::GetStringUTF16(id_string));
}
permissions::PermissionActionsHistory* GetPermissionActionsHistory() {
return permissions::PermissionsClient::Get()->GetPermissionActionsHistory(
browser()
->tab_strip_model()
->GetActiveWebContents()
->GetBrowserContext());
}
const base::HistogramTester& HistogramTester() const {
return histogram_tester_;
}
protected:
base::HistogramTester histogram_tester_;
private:
std::unique_ptr<net::EmbeddedTestServer> https_server_;
std::unique_ptr<test::PermissionRequestManagerTestApi> test_api_;
};
IN_PROC_BROWSER_TEST_F(QuietPromptInteractiveUITest,
CPSSv3Notification1DenyRequestChipTest) {
SetCannedUiDecision(QuietUiReason::kServicePredictedVeryUnlikelyGrant,
std::nullopt);
permissions::PermissionActionsHistory* permission_actions_history =
GetPermissionActionsHistory();
// 1 deny = Crowd Deny message.
permission_actions_history->RecordAction(
permissions::PermissionAction::DENIED,
permissions::RequestType::kNotifications,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
RunTestSequence(
InstrumentTab(kWebContentsElementId),
NavigateWebContents(kWebContentsElementId, GetURL()),
EnsureNotPresent(PermissionDashboardView::kDashboardElementId),
EnsureNotPresent(QuietChipElementId),
ExecuteJs(kWebContentsElementId, "requestNotification"),
WaitForShow(QuietChipElementId), CheckChipIsRequest(true),
CheckChipText(IDS_NOTIFICATIONS_QUIET_PERMISSION_BUBBLE_TITLE),
NameView(kLocationBarView, GetLocationBarView()),
SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
"Screenshot not supported in all test modes."),
Screenshot(kLocationBarView, "RequestChip", "5875965"));
}
IN_PROC_BROWSER_TEST_F(QuietPromptInteractiveUITest,
CPSSv3Notification1DenyPromptTest) {
SetCannedUiDecision(QuietUiReason::kServicePredictedVeryUnlikelyGrant,
std::nullopt);
permissions::PermissionActionsHistory* permission_actions_history =
GetPermissionActionsHistory();
// 1 deny = Crowd Deny message.
permission_actions_history->RecordAction(
permissions::PermissionAction::DENIED,
permissions::RequestType::kNotifications,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
RunTestSequence(
InstrumentTab(kWebContentsElementId),
NavigateWebContents(kWebContentsElementId, GetURL()),
EnsureNotPresent(PermissionDashboardView::kDashboardElementId),
EnsureNotPresent(QuietChipElementId),
ExecuteJs(kWebContentsElementId, "requestNotification"),
WaitForShow(QuietChipElementId), CheckChipIsRequest(true),
CheckChipText(IDS_NOTIFICATIONS_QUIET_PERMISSION_BUBBLE_TITLE),
EnsureNotPresent(QuietBubbleElementId), PressButton(QuietChipElementId),
WaitForShow(QuietBubbleElementId),
CheckQuietPromptMessage(
IDS_NOTIFICATIONS_QUIET_PERMISSION_BUBBLE_PREDICTION_SERVICE_DESCRIPTION),
SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
"Screenshot not supported in all test modes."),
ScreenshotSurface(QuietBubbleElementId, "QuietPromptPopupBubble",
"5934206"));
}
IN_PROC_BROWSER_TEST_F(QuietPromptInteractiveUITest,
CPSSv3Notification5DeniesPromptTest) {
SetCannedUiDecision(QuietUiReason::kServicePredictedVeryUnlikelyGrant,
std::nullopt);
permissions::PermissionActionsHistory* permission_actions_history =
GetPermissionActionsHistory();
// 5 denies = CPSS message.
for (int i = 0; i < 5; i++) {
permission_actions_history->RecordAction(
permissions::PermissionAction::DENIED,
permissions::RequestType::kNotifications,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
}
RunTestSequence(
InstrumentTab(kWebContentsElementId),
NavigateWebContents(kWebContentsElementId, GetURL()),
EnsureNotPresent(PermissionDashboardView::kDashboardElementId),
EnsureNotPresent(QuietChipElementId),
ExecuteJs(kWebContentsElementId, "requestNotification"),
WaitForShow(QuietChipElementId), CheckChipIsRequest(true),
CheckChipText(IDS_NOTIFICATIONS_QUIET_PERMISSION_BUBBLE_TITLE),
EnsureNotPresent(QuietBubbleElementId), PressButton(QuietChipElementId),
WaitForShow(QuietBubbleElementId),
CheckQuietPromptMessage(
IDS_NOTIFICATIONS_QUIET_PERMISSION_BUBBLE_PREDICTION_SERVICE_DESCRIPTION),
SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
"Screenshot not supported in all test modes."),
ScreenshotSurface(QuietBubbleElementId, "QuietPromptPopupBubble",
"5875965"));
}
IN_PROC_BROWSER_TEST_F(QuietPromptInteractiveUITest,
CPSSv3Geolocation1DenyRequestChipTest) {
SetCannedUiDecision(QuietUiReason::kServicePredictedVeryUnlikelyGrant,
std::nullopt);
permissions::PermissionActionsHistory* permission_actions_history =
GetPermissionActionsHistory();
// 1 deny = Crowd Deny message.
permission_actions_history->RecordAction(
permissions::PermissionAction::DENIED,
permissions::RequestType::kGeolocation,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
RunTestSequence(
InstrumentTab(kWebContentsElementId),
NavigateWebContents(kWebContentsElementId, GetURL()),
EnsureNotPresent(PermissionDashboardView::kDashboardElementId),
EnsureNotPresent(QuietChipElementId),
ExecuteJs(kWebContentsElementId, "requestLocation"),
WaitForShow(QuietChipElementId), CheckChipIsRequest(true),
CheckChipText(IDS_GEOLOCATION_QUIET_PERMISSION_BUBBLE_TITLE),
NameView(kLocationBarView, GetLocationBarView()),
SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
"Screenshot not supported in all test modes."),
Screenshot(kLocationBarView, "RequestChip", "5875965"));
}
IN_PROC_BROWSER_TEST_F(QuietPromptInteractiveUITest,
CPSSv3Geolocation1DenyPromptTest) {
SetCannedUiDecision(QuietUiReason::kServicePredictedVeryUnlikelyGrant,
std::nullopt);
permissions::PermissionActionsHistory* permission_actions_history =
GetPermissionActionsHistory();
// 1 deny = Crowd Deny message.
permission_actions_history->RecordAction(
permissions::PermissionAction::DENIED,
permissions::RequestType::kGeolocation,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
RunTestSequence(
InstrumentTab(kWebContentsElementId),
NavigateWebContents(kWebContentsElementId, GetURL()),
EnsureNotPresent(PermissionDashboardView::kDashboardElementId),
EnsureNotPresent(QuietChipElementId),
ExecuteJs(kWebContentsElementId, "requestLocation"),
WaitForShow(QuietChipElementId), CheckChipIsRequest(true),
CheckChipText(IDS_GEOLOCATION_QUIET_PERMISSION_BUBBLE_TITLE),
EnsureNotPresent(QuietBubbleElementId), PressButton(QuietChipElementId),
WaitForShow(QuietBubbleElementId),
CheckQuietPromptMessage(
IDS_GEOLOCATION_QUIET_PERMISSION_BUBBLE_PREDICTION_SERVICE_DESCRIPTION),
SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
"Screenshot not supported in all test modes."),
ScreenshotSurface(QuietBubbleElementId, "QuietPromptPopupBubble",
"5934206"));
}
IN_PROC_BROWSER_TEST_F(QuietPromptInteractiveUITest,
CPSSv3Geolocation5DeniesPromptTest) {
SetCannedUiDecision(QuietUiReason::kServicePredictedVeryUnlikelyGrant,
std::nullopt);
permissions::PermissionActionsHistory* permission_actions_history =
GetPermissionActionsHistory();
// 5 denies = CPSS message.
for (int i = 0; i < 5; i++) {
permission_actions_history->RecordAction(
permissions::PermissionAction::DENIED,
permissions::RequestType::kGeolocation,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
}
RunTestSequence(
InstrumentTab(kWebContentsElementId),
NavigateWebContents(kWebContentsElementId, GetURL()),
EnsureNotPresent(PermissionDashboardView::kDashboardElementId),
EnsureNotPresent(QuietChipElementId),
ExecuteJs(kWebContentsElementId, "requestLocation"),
WaitForShow(QuietChipElementId), CheckChipIsRequest(true),
CheckChipText(IDS_GEOLOCATION_QUIET_PERMISSION_BUBBLE_TITLE),
EnsureNotPresent(QuietBubbleElementId), PressButton(QuietChipElementId),
WaitForShow(QuietBubbleElementId),
CheckQuietPromptMessage(
IDS_GEOLOCATION_QUIET_PERMISSION_BUBBLE_PREDICTION_SERVICE_DESCRIPTION),
SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
"Screenshot not supported in all test modes."),
ScreenshotSurface(QuietBubbleElementId, "QuietPromptPopupBubble",
"5875965"));
}
struct QuietPromptInfoBarTestCase {
std::string test_name;
std::string js;
bool should_show_infobar;
};
class QuietPromptInteractiveParamUITest
: public QuietPromptInteractiveUITest,
public testing::WithParamInterface<QuietPromptInfoBarTestCase> {
public:
void SetUp() override {
feature_list_->InitWithFeatures(
{permissions::features::kPermissionPromiseLifetimeModulation},
/*disabled_features=*/{});
QuietPromptInteractiveUITest::SetUp();
}
private:
std::unique_ptr<ScopedFeatureList> feature_list_ =
std::make_unique<ScopedFeatureList>();
};
INSTANTIATE_TEST_SUITE_P(
PermissionChangeListenerTests,
QuietPromptInteractiveParamUITest,
ValuesIn<QuietPromptInfoBarTestCase>({
{"NotificationWithoutInfobar",
"() => {"
" registerDummyPermissionChangeListener(\"notifications\")"
" .then(()=> {"
" requestNotification();"
" });"
"}",
false},
{"NotificationWithInfobar", "requestNotification", true},
{"LocationWithoutInfobar",
"() => {"
" registerDummyPermissionChangeListener(\"geolocation\")"
" .then(()=> {"
" requestLocation();"
" });"
"}",
false},
{"GeolocationWithInfobar", "requestLocation", true},
}),
/*name_generator=*/
[](const testing::TestParamInfo<
QuietPromptInteractiveParamUITest::ParamType>& info) {
return info.param.test_name;
});
IN_PROC_BROWSER_TEST_P(QuietPromptInteractiveParamUITest,
AllowQuietPromptAndMaybeShowInfobar) {
SetCannedUiDecision(QuietUiReason::kServicePredictedVeryUnlikelyGrant,
std::nullopt);
auto [test_name, js, should_show] = GetParam();
RunTestSequence(
InstrumentTab(kWebContentsElementId),
NavigateWebContents(kWebContentsElementId, GetURL()),
ExecuteJs(kWebContentsElementId, js), WaitForShow(QuietChipElementId),
CheckChipIsRequest(true), PressButton(QuietChipElementId),
WaitForShow(QuietBubbleElementId), PressButton(QuietBubbleAllowElementId),
WaitForHide(QuietBubbleElementId), WaitForShow(QuietChipElementId),
WaitForHide(QuietChipElementId),
If([should_show]() { return should_show; },
Then(WaitForShow(InfobarElementId)),
Else(EnsureNotPresent(InfobarElementId))),
Do([&] {
histogram_tester_.ExpectBucketCount(
"Permissions.QuietPrompt.Preignore.PageReloadInfoBar", should_show,
1);
}),
NameView(kLocationBarView, GetLocationBarView()),
SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
"Screenshot not supported in all test modes."),
Screenshot(kLocationBarView, test_name, "6768828"));
}