// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://settings/lazy_load.js';
import {assert} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import type {CrDialogElement, CrExpandButtonElement, SettingsPrivacySandboxAdMeasurementSubpageElement, SettingsPrivacySandboxManageTopicsSubpageElement, SettingsPrivacySandboxPageElement, SettingsPrivacySandboxTopicsSubpageElement, SettingsSimpleConfirmationDialogElement} from 'chrome://settings/lazy_load.js';
import {SettingsPrivacySandboxFledgeSubpageElement} from 'chrome://settings/lazy_load.js';
import type {CrButtonElement, CrLinkRowElement, FirstLevelTopicsState, SettingsPrefsElement, TopicsState} from 'chrome://settings/settings.js';
import {CrSettingsPrefs, HatsBrowserProxyImpl, MetricsBrowserProxyImpl, PrivacySandboxBrowserProxyImpl, Router, routes, TrustSafetyInteraction} from 'chrome://settings/settings.js';
import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
import {eventToPromise, isChildVisible, isVisible, whenAttributeIs} from 'chrome://webui-test/test_util.js';
import {TestHatsBrowserProxy} from './test_hats_browser_proxy.js';
import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js';
import {TestPrivacySandboxBrowserProxy} from './test_privacy_sandbox_browser_proxy.js';
suite('PrivacySandboxPage', function() {
let page: SettingsPrivacySandboxPageElement;
let settingsPrefs: SettingsPrefsElement;
let hatsBrowserProxy: TestHatsBrowserProxy;
let metricsBrowserProxy: TestMetricsBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(function() {
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
hatsBrowserProxy = new TestHatsBrowserProxy();
HatsBrowserProxyImpl.setInstance(hatsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-page');
page.prefs = settingsPrefs.prefs!;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX);
document.body.appendChild(page);
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
test('privacySandboxLinkRowsVisible', function() {
assertTrue(isChildVisible(page, '#privacySandboxTopicsLinkRow'));
assertTrue(isChildVisible(page, '#privacySandboxFledgeLinkRow'));
assertTrue(isChildVisible(page, '#privacySandboxAdMeasurementLinkRow'));
});
test('hatsSurveyRequested', async function() {
const result =
await hatsBrowserProxy.whenCalled('trustSafetyInteractionOccurred');
assertEquals(TrustSafetyInteraction.OPENED_AD_PRIVACY, result);
});
test('privacySandboxTopicsRowSublabel', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
await flushTasks();
const topicsRow = page.shadowRoot!.querySelector<CrLinkRowElement>(
'#privacySandboxTopicsLinkRow');
assertTrue(!!topicsRow);
assertTrue(isVisible(topicsRow));
assertEquals(
loadTimeData.getString('adPrivacyPageTopicsLinkRowSubLabelEnabled'),
topicsRow.subLabel);
page.setPrefValue('privacy_sandbox.m1.topics_enabled', false);
await flushTasks();
assertTrue(isVisible(topicsRow));
assertEquals(
loadTimeData.getString('adPrivacyPageTopicsLinkRowSubLabelDisabled'),
topicsRow.subLabel);
});
test('privacySandboxFledgeRowSublabel', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
await flushTasks();
const fledgeRow = page.shadowRoot!.querySelector<CrLinkRowElement>(
'#privacySandboxFledgeLinkRow');
assertTrue(!!fledgeRow);
assertTrue(isVisible(fledgeRow));
assertEquals(
loadTimeData.getString('adPrivacyPageFledgeLinkRowSubLabelEnabled'),
fledgeRow.subLabel);
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', false);
await flushTasks();
assertTrue(isVisible(fledgeRow));
assertEquals(
loadTimeData.getString('adPrivacyPageFledgeLinkRowSubLabelDisabled'),
fledgeRow.subLabel);
});
test('privacySandboxAdMeasurementRowSublabel', async function() {
page.setPrefValue('privacy_sandbox.m1.ad_measurement_enabled', true);
await flushTasks();
const measurementRow = page.shadowRoot!.querySelector<CrLinkRowElement>(
'#privacySandboxAdMeasurementLinkRow');
assertTrue(!!measurementRow);
assertTrue(isVisible(measurementRow));
assertEquals(
loadTimeData.getString(
'adPrivacyPageAdMeasurementLinkRowSubLabelEnabled'),
measurementRow.subLabel);
page.setPrefValue('privacy_sandbox.m1.ad_measurement_enabled', false);
await flushTasks();
assertTrue(isChildVisible(page, '#privacySandboxAdMeasurementLinkRow'));
assertEquals(
loadTimeData.getString(
'adPrivacyPageAdMeasurementLinkRowSubLabelDisabled'),
measurementRow.subLabel);
});
test('clickPrivacySandboxTopicsLinkRow', async function() {
const topicsRow = page.shadowRoot!.querySelector<HTMLElement>(
'#privacySandboxTopicsLinkRow');
assertTrue(!!topicsRow);
topicsRow.click();
assertEquals(
'Settings.PrivacySandbox.Topics.Opened',
await metricsBrowserProxy.whenCalled('recordAction'));
assertEquals(
routes.PRIVACY_SANDBOX_TOPICS, Router.getInstance().getCurrentRoute());
});
test('clickPrivacySandboxFledgeLinkRow', async function() {
const fledgeRow = page.shadowRoot!.querySelector<HTMLElement>(
'#privacySandboxFledgeLinkRow');
assertTrue(!!fledgeRow);
fledgeRow.click();
assertEquals(
'Settings.PrivacySandbox.Fledge.Opened',
await metricsBrowserProxy.whenCalled('recordAction'));
assertEquals(
routes.PRIVACY_SANDBOX_FLEDGE, Router.getInstance().getCurrentRoute());
});
test('clickPrivacySandboxAdMeasurementLinkRow', async function() {
const measurementRow = page.shadowRoot!.querySelector<HTMLElement>(
'#privacySandboxAdMeasurementLinkRow');
assertTrue(!!measurementRow);
measurementRow.click();
assertEquals(
'Settings.PrivacySandbox.AdMeasurement.Opened',
await metricsBrowserProxy.whenCalled('recordAction'));
assertEquals(
routes.PRIVACY_SANDBOX_AD_MEASUREMENT,
Router.getInstance().getCurrentRoute());
});
});
suite('PrivacySandboxPageRedesignToggles', function() {
let page: SettingsPrivacySandboxPageElement;
let settingsPrefs: SettingsPrefsElement;
let hatsBrowserProxy: TestHatsBrowserProxy;
let metricsBrowserProxy: TestMetricsBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
psRedesignAdPrivacyPageEnabled: true,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(function() {
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
hatsBrowserProxy = new TestHatsBrowserProxy();
HatsBrowserProxyImpl.setInstance(hatsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-page');
page.prefs = settingsPrefs.prefs!;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX);
document.body.appendChild(page);
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
test('privacySandboxLinkRowsVisible', function() {
assertTrue(isChildVisible(page, '#privacySandboxTopicsLinkRowV2'));
assertTrue(isChildVisible(page, '#privacySandboxFledgeLinkRowV2'));
assertTrue(isChildVisible(page, '#privacySandboxAdMeasurementLinkRowV2'));
});
test('hatsSurveyRequested', async function() {
const result =
await hatsBrowserProxy.whenCalled('trustSafetyInteractionOccurred');
assertEquals(TrustSafetyInteraction.OPENED_AD_PRIVACY, result);
});
test('privacySandboxTopicsRowSublabel', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
await flushTasks();
const topicsRow = page.shadowRoot!.querySelector<CrLinkRowElement>(
'#privacySandboxTopicsLinkRowV2');
assertTrue(!!topicsRow);
assertTrue(isVisible(topicsRow));
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabelV2'),
topicsRow.subLabel);
page.setPrefValue('privacy_sandbox.m1.topics_enabled', false);
await flushTasks();
assertTrue(isVisible(topicsRow));
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabelV2'),
topicsRow.subLabel);
});
test('privacySandboxFledgeRowSublabel', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
await flushTasks();
const fledgeRow = page.shadowRoot!.querySelector<CrLinkRowElement>(
'#privacySandboxFledgeLinkRowV2');
assertTrue(!!fledgeRow);
assertTrue(isVisible(fledgeRow));
assertEquals(
loadTimeData.getString('fledgePageToggleSubLabel'), fledgeRow.subLabel);
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', false);
await flushTasks();
assertTrue(isVisible(fledgeRow));
assertEquals(
loadTimeData.getString('fledgePageToggleSubLabel'), fledgeRow.subLabel);
});
test('privacySandboxAdMeasurementRowSublabel', async function() {
page.setPrefValue('privacy_sandbox.m1.ad_measurement_enabled', true);
await flushTasks();
const measurementRow = page.shadowRoot!.querySelector<CrLinkRowElement>(
'#privacySandboxAdMeasurementLinkRowV2');
assertTrue(!!measurementRow);
assertTrue(isVisible(measurementRow));
assertEquals(
loadTimeData.getString('adMeasurementPageToggleSubLabel'),
measurementRow.subLabel);
page.setPrefValue('privacy_sandbox.m1.ad_measurement_enabled', false);
await flushTasks();
assertTrue(isChildVisible(page, '#privacySandboxAdMeasurementLinkRowV2'));
assertEquals(
loadTimeData.getString('adMeasurementPageToggleSubLabel'),
measurementRow.subLabel);
});
test('clickPrivacySandboxTopicsLinkRow', async function() {
const topicsRow = page.shadowRoot!.querySelector<HTMLElement>(
'#privacySandboxTopicsLinkRowV2');
assertTrue(!!topicsRow);
topicsRow.click();
assertEquals(
'Settings.PrivacySandbox.Topics.Opened',
await metricsBrowserProxy.whenCalled('recordAction'));
assertEquals(
routes.PRIVACY_SANDBOX_TOPICS, Router.getInstance().getCurrentRoute());
});
test('clickPrivacySandboxFledgeLinkRow', async function() {
const fledgeRow = page.shadowRoot!.querySelector<HTMLElement>(
'#privacySandboxFledgeLinkRowV2');
assertTrue(!!fledgeRow);
fledgeRow.click();
assertEquals(
'Settings.PrivacySandbox.Fledge.Opened',
await metricsBrowserProxy.whenCalled('recordAction'));
assertEquals(
routes.PRIVACY_SANDBOX_FLEDGE, Router.getInstance().getCurrentRoute());
});
test('clickPrivacySandboxAdMeasurementLinkRow', async function() {
const measurementRow = page.shadowRoot!.querySelector<HTMLElement>(
'#privacySandboxAdMeasurementLinkRowV2');
assertTrue(!!measurementRow);
measurementRow.click();
assertEquals(
'Settings.PrivacySandbox.AdMeasurement.Opened',
await metricsBrowserProxy.whenCalled('recordAction'));
assertEquals(
routes.PRIVACY_SANDBOX_AD_MEASUREMENT,
Router.getInstance().getCurrentRoute());
});
test('privacySandboxTopicsLinkRowToggleCheck', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
const topicsRow = page.shadowRoot!.querySelector<HTMLElement>(
'#privacySandboxTopicsLinkRowV2');
assertTrue(!!topicsRow);
const topicsToggle = topicsRow.querySelector('cr-toggle');
assertTrue(!!topicsToggle);
assertTrue(topicsToggle.disabled);
assertTrue(topicsToggle.checked);
topicsToggle.click();
assertTrue(topicsToggle.checked);
page.setPrefValue('privacy_sandbox.m1.topics_enabled', false);
await flushTasks();
assertTrue(!!topicsRow);
assertFalse(topicsToggle.checked);
});
test('privacySandboxFledgeLinkRowToggleCheck', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
const fledgeRow = page.shadowRoot!.querySelector<HTMLElement>(
'#privacySandboxFledgeLinkRowV2');
assertTrue(!!fledgeRow);
const fledgeToggle = fledgeRow.querySelector('cr-toggle');
assertTrue(!!fledgeToggle);
assertTrue(fledgeToggle.disabled);
assertTrue(fledgeToggle.checked);
fledgeToggle.click();
assertTrue(fledgeToggle.checked);
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', false);
await flushTasks();
assertTrue(!!fledgeToggle);
assertFalse(fledgeToggle.checked);
});
test('privacySandboAdMeasurementLinkRowToggleCheck', async function() {
page.setPrefValue('privacy_sandbox.m1.ad_measurement_enabled', true);
const adMeasurementRow = page.shadowRoot!.querySelector<HTMLElement>(
'#privacySandboxAdMeasurementLinkRowV2');
assertTrue(!!adMeasurementRow);
const adMeasurementToggle = adMeasurementRow.querySelector('cr-toggle');
assertTrue(!!adMeasurementToggle);
assertTrue(adMeasurementToggle.disabled);
assertTrue(adMeasurementToggle.checked);
adMeasurementToggle.click();
assertTrue(adMeasurementToggle.checked);
page.setPrefValue('privacy_sandbox.m1.ad_measurement_enabled', false);
await flushTasks();
assertTrue(!!adMeasurementToggle);
assertFalse(adMeasurementToggle.checked);
});
});
suite('RestrictedEnabled', function() {
let page: SettingsPrivacySandboxPageElement;
let settingsPrefs: SettingsPrefsElement;
let metricsBrowserProxy: TestMetricsBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: true,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(function() {
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-page');
page.prefs = settingsPrefs.prefs!;
document.body.appendChild(page);
return flushTasks();
});
// When the privacy sandbox is restricted, ensure only measurement is shown.
test('privacySandboxLinkRowsNotVisible', function() {
assertFalse(isChildVisible(page, '#privacySandboxTopicsLinkRow'));
assertFalse(isChildVisible(page, '#privacySandboxFledgeLinkRow'));
assertTrue(isChildVisible(page, '#privacySandboxAdMeasurementLinkRow'));
});
});
suite('TopicsSubpageWithProactiveTopicsBlockingDisabled', function() {
let page: SettingsPrivacySandboxTopicsSubpageElement;
let testPrivacySandboxBrowserProxy: TestPrivacySandboxBrowserProxy;
let settingsPrefs: SettingsPrefsElement;
let hatsBrowserProxy: TestHatsBrowserProxy;
let metricsBrowserProxy: TestMetricsBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
isProactiveTopicsBlockingEnabled: false,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(async function() {
testPrivacySandboxBrowserProxy = new TestPrivacySandboxBrowserProxy();
testPrivacySandboxBrowserProxy.setTestTopicState(getTestTopicsState());
PrivacySandboxBrowserProxyImpl.setInstance(testPrivacySandboxBrowserProxy);
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
hatsBrowserProxy = new TestHatsBrowserProxy();
HatsBrowserProxyImpl.setInstance(hatsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-topics-subpage');
page.prefs = settingsPrefs.prefs!;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_TOPICS);
document.body.appendChild(page);
await testPrivacySandboxBrowserProxy.whenCalled('getTopicsState');
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
function getTestTopicsState(): TopicsState {
return {
topTopics: [{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: '',
}],
blockedTopics: [{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: '',
}],
};
}
function assertLearnMoreDialogClosed() {
const dialog = page.shadowRoot!.querySelector<CrDialogElement>('#dialog');
assertFalse(!!dialog);
}
function assertLearnMoreDialogOpened() {
const dialog = page.shadowRoot!.querySelector<CrDialogElement>('#dialog');
assertTrue(!!dialog);
assertTrue(dialog.open);
}
test('hatsSurveyRequested', async function() {
const result =
await hatsBrowserProxy.whenCalled('trustSafetyInteractionOccurred');
assertEquals(TrustSafetyInteraction.OPENED_TOPICS_SUBPAGE, result);
});
test('enableTopicsToggle', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', false);
await flushTasks();
assertTrue(isVisible(page.$.topicsToggle));
assertFalse(page.$.topicsToggle.checked);
assertFalse(page.$.topicsToggle.controlDisabled());
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabel'),
page.$.topicsToggle.subLabel);
assertTrue(isChildVisible(page, '#currentTopicsDescription'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionEmpty'));
assertTrue(isChildVisible(page, '#currentTopicsDescriptionDisabled'));
assertEquals(
0, testPrivacySandboxBrowserProxy.getCallCount('topicsToggleChanged'));
page.$.topicsToggle.click();
await flushTasks();
assertTrue(isVisible(page.$.topicsToggle));
assertTrue(page.$.topicsToggle.checked);
assertFalse(page.$.topicsToggle.controlDisabled());
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabel'),
page.$.topicsToggle.subLabel);
assertTrue(!!page.getPref('privacy_sandbox.m1.topics_enabled.value'));
assertTrue(isChildVisible(page, '#currentTopicsDescription'));
// The current list is always empty after re-enabling the toggle.
assertTrue(isChildVisible(page, '#currentTopicsDescriptionEmpty'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionDisabled'));
assertEquals(
'Settings.PrivacySandbox.Topics.Enabled',
await metricsBrowserProxy.whenCalled('recordAction'));
assertTrue((await testPrivacySandboxBrowserProxy.whenCalled(
'topicsToggleChanged'))[0]);
});
test('disableTopicsToggle', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
await flushTasks();
assertTrue(isVisible(page.$.topicsToggle));
assertTrue(page.$.topicsToggle.checked);
assertFalse(page.$.topicsToggle.controlDisabled());
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabel'),
page.$.topicsToggle.subLabel);
assertTrue(isChildVisible(page, '#currentTopicsDescription'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionEmpty'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionDisabled'));
assertEquals(
0, testPrivacySandboxBrowserProxy.getCallCount('topicsToggleChanged'));
page.$.topicsToggle.click();
await flushTasks();
assertTrue(isVisible(page.$.topicsToggle));
assertFalse(page.$.topicsToggle.checked);
assertFalse(page.$.topicsToggle.controlDisabled());
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabel'),
page.$.topicsToggle.subLabel);
assertFalse(!!page.getPref('privacy_sandbox.m1.topics_enabled.value'));
assertTrue(isChildVisible(page, '#currentTopicsDescription'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionEmpty'));
assertTrue(isChildVisible(page, '#currentTopicsDescriptionDisabled'));
assertEquals(
'Settings.PrivacySandbox.Topics.Disabled',
await metricsBrowserProxy.whenCalled('recordAction'));
assertFalse((await testPrivacySandboxBrowserProxy.whenCalled(
'topicsToggleChanged'))[0]);
});
test('learnMoreDialog', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
await flushTasks();
assertLearnMoreDialogClosed();
const learnMoreButton =
page.shadowRoot!.querySelector<HTMLElement>('#learnMoreLink')!;
assertTrue(isVisible(learnMoreButton));
assertEquals(
loadTimeData.getString(
'topicsPageCurrentTopicsDescriptionLearnMoreA11yLabel'),
learnMoreButton.getAttribute('aria-label'));
learnMoreButton.click();
await flushTasks();
assertLearnMoreDialogOpened();
assertEquals(
'Settings.PrivacySandbox.Topics.LearnMoreClicked',
await metricsBrowserProxy.whenCalled('recordAction'));
const closeButton =
page.shadowRoot!.querySelector<HTMLElement>('#closeButton')!;
assertTrue(isVisible(closeButton));
closeButton.click();
await flushTasks();
assertLearnMoreDialogClosed();
await waitAfterNextRender(page);
assertEquals(learnMoreButton, page.shadowRoot!.activeElement);
});
test('blockedTopicsNotEmpty', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', false);
const blockedTopicsRow =
page.shadowRoot!.querySelector<HTMLElement>('#blockedTopicsRow')!;
let blockedTopicsDescription = page.shadowRoot!.querySelector<HTMLElement>(
'#blockedTopicsDescription')!;
assertTrue(isVisible(blockedTopicsRow));
assertFalse(isVisible(blockedTopicsDescription));
blockedTopicsRow.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.BlockedTopicsOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
// Check that blocked topics are shown even when toggle is disabled.
blockedTopicsDescription = page.shadowRoot!.querySelector<HTMLElement>(
'#blockedTopicsDescription')!;
assertTrue(isVisible(blockedTopicsDescription));
assertEquals(
loadTimeData.getString('topicsPageBlockedTopicsDescription'),
blockedTopicsDescription.innerText);
const blockedTopicsList =
page.shadowRoot!.querySelector('#blockedTopicsList')!;
let blockedTopics = blockedTopicsList.querySelector('dom-repeat');
assertTrue(!!blockedTopics);
assertEquals(1, blockedTopics.items!.length);
// Check that blocked topics are shown when toggle is enabled.
page.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
await flushTasks();
blockedTopicsDescription = page.shadowRoot!.querySelector<HTMLElement>(
'#blockedTopicsDescription')!;
assertTrue(isVisible(blockedTopicsDescription));
assertEquals(
loadTimeData.getString('topicsPageBlockedTopicsDescription'),
blockedTopicsDescription.innerText);
blockedTopics = blockedTopicsList.querySelector('dom-repeat');
assertTrue(!!blockedTopics);
assertEquals(1, blockedTopics.items!.length);
});
test('blockAndAllowTopics', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
await flushTasks();
// Check for current topics.
const currentTopicsSection =
page.shadowRoot!.querySelector<HTMLElement>('#currentTopicsSection')!;
const currentTopics = currentTopicsSection.querySelector('dom-repeat');
assertTrue(!!currentTopics);
assertEquals(1, currentTopics.items!.length);
assertFalse(isVisible(
currentTopicsSection.querySelector('#currentTopicsDescriptionEmpty')));
assertEquals('test-topic-1', currentTopics.items![0].topic!.displayString);
// Check for blocked topics.
const blockedTopicsRow =
page.shadowRoot!.querySelector<HTMLElement>('#blockedTopicsRow');
blockedTopicsRow!.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.BlockedTopicsOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
const blockedTopicsList =
page.shadowRoot!.querySelector('#blockedTopicsList')!;
let blockedTopics = blockedTopicsList.querySelector('dom-repeat');
assertTrue(!!blockedTopics);
const blockedTopicsDescription =
page.shadowRoot!.querySelector<HTMLElement>(
'#blockedTopicsDescription')!;
assertTrue(isVisible(blockedTopicsDescription));
assertEquals(
loadTimeData.getString('topicsPageBlockedTopicsDescription'),
blockedTopicsDescription.innerText);
assertEquals(1, blockedTopics.items!.length);
assertEquals('test-topic-2', blockedTopics.items![0].topic!.displayString);
// Set test topic state before blocking topic
testPrivacySandboxBrowserProxy.setTestTopicState(
{
topTopics: [],
blockedTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: '',
},
{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: '',
},
],
},
);
// Block topic.
const item =
currentTopicsSection.querySelector('privacy-sandbox-interest-item')!;
const blockButton = item.shadowRoot!.querySelector('cr-button');
assertEquals(
page.i18n('topicsPageBlockTopicA11yLabel', 'test-topic-1'),
blockButton!.getAttribute('aria-label'));
blockButton!.click();
assertEquals(
'Settings.PrivacySandbox.Topics.TopicRemoved',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
await testPrivacySandboxBrowserProxy.whenCalled('setTopicAllowed');
await testPrivacySandboxBrowserProxy.whenCalled('getTopicsState');
// Assert the topic is no longer visible.
assertEquals(
0, currentTopicsSection.querySelector('dom-repeat')!.items!.length);
assertTrue(isVisible(
currentTopicsSection.querySelector('#currentTopicsDescriptionEmpty')));
// Check that the focus is not lost after blocking the last item.
await waitAfterNextRender(page);
assertEquals(blockedTopicsRow, page.shadowRoot!.activeElement);
// Assert the topic was moved to blocked topics section.
blockedTopics = blockedTopicsList.querySelector('dom-repeat')!;
assertEquals(2, blockedTopics.items!.length);
assertEquals('test-topic-1', blockedTopics.items![0].topic!.displayString);
assertEquals('test-topic-2', blockedTopics.items![1].topic!.displayString);
// Setting test topic state before allowing first blocked topic.
testPrivacySandboxBrowserProxy.setTestTopicState(
{
topTopics: [],
blockedTopics: [{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: '',
}],
},
);
// Allow first blocked topic.
let blockedItems =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(2, blockedItems.length);
const allowButton = blockedItems[0]!.shadowRoot!.querySelector('cr-button');
assertEquals(
page.i18n('topicsPageAllowTopicA11yLabel', 'test-topic-1'),
allowButton!.getAttribute('aria-label'));
allowButton!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setTopicAllowed');
await testPrivacySandboxBrowserProxy.whenCalled('getTopicsState');
assertEquals(
'Settings.PrivacySandbox.Topics.TopicAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Setting test topic state before allowing last blocked topic.
testPrivacySandboxBrowserProxy.setTestTopicState(
{
topTopics: [],
blockedTopics: [],
},
);
// Allow second blocked topic.
blockedItems =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(1, blockedItems.length);
assert(!!blockedItems[0]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-2',
blockedItems[0]!.shadowRoot!.querySelector('#label')!.textContent);
blockedItems[0]!.shadowRoot!.querySelector('cr-button')!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setTopicAllowed');
await testPrivacySandboxBrowserProxy.whenCalled('getTopicsState');
assertEquals(
'Settings.PrivacySandbox.Topics.TopicAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
// Assert all blocked topics are gone.
assertEquals(
0, blockedTopicsList.querySelector('dom-repeat')!.items!.length);
assertTrue(isVisible(blockedTopicsDescription));
assertEquals(
loadTimeData.getString('topicsPageBlockedTopicsDescriptionEmpty'),
blockedTopicsDescription.innerText);
// Check that the focus is not lost after allowing the last item.
await waitAfterNextRender(page);
assertEquals(blockedTopicsRow, page.shadowRoot!.activeElement);
});
test('topicsManaged', async function() {
page.set('prefs.privacy_sandbox.m1.topics_enabled', {
...page.get('prefs.privacy_sandbox.m1.topics_enabled'),
value: false,
controlledBy: chrome.settingsPrivate.ControlledBy.USER_POLICY,
enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
});
await flushTasks();
assertFalse(page.$.topicsToggle.checked);
assertTrue(page.$.topicsToggle.controlDisabled());
assertFalse(isChildVisible(page, '#currentTopicsSection'));
});
test('footerLinks', async function() {
assertTrue(isChildVisible(page, '#footer'));
const links =
page.shadowRoot!.querySelectorAll<HTMLAnchorElement>('#footer a[href]');
assertEquals(links.length, 2, 'footer should contains two links');
links.forEach(
link => assertEquals(
link.getAttribute('aria-description'),
loadTimeData.getString('opensInNewTab'),
'the link should indicate that it will be opened in a new tab'));
const hrefs = Array.from<HTMLAnchorElement>(links).map(link => link.href);
const expectedLinks =
['chrome://settings/adPrivacy/sites', 'chrome://settings/cookies'];
assertDeepEquals(hrefs, expectedLinks);
});
});
suite('TopicsSubpageEmptyWithProactiveTopicsBlockingDisabled', function() {
let page: SettingsPrivacySandboxTopicsSubpageElement;
let testPrivacySandboxBrowserProxy: TestPrivacySandboxBrowserProxy;
let metricsBrowserProxy: TestMetricsBrowserProxy;
let settingsPrefs: SettingsPrefsElement;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
isProactiveTopicsBlockingEnabled: false,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(async function() {
testPrivacySandboxBrowserProxy = new TestPrivacySandboxBrowserProxy();
testPrivacySandboxBrowserProxy.setTopicsState({
topTopics: [],
blockedTopics: [],
});
PrivacySandboxBrowserProxyImpl.setInstance(testPrivacySandboxBrowserProxy);
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-topics-subpage');
page.prefs = settingsPrefs.prefs!;
document.body.appendChild(page);
await testPrivacySandboxBrowserProxy.whenCalled('getTopicsState');
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
test('topicsDisabled', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', false);
await flushTasks();
// Check the current topics descriptions.
assertTrue(isChildVisible(page, '#currentTopicsDescription'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionEmpty'));
assertTrue(isChildVisible(page, '#currentTopicsDescriptionDisabled'));
});
test('topicsEnabled', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
await flushTasks();
// Check the current topics descriptions.
assertTrue(isChildVisible(page, '#currentTopicsDescription'));
assertTrue(isChildVisible(page, '#currentTopicsDescriptionEmpty'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionDisabled'));
// Check that there are no current topics.
const currentTopics =
page.shadowRoot!.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(0, currentTopics.length);
});
test('blockedTopicsEmpty', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
await flushTasks();
const blockedTopicsRow =
page.shadowRoot!.querySelector<HTMLElement>('#blockedTopicsRow')!;
const blockedTopicsDescription =
page.shadowRoot!.querySelector<HTMLElement>(
'#blockedTopicsDescription')!;
assertTrue(isVisible(blockedTopicsRow));
assertFalse(isVisible(blockedTopicsDescription));
blockedTopicsRow.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.BlockedTopicsOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
// Check the blocked topics description.
assertTrue(isVisible(blockedTopicsDescription));
assertEquals(
loadTimeData.getString('topicsPageBlockedTopicsDescriptionEmpty'),
blockedTopicsDescription.innerText);
// Check that there are no blocked topics.
const blockedTopicsList =
page.shadowRoot!.querySelector('#blockedTopicsList')!;
const blockedTopics =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(0, blockedTopics.length);
});
});
suite('FledgeSubpageWithProactiveTopicsBlockingEnabled', function() {
let page: SettingsPrivacySandboxFledgeSubpageElement;
let testPrivacySandboxBrowserProxy: TestPrivacySandboxBrowserProxy;
let settingsPrefs: SettingsPrefsElement;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
isProactiveTopicsBlockingEnabled: true,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(async function() {
testPrivacySandboxBrowserProxy = new TestPrivacySandboxBrowserProxy();
testPrivacySandboxBrowserProxy.setFledgeState({
joiningSites: ['test-site-one.com'],
blockedSites: ['test-site-two.com'],
});
PrivacySandboxBrowserProxyImpl.setInstance(testPrivacySandboxBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-fledge-subpage');
page.prefs = settingsPrefs.prefs!;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_FLEDGE);
document.body.appendChild(page);
await testPrivacySandboxBrowserProxy.whenCalled('getFledgeState');
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
test('secondDescription', async function() {
const secondDescription =
page.shadowRoot!.querySelector<HTMLElement>('#secondDescription');
assert(secondDescription);
assertEquals(
secondDescription?.innerText, page.i18n('fledgePageExplanation'));
});
test('footerLinks', async function() {
assertTrue(isChildVisible(page, '#footerV2'));
const links = page.shadowRoot!.querySelectorAll<HTMLAnchorElement>(
'#footerV2 a[href]');
assertEquals(links.length, 3, 'footer should contains three links');
links.forEach(
link => assertEquals(
link.getAttribute('aria-description'),
loadTimeData.getString('opensInNewTab'),
'the link should indicate that it will be opened in a new tab'));
const hrefs = Array.from<HTMLAnchorElement>(links).map(link => link.href);
const expectedLinks = [
'chrome://settings/adPrivacy/interests',
'chrome://settings/cookies',
'https://support.google.com/chrome?p=ad_privacy',
];
assertDeepEquals(hrefs, expectedLinks);
});
});
suite('TopicsSubpageWithProactiveTopicsBlockingEnabled', function() {
let page: SettingsPrivacySandboxTopicsSubpageElement;
let testPrivacySandboxBrowserProxy: TestPrivacySandboxBrowserProxy;
let settingsPrefs: SettingsPrefsElement;
let metricsBrowserProxy: TestMetricsBrowserProxy;
let hatsBrowserProxy: TestHatsBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
isProactiveTopicsBlockingEnabled: true,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(async function() {
testPrivacySandboxBrowserProxy = new TestPrivacySandboxBrowserProxy();
PrivacySandboxBrowserProxyImpl.setInstance(testPrivacySandboxBrowserProxy);
testPrivacySandboxBrowserProxy.setTestTopicState(getTestTopicsState());
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
hatsBrowserProxy = new TestHatsBrowserProxy();
HatsBrowserProxyImpl.setInstance(hatsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-topics-subpage');
page.prefs = settingsPrefs.prefs!;
page.set('prefs.privacy_sandbox.m1.topics_enabled', {value: true});
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_TOPICS);
document.body.appendChild(page);
await testPrivacySandboxBrowserProxy.whenCalled('getTopicsState');
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
function getTestTopicsState(): TopicsState {
return {
topTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
},
{
topicId: 3,
taxonomyVersion: 1,
displayString: 'test-topic-3',
description: '',
},
{
topicId: 4,
taxonomyVersion: 1,
displayString: 'test-topic-4',
description: '',
},
],
blockedTopics: [{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: '',
}],
};
}
test('hatsSurveyRequested', async function() {
const result =
await hatsBrowserProxy.whenCalled('trustSafetyInteractionOccurred');
assertEquals(TrustSafetyInteraction.OPENED_TOPICS_SUBPAGE, result);
});
// When prefs.privacy_sandbox.m1.topics_enabled value is false
// and Proactive Topic Blocking feature is turned on,
// everything on the ad topics page but the settings toggle button,
// disclaimer and footer is hidden.
test('enableTopicsToggle', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', false);
await flushTasks();
assertTrue(isVisible(page.$.topicsToggle));
assertFalse(page.$.topicsToggle.checked);
assertFalse(page.$.topicsToggle.controlDisabled());
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabelV2'),
page.$.topicsToggle.subLabel);
// Assert V2 Layout for ids to be hidden.
const idsToBeHidden = [
'#currentTopicsSection',
'#currentTopicsHeading',
'#currentTopicsDescription',
'#currentTopicsDescriptionEmpty',
'#currentTopicsDescriptionEmptyTextHeading',
'#currentTopicsDescriptionEmptyTextV2',
'#currentTopicsDescriptionDisabled',
'#blockedTopicsRow',
'#blockedTopicsDescriptionV2',
'#blockedTopicsDescriptionEmptyTextHeading',
'#blockedTopicsDescriptionEmptyTextV2',
'#blockedTopicsList',
'#manageTopicsSection',
];
idsToBeHidden.forEach(id => assertFalse(isChildVisible(page, id)));
// FooterV2 should be visible if pref is on or not.
assertTrue(isChildVisible(page, '#footerV2'));
assertEquals(
0, testPrivacySandboxBrowserProxy.getCallCount('topicsToggleChanged'));
page.$.topicsToggle.click();
await flushTasks();
assertTrue((await testPrivacySandboxBrowserProxy.whenCalled(
'topicsToggleChanged'))[0]);
assertEquals(
'Settings.PrivacySandbox.Topics.Enabled',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
assertTrue(isVisible(page.$.topicsToggle));
assertTrue(page.$.topicsToggle.checked);
assertFalse(page.$.topicsToggle.controlDisabled());
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabelV2'),
page.$.topicsToggle.subLabel);
assertTrue(!!page.getPref('privacy_sandbox.m1.topics_enabled.value'));
// Non V2 empty text should not be visible
assertFalse(isChildVisible(page, '#currentTopicsDescriptionEmpty'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionDisabled'));
const blockedTopicsRow =
page.shadowRoot!.querySelector<HTMLElement>('#blockedTopicsRow');
blockedTopicsRow!.click();
assertEquals(
'Settings.PrivacySandbox.Topics.BlockedTopicsOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Non V2 blocked topics description should not be visible
assertFalse(isChildVisible(page, '#blockedTopicsDescription'));
// The blocked topic list is NOT empty after re-enabling the toggle
assertFalse(
isChildVisible(page, '#blockedTopicsDescriptionEmptyTextHeading'));
assertFalse(isChildVisible(page, '#blockedTopicsDescriptionEmptyTextV2'));
// Assert V2 Layout for ids to be shown.
const idsToBeShown = [
'#currentTopicsSection',
'#currentTopicsHeading',
'#currentTopicsDescription',
'#currentTopicsDescriptionEmptyTextHeading',
'#currentTopicsDescriptionEmptyTextV2',
'#blockedTopicsRow',
'#blockedTopicsDescriptionV2',
'#blockedTopicsList',
'#manageTopicsSection',
'#footerV2',
];
idsToBeShown.forEach(id => assertTrue(isChildVisible(page, id)));
});
test('disableTopicsToggle', async function() {
assertTrue(isVisible(page.$.topicsToggle));
assertTrue(page.$.topicsToggle.checked);
assertFalse(page.$.topicsToggle.controlDisabled());
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabelV2'),
page.$.topicsToggle.subLabel);
assertFalse(isChildVisible(page, '#currentTopicsDescriptionEmpty'));
assertFalse(
isChildVisible(page, '#currentTopicsDescriptionEmptyTextHeading'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionEmptyTextV2'));
assertFalse(isChildVisible(page, '#currentTopicsDescriptionDisabled'));
const blockedTopicsRow =
page.shadowRoot!.querySelector<HTMLElement>('#blockedTopicsRow');
blockedTopicsRow!.click();
assertEquals(
'Settings.PrivacySandbox.Topics.BlockedTopicsOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Non V2 blocked topics description should not be visible
assertFalse(isChildVisible(page, '#blockedTopicsDescription'));
// Blocked topics list is not empty
assertFalse(
isChildVisible(page, '#blockedTopicsDescriptionEmptyTextHeading'));
assertFalse(isChildVisible(page, '#blockedTopicsDescriptionEmptyTextV2'));
// Assert V2 Layout for ids to be shown.
const idsToBeShown = [
'#currentTopicsSection',
'#currentTopicsHeading',
'#currentTopicsDescription',
'#blockedTopicsRow',
'#blockedTopicsDescriptionV2',
'#blockedTopicsList',
'#manageTopicsSection',
'#footerV2',
];
idsToBeShown.forEach(id => assertTrue(isChildVisible(page, id)));
assertEquals(
0, testPrivacySandboxBrowserProxy.getCallCount('topicsToggleChanged'));
page.$.topicsToggle.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.Disabled',
await metricsBrowserProxy.whenCalled('recordAction'));
assertFalse((await testPrivacySandboxBrowserProxy.whenCalled(
'topicsToggleChanged'))[0]);
assertTrue(isVisible(page.$.topicsToggle));
assertFalse(page.$.topicsToggle.checked);
assertFalse(page.$.topicsToggle.controlDisabled());
assertEquals(
loadTimeData.getString('topicsPageToggleSubLabelV2'),
page.$.topicsToggle.subLabel);
// Assert V2 Layout for ids to be hidden.
const idsToBeHidden = [
'#currentTopicsSection',
'#currentTopicsHeading',
'#currentTopicsDescription',
'#currentTopicsDescriptionEmpty',
'#currentTopicsDescriptionEmptyTextHeading',
'#currentTopicsDescriptionEmptyTextV2',
'#currentTopicsDescriptionDisabled',
'#blockedTopicsRow',
'#blockedTopicsDescription',
'#blockedTopicsDescriptionV2',
'#blockedTopicsDescriptionEmptyTextHeading',
'#blockedTopicsDescriptionEmptyTextV2',
'#blockedTopicsList',
'#manageTopicsSection',
];
idsToBeHidden.forEach(id => assertFalse(isChildVisible(page, id)));
});
test('disclaimerLinks', async function() {
const disclaimer = page.shadowRoot!.querySelector('#disclaimer');
assertTrue(!!disclaimer);
assertTrue(isVisible(disclaimer));
const links = page.shadowRoot!.querySelectorAll<HTMLAnchorElement>(
'#disclaimer a[href]');
assertEquals(1, links.length);
assertEquals(
links[0]!.getAttribute('aria-description'),
loadTimeData.getString('opensInNewTab'),
'the link should indicate that it will be opened in a new tab');
assertEquals(
links[0]!.href, 'https://support.google.com/chrome?p=ad_privacy');
});
function assertToastOpened() {
const toast = page.shadowRoot!.querySelector('cr-toast');
assert(toast);
assertTrue(toast.open);
const toastBody =
page.shadowRoot!.querySelector<HTMLElement>('#unblockTopicToastBody');
assertEquals(toastBody?.innerText, page.i18n('unblockTopicToastBody'));
const toastButton =
page.shadowRoot!.querySelector<CrButtonElement>('#closeToastButton');
assertEquals(
toastButton?.innerText, page.i18n('unblockTopicToastButtonText'));
toastButton?.click();
assertFalse(toast.open);
}
test('blockAndAllowTopics', async function() {
testPrivacySandboxBrowserProxy.setChildTopics([{
topicId: 3,
taxonomyVersion: 1,
displayString: 'test-topic-3',
description: '',
}]);
assertTrue(isVisible(page.$.topicsToggle));
assertTrue(page.$.topicsToggle.checked);
assertFalse(page.$.topicsToggle.controlDisabled());
// Check for current topics.
const currentTopicsSection =
page.shadowRoot!.querySelector<HTMLElement>('#currentTopicsSection')!;
const currentTopics =
currentTopicsSection.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(3, currentTopics.length);
assertFalse(isVisible(currentTopicsSection.querySelector(
'#currentTopicsDescriptionEmptyTextHeading')));
assertFalse(isVisible(currentTopicsSection.querySelector(
'#currentTopicsDescriptionEmptyTextV2')));
assert(!!currentTopics[0]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-1',
currentTopics[0]!.shadowRoot!.querySelector('#label')!.textContent);
assert(!!currentTopics[1]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-3',
currentTopics[1]!.shadowRoot!.querySelector('#label')!.textContent);
assert(!!currentTopics[2]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-4',
currentTopics[2]!.shadowRoot!.querySelector('#label')!.textContent);
// Check for blocked topics.
const blockedTopicsRow =
page.shadowRoot!.querySelector<HTMLElement>('#blockedTopicsRow');
blockedTopicsRow!.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.BlockedTopicsOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
const blockedTopicsList =
page.shadowRoot!.querySelector('#blockedTopicsList')!;
let blockedTopics =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
const blockedTopicsDescription =
page.shadowRoot!.querySelector<HTMLElement>(
'#blockedTopicsDescriptionV2')!;
assertTrue(isVisible(blockedTopicsDescription));
assertEquals(
loadTimeData.getString('topicsPageBlockedTopicsDescriptionNew'),
blockedTopicsDescription.innerText);
assertEquals(1, blockedTopics.length);
assert(!!blockedTopics[0]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-2',
blockedTopics[0]!.shadowRoot!.querySelector('#label')!.textContent);
// Block topic.
const items =
currentTopicsSection.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(3, items.length);
let blockButton = items[0]?.shadowRoot!.querySelector('cr-button');
assertEquals(
page.i18n('topicsPageBlockTopicA11yLabel', 'test-topic-1'),
blockButton!.getAttribute('aria-label'));
blockButton!.click();
await flushTasks();
let blockTopicDialog =
page.shadowRoot!.querySelector<SettingsSimpleConfirmationDialogElement>(
'#blockTopicDialog');
assertTrue(!!blockTopicDialog);
await (whenAttributeIs(blockTopicDialog.$.dialog, 'open', ''));
blockTopicDialog.$.cancel.click();
await eventToPromise('close', blockTopicDialog);
await flushTasks();
// Make sure we still have 3 active topics
assertEquals(
3,
currentTopicsSection.querySelectorAll('privacy-sandbox-interest-item')
.length);
// Setting topic state to reflect blocking parent topic
testPrivacySandboxBrowserProxy.setTestTopicState(
{
topTopics: [
{
topicId: 4,
taxonomyVersion: 1,
displayString: 'test-topic-4',
description: '',
},
],
blockedTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
},
{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: '',
},
],
},
);
// Try blocking topic again
blockButton!.click();
await flushTasks();
blockTopicDialog =
page.shadowRoot!.querySelector<SettingsSimpleConfirmationDialogElement>(
'#blockTopicDialog');
assertTrue(!!blockTopicDialog);
await (whenAttributeIs(blockTopicDialog.$.dialog, 'open', ''));
blockTopicDialog.$.confirm.click();
await eventToPromise('close', blockTopicDialog);
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.TopicRemoved',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
await testPrivacySandboxBrowserProxy.whenCalled('setTopicAllowed');
const expandedButton =
page.shadowRoot!.querySelector<CrExpandButtonElement>(
'#blockedTopicsRow');
assert(expandedButton);
assertTrue(expandedButton.expanded);
await waitAfterNextRender(page);
assertEquals(blockedTopicsRow, page.shadowRoot!.activeElement);
// Assert the topic AND it's child topic is no longer visible.
assertEquals(
1,
currentTopicsSection.querySelectorAll('privacy-sandbox-interest-item')
.length);
assert(!!currentTopicsSection
.querySelectorAll('privacy-sandbox-interest-item')[0]!
.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-4',
currentTopicsSection
.querySelectorAll('privacy-sandbox-interest-item')[0]!.shadowRoot!
.querySelector('#label')!.textContent);
// Setting topic state to reflect blocking the last active topic
testPrivacySandboxBrowserProxy.setTestTopicState(
{
topTopics: [],
blockedTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
},
{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: '',
},
{
topicId: 4,
taxonomyVersion: 1,
displayString: 'test-topic-4',
description: '',
},
],
},
);
testPrivacySandboxBrowserProxy.setChildTopics([]);
blockButton = items[2]?.shadowRoot!.querySelector('cr-button');
blockButton!.click();
await flushTasks();
assertEquals(
0,
currentTopicsSection.querySelectorAll('privacy-sandbox-interest-item')
.length);
assertEquals(
'Settings.PrivacySandbox.Topics.TopicRemoved',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
await testPrivacySandboxBrowserProxy.whenCalled('setTopicAllowed');
assertTrue(isVisible(currentTopicsSection.querySelector(
'#currentTopicsDescriptionEmptyTextHeading')));
assertTrue(isVisible(currentTopicsSection.querySelector(
'#currentTopicsDescriptionEmptyTextV2')));
// Check that the focus is not lost after blocking the last item.
await waitAfterNextRender(page);
assertEquals(blockedTopicsRow, page.shadowRoot!.activeElement);
// Assert the topic was moved to blocked topics section.
blockedTopics =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(3, blockedTopics.length);
assert(!!blockedTopics[0]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-1',
blockedTopics[0]!.shadowRoot!.querySelector('#label')!.textContent);
assert(!!blockedTopics[1]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-2',
blockedTopics[1]!.shadowRoot!.querySelector('#label')!.textContent);
assert(!!blockedTopics[2]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-4',
blockedTopics[2]!.shadowRoot!.querySelector('#label')!.textContent);
// Setting topic state to reflect allowing a blocked topic
testPrivacySandboxBrowserProxy.setTestTopicState(
{
topTopics: [],
blockedTopics: [
{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: '',
},
{
topicId: 4,
taxonomyVersion: 1,
displayString: 'test-topic-4',
description: '',
},
],
},
);
// Allow first blocked topic.
let blockedItems =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
// When the parent topic was blocked, the child topic does not get moved
// to the blocked items list which is why we only have 3 blocked topics
assertEquals(3, blockedItems.length);
const unblockButton =
blockedItems[0]!.shadowRoot!.querySelector('cr-button');
assert(unblockButton);
assertEquals('Unblock', unblockButton.innerText);
assertEquals(
'Unblock test-topic-1', unblockButton.getAttribute('aria-label'));
unblockButton.click();
await testPrivacySandboxBrowserProxy.whenCalled('setTopicAllowed');
assertEquals(
'Settings.PrivacySandbox.Topics.TopicAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
assertToastOpened();
// Setting topic state to reflect allowing another blocked topic
testPrivacySandboxBrowserProxy.setTestTopicState(
{
topTopics: [],
blockedTopics: [{
topicId: 4,
taxonomyVersion: 1,
displayString: 'test-topic-4',
description: '',
}],
},
);
// Allow second blocked topic.
blockedItems =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(2, blockedItems.length);
assert(!!blockedTopics[0]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-2',
blockedTopics[0]!.shadowRoot!.querySelector('#label')!.textContent);
blockedItems[0]!.shadowRoot!.querySelector('cr-button')!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setTopicAllowed');
assertEquals(
'Settings.PrivacySandbox.Topics.TopicAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
assertToastOpened();
// Setting topic state to reflect allowing the last blocked topic
testPrivacySandboxBrowserProxy.setTestTopicState(
{
topTopics: [],
blockedTopics: [],
},
);
// Allow third blocked topic
blockedItems =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(1, blockedItems.length);
assert(!!blockedTopics[0]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-4',
blockedTopics[0]!.shadowRoot!.querySelector('#label')!.textContent);
blockedItems[0]!.shadowRoot!.querySelector('cr-button')!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setTopicAllowed');
assertEquals(
'Settings.PrivacySandbox.Topics.TopicAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
assertToastOpened();
// Assert all blocked topics are gone.
assertEquals(
0,
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item')
.length);
// Check that the focus is not lost after allowing the last item.
await waitAfterNextRender(page);
assertEquals(blockedTopicsRow, page.shadowRoot!.activeElement);
// Check that blocked topics empty text appears
assertTrue(
isChildVisible(page, '#blockedTopicsDescriptionEmptyTextHeading'));
assertTrue(isChildVisible(page, '#blockedTopicsDescriptionEmptyTextV2'));
});
test('topicsManaged', async function() {
page.set('prefs.privacy_sandbox.m1.topics_enabled', {
...page.get('prefs.privacy_sandbox.m1.topics_enabled'),
value: false,
controlledBy: chrome.settingsPrivate.ControlledBy.USER_POLICY,
enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
});
await flushTasks();
assertFalse(page.$.topicsToggle.checked);
assertTrue(page.$.topicsToggle.controlDisabled());
assertFalse(isChildVisible(page, '#currentTopicsSection'));
});
test('footerLinks', async function() {
assertTrue(isChildVisible(page, '#footerV2'));
const links = page.shadowRoot!.querySelectorAll<HTMLAnchorElement>(
'#footerV2 a[href]');
assertEquals(links.length, 3, 'footer should contains three links');
links.forEach(
link => assertEquals(
link.getAttribute('aria-description'),
loadTimeData.getString('opensInNewTab'),
'the link should indicate that it will be opened in a new tab'));
const hrefs = Array.from<HTMLAnchorElement>(links).map(link => link.href);
const expectedLinks = [
'chrome://settings/adPrivacy/sites',
'chrome://settings/cookies',
'https://support.google.com/chrome?p=ad_privacy',
];
assertDeepEquals(hrefs, expectedLinks);
});
test('manageTopicsRow', async function() {
const manageTopicsRow = page.shadowRoot!.querySelector<CrLinkRowElement>(
'#privacySandboxManageTopicsLinkRow');
assertTrue(!!manageTopicsRow);
assertTrue(isVisible(manageTopicsRow));
assertEquals(
loadTimeData.getString('manageTopicsHeading'), manageTopicsRow.label);
assertEquals(
loadTimeData.getString('manageTopicsDescription'),
manageTopicsRow.subLabel);
});
test('clickManageTopicsRow', async function() {
const manageTopicsRow = page.shadowRoot!.querySelector<CrLinkRowElement>(
'#privacySandboxManageTopicsLinkRow');
assertTrue(!!manageTopicsRow);
manageTopicsRow.click();
assertEquals(
routes.PRIVACY_SANDBOX_MANAGE_TOPICS,
Router.getInstance().getCurrentRoute());
});
test('navigateToManageTopicsPrefDisabled', async function() {
page.setPrefValue('privacy_sandbox.m1.topics_enabled', false);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
const manageTopicsPage = document.createElement(
'settings-privacy-sandbox-manage-topics-subpage');
manageTopicsPage.prefs = settingsPrefs.prefs!;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_MANAGE_TOPICS);
document.body.appendChild(manageTopicsPage);
assertEquals(
Router.getInstance().getCurrentRoute(), routes.PRIVACY_SANDBOX_TOPICS);
});
});
suite('ManageTopics', function() {
let page: SettingsPrivacySandboxManageTopicsSubpageElement;
let testPrivacySandboxBrowserProxy: TestPrivacySandboxBrowserProxy;
let settingsPrefs: SettingsPrefsElement;
let metricsBrowserProxy: TestMetricsBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
isProactiveTopicsBlockingEnabled: true,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(async function() {
testPrivacySandboxBrowserProxy = new TestPrivacySandboxBrowserProxy();
PrivacySandboxBrowserProxyImpl.setInstance(testPrivacySandboxBrowserProxy);
testPrivacySandboxBrowserProxy.setFirstLevelTopicsState(
getFirstLevelTopicsState());
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement(
'settings-privacy-sandbox-manage-topics-subpage');
page.prefs = settingsPrefs.prefs!;
page.set('prefs.privacy_sandbox.m1.topics_enabled', {value: true});
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_MANAGE_TOPICS);
document.body.appendChild(page);
await testPrivacySandboxBrowserProxy.whenCalled('getFirstLevelTopics');
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
function getFirstLevelTopicsState(): FirstLevelTopicsState {
return {
firstLevelTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
},
{
topicId: 4,
taxonomyVersion: 1,
displayString: 'test-topic-4',
description: 'test-topic-4-description',
},
],
blockedTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
},
{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: '',
},
],
};
}
test('ManageTopicsPageTestExplanationText', async function() {
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.PageOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
const manageTopicsExplanationText =
page.shadowRoot!.querySelector('#explanationText');
assertTrue(!!manageTopicsExplanationText);
assertTrue(isVisible(manageTopicsExplanationText));
const links = page.shadowRoot!.querySelectorAll<HTMLAnchorElement>(
'#explanationText a[href]');
assertEquals(
links.length, 1, 'Explanation text should have one Learn more link');
assertEquals(
links[0]!.getAttribute('aria-description'),
loadTimeData.getString('opensInNewTab'),
'the link should indicate that it will be opened in a new tab');
assertEquals(
links[0]!.getAttribute('aria-label'),
'Learn more about managing your ad privacy in Chrome.');
assertEquals(
'https://support.google.com/chrome?p=ad_privacy', links[0]!.href);
const learnMoreLink =
manageTopicsExplanationText.querySelector<HTMLElement>(
'#learnMoreLink');
assertTrue(!!learnMoreLink);
learnMoreLink.click();
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.LearnMoreClicked',
await metricsBrowserProxy.whenCalled('recordAction'));
});
test('ManageTopicsPageTestLabelsAndSubLabels', async function() {
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.PageOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
const firstLevelTopics =
page.shadowRoot!.querySelectorAll('.topic-toggle-row');
assertEquals(2, firstLevelTopics.length);
const labels = Array.from(page.shadowRoot!.querySelectorAll('.label'))
.map(label => label.textContent);
assertDeepEquals(['test-topic-1', 'test-topic-4'], labels);
const subLabels =
Array.from(page.shadowRoot!.querySelectorAll('.sub-label-text'))
.map(subLabel => subLabel.textContent);
assertDeepEquals(
['test-topic-1-description', 'test-topic-4-description'], subLabels);
});
test('ManageTopicsPageTestToggles', async function() {
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.PageOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
const toggles = page.shadowRoot!.querySelectorAll('cr-toggle');
assertEquals(2, toggles.length);
const toggleAriaLabels =
Array.from(toggles).map(toggle => toggle.getAttribute('aria-label'));
assertDeepEquals(['test-topic-1', 'test-topic-4'], toggleAriaLabels);
const toggleAriaDescriptions = Array.from(toggles).map(
toggle => toggle.getAttribute('aria-description'));
assertDeepEquals(
['test-topic-1-description', 'test-topic-4-description'],
toggleAriaDescriptions);
const toggleIds = Array.from(toggles).map(topicToggle => topicToggle.id);
assertDeepEquals(['toggle-1', 'toggle-4'], toggleIds);
// Toggle 1 (topic 1) is also blocked so it is toggled OFF.
assertFalse(toggles[0]!.checked);
// Toggle 2 (topic 4) is not blocked so it is toggled ON.
assertTrue(toggles[1]!.checked);
});
test('ManageTopicsPageChangeToggle', async function() {
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.PageOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
testPrivacySandboxBrowserProxy.setChildTopics([{
topicId: 3,
taxonomyVersion: 1,
displayString: 'test-topic-3',
description: '',
}]);
// Unblocking topic 1, toggle should now be checked meaning it's unblocked.
const toggles = page.shadowRoot!.querySelectorAll('cr-toggle');
assertEquals(2, toggles.length);
toggles[0]!.click();
assertTrue(toggles[0]!.checked);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicEnabled',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Attempting to block topic 1, causes a dialog to open due to
// getChildTopicsCurrentlyAssigned returning a non empty list of
// child topics that would be blocked if they chose to continue.
toggles[0]!.click();
await flushTasks();
let blockTopicDialog =
page.shadowRoot!.querySelector<SettingsSimpleConfirmationDialogElement>(
'#blockTopicDialog');
assertTrue(!!blockTopicDialog);
await (whenAttributeIs(blockTopicDialog.$.dialog, 'open', ''));
blockTopicDialog.$.cancel.click();
await eventToPromise('close', blockTopicDialog);
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicBlockingCanceled',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// After closing the dialog and choosing to not block it, the
// toggle is turned back ON.
assertTrue(toggles[0]!.checked);
// Attempt to block topic 1 again
toggles[0]!.click();
await flushTasks();
blockTopicDialog =
page.shadowRoot!.querySelector<SettingsSimpleConfirmationDialogElement>(
'#blockTopicDialog');
assertTrue(!!blockTopicDialog);
await (whenAttributeIs(blockTopicDialog.$.dialog, 'open', ''));
blockTopicDialog.$.confirm.click();
await eventToPromise('close', blockTopicDialog);
await flushTasks();
// The block button blocks the topic and changes the
// toggle to be turned OFF.
assertFalse(toggles[0]!.checked);
assertEquals(2, metricsBrowserProxy.getArgs('recordAction').length);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicBlockingConfirmed',
metricsBrowserProxy.getArgs('recordAction')[0]);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicBlocked',
metricsBrowserProxy.getArgs('recordAction')[1]);
metricsBrowserProxy.resetResolver('recordAction');
testPrivacySandboxBrowserProxy.setChildTopics([]);
// Toggle 2 (topic 4) has no child topics
// that are currently assigned which is why the
// dialog does not appear and the toggle is turned OFF.
toggles[1]!.click();
await flushTasks();
assertFalse(toggles[1]!.checked);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicBlocked',
await metricsBrowserProxy.whenCalled('recordAction'));
});
test('ManageTopicsPageClickOnToggleRow', async function() {
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.PageOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
testPrivacySandboxBrowserProxy.setChildTopics([{
topicId: 3,
taxonomyVersion: 1,
displayString: 'test-topic-3',
description: '',
}]);
// Unblocking topic 1, toggle should now be checked meaning it's unblocked.
const topicToggleRows =
page.shadowRoot!.querySelectorAll<HTMLElement>('.topic-toggle-row');
const toggles = page.shadowRoot!.querySelectorAll('cr-toggle');
assertEquals(2, topicToggleRows.length);
assertEquals(2, toggles.length);
topicToggleRows[0]!.click();
assertTrue(toggles[0]!.checked);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicEnabled',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Attempting to block topic 1, causes a dialog to open due to
// getChildTopicsCurrentlyAssigned returning a non empty list of child
// topics that would be blocked if they choose to continue.
topicToggleRows[0]!.click();
await flushTasks();
let blockTopicDialog =
page.shadowRoot!.querySelector<SettingsSimpleConfirmationDialogElement>(
'#blockTopicDialog');
assertTrue(!!blockTopicDialog);
await (whenAttributeIs(blockTopicDialog.$.dialog, 'open', ''));
blockTopicDialog.$.cancel.click();
await eventToPromise('close', blockTopicDialog);
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicBlockingCanceled',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// After closing the dialog and choosing to not block it, the toggle is
// turned back ON.
assertTrue(toggles[0]!.checked);
// Attempt to block topic 1 again
topicToggleRows[0]!.click();
await flushTasks();
blockTopicDialog =
page.shadowRoot!.querySelector<SettingsSimpleConfirmationDialogElement>(
'#blockTopicDialog');
assertTrue(!!blockTopicDialog);
await (whenAttributeIs(blockTopicDialog.$.dialog, 'open', ''));
blockTopicDialog.$.confirm.click();
await eventToPromise('close', blockTopicDialog);
await flushTasks();
// The block button blocks the topic and changes the toggle to be turned
// OFF.
assertFalse(toggles[0]!.checked);
assertEquals(2, metricsBrowserProxy.getArgs('recordAction').length);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicBlockingConfirmed',
metricsBrowserProxy.getArgs('recordAction')[0]);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicBlocked',
metricsBrowserProxy.getArgs('recordAction')[1]);
metricsBrowserProxy.resetResolver('recordAction');
testPrivacySandboxBrowserProxy.setChildTopics([]);
// Toggle 2 (topic 4) has no child topics that are currently assigned which
// is why the dialog does not appear and the toggle is turned OFF.
topicToggleRows[1]!.click();
await flushTasks();
assertFalse(toggles[1]!.checked);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicBlocked',
await metricsBrowserProxy.whenCalled('recordAction'));
});
});
suite('ManageTopicsAndAdTopicsPageState', function() {
let adTopicsPage: SettingsPrivacySandboxTopicsSubpageElement;
let testPrivacySandboxBrowserProxy: TestPrivacySandboxBrowserProxy;
let settingsPrefs: SettingsPrefsElement;
let metricsBrowserProxy: TestMetricsBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
isProactiveTopicsBlockingEnabled: true,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(async function() {
testPrivacySandboxBrowserProxy = new TestPrivacySandboxBrowserProxy();
PrivacySandboxBrowserProxyImpl.setInstance(testPrivacySandboxBrowserProxy);
testPrivacySandboxBrowserProxy.setFirstLevelTopicsState(
getInitialFirstLevelTopicsState());
testPrivacySandboxBrowserProxy.setTestTopicState(getInitialTopicsState());
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
document.body.appendChild(settingsPrefs);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
adTopicsPage =
document.createElement('settings-privacy-sandbox-topics-subpage');
adTopicsPage.prefs = settingsPrefs.prefs;
adTopicsPage.set('prefs.privacy_sandbox.m1.topics_enabled', {value: true});
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_TOPICS);
document.body.appendChild(adTopicsPage);
await testPrivacySandboxBrowserProxy.whenCalled('getTopicsState');
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
function getInitialTopicsState(): TopicsState {
return {
topTopics: [],
blockedTopics: [{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
}],
};
}
function getInitialFirstLevelTopicsState(): FirstLevelTopicsState {
return {
firstLevelTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
},
{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: 'test-topic-2-description',
},
],
blockedTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
},
],
};
}
function getFinalTopicsState(): TopicsState {
return {
topTopics: [],
blockedTopics: [
{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: 'test-topic-2-description',
},
],
};
}
function getFinalFirstLevelTopicsState(): FirstLevelTopicsState {
return {
firstLevelTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
},
{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: 'test-topic-2-description',
},
],
blockedTopics: [
{
topicId: 1,
taxonomyVersion: 1,
displayString: 'test-topic-1',
description: 'test-topic-1-description',
},
{
topicId: 2,
taxonomyVersion: 1,
displayString: 'test-topic-2',
description: 'test-topic-2-description',
},
],
};
}
test('BlockAndAllowVerifyUpToDateState', async function() {
// Start with Ad Topics Page.
adTopicsPage.setPrefValue('privacy_sandbox.m1.topics_enabled', true);
await flushTasks();
let blockedTopicsRow = adTopicsPage.shadowRoot!.querySelector<HTMLElement>(
'#blockedTopicsRow');
blockedTopicsRow!.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.BlockedTopicsOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Assert initial values
let blockedTopicsList =
adTopicsPage.shadowRoot!.querySelector('#blockedTopicsList')!;
let blockedTopics =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
assertTrue(!!blockedTopics);
assertEquals(1, blockedTopics.length);
assert(!!blockedTopics[0]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-1',
blockedTopics[0]!.shadowRoot!.querySelector('#label')!.textContent);
// Navigate to Manage Topics Page.
document.body.innerHTML = window.trustedTypes!.emptyHTML;
const manageTopicsPage = document.createElement(
'settings-privacy-sandbox-manage-topics-subpage');
manageTopicsPage.prefs = settingsPrefs.prefs!;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_MANAGE_TOPICS);
document.body.appendChild(manageTopicsPage);
await testPrivacySandboxBrowserProxy.whenCalled('getFirstLevelTopics');
flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.PageOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Assert initial values and unblock test-topic-1 and block test-topic-2.
let toggles = manageTopicsPage.shadowRoot!.querySelectorAll('cr-toggle');
assertEquals(2, toggles.length);
let toggleIds = Array.from(toggles).map(topicToggle => topicToggle.id);
assertDeepEquals(['toggle-1', 'toggle-2'], toggleIds);
assertFalse(toggles[0]!.checked);
assertTrue(toggles[1]!.checked);
toggles[0]!.click();
assertTrue(toggles[0]!.checked);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicEnabled',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
toggles[1]!.click();
assertFalse(toggles[1]!.checked);
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.TopicBlocked',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Setting TopicState to reflect changes in Manage Topics page.
testPrivacySandboxBrowserProxy.setTestTopicState(getFinalTopicsState());
// Navigate back to Ad Topics Page
document.body.innerHTML = window.trustedTypes!.emptyHTML;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_TOPICS);
document.body.appendChild(adTopicsPage);
await testPrivacySandboxBrowserProxy.whenCalled('getTopicsState');
flushTasks();
// Check that unblocking test-topic-1 and blocking test-topic-2 in Manage
// Topics Page are reflected in Ad Topics Page.
blockedTopicsRow = adTopicsPage.shadowRoot!.querySelector<HTMLElement>(
'#blockedTopicsRow');
blockedTopicsRow!.click();
await flushTasks();
blockedTopicsList =
adTopicsPage.shadowRoot!.querySelector('#blockedTopicsList')!;
blockedTopics =
blockedTopicsList.querySelectorAll('privacy-sandbox-interest-item');
assertTrue(!!blockedTopics);
assertEquals(1, blockedTopics.length);
assert(!!blockedTopics[0]!.shadowRoot!.querySelector('#label'));
assertEquals(
'test-topic-2',
blockedTopics[0]!.shadowRoot!.querySelector('#label')!.textContent);
blockedTopics[0]!.shadowRoot!.querySelector('cr-button')!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setTopicAllowed');
assertEquals(
'Settings.PrivacySandbox.Topics.TopicAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Setting FirstLevelTopicsState to reflect changes in Ad Topics Page.
testPrivacySandboxBrowserProxy.setFirstLevelTopicsState(
getFinalFirstLevelTopicsState());
// Navigate back to Manage Topics Page.
document.body.innerHTML = window.trustedTypes!.emptyHTML;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_MANAGE_TOPICS);
document.body.appendChild(manageTopicsPage);
await testPrivacySandboxBrowserProxy.whenCalled('getFirstLevelTopics');
flushTasks();
assertEquals(
'Settings.PrivacySandbox.Topics.Manage.PageOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
// Confirm that blocking test-topic-2 in Ad Topics Page are reflected in
// Manage Topics Page. Both topics should be unchecked (blocked).
toggles = manageTopicsPage.shadowRoot!.querySelectorAll('cr-toggle');
assertEquals(2, toggles.length);
toggleIds = Array.from(toggles).map(topicToggle => topicToggle.id);
assertDeepEquals(['toggle-1', 'toggle-2'], toggleIds);
assertFalse(toggles[0]!.checked);
assertFalse(toggles[1]!.checked);
});
});
suite('FledgeSubpageWithProactiveTopicsBlockingDisabled', function() {
let page: SettingsPrivacySandboxFledgeSubpageElement;
let testPrivacySandboxBrowserProxy: TestPrivacySandboxBrowserProxy;
let settingsPrefs: SettingsPrefsElement;
let hatsBrowserProxy: TestHatsBrowserProxy;
let metricsBrowserProxy: TestMetricsBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
isProactiveTopicsBlockingEnabled: false,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(async function() {
testPrivacySandboxBrowserProxy = new TestPrivacySandboxBrowserProxy();
testPrivacySandboxBrowserProxy.setFledgeState({
joiningSites: ['test-site-one.com'],
blockedSites: ['test-site-two.com'],
});
PrivacySandboxBrowserProxyImpl.setInstance(testPrivacySandboxBrowserProxy);
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
hatsBrowserProxy = new TestHatsBrowserProxy();
HatsBrowserProxyImpl.setInstance(hatsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-fledge-subpage');
page.prefs = settingsPrefs.prefs!;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_FLEDGE);
document.body.appendChild(page);
await testPrivacySandboxBrowserProxy.whenCalled('getFledgeState');
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
function assertLearnMoreDialogClosed() {
const dialog = page.shadowRoot!.querySelector<CrDialogElement>('#dialog');
assertFalse(!!dialog);
}
function assertLearnMoreDialogOpened() {
const dialog = page.shadowRoot!.querySelector<CrDialogElement>('#dialog');
assertTrue(!!dialog);
assertTrue(dialog.open);
}
test('hatsSurveyRequested', async function() {
const result =
await hatsBrowserProxy.whenCalled('trustSafetyInteractionOccurred');
assertEquals(TrustSafetyInteraction.OPENED_FLEDGE_SUBPAGE, result);
});
test('enableFledgeToggle', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', false);
await flushTasks();
assertTrue(isVisible(page.$.fledgeToggle));
assertFalse(page.$.fledgeToggle.checked);
assertFalse(page.$.fledgeToggle.controlDisabled());
assertEquals(
loadTimeData.getString('fledgePageToggleSubLabel'),
page.$.fledgeToggle.subLabel);
assertTrue(isChildVisible(page, '#currentSitesDescription'));
assertFalse(isChildVisible(page, '#currentSitesDescriptionEmpty'));
assertTrue(isChildVisible(page, '#currentSitesDescriptionDisabled'));
page.$.fledgeToggle.click();
await flushTasks();
assertTrue(isVisible(page.$.fledgeToggle));
assertTrue(page.$.fledgeToggle.checked);
assertFalse(page.$.fledgeToggle.controlDisabled());
assertEquals(
loadTimeData.getString('fledgePageToggleSubLabel'),
page.$.fledgeToggle.subLabel);
assertTrue(!!page.getPref('privacy_sandbox.m1.fledge_enabled.value'));
assertTrue(isChildVisible(page, '#currentSitesDescription'));
// The current list is always empty after re-enabling the toggle.
assertTrue(isChildVisible(page, '#currentSitesDescriptionEmpty'));
assertFalse(isChildVisible(page, '#currentSitesDescriptionDisabled'));
assertEquals(
'Settings.PrivacySandbox.Fledge.Enabled',
await metricsBrowserProxy.whenCalled('recordAction'));
});
test('disableFledgeToggle', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
await flushTasks();
assertTrue(isVisible(page.$.fledgeToggle));
assertTrue(page.$.fledgeToggle.checked);
assertFalse(page.$.fledgeToggle.controlDisabled());
assertEquals(
loadTimeData.getString('fledgePageToggleSubLabel'),
page.$.fledgeToggle.subLabel);
assertTrue(isChildVisible(page, '#currentSitesDescription'));
assertFalse(isChildVisible(page, '#currentSitesDescriptionEmpty'));
assertFalse(isChildVisible(page, '#currentSitesDescriptionDisabled'));
page.$.fledgeToggle.click();
await flushTasks();
assertTrue(isVisible(page.$.fledgeToggle));
assertFalse(page.$.fledgeToggle.checked);
assertFalse(page.$.fledgeToggle.controlDisabled());
assertEquals(
loadTimeData.getString('fledgePageToggleSubLabel'),
page.$.fledgeToggle.subLabel);
assertFalse(!!page.getPref('privacy_sandbox.m1.fledge_enabled.value'));
assertTrue(isChildVisible(page, '#currentSitesDescription'));
assertFalse(isChildVisible(page, '#currentSitesDescriptionEmpty'));
assertTrue(isChildVisible(page, '#currentSitesDescriptionDisabled'));
assertEquals(
'Settings.PrivacySandbox.Fledge.Disabled',
await metricsBrowserProxy.whenCalled('recordAction'));
});
test('learnMoreDialog', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
await flushTasks();
assertLearnMoreDialogClosed();
const learnMoreButton =
page.shadowRoot!.querySelector<HTMLElement>('#learnMoreLink')!;
assertTrue(isVisible(learnMoreButton));
assertEquals(
loadTimeData.getString(
'fledgePageCurrentSitesDescriptionLearnMoreA11yLabel'),
learnMoreButton.getAttribute('aria-label'));
learnMoreButton.click();
await flushTasks();
assertLearnMoreDialogOpened();
assertEquals(
'Settings.PrivacySandbox.Fledge.LearnMoreClicked',
await metricsBrowserProxy.whenCalled('recordAction'));
const closeButton =
page.shadowRoot!.querySelector<HTMLElement>('#closeButton')!;
assertTrue(isVisible(closeButton));
closeButton.click();
await flushTasks();
assertLearnMoreDialogClosed();
await waitAfterNextRender(page);
assertEquals(learnMoreButton, page.shadowRoot!.activeElement);
});
test('blockedSitesDescriptionNotEmpty', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', false);
const blockedSitesRow =
page.shadowRoot!.querySelector<HTMLElement>('#blockedSitesRow')!;
let blockedSitesDescription = page.shadowRoot!.querySelector<HTMLElement>(
'#blockedSitesDescription')!;
assertTrue(isVisible(blockedSitesRow));
assertFalse(isVisible(blockedSitesDescription));
blockedSitesRow.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Fledge.BlockedSitesOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
blockedSitesDescription = page.shadowRoot!.querySelector<HTMLElement>(
'#blockedSitesDescription')!;
assertTrue(isVisible(blockedSitesDescription));
assertEquals(
loadTimeData.getString('fledgePageBlockedSitesDescription'),
blockedSitesDescription.innerText);
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
await flushTasks();
blockedSitesDescription = page.shadowRoot!.querySelector<HTMLElement>(
'#blockedSitesDescription')!;
assertTrue(isVisible(blockedSitesDescription));
assertEquals(
loadTimeData.getString('fledgePageBlockedSitesDescription'),
blockedSitesDescription.innerText);
});
test('blockAndAllowSites', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
await flushTasks();
// Check for current sites.
const currentSitesSection =
page.shadowRoot!.querySelector<HTMLElement>('#currentSitesSection')!;
const currentSites = currentSitesSection.querySelector('dom-repeat');
assertTrue(!!currentSites);
assertEquals(1, currentSites.items!.length);
assertFalse(isVisible(
currentSitesSection.querySelector('#currentSitesDescriptionEmpty')));
assertEquals('test-site-one.com', currentSites.items![0].site!);
assertFalse(isVisible(currentSitesSection.querySelector('#seeAllSites')));
// Check for blocked sites.
const blockedSitesRow =
page.shadowRoot!.querySelector<HTMLElement>('#blockedSitesRow');
blockedSitesRow!.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Fledge.BlockedSitesOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
const blockedSitesList =
page.shadowRoot!.querySelector('#blockedSitesList')!;
let blockedSites = blockedSitesList.querySelector('dom-repeat');
assertTrue(!!blockedSites);
const blockedSitesDescription = page.shadowRoot!.querySelector<HTMLElement>(
'#blockedSitesDescription')!;
assertTrue(isVisible(blockedSitesDescription));
assertEquals(
loadTimeData.getString('fledgePageBlockedSitesDescription'),
blockedSitesDescription.innerText);
assertEquals(1, blockedSites.items!.length);
assertEquals('test-site-two.com', blockedSites.items![0].site!);
// Block site.
const item =
currentSitesSection.querySelector('privacy-sandbox-interest-item')!;
const blockButton = item.shadowRoot!.querySelector('cr-button');
assertEquals(
page.i18n('fledgePageBlockSiteA11yLabel', 'test-site-one.com'),
blockButton!.getAttribute('aria-label'));
blockButton!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setFledgeJoiningAllowed');
assertEquals(
'Settings.PrivacySandbox.Fledge.SiteRemoved',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Assert the site is no longer visible.
assertEquals(
0, currentSitesSection.querySelector('dom-repeat')!.items!.length);
assertTrue(isVisible(
currentSitesSection.querySelector('#currentSitesDescriptionEmpty')));
// Check that the focus is not lost after blocking the last item.
await waitAfterNextRender(page);
assertEquals(blockedSitesRow, page.shadowRoot!.activeElement);
// Assert the site was moved to blocked sites section.
blockedSites = blockedSitesList.querySelector('dom-repeat')!;
assertEquals(2, blockedSites.items!.length);
assertEquals('test-site-one.com', blockedSites.items![0].site!);
assertEquals('test-site-two.com', blockedSites.items![1].site!);
// Allow first blocked site.
let blockedItems =
blockedSitesList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(2, blockedItems.length);
const allowButton = blockedItems[0]!.shadowRoot!.querySelector('cr-button');
assertEquals(
page.i18n('fledgePageAllowSiteA11yLabel', 'test-site-one.com'),
allowButton!.getAttribute('aria-label'));
allowButton!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setFledgeJoiningAllowed');
assertEquals(
'Settings.PrivacySandbox.Fledge.SiteAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Allow second blocked site.
blockedItems =
blockedSitesList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(1, blockedItems.length);
assertEquals('test-site-two.com', blockedSites.items![0].site!);
blockedItems[0]!.shadowRoot!.querySelector('cr-button')!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setFledgeJoiningAllowed');
assertEquals(
'Settings.PrivacySandbox.Fledge.SiteAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
// Assert all blocked sites are gone.
assertEquals(
0, blockedSitesList.querySelector('dom-repeat')!.items!.length);
assertTrue(isVisible(blockedSitesDescription));
assertEquals(
loadTimeData.getString('fledgePageBlockedSitesDescriptionEmpty'),
blockedSitesDescription.innerText);
// Check that the focus is not lost after allowing the last item.
await waitAfterNextRender(page);
assertEquals(blockedSitesRow, page.shadowRoot!.activeElement);
});
test('fledgeManaged', async function() {
page.set('prefs.privacy_sandbox.m1.fledge_enabled', {
...page.get('prefs.privacy_sandbox.m1.fledge_enabled'),
value: false,
controlledBy: chrome.settingsPrivate.ControlledBy.USER_POLICY,
enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
});
await flushTasks();
assertFalse(page.$.fledgeToggle.checked);
assertTrue(page.$.fledgeToggle.controlDisabled());
assertFalse(isChildVisible(page, '#currentSitesSection'));
});
test('footerLinks', async function() {
assertTrue(isChildVisible(page, '#footer'));
const links =
page.shadowRoot!.querySelectorAll<HTMLAnchorElement>('#footer a[href]');
assertEquals(links.length, 2, 'footer should contains two links');
links.forEach(
link => assertEquals(
link.getAttribute('aria-description'),
loadTimeData.getString('opensInNewTab'),
'the link should indicate that it will be opened in a new tab'));
const hrefs = Array.from<HTMLAnchorElement>(links).map(link => link.href);
const expectedLinks =
['chrome://settings/adPrivacy/interests', 'chrome://settings/cookies'];
assertDeepEquals(hrefs, expectedLinks);
});
});
suite('FledgeSubpageEmpty', function() {
let page: SettingsPrivacySandboxFledgeSubpageElement;
let testPrivacySandboxBrowserProxy: TestPrivacySandboxBrowserProxy;
let metricsBrowserProxy: TestMetricsBrowserProxy;
let settingsPrefs: SettingsPrefsElement;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(async function() {
testPrivacySandboxBrowserProxy = new TestPrivacySandboxBrowserProxy();
testPrivacySandboxBrowserProxy.setFledgeState({
joiningSites: [],
blockedSites: [],
});
PrivacySandboxBrowserProxyImpl.setInstance(testPrivacySandboxBrowserProxy);
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-fledge-subpage');
page.prefs = settingsPrefs.prefs!;
document.body.appendChild(page);
await testPrivacySandboxBrowserProxy.whenCalled('getFledgeState');
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
test('fledgeDisabled', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', false);
await flushTasks();
// Check the current sites descriptions.
assertTrue(isChildVisible(page, '#currentSitesDescription'));
assertFalse(isChildVisible(page, '#currentSitesDescriptionEmpty'));
assertTrue(isChildVisible(page, '#currentSitesDescriptionDisabled'));
});
test('fledgeEnabled', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
await flushTasks();
// Check the current sites descriptions.
assertTrue(isChildVisible(page, '#currentSitesDescription'));
assertTrue(isChildVisible(page, '#currentSitesDescriptionEmpty'));
assertFalse(isChildVisible(page, '#currentSitesDescriptionDisabled'));
assertFalse(isChildVisible(page, '#seeAllSites'));
// Check that there are no current sites.
const currentSites =
page.shadowRoot!.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(0, currentSites.length);
});
test('blockedSitesEmpty', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
await flushTasks();
const blockedSitesRow =
page.shadowRoot!.querySelector<HTMLElement>('#blockedSitesRow')!;
const blockedSitesDescription = page.shadowRoot!.querySelector<HTMLElement>(
'#blockedSitesDescription')!;
assertTrue(isVisible(blockedSitesRow));
assertFalse(isVisible(blockedSitesDescription));
blockedSitesRow.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Fledge.BlockedSitesOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
// Check the blocked sites description.
assertTrue(isVisible(blockedSitesDescription));
assertEquals(
loadTimeData.getString('fledgePageBlockedSitesDescriptionEmpty'),
blockedSitesDescription.innerText);
// Check that there are no blocked sites.
const blockedSitesList =
page.shadowRoot!.querySelector('#blockedSitesList')!;
const blockedSites =
blockedSitesList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(0, blockedSites.length);
});
});
suite('FledgeSubpageSeeAllSites', function() {
let page: SettingsPrivacySandboxFledgeSubpageElement;
let testPrivacySandboxBrowserProxy: TestPrivacySandboxBrowserProxy;
let settingsPrefs: SettingsPrefsElement;
let metricsBrowserProxy: TestMetricsBrowserProxy;
const sitesList: string[] = [];
const sitesCount: number =
SettingsPrivacySandboxFledgeSubpageElement.maxFledgeSites + 2;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(async function() {
testPrivacySandboxBrowserProxy = new TestPrivacySandboxBrowserProxy();
// Setup long list of sites.
for (let i = 0; i < sitesCount; i++) {
sitesList.push(`site-${i}.com`);
}
testPrivacySandboxBrowserProxy.setFledgeState({
joiningSites: sitesList,
blockedSites: [],
});
PrivacySandboxBrowserProxyImpl.setInstance(testPrivacySandboxBrowserProxy);
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement('settings-privacy-sandbox-fledge-subpage');
page.prefs = settingsPrefs.prefs!;
document.body.appendChild(page);
await testPrivacySandboxBrowserProxy.whenCalled('getFledgeState');
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
test('blockAndAllowSites', async function() {
page.setPrefValue('privacy_sandbox.m1.fledge_enabled', true);
await flushTasks();
// Check for current sites.
const currentSitesSection =
page.shadowRoot!.querySelector<HTMLElement>('#currentSitesSection')!;
const currentSites = currentSitesSection.querySelector('dom-repeat');
assertTrue(!!currentSites);
assertEquals(
SettingsPrivacySandboxFledgeSubpageElement.maxFledgeSites,
currentSites.items!.length);
assertFalse(isVisible(
currentSitesSection.querySelector('#currentSitesDescriptionEmpty')));
// Check for blocked sites.
page.shadowRoot!.querySelector<HTMLElement>('#blockedSitesRow')!.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Fledge.BlockedSitesOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
const blockedSitesList =
page.shadowRoot!.querySelector('#blockedSitesList')!;
const blockedSites = blockedSitesList.querySelector('dom-repeat');
assertTrue(!!blockedSites);
assertEquals(0, blockedSites!.items!.length);
const blockedSitesDescription = page.shadowRoot!.querySelector<HTMLElement>(
'#blockedSitesDescription')!;
assertTrue(isVisible(blockedSitesDescription));
assertEquals(
loadTimeData.getString('fledgePageBlockedSitesDescriptionEmpty'),
blockedSitesDescription.innerText);
// Check for "See all sites" button.
const seeAllSites =
currentSitesSection.querySelector<HTMLElement>('#seeAllSites');
assertTrue(isVisible(seeAllSites));
seeAllSites!.click();
await flushTasks();
assertEquals(
'Settings.PrivacySandbox.Fledge.AllSitesOpened',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
const allCurrentSites = currentSitesSection.querySelectorAll('dom-repeat');
assertTrue(!!currentSites);
assertEquals(2, allCurrentSites.length);
const mainSitesList = allCurrentSites[0];
const remainingSitesList = allCurrentSites[1];
assertEquals(
SettingsPrivacySandboxFledgeSubpageElement.maxFledgeSites,
mainSitesList!.items!.length);
assertEquals(2, remainingSitesList!.items!.length);
assertEquals(sitesList[0], mainSitesList!.items![0].site!);
assertEquals(
sitesList[sitesCount - 2], remainingSitesList!.items![0].site!);
// Block site from the main current sites section.
let items =
currentSitesSection!.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(sitesCount, items.length);
items[0]!.shadowRoot!.querySelector('cr-button')!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setFledgeJoiningAllowed');
assertEquals(
'Settings.PrivacySandbox.Fledge.SiteRemoved',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Check that a site from "See all sites" section move to the main one.
assertEquals(
SettingsPrivacySandboxFledgeSubpageElement.maxFledgeSites,
mainSitesList!.items!.length);
assertEquals(1, remainingSitesList!.items!.length);
assertEquals(sitesList[1], mainSitesList!.items![0].site!);
assertEquals(sitesList[sitesCount - 2], mainSitesList!.items!.at(-1).site!);
assertEquals(
sitesList[sitesCount - 1], remainingSitesList!.items![0].site!);
items = mainSitesList!.querySelectorAll('privacy-sandbox-interest-item');
// Check that site was blocked.
assertEquals(1, blockedSites.items!.length);
assertEquals(sitesList[0], blockedSites.items![0].site!);
assertEquals(
loadTimeData.getString('fledgePageBlockedSitesDescription'),
blockedSitesDescription.innerText);
// Block site from the "See all sites" section.
items =
currentSitesSection!.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(sitesCount - 1, items.length);
items[SettingsPrivacySandboxFledgeSubpageElement.maxFledgeSites]!
.shadowRoot!.querySelector('cr-button')!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setFledgeJoiningAllowed');
assertEquals(
'Settings.PrivacySandbox.Fledge.SiteRemoved',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Check that "See all sites" section was removed.
assertFalse(isChildVisible(page, '#seeAllSites'));
// Check that site was blocked.
assertEquals(2, blockedSites.items!.length);
assertEquals(sitesList[0], blockedSites.items![0].site!);
assertEquals(sitesList[sitesCount - 1], blockedSites.items![1].site!);
// Allow first blocked site.
let blockedItems =
blockedSitesList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(2, blockedItems.length);
blockedItems[0]!.shadowRoot!.querySelector('cr-button')!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setFledgeJoiningAllowed');
assertEquals(
'Settings.PrivacySandbox.Fledge.SiteAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
metricsBrowserProxy.resetResolver('recordAction');
// Allow second blocked site.
blockedItems =
blockedSitesList.querySelectorAll('privacy-sandbox-interest-item');
assertEquals(1, blockedItems.length);
assertEquals(sitesList[sitesCount - 1], blockedSites.items![0].site!);
blockedItems[0]!.shadowRoot!.querySelector('cr-button')!.click();
await testPrivacySandboxBrowserProxy.whenCalled('setFledgeJoiningAllowed');
assertEquals(
'Settings.PrivacySandbox.Fledge.SiteAdded',
await metricsBrowserProxy.whenCalled('recordAction'));
// Assert all blocked sites are gone.
assertEquals(
0, blockedSitesList.querySelector('dom-repeat')!.items!.length);
assertTrue(isVisible(blockedSitesDescription));
assertEquals(
loadTimeData.getString('fledgePageBlockedSitesDescriptionEmpty'),
blockedSitesDescription.innerText);
});
});
suite('AdMeasurementSubpage', function() {
let page: SettingsPrivacySandboxAdMeasurementSubpageElement;
let settingsPrefs: SettingsPrefsElement;
let hatsBrowserProxy: TestHatsBrowserProxy;
let metricsBrowserProxy: TestMetricsBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isPrivacySandboxRestricted: false,
psRedesignAdPrivacyPageEnabled: false,
});
settingsPrefs = document.createElement('settings-prefs');
return CrSettingsPrefs.initialized;
});
setup(function() {
metricsBrowserProxy = new TestMetricsBrowserProxy();
MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
hatsBrowserProxy = new TestHatsBrowserProxy();
HatsBrowserProxyImpl.setInstance(hatsBrowserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
document.body.appendChild(settingsPrefs);
page = document.createElement(
'settings-privacy-sandbox-ad-measurement-subpage');
page.prefs = settingsPrefs.prefs!;
Router.getInstance().navigateTo(routes.PRIVACY_SANDBOX_AD_MEASUREMENT);
document.body.appendChild(page);
return flushTasks();
});
teardown(function() {
Router.getInstance().resetRouteForTesting();
});
test('hatsSurveyRequested', async function() {
const result =
await hatsBrowserProxy.whenCalled('trustSafetyInteractionOccurred');
assertEquals(TrustSafetyInteraction.OPENED_AD_MEASUREMENT_SUBPAGE, result);
});
test('enableAdMeasurementToggle', async function() {
page.setPrefValue('privacy_sandbox.m1.ad_measurement_enabled', false);
await flushTasks();
assertTrue(isVisible(page.$.adMeasurementToggle));
assertFalse(page.$.adMeasurementToggle.checked);
assertFalse(page.$.adMeasurementToggle.controlDisabled());
assertEquals(
loadTimeData.getString('adMeasurementPageToggleSubLabel'),
page.$.adMeasurementToggle.subLabel);
page.$.adMeasurementToggle.click();
await flushTasks();
assertTrue(isVisible(page.$.adMeasurementToggle));
assertTrue(page.$.adMeasurementToggle.checked);
assertFalse(page.$.adMeasurementToggle.controlDisabled());
assertEquals(
loadTimeData.getString('adMeasurementPageToggleSubLabel'),
page.$.adMeasurementToggle.subLabel);
assertTrue(
!!page.getPref('privacy_sandbox.m1.ad_measurement_enabled.value'));
assertEquals(
'Settings.PrivacySandbox.AdMeasurement.Enabled',
await metricsBrowserProxy.whenCalled('recordAction'));
});
test('disableAdMeasurementToggle', async function() {
page.setPrefValue('privacy_sandbox.m1.ad_measurement_enabled', true);
await flushTasks();
assertTrue(isVisible(page.$.adMeasurementToggle));
assertTrue(page.$.adMeasurementToggle.checked);
assertFalse(page.$.adMeasurementToggle.controlDisabled());
assertEquals(
loadTimeData.getString('adMeasurementPageToggleSubLabel'),
page.$.adMeasurementToggle.subLabel);
page.$.adMeasurementToggle.click();
await flushTasks();
assertTrue(isVisible(page.$.adMeasurementToggle));
assertFalse(page.$.adMeasurementToggle.checked);
assertFalse(page.$.adMeasurementToggle.controlDisabled());
assertEquals(
loadTimeData.getString('adMeasurementPageToggleSubLabel'),
page.$.adMeasurementToggle.subLabel);
assertFalse(
!!page.getPref('privacy_sandbox.m1.ad_measurement_enabled.value'));
assertEquals(
'Settings.PrivacySandbox.AdMeasurement.Disabled',
await metricsBrowserProxy.whenCalled('recordAction'));
});
test('adMeasurementManaged', async function() {
page.set('prefs.privacy_sandbox.m1.ad_measurement_enabled', {
...page.get('prefs.privacy_sandbox.m1.ad_measurement_enabled'),
value: false,
controlledBy: chrome.settingsPrivate.ControlledBy.USER_POLICY,
enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
});
await flushTasks();
assertFalse(page.$.adMeasurementToggle.checked);
assertTrue(page.$.adMeasurementToggle.controlDisabled());
});
});