chromium/chrome/test/data/webui/settings/site_settings_page_test.ts

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// clang-format off
import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import type {CrExpandButtonElement, SettingsSiteSettingsPageElement} from 'chrome://settings/lazy_load.js';
import {ContentSetting, CookieControlsMode, ContentSettingsTypes, defaultSettingLabel, SettingsState, SafetyHubBrowserProxyImpl, SafetyHubEvent} from 'chrome://settings/lazy_load.js';
import type {CrLinkRowElement, SettingsToggleButtonElement} from 'chrome://settings/settings.js';
import {Router, routes} from 'chrome://settings/settings.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {isChildVisible} from 'chrome://webui-test/test_util.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';

import {TestSafetyHubBrowserProxy} from './test_safety_hub_browser_proxy.js';

// clang-format on

suite('SiteSettingsPage', function() {
  let page: SettingsSiteSettingsPageElement;

  function setupPage() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-site-settings-page');
    page.prefs = {
      generated: {
        notification: {
          type: chrome.settingsPrivate.PrefType.NUMBER,
          value: SettingsState.LOUD,
        },
        cookie_default_content_setting: {
          type: chrome.settingsPrivate.PrefType.STRING,
          value: ContentSetting.ALLOW,
        },
        geolocation: {
          type: chrome.settingsPrivate.PrefType.NUMBER,
          value: SettingsState.LOUD,
        },
      },
      profile: {
        cookie_controls_mode: {
          type: chrome.settingsPrivate.PrefType.NUMBER,
          value: CookieControlsMode.OFF,
        },
      },
      safety_hub: {
        unused_site_permissions_revocation: {
          enabled: {
            type: chrome.settingsPrivate.PrefType.BOOLEAN,
            value: true,
          },
        },
      },
      compose: {
        proactive_nudge_enabled: {
          enabled: {
            type: chrome.settingsPrivate.PrefType.BOOLEAN,
            value: true,
          },
        },
      },
    };
    document.body.appendChild(page);
    flush();
  }

  setup(setupPage);

  teardown(function() {
    page.remove();
  });

  test('DefaultLabels', function() {
    assertEquals('a', defaultSettingLabel(ContentSetting.ALLOW, 'a', 'b'));
    assertEquals('b', defaultSettingLabel(ContentSetting.BLOCK, 'a', 'b'));
    assertEquals('a', defaultSettingLabel(ContentSetting.ALLOW, 'a', 'b', 'c'));
    assertEquals('b', defaultSettingLabel(ContentSetting.BLOCK, 'a', 'b', 'c'));
    assertEquals(
        'c', defaultSettingLabel(ContentSetting.SESSION_ONLY, 'a', 'b', 'c'));
    assertEquals(
        'c', defaultSettingLabel(ContentSetting.DEFAULT, 'a', 'b', 'c'));
    assertEquals('c', defaultSettingLabel(ContentSetting.ASK, 'a', 'b', 'c'));
    assertEquals(
        'c',
        defaultSettingLabel(ContentSetting.IMPORTANT_CONTENT, 'a', 'b', 'c'));
  });

  test('AntiAbuseLinkRowHidden', async function() {
    loadTimeData.overrideValues({
      privateStateTokensEnabled: false,
    });
    setupPage();
    assertFalse(isChildVisible(
        page.$.advancedContentList, `#${ContentSettingsTypes.ANTI_ABUSE}`));
  });

  test('CookiesLinkRowSublabel', async function() {
    // This test verifies the pre-3PCD label.
    loadTimeData.overrideValues({
      is3pcdCookieSettingsRedesignEnabled: false,
    });
    setupPage();
    const cookiesLinkRow =
        page.shadowRoot!.querySelector('#basicContentList')!.shadowRoot!
            .querySelector<CrLinkRowElement>('#cookies')!;

    page.set(
        'prefs.profile.cookie_controls_mode.value',
        CookieControlsMode.BLOCK_THIRD_PARTY);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('thirdPartyCookiesLinkRowSublabelDisabled'),
        cookiesLinkRow.subLabel);

    page.set(
        'prefs.profile.cookie_controls_mode.value',
        CookieControlsMode.INCOGNITO_ONLY);
    await flushTasks();
    assertEquals(
        loadTimeData.getString(
            'thirdPartyCookiesLinkRowSublabelDisabledIncognito'),
        cookiesLinkRow.subLabel);

    page.set(
        'prefs.profile.cookie_controls_mode.value', CookieControlsMode.OFF);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('thirdPartyCookiesLinkRowSublabelEnabled'),
        cookiesLinkRow.subLabel);
  });

  test('TrackingProtectionLinkRowSubLabel', async function() {
    loadTimeData.overrideValues({
      is3pcdCookieSettingsRedesignEnabled: true,
    });
    setupPage();
    const cookiesLinkRow =
        page.shadowRoot!.querySelector('#basicContentList')!.shadowRoot!
            .querySelector<CrLinkRowElement>('#cookies')!;
    assertEquals(
        loadTimeData.getString('trackingProtectionLinkRowSubLabel'),
        cookiesLinkRow.subLabel);

    // Even if cookie controls mode changes, sub-label stays the same.
    page.set(
        'prefs.profile.cookie_controls_mode.value',
        CookieControlsMode.BLOCK_THIRD_PARTY);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('trackingProtectionLinkRowSubLabel'),
        cookiesLinkRow.subLabel);

    page.set(
        'prefs.profile.cookie_controls_mode.value', CookieControlsMode.OFF);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('trackingProtectionLinkRowSubLabel'),
        cookiesLinkRow.subLabel);
  });

  test('NotificationsLinkRowSublabel', async function() {
    const notificationsLinkRow =
        page.shadowRoot!.querySelector('#basicPermissionsList')!.shadowRoot!
            .querySelector<CrLinkRowElement>('#notifications')!;

    page.set('prefs.generated.notification.value', SettingsState.BLOCK);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('siteSettingsNotificationsBlocked'),
        notificationsLinkRow.subLabel);

    page.set('prefs.generated.notification.value', SettingsState.QUIET);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('siteSettingsNotificationsAskQuiet'),
        notificationsLinkRow.subLabel);

    page.set('prefs.generated.notification.value', SettingsState.LOUD);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('siteSettingsNotificationsAskLoud'),
        notificationsLinkRow.subLabel);
  });

  test('ProtectedContentRow', async function() {
    setupPage();
    const expandButton =
        page.shadowRoot!.querySelector<CrExpandButtonElement>('#expandContent');
    assertTrue(!!expandButton);
    expandButton.click();
    await expandButton.updateComplete;
    assertTrue(isChildVisible(
        page.shadowRoot!.querySelector('#advancedContentList')!,
        '#protected-content'));
  });

  test('SiteDataLinkRowSublabel', async function() {
    setupPage();
    page.shadowRoot!.querySelector<HTMLElement>('#expandContent')!.click();
    flush();

    const siteDataLinkRow =
        page.shadowRoot!.querySelector('#advancedContentList')!.shadowRoot!
            .querySelector<CrLinkRowElement>('#site-data')!;

    page.set(
        'prefs.generated.cookie_default_content_setting.value',
        ContentSetting.BLOCK);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('siteSettingsSiteDataBlockedSubLabel'),
        siteDataLinkRow.subLabel);

    page.set(
        'prefs.generated.cookie_default_content_setting.value',
        ContentSetting.SESSION_ONLY);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('siteSettingsSiteDataDeleteOnExitSubLabel'),
        siteDataLinkRow.subLabel);

    page.set(
        'prefs.generated.cookie_default_content_setting.value',
        ContentSetting.ALLOW);
    await flushTasks();
    assertEquals(
        loadTimeData.getString('siteSettingsSiteDataAllowedSubLabel'),
        siteDataLinkRow.subLabel);
  });

  test('StorageAccessLinkRow', function() {
    assertTrue(isChildVisible(
        page.shadowRoot!.querySelector('#basicPermissionsList')!,
        '#storage-access'));
  });

  test('AutomaticFullscreenRow', async function() {
    const expandButton =
        page.shadowRoot!.querySelector<CrExpandButtonElement>('#expandContent');
    assertTrue(!!expandButton);
    expandButton.click();
    await expandButton.updateComplete;
    assertTrue(isChildVisible(
      page.shadowRoot!.querySelector('#advancedContentList')!,
      '#automatic-fullscreen'));
  });

  // TODO(crbug.com/40267370): Remove after SafetyHub is launched.
  test('UnusedSitePermissionsControlToggleExists', function() {
    assertTrue(isChildVisible(page, '#unusedSitePermissionsRevocationToggle'));
  });

  test('UnusedSitePermissionsControlToggleUpdatesPrefs', function() {
    const unusedSitePermissionsRevocationToggle =
        page.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#unusedSitePermissionsRevocationToggle')!;

    unusedSitePermissionsRevocationToggle.click();
    flush();
    assertFalse(Boolean(page.get(
        'prefs.safety_hub.unused_site_permissions_revocation.enabled.value')));

    unusedSitePermissionsRevocationToggle.click();
    flush();
    assertTrue(Boolean(page.get(
        'prefs.safety_hub.unused_site_permissions_revocation.enabled.value')));
  });

});

const unusedSitePermissionMockData = [{
  origin: 'www.example.com',
  permissions: [ContentSettingsTypes.CAMERA],
  expiration: '13317004800000000',  // Represents 2023-01-01T00:00:00.
}];

suite('UnusedSitePermissionsReview', function() {
  let page: SettingsSiteSettingsPageElement;
  let safetyHubBrowserProxy: TestSafetyHubBrowserProxy;

  setup(async function() {
    safetyHubBrowserProxy = new TestSafetyHubBrowserProxy();
    SafetyHubBrowserProxyImpl.setInstance(safetyHubBrowserProxy);
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-site-settings-page');
    document.body.appendChild(page);
    await flushTasks();
  });

  test('VisibilityWithChangingPermissionList', async function() {
    // The element is not visible when there is nothing to review.
    assertFalse(isChildVisible(page, '#safetyHubModule'));

    // The element becomes visible if the list of permissions is no longer
    // empty.
    webUIListenerCallback(
        SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED,
        unusedSitePermissionMockData);
    await flushTasks();
    assertTrue(isChildVisible(page, '#safetyHubModule'));

    // Once visible, it remains visible regardless of list length.
    webUIListenerCallback(SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED, []);
    await flushTasks();
    assertTrue(isChildVisible(page, '#safetyHubModule'));

    webUIListenerCallback(
        SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED,
        unusedSitePermissionMockData);
    await flushTasks();
    assertTrue(isChildVisible(page, '#safetyHubModule'));
  });

  test('Button Click', async function() {
    // The element becomes visible if the list of permissions isn't empty.
    webUIListenerCallback(
        SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED,
        unusedSitePermissionMockData);
    await flushTasks();

    page.shadowRoot!.querySelector<HTMLElement>('#safetyHubButton')!.click();
    // Ensure the safety hub page is shown.
    assertEquals(routes.SAFETY_HUB, Router.getInstance().getCurrentRoute());
  });

  test('InvisibleWhenGuestMode', async function() {
    loadTimeData.overrideValues({
      isGuest: true,
    });

    // The element is not visible since it is guest mode.
    webUIListenerCallback(
        SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED,
        unusedSitePermissionMockData);
    await flushTasks();
    assertFalse(isChildVisible(page, '#safetyHubModule'));

    // Reset loadTimeData values.
    loadTimeData.overrideValues({
      isGuest: false,
    });
  });
});

// TODO(crbug.com/40267370): Remove after crbug/1443466 launched.
suite('UnusedSitePermissionsReviewSafetyHubDisabled', function() {
  let page: SettingsSiteSettingsPageElement;
  let safetyHubBrowserProxy: TestSafetyHubBrowserProxy;

  suiteSetup(function() {
    loadTimeData.overrideValues({
      enableSafetyHub: false,
    });
  });

  setup(async function() {
    safetyHubBrowserProxy = new TestSafetyHubBrowserProxy();
    SafetyHubBrowserProxyImpl.setInstance(safetyHubBrowserProxy);
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-site-settings-page');
    document.body.appendChild(page);
    await flushTasks();
  });

  test('VisibilityWithChangingPermissionList', async function() {
    // The element is not visible when there is nothing to review.
    assertFalse(isChildVisible(page, 'settings-unused-site-permissions'));

    // The element becomes visible if the list of permissions is no longer
    // empty.
    webUIListenerCallback(
        SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED,
        unusedSitePermissionMockData);
    await flushTasks();
    assertTrue(isChildVisible(page, 'settings-unused-site-permissions'));

    // Once visible, it remains visible regardless of list length.
    webUIListenerCallback(SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED, []);
    await flushTasks();
    assertTrue(isChildVisible(page, 'settings-unused-site-permissions'));

    webUIListenerCallback(
        SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED,
        unusedSitePermissionMockData);
    await flushTasks();
    assertTrue(isChildVisible(page, 'settings-unused-site-permissions'));
  });

  test('InvisibleWhenGuestMode', async function() {
    loadTimeData.overrideValues({
      isGuest: true,
    });

    // The element is not visible since it is guest mode.
    webUIListenerCallback(
        SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED,
        unusedSitePermissionMockData);
    await flushTasks();
    assertFalse(isChildVisible(page, 'settings-unused-site-permissions'));

    // Reset loadTimeData values.
    loadTimeData.overrideValues({
      isGuest: false,
    });
  });
});

/**
 * If feature is not enabled, the UI should not be shown regardless of whether
 * there would be unused site permissions for the user to review.
 *
 * TODO(crbug.com/40232296): Remove after crbug/1345920 launched.
 */
suite('UnusedSitePermissionsReviewDisabled', function() {
  let page: SettingsSiteSettingsPageElement;
  let safetyHubBrowserProxy: TestSafetyHubBrowserProxy;

  suiteSetup(function() {
    loadTimeData.overrideValues({
      safetyCheckUnusedSitePermissionsEnabled: false,
    });
  });

  setup(function() {
    safetyHubBrowserProxy = new TestSafetyHubBrowserProxy();
    SafetyHubBrowserProxyImpl.setInstance(safetyHubBrowserProxy);
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
  });

  test('InvisibleWhenFeatureDisabled', async function() {
    safetyHubBrowserProxy.setUnusedSitePermissions([]);
    page = document.createElement('settings-site-settings-page');
    document.body.appendChild(page);
    await flushTasks();

    assertFalse(isChildVisible(page, 'settings-unused-site-permissions'));
  });

  test('InvisibleWhenFeatureDisabledWithItemsToReview', async function() {
    safetyHubBrowserProxy.setUnusedSitePermissions(
        unusedSitePermissionMockData);
    page = document.createElement('settings-site-settings-page');
    document.body.appendChild(page);
    await flushTasks();

    assertFalse(isChildVisible(page, 'settings-unused-site-permissions'));
  });
});

// TODO(crbug.com/40267370): Remove after SafetyHub is launched.
suite('SafetyHubDisabled', function() {
  let page: SettingsSiteSettingsPageElement;

  suiteSetup(function() {
    loadTimeData.overrideValues({
      enableSafetyHub: false,
    });
  });

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-site-settings-page');
    document.body.appendChild(page);
    flush();
  });

  test('NoUnusedSitePermissionsControlToggle', function() {
    assertFalse(
        Boolean(page.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#unusedSitePermissionsRevocationToggle')));
  });
});

/**
 * If unused site permissions feature is not enabled, but abusive notification
 * revocation is enabled, the UI should be shown if there are permissions for
 * the user to review.
 *
 * TODO(crbug.com/328773301): Remove after
 * SafetyHubAbusiveNotificationRevocation is launched.
 */
suite('AbusiveNotificationsEnabledUnusedSitePermissionsDisabled', function() {
  let page: SettingsSiteSettingsPageElement;
  let safetyHubBrowserProxy: TestSafetyHubBrowserProxy;

  suiteSetup(function() {
    loadTimeData.overrideValues({
      enableSafetyHub: false,
      safetyCheckUnusedSitePermissionsEnabled: false,
      safetyHubAbusiveNotificationRevocationEnabled: true,
    });
  });

  setup(async function() {
    safetyHubBrowserProxy = new TestSafetyHubBrowserProxy();
    SafetyHubBrowserProxyImpl.setInstance(safetyHubBrowserProxy);
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-site-settings-page');
    document.body.appendChild(page);
    await flushTasks();
  });

  test(
      'VisibleWithItemsToReviewUnusedSitePermissionsDisabled',
      async function() {
        // The element is not visible when there is nothing to review.
        assertFalse(isChildVisible(page, 'settings-unused-site-permissions'));

        // The element becomes visible if the list of permissions is no longer
        // empty.
        webUIListenerCallback(
            SafetyHubEvent.UNUSED_PERMISSIONS_MAYBE_CHANGED,
            unusedSitePermissionMockData);
        await flushTasks();
        assertTrue(isChildVisible(page, 'settings-unused-site-permissions'));
      });
});