// Copyright 2020 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://privacy-sandbox-dialog/privacy_sandbox_dialog_app.js';
import 'chrome://privacy-sandbox-dialog/privacy_sandbox_notice_dialog_app.js';
import 'chrome://privacy-sandbox-dialog/privacy_sandbox_notice_restricted_dialog_app.js';
import 'chrome://privacy-sandbox-dialog/privacy_sandbox_combined_dialog_app.js';
import type {PrivacySandboxCombinedDialogAppElement} from 'chrome://privacy-sandbox-dialog/privacy_sandbox_combined_dialog_app.js';
import {PrivacySandboxCombinedDialogStep} from 'chrome://privacy-sandbox-dialog/privacy_sandbox_combined_dialog_app.js';
import type {PrivacySandboxDialogAppElement} from 'chrome://privacy-sandbox-dialog/privacy_sandbox_dialog_app.js';
import {PrivacySandboxDialogBrowserProxy, PrivacySandboxPromptAction} from 'chrome://privacy-sandbox-dialog/privacy_sandbox_dialog_browser_proxy.js';
import type {PrivacySandboxDialogConsentStepElement} from 'chrome://privacy-sandbox-dialog/privacy_sandbox_dialog_consent_step.js';
import {PrivacySandboxDialogMixin} from 'chrome://privacy-sandbox-dialog/privacy_sandbox_dialog_mixin.js';
import type {PrivacySandboxDialogNoticeStepElement} from 'chrome://privacy-sandbox-dialog/privacy_sandbox_dialog_notice_step.js';
import type {PrivacySandboxNoticeDialogAppElement} from 'chrome://privacy-sandbox-dialog/privacy_sandbox_notice_dialog_app.js';
import type {PrivacySandboxNoticeRestrictedDialogAppElement} from 'chrome://privacy-sandbox-dialog/privacy_sandbox_notice_restricted_dialog_app.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {flush, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {pressAndReleaseKeyOn} from 'chrome://webui-test/keyboard_mock_interactions.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
import {isChildVisible} from 'chrome://webui-test/test_util.js';
class TestPrivacySandboxDialogBrowserProxy extends TestBrowserProxy implements
PrivacySandboxDialogBrowserProxy {
constructor() {
super(['promptActionOccurred', 'resizeDialog', 'showDialog']);
}
promptActionOccurred() {
this.methodCalled('promptActionOccurred', arguments);
}
resizeDialog() {
this.methodCalled('resizeDialog', arguments);
return Promise.resolve();
}
showDialog() {
this.methodCalled('showDialog');
}
}
function isChildInParentBounds(
viewport: HTMLElement, targetSelector: string): boolean {
const target = viewport.shadowRoot!.querySelector(targetSelector);
assertTrue(
!!target, `target element ${targetSelector} not found in the viewport`);
const targetBounds = target!.getBoundingClientRect();
const viewportBounds = viewport.getBoundingClientRect();
return targetBounds.top >= 0 && targetBounds.left >= 0 &&
targetBounds.top < viewportBounds.height &&
targetBounds.bottom <= viewportBounds.height &&
targetBounds.left < viewportBounds.width &&
targetBounds.right <= viewportBounds.width;
}
// Wait until there hasn't been a scroll event for 100ms. It is sufficient
// for tests but shouldn't be used in production.
async function waitForScrollToFinish(scrollable: HTMLElement) {
await new Promise(resolve => {
let timeout: number;
scrollable.addEventListener('scroll', () => {
clearTimeout(timeout);
timeout = setTimeout(resolve, 100);
});
});
}
function doesElemenHaveScrollbar(element: HTMLElement) {
return element.clientHeight < element.scrollHeight;
}
function isAllContentVisible(element: HTMLElement) {
const lastBottomMargin = 8;
return element.clientHeight >= element.scrollHeight - lastBottomMargin;
}
async function verifyActionOccured(
browserProxy: TestPrivacySandboxDialogBrowserProxy,
targetAction: PrivacySandboxPromptAction) {
const [action] = await browserProxy.whenCalled('promptActionOccurred');
assertEquals(action, targetAction);
browserProxy.reset();
}
function testClickButton(buttonSelector: string, element: HTMLElement|null) {
const actionButton =
element!.shadowRoot!.querySelector<HTMLElement>(buttonSelector);
assertTrue(
!!actionButton, `the button isn\'t found, selector: ${buttonSelector}`);
actionButton.click();
}
suite('Consent', function() {
let page: PrivacySandboxDialogAppElement;
let browserProxy: TestPrivacySandboxDialogBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isConsent: true,
});
});
setup(async function() {
browserProxy = new TestPrivacySandboxDialogBrowserProxy();
PrivacySandboxDialogBrowserProxy.setInstance(browserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
page = document.createElement('privacy-sandbox-dialog-app');
document.body.appendChild(page);
await browserProxy.whenCalled('resizeDialog');
await browserProxy.whenCalled('showDialog');
});
test('dialogStructure', function() {
// Consent dialog has addditionally an expand button and H2 title. It also
// has a different set of buttons.
assertTrue(isChildVisible(page, '.header h2'));
assertTrue(isChildVisible(page, '.header h3'));
assertTrue(isChildVisible(page, '.section'));
assertTrue(isChildVisible(page, '#expandSection cr-expand-button'));
assertTrue(isChildVisible(page, '#declineButton'));
assertTrue(isChildVisible(page, '#confirmButton'));
assertFalse(isChildVisible(page, '#settingsButton'));
assertFalse(isChildVisible(page, '#ackButton'));
});
test('acceptClicked', async function() {
testClickButton('#confirmButton', page);
const [action] = await browserProxy.whenCalled('promptActionOccurred');
assertEquals(action, PrivacySandboxPromptAction.CONSENT_ACCEPTED);
});
test('declineClicked', async function() {
testClickButton('#declineButton', page);
const [action] = await browserProxy.whenCalled('promptActionOccurred');
assertEquals(action, PrivacySandboxPromptAction.CONSENT_DECLINED);
});
test('learnMoreClicked', async function() {
// In the initial state, the content area isn't scrollable and doesn't have
// a separator in the bottom (represented by 'can-scroll' class).
// The collapse section is closed.
const collapseElement = page.shadowRoot!.querySelector('cr-collapse');
const contentArea: HTMLElement|null =
page.shadowRoot!.querySelector('#contentArea');
let hasScrollbar = doesElemenHaveScrollbar(contentArea!);
assertFalse(collapseElement!.opened);
assertEquals(contentArea!.classList.contains('can-scroll'), hasScrollbar);
// After clicking on the collapse section, the content area expands and
// becomes scrollable with a separator in the bottom. The collapse section
// is opened and the native UI is notified about the action.
testClickButton('#expandSection cr-expand-button', page);
// TODO(crbug.com/40210776): Add testing for the scroll position.
const [openedAction] =
await browserProxy.whenCalled('promptActionOccurred');
assertEquals(
openedAction, PrivacySandboxPromptAction.CONSENT_MORE_INFO_OPENED);
assertTrue(collapseElement!.opened);
assertTrue(contentArea!.classList.contains('can-scroll'));
// Reset proxy in between button clicks.
browserProxy.reset();
// After clicking on the collapse section again, the content area collapses
// and returns to the initial state.
testClickButton('#expandSection cr-expand-button', page);
const [closedAction] =
await browserProxy.whenCalled('promptActionOccurred');
hasScrollbar = doesElemenHaveScrollbar(contentArea!);
assertEquals(
closedAction, PrivacySandboxPromptAction.CONSENT_MORE_INFO_CLOSED);
assertFalse(collapseElement!.opened);
assertEquals(contentArea!.classList.contains('can-scroll'), hasScrollbar);
});
test('escPressed', async function() {
browserProxy.reset();
pressAndReleaseKeyOn(page, 0, [], 'Escape');
// No user action is triggered by pressing Esc.
assertEquals(browserProxy.getCallCount('promptActionOccurred'), 0);
});
});
suite('Notice', function() {
let page: PrivacySandboxDialogAppElement;
let browserProxy: TestPrivacySandboxDialogBrowserProxy;
suiteSetup(function() {
loadTimeData.overrideValues({
isConsent: false,
});
});
setup(async function() {
browserProxy = new TestPrivacySandboxDialogBrowserProxy();
PrivacySandboxDialogBrowserProxy.setInstance(browserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
page = document.createElement('privacy-sandbox-dialog-app');
document.body.appendChild(page);
await browserProxy.whenCalled('resizeDialog');
await browserProxy.whenCalled('showDialog');
});
test('dialogStructure', function() {
// Notice dialog doesn't have an expand button and H2 title. It also has
// a different set of buttons.
assertFalse(isChildVisible(page, '.header h2'));
assertTrue(isChildVisible(page, '.header h3'));
assertTrue(isChildVisible(page, '.section'));
assertFalse(isChildVisible(page, '#expandSection cr-expand-button'));
assertFalse(isChildVisible(page, '#declineButton'));
assertFalse(isChildVisible(page, '#confirmButton'));
assertTrue(isChildVisible(page, '#settingsButton'));
assertTrue(isChildVisible(page, '#ackButton'));
});
test('ackClicked', async function() {
testClickButton('#ackButton', page);
const [action] = await browserProxy.whenCalled('promptActionOccurred');
assertEquals(action, PrivacySandboxPromptAction.NOTICE_ACKNOWLEDGE);
});
test('settingsClicked', async function() {
testClickButton('#settingsButton', page);
const [action] = await browserProxy.whenCalled('promptActionOccurred');
assertEquals(action, PrivacySandboxPromptAction.NOTICE_OPEN_SETTINGS);
});
test('escPressed', async function() {
pressAndReleaseKeyOn(page, 0, [], 'Escape');
const [action] = await browserProxy.whenCalled('promptActionOccurred');
assertEquals(action, PrivacySandboxPromptAction.NOTICE_DISMISS);
});
});
suite('Combined', function() {
let page: PrivacySandboxCombinedDialogAppElement;
let browserProxy: TestPrivacySandboxDialogBrowserProxy;
function getActiveStep(): PrivacySandboxDialogConsentStepElement|
PrivacySandboxDialogNoticeStepElement {
return page.shadowRoot!.querySelector('.active')!;
}
setup(async function() {
browserProxy = new TestPrivacySandboxDialogBrowserProxy();
PrivacySandboxDialogBrowserProxy.setInstance(browserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
page = document.createElement('privacy-sandbox-combined-dialog-app');
page.disableAnimationsForTesting();
document.body.appendChild(page);
await browserProxy.whenCalled('resizeDialog');
await browserProxy.whenCalled('showDialog');
});
test('moreButton', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_SHOWN);
const consentStep = getActiveStep()!;
assertEquals(getActiveStep()!.id, PrivacySandboxCombinedDialogStep.CONSENT);
await flushTasks();
const scrollable: HTMLElement =
consentStep.shadowRoot!.querySelector('[scrollable]')!;
// Turn-off scroll animations.
scrollable.style.scrollBehavior = 'auto';
const allContentVisible = isAllContentVisible(scrollable);
assertEquals(
isChildVisible(consentStep, '#moreButton'), !allContentVisible,
`more button should only be visible when some of the dialog content \
wasn't visible`);
assertEquals(
isChildVisible(consentStep, '#confirmButton'), true,
`confirm button should never be hidden`);
assertEquals(
isChildInParentBounds(consentStep, '#confirmButton'), allContentVisible,
allContentVisible ?
'confirm button should visible if all content dialog is visible' :
`confirm button should not be visible if some of the dialog
content isn't visible from the start`);
assertEquals(
isChildVisible(consentStep, '#declineButton'), true,
`decline button should never be hidden`);
assertEquals(
isChildInParentBounds(consentStep, '#declineButton'), allContentVisible,
allContentVisible ?
'decline button should visible if all content dialog is visible' :
`decline button should not be visible if some of the dialog
content isn't visible from the start`);
if (allContentVisible) {
return;
}
const moreButton: HTMLElement =
consentStep.shadowRoot!.querySelector('#moreButton')!;
moreButton.click();
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_MORE_BUTTON_CLICKED);
await consentStep.whenWasScrolledToBottomForTest();
// After scrolling down, the "More" button is hidden and dialog button are
// visible in the parent bounds.
assertEquals(
isChildVisible(consentStep, '#moreButton'), false,
'more button should not be visible anymore');
assertEquals(
isChildInParentBounds(consentStep, '#confirmButton'), true,
'confirm button should be visible after scrolling to the bottom');
assertEquals(
isChildInParentBounds(consentStep, '#declineButton'), true,
'decline button should be visible after scrolling to the bottom');
});
test('acceptConsentAndAckNotice', async function() {
// Verify that dialog starts with consent step.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_SHOWN);
const consentStep = getActiveStep()!;
assertEquals(getActiveStep()!.id, PrivacySandboxCombinedDialogStep.CONSENT);
// Accept the consent step.
testClickButton('#confirmButton', consentStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_ACCEPTED);
// Resolving consent step triggers saving step.
assertEquals(getActiveStep()!.id, PrivacySandboxCombinedDialogStep.SAVING);
// After saving step has ended (with a delay), the notice is shown.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
const noticeStep = getActiveStep()!;
assertEquals(noticeStep!.id, PrivacySandboxCombinedDialogStep.NOTICE);
// Acknowledge the notice.
testClickButton('#ackButton', noticeStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_ACKNOWLEDGE);
});
test('acceptConsentAndOpenSettings', async function() {
// Verify that dialog starts with consent step.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_SHOWN);
const consentStep = getActiveStep()!;
assertEquals(consentStep!.id, PrivacySandboxCombinedDialogStep.CONSENT);
// Accept the consent step.
testClickButton('#confirmButton', consentStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_ACCEPTED);
// Resolving consent step triggers saving step.
assertEquals(getActiveStep()!.id, PrivacySandboxCombinedDialogStep.SAVING);
// After saving step has ended (with a delay), the notice is shown.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
const noticeStep = getActiveStep()!;
assertEquals(getActiveStep()!.id, PrivacySandboxCombinedDialogStep.NOTICE);
// Click 'Open settings' button.
testClickButton('#settingsButton', noticeStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_OPEN_SETTINGS);
});
test('declineConsentAndAckNotice', async function() {
// Verify that dialog starts with consent step.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_SHOWN);
const consentStep = getActiveStep()!;
assertEquals(consentStep!.id, PrivacySandboxCombinedDialogStep.CONSENT);
// Decline the consent step.
testClickButton('#declineButton', consentStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_DECLINED);
// Resolving consent step triggers saving step.
assertEquals(getActiveStep()!.id, PrivacySandboxCombinedDialogStep.SAVING);
// After saving step has ended (with a delay), the notice is shown.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
const noticeStep = getActiveStep()!;
assertEquals(noticeStep!.id, PrivacySandboxCombinedDialogStep.NOTICE);
// Acknowledge the notice.
testClickButton('#ackButton', noticeStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_ACKNOWLEDGE);
});
test('declineConsentAndOpenSettings', async function() {
// Verify that dialog starts with consent step.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_SHOWN);
const consentStep = getActiveStep()!;
assertEquals(consentStep!.id, PrivacySandboxCombinedDialogStep.CONSENT);
// Decline the consent step.
testClickButton('#declineButton', consentStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_DECLINED);
// Resolving consent step triggers saving step.
assertEquals(getActiveStep()!.id, PrivacySandboxCombinedDialogStep.SAVING);
// After saving step has ended (with a delay), the notice is shown.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
const noticeStep = getActiveStep()!;
assertEquals(noticeStep!.id, PrivacySandboxCombinedDialogStep.NOTICE);
// Click 'Open settings' button.
testClickButton('#settingsButton', noticeStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_OPEN_SETTINGS);
});
test('learnMoreClicked', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_SHOWN);
const consentStep = getActiveStep()!;
assertEquals(consentStep!.id, PrivacySandboxCombinedDialogStep.CONSENT);
// TODO(crbug.com/40244046): Test scrolling behaviour.
// The collapse section is closed.
const learnMoreElement = consentStep!.shadowRoot!.querySelector(
'privacy-sandbox-dialog-learn-more');
const collapseElement =
learnMoreElement!.shadowRoot!.querySelector('cr-collapse');
assertFalse(collapseElement!.opened);
// The collapse section is opened and the native UI is notified about the
// action.
testClickButton('cr-expand-button', learnMoreElement);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_MORE_INFO_OPENED);
assertTrue(collapseElement!.opened);
// After clicking on the collapse section again, the content area collapses
// and returns to the initial state.
testClickButton('cr-expand-button', learnMoreElement);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_MORE_INFO_CLOSED);
assertFalse(collapseElement!.opened);
});
test('privacyPolicy', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_SHOWN);
const consentStep = getActiveStep()!;
assertEquals(getActiveStep()!.id, PrivacySandboxCombinedDialogStep.CONSENT);
// The collapse section is opened.
const learnMore: HTMLElement = consentStep!.shadowRoot!.querySelector(
'privacy-sandbox-dialog-learn-more')!;
const collapseElement = learnMore!.shadowRoot!.querySelector('cr-collapse');
testClickButton('cr-expand-button', learnMore);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.CONSENT_MORE_INFO_OPENED);
assertTrue(collapseElement!.opened);
// After clicking the privacy policy link, the privacy policy page should be
// opened.
const privacyPolicyDiv =
learnMore!.querySelector<HTMLElement>('#privacyPolicyDiv');
const privacyPolicyLink =
privacyPolicyDiv!.querySelector<HTMLElement>('#privacyPolicyLink');
assertTrue(
!!privacyPolicyLink,
`the link isn\'t found, selector: ${privacyPolicyDiv}`);
privacyPolicyLink.click();
assertEquals(
getActiveStep()!.id, PrivacySandboxCombinedDialogStep.PRIVACYPOLICY);
});
});
suite('NoticeEEA', function() {
let page: PrivacySandboxCombinedDialogAppElement;
let browserProxy: TestPrivacySandboxDialogBrowserProxy;
function getActiveStep(): PrivacySandboxDialogNoticeStepElement {
return page.shadowRoot!.querySelector('.active')!;
}
setup(async function() {
browserProxy = new TestPrivacySandboxDialogBrowserProxy();
PrivacySandboxDialogBrowserProxy.setInstance(browserProxy);
window.history.replaceState({}, '', '?step=notice');
document.body.innerHTML = window.trustedTypes!.emptyHTML;
page = document.createElement('privacy-sandbox-combined-dialog-app');
page.disableAnimationsForTesting();
document.body.appendChild(page);
await browserProxy.whenCalled('resizeDialog');
await browserProxy.whenCalled('showDialog');
});
test('moreButton', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
const noticeStep = getActiveStep();
assertEquals(noticeStep!.id, PrivacySandboxCombinedDialogStep.NOTICE);
await flushTasks();
const scrollable: HTMLElement =
noticeStep.shadowRoot!.querySelector('[scrollable]')!;
// Turn-off scroll animations.
scrollable.style.scrollBehavior = 'auto';
const allContentVisible = isAllContentVisible(scrollable);
assertEquals(
isChildVisible(noticeStep, '#moreButton'), !allContentVisible,
`more button should only be visible when some of the dialog content
wasn't visible`);
assertEquals(
isChildVisible(noticeStep, '#ackButton'), true,
`ack button should never be hidden`);
assertEquals(
isChildInParentBounds(noticeStep, '#ackButton'), allContentVisible,
allContentVisible ?
'ack button should visible if all content dialog is visible' :
`ack button should not be visible if some of the dialog content
isn't visible from the start`);
assertEquals(
isChildVisible(noticeStep, '#settingsButton'), true,
`settings button should never be hidden`);
assertEquals(
isChildInParentBounds(noticeStep, '#settingsButton'), allContentVisible,
allContentVisible ?
'settings button should visible if all content dialog is visible' :
`settings button should not be visible if some of the dialog \
content isn't visible from the start`);
if (allContentVisible) {
return;
}
const moreButton: HTMLElement =
noticeStep.shadowRoot!.querySelector('#moreButton')!;
moreButton.click();
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_MORE_BUTTON_CLICKED);
await noticeStep.whenWasScrolledToBottomForTest();
// After scrolling down, the "More" button is hidden and dialog button are
// visible in the parent bounds.
assertEquals(
isChildVisible(noticeStep, '#moreButton'), false,
'more button should not be visible anymore');
assertEquals(
isChildInParentBounds(noticeStep, '#ackButton'), true,
'ack button should be visible after scrolling to the bottom');
assertEquals(
isChildInParentBounds(noticeStep, '#settingsButton'), true,
'settings button should be visible after scrolling to the bottom');
});
test('ackClicked', async function() {
// Verify that dialog starts with notice step.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
const noticeStep = getActiveStep();
assertEquals(noticeStep!.id, PrivacySandboxCombinedDialogStep.NOTICE);
// Acknowledge the notice.
testClickButton('#ackButton', noticeStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_ACKNOWLEDGE);
});
test('settingsClicked', async function() {
// Verify that dialog starts with notice step.
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
const noticeStep = getActiveStep();
assertEquals(noticeStep!.id, PrivacySandboxCombinedDialogStep.NOTICE);
// Acknowledge the notice.
testClickButton('#settingsButton', noticeStep);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_OPEN_SETTINGS);
});
test('learnMoreClicked', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
const noticeStep = getActiveStep();
assertEquals(noticeStep!.id, PrivacySandboxCombinedDialogStep.NOTICE);
// TODO(crbug.com/40244046): Test scrolling behaviour.
// The collapse section is closed.
const learnMoreElement = noticeStep!.shadowRoot!.querySelector(
'privacy-sandbox-dialog-learn-more');
const collapseElement =
learnMoreElement!.shadowRoot!.querySelector('cr-collapse');
assertFalse(collapseElement!.opened);
// The collapse section is opened and the native UI is notified about the
// action.
testClickButton('cr-expand-button', learnMoreElement);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_MORE_INFO_OPENED);
assertTrue(collapseElement!.opened);
// After clicking on the collapse section again, the content area collapses
// and returns to the initial state.
testClickButton('cr-expand-button', learnMoreElement);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_MORE_INFO_CLOSED);
assertFalse(collapseElement!.opened);
});
});
suite('NoticeROW', function() {
let page: PrivacySandboxNoticeDialogAppElement;
let browserProxy: TestPrivacySandboxDialogBrowserProxy;
setup(async function() {
browserProxy = new TestPrivacySandboxDialogBrowserProxy();
PrivacySandboxDialogBrowserProxy.setInstance(browserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
page = document.createElement('privacy-sandbox-notice-dialog-app');
document.body.appendChild(page);
await browserProxy.whenCalled('resizeDialog');
await browserProxy.whenCalled('showDialog');
});
// TODO(crbug.com/1432915, crbug.com/1432915): various more button test
// issues. Re-enable once resolved.
test.skip('moreButton', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
await flushTasks();
const scrollable: HTMLElement =
page.shadowRoot!.querySelector('[scrollable]')!;
// Turn-off scroll animations.
scrollable.style.scrollBehavior = 'auto';
const allContentVisible = isAllContentVisible(scrollable);
assertEquals(
isChildVisible(page, '#moreButton'), !allContentVisible,
`more button should only be visible when some of the dialog content
wasn't visible`);
assertEquals(
isChildVisible(page, '#ackButton'), true,
`ack button should never be hidden`);
assertEquals(
isChildInParentBounds(page, '#ackButton'), allContentVisible,
allContentVisible ?
'ack button should visible if all content dialog is visible' :
`ack button should not be visible if some of the dialog content \
isn't visible from the start`);
assertEquals(
isChildVisible(page, '#settingsButton'), true,
`settings button should never be hidden`);
assertEquals(
isChildInParentBounds(page, '#settingsButton'), allContentVisible,
allContentVisible ?
'settings button should visible if all content dialog is visible' :
`settings button should not be visible if some of the dialog \
content isn't visible from the start`);
if (allContentVisible) {
return;
}
const moreButton: HTMLElement =
page.shadowRoot!.querySelector('#moreButton')!;
moreButton.click();
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_MORE_BUTTON_CLICKED);
await page.whenWasScrolledToBottomForTest();
// After scrolling down, the "More" button is hidden and dialog button are
// visible in the parent bounds.
assertEquals(
isChildVisible(page, '#moreButton'), false,
'more button should not be visible anymore');
assertEquals(
isChildInParentBounds(page, '#ackButton'), true,
'ack button should be visible after scrolling to the bottom');
assertEquals(
isChildInParentBounds(page, '#settingsButton'), true,
'settings button should be visible after scrolling to the bottom');
});
test('ackClicked', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
testClickButton('#ackButton', page);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_ACKNOWLEDGE);
});
test('settingsClicked', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
testClickButton('#settingsButton', page);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_OPEN_SETTINGS);
});
test('learnMoreClicked', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_SHOWN);
// TODO(crbug.com/40244046): Test scrolling behaviour.
// The collapse section is closed.
const learnMoreElement =
page.shadowRoot!.querySelector('privacy-sandbox-dialog-learn-more');
const collapseElement =
learnMoreElement!.shadowRoot!.querySelector('cr-collapse');
assertFalse(collapseElement!.opened);
// The collapse section is opened and the native UI is notified about the
// action.
testClickButton('cr-expand-button', learnMoreElement);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_MORE_INFO_OPENED);
assertTrue(collapseElement!.opened);
// After clicking on the collapse section again, the content area collapses
// and returns to the initial state.
testClickButton('cr-expand-button', learnMoreElement);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.NOTICE_MORE_INFO_CLOSED);
assertFalse(collapseElement!.opened);
});
});
suite('NoticeRestricted', function() {
let page: PrivacySandboxNoticeRestrictedDialogAppElement;
let browserProxy: TestPrivacySandboxDialogBrowserProxy;
setup(async function() {
browserProxy = new TestPrivacySandboxDialogBrowserProxy();
PrivacySandboxDialogBrowserProxy.setInstance(browserProxy);
document.body.innerHTML = window.trustedTypes!.emptyHTML;
page =
document.createElement('privacy-sandbox-notice-restricted-dialog-app');
document.body.appendChild(page);
await browserProxy.whenCalled('resizeDialog');
await browserProxy.whenCalled('showDialog');
});
test('validDialog', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.RESTRICTED_NOTICE_SHOWN);
assertTrue(!!page.shadowRoot!.querySelector('div'));
});
test('settingsClicked', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.RESTRICTED_NOTICE_SHOWN);
testClickButton('#settingsButton', page);
await verifyActionOccured(
browserProxy,
PrivacySandboxPromptAction.RESTRICTED_NOTICE_OPEN_SETTINGS);
});
test('acknowledgeClicked', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.RESTRICTED_NOTICE_SHOWN);
testClickButton('#ackButton', page);
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.RESTRICTED_NOTICE_ACKNOWLEDGE);
});
// TODO(b/277180533): determine whether some of the more button test logic can
// be shared.
// TODO(crbug.com/40903181): various more button test issues. Re-enable once
// resolved.
test.skip('moreButton', async function() {
await verifyActionOccured(
browserProxy, PrivacySandboxPromptAction.RESTRICTED_NOTICE_SHOWN);
await flushTasks();
const scrollable: HTMLElement =
page.shadowRoot!.querySelector('[scrollable]')!;
// Turn-off scroll animations.
scrollable.style.scrollBehavior = 'auto';
const allContentVisible = isAllContentVisible(scrollable);
assertEquals(
isChildVisible(page, '#moreButton'), !allContentVisible,
`more button should only be visible when some of the dialog content
wasn't visible`);
assertEquals(
isChildVisible(page, '#ackButton'), true,
`ack button should never be hidden`);
assertEquals(
isChildInParentBounds(page, '#ackButton'), allContentVisible,
allContentVisible ?
'ack button should visible if all content dialog is visible' :
`ack button should not be visible if some of the dialog content \
isn't visible from the start`);
assertEquals(
isChildVisible(page, '#settingsButton'), true,
`settings button should never be hidden`);
assertEquals(
isChildInParentBounds(page, '#settingsButton'), allContentVisible,
allContentVisible ?
'settings button should visible if all content dialog is visible' :
`settings button should not be visible if some of the dialog \
content isn't visible from the start`);
if (allContentVisible) {
return;
}
const moreButton: HTMLElement =
page.shadowRoot!.querySelector('#moreButton')!;
// Click until reaching the bottom.
while (isChildVisible(page, '#moreButton')) {
moreButton.click();
await waitForScrollToFinish(scrollable);
}
await verifyActionOccured(
browserProxy,
PrivacySandboxPromptAction.RESTRICTED_NOTICE_MORE_BUTTON_CLICKED);
await page.whenWasScrolledToBottomForTest();
// After scrolling down, the "More" button is hidden and dialog button are
// visible in the parent bounds.
assertEquals(
isChildVisible(page, '#moreButton'), false,
'more button should not be visible anymore');
assertEquals(
isChildInParentBounds(page, '#ackButton'), true,
'ack button should be visible after scrolling to the bottom');
assertEquals(
isChildInParentBounds(page, '#settingsButton'), true,
'settings button should be visible after scrolling to the bottom');
});
});
suite('Mixin', function() {
const TestElementBase = PrivacySandboxDialogMixin(PolymerElement);
// Create a test element to have more control over size of the element and
// test edge cases for 'more' button logic.
class TestElement extends TestElementBase {
static get is() {
return 'test-element';
}
static get template() {
return html`
<style>
#container {
width: 500px;
height: 614px;
position: relative;
border: 1px solid red;
}
.content-area {
bottom: 64px;
position: absolute;
background: green;
overflow-y: overlay;
top: 0;
width: 100%;
}
.buttons-container {
height: 64px;
position: fixed;
box-sizing: border-box;
bottom: 0;
right: 0;
width: 100%;
background: yellow;
}
.more-content-available .buttons-container {
position: static;
}
.more-content-available.content-area {
bottom: 0;
}
.section {
height: 100px;
margin: 10px 0px;
background: blue;
}
.section.big {
height: 200px;
}
#showMoreOverlay {
position: fixed;
bottom: 0;
width: 100%;
height: 64px;
}
</style>
<div id="container">
<div id="textContent" class="content-area" scrollable>
<div class="section">Text paragraph 1</div>
<div class="section big">Text paragraph 2</div>
<div class="section">Text paragraph 3</div>
<div id="lastTextElement" class="section">Text paragraph 4</div>
<div class="buttons-container">
Button container
</div>
</div>
<div id="showMoreOverlay" hidden="[[wasScrolledToBottom]]">
<button id="moreButton" on-click="onMoreClicked_">More</button>
</div>
</div>
`;
}
}
customElements.define(TestElement.is, TestElement);
let testElement: TestElement;
let container: HTMLElement;
let scrollable: HTMLElement;
let moreButton: HTMLElement;
let fullContainerHeight: number;
const LAST_BOTTOM_MARGIN = 10;
setup(function() {
document.body.innerHTML = window.trustedTypes!.emptyHTML;
testElement = document.createElement('test-element') as TestElement;
document.body.appendChild(testElement);
container = testElement.shadowRoot!.querySelector('#container')!;
scrollable = testElement.shadowRoot!.querySelector('[scrollable]')!;
moreButton = testElement.shadowRoot!.querySelector('#moreButton')!;
const buttons: HTMLElement =
testElement.shadowRoot!.querySelector('.buttons-container')!;
fullContainerHeight = scrollable.scrollHeight + buttons.clientHeight;
});
test('content not scrollable', async function() {
container.style.height = `${fullContainerHeight}px`;
assertFalse(
doesElemenHaveScrollbar(scrollable),
'content should not have a scrollbar');
await testElement.maybeShowMoreButton();
assertTrue(
testElement.wasScrolledToBottom, 'last text element should be visible');
});
test('only bottom margin of the last element not shown', async function() {
container.style.height = `${fullContainerHeight - LAST_BOTTOM_MARGIN}px`;
flush();
assertTrue(
doesElemenHaveScrollbar(scrollable), 'content should have a scrollbar');
await testElement.maybeShowMoreButton();
assertTrue(
testElement.wasScrolledToBottom, 'last text element should be visible');
});
// The 2 pixels vs 1 pixel choice here is due to intersectionRatio being
// sometimes reported as 0.99 instead of 1.
// See more at crbug.com/1020466 and b/299120185.
test('2px of the last text element not shown', async function() {
container.style.height =
`${fullContainerHeight - LAST_BOTTOM_MARGIN - 2}px`;
assertTrue(
doesElemenHaveScrollbar(scrollable), 'content should have a scrollbar');
await testElement.maybeShowMoreButton();
assertFalse(
testElement.wasScrolledToBottom, 'last text element wasn\'t shown');
moreButton.click();
await testElement.whenWasScrolledToBottomForTest();
assertTrue(
testElement.wasScrolledToBottom,
'last text element was shown after scrolling to the bottom');
});
test('last element not shown', async function() {
container.style.height = `${fullContainerHeight - 100}px`;
assertTrue(
doesElemenHaveScrollbar(scrollable), 'content should have a scrollbar');
await testElement.maybeShowMoreButton();
assertFalse(
testElement.wasScrolledToBottom, 'last text element wasn\'t shown');
moreButton.click();
await testElement.whenWasScrolledToBottomForTest();
assertTrue(
testElement.wasScrolledToBottom,
'last text element was shown after scrolling to the bottom');
});
test('requires more than one "more" button click', async function() {
const containerHeight = fullContainerHeight / 2 - 50;
container.style.height = `${containerHeight}px`;
assertTrue(
doesElemenHaveScrollbar(scrollable), 'content should have a scrollbar');
await testElement.maybeShowMoreButton();
assertFalse(
testElement.wasScrolledToBottom, 'last text element wasn\'t shown');
moreButton.click();
await waitForScrollToFinish(scrollable);
assertEquals(containerHeight, scrollable.scrollTop);
assertFalse(
testElement.wasScrolledToBottom, 'last text element wasn\'t yet shown');
moreButton.click();
await testElement.whenWasScrolledToBottomForTest();
assertTrue(
testElement.wasScrolledToBottom,
'last text element was shown after scrolling to the bottom');
});
});