blob: ada656666a37964b7be8803bb6c8f3ec346da368 [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 "chrome/browser/privacy_sandbox/privacy_sandbox_service.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/interaction/interactive_browser_test.h"
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/canonical_topic.h"
#include "components/privacy_sandbox/privacy_sandbox_features.h"
#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
#include "content/public/test/browser_test.h"
#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif
namespace {
using DeepQuery = WebContentsInteractionTestUtil::DeepQuery;
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kPrivacySandboxTopicsElementId);
DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kIronCollapseFinishedTransitioningEvent);
constexpr char BlockedTopicsListLengthFunc[] =
"(el) => el.querySelectorAll('privacy-sandbox-interest-item').length";
constexpr char BlockedTopicsListFirstTopicIdFunc[] =
"(el) => "
"el.querySelectorAll('privacy-sandbox-interest-item')[0].interest.topic."
"topicId";
DeepQuery GetManageTopicsPageQuery() {
return DeepQuery({{"settings-ui", "settings-main", "settings-basic-page",
"settings-privacy-page",
"settings-privacy-sandbox-manage-topics-subpage"}});
}
DeepQuery GetAdTopicsPageQuery() {
return DeepQuery(
{{"settings-ui", "settings-main", "settings-basic-page",
"settings-privacy-page", "settings-privacy-sandbox-topics-subpage"}});
}
class PrivacySandboxSettingsTopicsInteractiveTest
: public InteractiveBrowserTest {
public:
void SetUpOnMainThread() override {
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kPrivacySandboxM1TopicsEnabled, true);
InteractiveBrowserTest::SetUpOnMainThread();
browser()->window()->SetBounds(gfx::Rect(600, 700));
}
void BlockTopic(int topic_id) {
auto* const privacy_sandbox_service =
PrivacySandboxServiceFactory::GetForProfile(browser()->profile());
privacy_sandbox_service->SetTopicAllowed(
privacy_sandbox::CanonicalTopic(browsing_topics::Topic(topic_id),
/*taxonomy_version=*/2),
false);
}
size_t GetBlockedTopicsSize() {
return PrivacySandboxServiceFactory::GetForProfile(browser()->profile())
->GetBlockedTopics()
.size();
}
int GetBlockedTopicsFirstTopicId() {
return PrivacySandboxServiceFactory::GetForProfile(browser()->profile())
->GetBlockedTopics()[0]
.topic_id()
.value();
}
const DeepQuery firstToggle = GetManageTopicsPageQuery() + "#toggle-1";
const DeepQuery secondToggle = GetManageTopicsPageQuery() + "#toggle-57";
const DeepQuery blockedTopicsList =
GetAdTopicsPageQuery() + "#blockedTopicsList";
const DeepQuery firstBlockedItemButton =
(blockedTopicsList + "privacy-sandbox-interest-item") + "cr-button";
const DeepQuery blockedTopicsRow =
GetAdTopicsPageQuery() + "#blockedTopicsRow";
const DeepQuery ironCollapse = GetAdTopicsPageQuery() + "cr-collapse";
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
// Block topic(1) and topic(57) through PS service and validate that it's
// toggled OFF (checked == false) on the Manage Topics Page.
IN_PROC_BROWSER_TEST_F(PrivacySandboxSettingsTopicsInteractiveTest,
StartWithTwoBlockedTopics) {
BlockTopic(1);
BlockTopic(57);
RunTestSequence(
InstrumentTab(kPrivacySandboxTopicsElementId),
NavigateWebContents(kPrivacySandboxTopicsElementId,
GURL(chrome::kPrivacySandboxManageTopicsURL)),
CheckJsResultAt(kPrivacySandboxTopicsElementId, firstToggle,
"(el) => el.checked", false),
CheckJsResultAt(kPrivacySandboxTopicsElementId, secondToggle,
"(el) => el.checked", false));
}
// Block first topic on Manage Topics Page. Validate that it is toggled off
// (checked == false). Validate that the PS service returns only 1 blocked topic
// with an ID of 1. Navigate to the Ad Topics Page and validate topic(1) is
// blocked topics list.
IN_PROC_BROWSER_TEST_F(PrivacySandboxSettingsTopicsInteractiveTest,
BlockFirstTopicOnManageTopicsPage) {
RunTestSequence(
InstrumentTab(kPrivacySandboxTopicsElementId),
NavigateWebContents(kPrivacySandboxTopicsElementId,
GURL(chrome::kPrivacySandboxManageTopicsURL)),
CheckJsResultAt(kPrivacySandboxTopicsElementId, firstToggle,
"(el) => el.checked"),
ExecuteJsAt(kPrivacySandboxTopicsElementId, firstToggle,
"(el) => el.click()"),
CheckJsResultAt(kPrivacySandboxTopicsElementId, firstToggle,
"(el) => el.checked", false),
CheckResult([this]() { return GetBlockedTopicsSize(); }, 1u,
"Checking that there is only one blocked topic"),
CheckResult([this]() { return GetBlockedTopicsFirstTopicId(); }, 1,
"Checking that the one blocked topic is topic(1)"),
NavigateWebContents(kPrivacySandboxTopicsElementId,
GURL(chrome::kPrivacySandboxAdTopicsURL)),
CheckJsResultAt(kPrivacySandboxTopicsElementId, blockedTopicsList,
BlockedTopicsListLengthFunc, 1),
CheckJsResultAt(kPrivacySandboxTopicsElementId, blockedTopicsList,
BlockedTopicsListFirstTopicIdFunc, 1));
}
// Block topic(1) through PS service and validate it is shown in the blocked
// topics list of the Ad Topics Page. Unblock the topic and validate PS service
// has 0 blocked topics. Navigate to Manage Topics Page and make sure the first
// topic toggle is ON (checked == true).
IN_PROC_BROWSER_TEST_F(PrivacySandboxSettingsTopicsInteractiveTest,
UnblockOneTopicOnAdTopicsPage) {
#if BUILDFLAG(IS_MAC)
// https://crbug.com/407801060
if (base::mac::MacOSMajorVersion() == 15) {
GTEST_SKIP() << "Disabled on macOS Sequoia.";
}
#endif
BlockTopic(1);
RunTestSequence(
InstrumentTab(kPrivacySandboxTopicsElementId),
NavigateWebContents(kPrivacySandboxTopicsElementId,
GURL(chrome::kPrivacySandboxAdTopicsURL)),
CheckJsResultAt(kPrivacySandboxTopicsElementId, blockedTopicsList,
BlockedTopicsListLengthFunc, 1),
CheckJsResultAt(kPrivacySandboxTopicsElementId, blockedTopicsList,
BlockedTopicsListFirstTopicIdFunc, 1),
ExecuteJsAt(kPrivacySandboxTopicsElementId, firstBlockedItemButton,
"(el) => el.click()"),
CheckResult([this]() { return GetBlockedTopicsSize(); }, 0u,
"Checking that there are 0 blocked topics"),
NavigateWebContents(kPrivacySandboxTopicsElementId,
GURL(chrome::kPrivacySandboxManageTopicsURL)),
CheckJsResultAt(kPrivacySandboxTopicsElementId, firstToggle,
"(el) => el.checked"));
}
// Validate that first icon is shown to confirm we are querying correctly, then
// check all icons to make sure default one is not used.
IN_PROC_BROWSER_TEST_F(PrivacySandboxSettingsTopicsInteractiveTest,
ConfirmDefaultIconIsNotUsed) {
RunTestSequence(
InstrumentTab(kPrivacySandboxTopicsElementId),
NavigateWebContents(kPrivacySandboxTopicsElementId,
GURL(chrome::kPrivacySandboxManageTopicsURL)),
CheckJsResultAt(kPrivacySandboxTopicsElementId,
GetManageTopicsPageQuery(),
R"(
(el) => Array.from(el.shadowRoot.querySelectorAll('cr-icon')).some(
el => el.icon === 'firstLevelTopics20:artist')
)"),
CheckJsResultAt(kPrivacySandboxTopicsElementId,
GetManageTopicsPageQuery(),
R"(
(el) => Array.from(el.shadowRoot.querySelectorAll('cr-icon')).some(
el => el.icon === 'firstLevelTopics20:category')
)",
false));
}
// TODO(b/334129738): clean up / re-enable tests
// Pixel test for Manage Topics Page with all topics set to their default state.
IN_PROC_BROWSER_TEST_F(PrivacySandboxSettingsTopicsInteractiveTest,
DISABLED_ValidateScreenshotDefaultManageTopicsPage) {
RunTestSequence(
InstrumentTab(kPrivacySandboxTopicsElementId),
NavigateWebContents(kPrivacySandboxTopicsElementId,
GURL(chrome::kPrivacySandboxManageTopicsURL)),
SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
"Screenshot not supported in all test modes."),
Screenshot(ContentsWebView::kContentsWebViewElementId, "", "5405426"));
}
// Pixel test for Manage Topics Page and Ad Topics Page with blocking the first
// topic through JS commands.
IN_PROC_BROWSER_TEST_F(
PrivacySandboxSettingsTopicsInteractiveTest,
DISABLED_ValidateScreenshotsWithFirstTopicBlockedWithJS) {
StateChange ironCollapseFinishedTransitioning;
ironCollapseFinishedTransitioning.event =
kIronCollapseFinishedTransitioningEvent;
ironCollapseFinishedTransitioning.type =
StateChange::Type::kExistsAndConditionTrue;
ironCollapseFinishedTransitioning.where = ironCollapse;
ironCollapseFinishedTransitioning.test_function =
"(el) => { return el.transitioning === false }";
RunTestSequence(
InstrumentTab(kPrivacySandboxTopicsElementId),
NavigateWebContents(kPrivacySandboxTopicsElementId,
GURL(chrome::kPrivacySandboxManageTopicsURL)),
ExecuteJsAt(kPrivacySandboxTopicsElementId, firstToggle,
"(el) => { el.click(); }"),
SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
"Screenshot not supported in all test modes."),
Screenshot(ContentsWebView::kContentsWebViewElementId,
"ManageTopicsPageAfterFirstTopicBlocked", "5405426"),
NavigateWebContents(kPrivacySandboxTopicsElementId,
GURL(chrome::kPrivacySandboxAdTopicsURL)),
ExecuteJsAt(kPrivacySandboxTopicsElementId, ironCollapse,
"(el) => { el.noAnimation = true; }"),
ExecuteJsAt(kPrivacySandboxTopicsElementId, blockedTopicsRow,
"(el) => { el.click(); }"),
WaitForStateChange(kPrivacySandboxTopicsElementId,
ironCollapseFinishedTransitioning),
Screenshot(ContentsWebView::kContentsWebViewElementId,
"AdTopicsPageAfterFirstTopicBlocked", "5405426"),
CheckResult([this]() { return GetBlockedTopicsSize(); }, 1u,
"Checking that there is only one blocked topic"),
CheckResult([this]() { return GetBlockedTopicsFirstTopicId(); }, 1,
"Checking that the one blocked topic is topic(1)"));
}
} // namespace