chromium/chrome/test/data/webui/settings/security_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 {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import type {SettingsSecurityPageElement} from 'chrome://settings/lazy_load.js';
import {HttpsFirstModeSetting, SafeBrowsingSetting} from 'chrome://settings/lazy_load.js';
import type {SettingsPrefsElement, SettingsToggleButtonElement} from 'chrome://settings/settings.js';
import {HatsBrowserProxyImpl, CrSettingsPrefs, MetricsBrowserProxyImpl, OpenWindowProxyImpl, PrivacyElementInteractions, PrivacyPageBrowserProxyImpl, resetRouterForTesting, Router, routes, SafeBrowsingInteractions, SecureDnsMode, SecurityPageInteraction} from 'chrome://settings/settings.js';
import {assertEquals, assertFalse, assertTrue, assertNotEquals} from 'chrome://webui-test/chai_assert.js';
import {isChildVisible, eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';

import {TestHatsBrowserProxy} from './test_hats_browser_proxy.js';
import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js';

import {TestOpenWindowProxy} from 'chrome://webui-test/test_open_window_proxy.js';

import {TestPrivacyPageBrowserProxy} from './test_privacy_page_browser_proxy.js';

// clang-format on

function pagePrefs() {
  return {
    profile: {password_manager_leak_detection: {value: false}},
    safebrowsing: {
      scout_reporting_enabled: {value: true},
      esb_opt_in_with_friendlier_settings: {value: false},
    },
    generated: {
      safe_browsing: {
        type: chrome.settingsPrivate.PrefType.NUMBER,
        value: SafeBrowsingSetting.STANDARD,
      },
      password_leak_detection: {value: false},
      https_first_mode_enabled: {
        type: chrome.settingsPrivate.PrefType.NUMBER,
        value: HttpsFirstModeSetting.DISABLED,
      },
    },
    dns_over_https:
        {mode: {value: SecureDnsMode.AUTOMATIC}, templates: {value: ''}},
    https_only_mode_enabled: {
      type: chrome.settingsPrivate.PrefType.NUMBER,
      value: HttpsFirstModeSetting.DISABLED,
    },
  };
}

suite('Main', function() {
  let testMetricsBrowserProxy: TestMetricsBrowserProxy;
  let testPrivacyBrowserProxy: TestPrivacyPageBrowserProxy;
  let page: SettingsSecurityPageElement;
  let openWindowProxy: TestOpenWindowProxy;

  suiteSetup(function() {
    loadTimeData.overrideValues({
      enableSecurityKeysSubpage: true,
      enableHttpsFirstModeNewSettings: true,
    });
    resetRouterForTesting();
  });

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;

    testMetricsBrowserProxy = new TestMetricsBrowserProxy();
    MetricsBrowserProxyImpl.setInstance(testMetricsBrowserProxy);
    testPrivacyBrowserProxy = new TestPrivacyPageBrowserProxy();
    PrivacyPageBrowserProxyImpl.setInstance(testPrivacyBrowserProxy);
    openWindowProxy = new TestOpenWindowProxy();
    OpenWindowProxyImpl.setInstance(openWindowProxy);

    page = document.createElement('settings-security-page');
    page.prefs = pagePrefs();
    document.body.appendChild(page);
    page.$.safeBrowsingEnhanced.updateCollapsed();
    page.$.safeBrowsingStandard.updateCollapsed();
    flush();
  });

  teardown(function() {
    page.remove();
    Router.getInstance().navigateTo(routes.BASIC);
  });

  test('ChromeRootStorePage', async function() {
    // Chrome Root Store Help link should not be present since
    // kEnableCertManagementUIV2 feature flag is enabled by
    // SettingsSecurityPageTest constructor.
    // TODO(crbug.com/40928765): remove this comment once the feature flag is
    // set to default enabled.
    const row =
        page.shadowRoot!.querySelector<HTMLElement>('#chromeCertificates');
    assertFalse(!!row, 'Chrome Root Store Help Center link unexpectedly found');
  });

  // <if expr="not chromeos_lacros">
  // TODO(crbug.com/40156980): This class directly calls
  // `CreateNSSCertDatabaseGetterForIOThread()` that causes crash at the
  // moment and is never called from Lacros-Chrome. This should be revisited
  // when there is a solution for the client certificates settings page on
  // Lacros-Chrome.
  test('ManageCertificatesClick', async function() {
    page.shadowRoot!.querySelector<HTMLElement>(
                        '#manageCertificatesLinkRow')!.click();
    const result =
        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
    assertEquals(PrivacyElementInteractions.MANAGE_CERTIFICATES, result);

    const url = await openWindowProxy.whenCalled('openUrl');
    assertEquals(url, loadTimeData.getString('certManagementV2URL'));
  });
  // </if>

  test('ManageSecurityKeysSubpageVisible', function() {
    assertTrue(isChildVisible(page, '#security-keys-subpage-trigger'));
  });

  test('ManageSecurityKeysPhonesSubpageHidden', function() {
    assertFalse(isChildVisible(page, '#security-keys-phones-subpage-trigger'));
  });

  // Tests that changing the HTTPS-First Mode setting sets the associated pref,
  // and that the radio options are correctly shown/hidden based on the top
  // level toggle.
  test('HttpsFirstModeControls', async () => {
    // Check that the old toggle row under "Advanced" is _not_ present.
    const oldToggle =
        page.shadowRoot!.querySelector<HTMLElement>('#httpsOnlyModeToggle');
    assertFalse(!!oldToggle);

    // Test the new settings UI.
    const secureConnections = page.shadowRoot!.querySelector<HTMLElement>(
        '#secureConnectionsSection');
    const toggleButton =
        page.shadowRoot!.querySelector<HTMLElement>('#httpsFirstModeToggle');
    const collapse = page.shadowRoot!.querySelector<HTMLElement>(
        '#httpsFirstModeRadioGroupCollapse');
    const radioGroup = page.shadowRoot!.querySelector<HTMLElement>(
        '#httpsFirstModeRadioGroup');
    assertTrue(!!secureConnections);
    assertTrue(!!toggleButton);
    assertTrue(!!collapse);
    assertTrue(!!radioGroup);

    assertEquals(
        HttpsFirstModeSetting.DISABLED,
        page.getPref('generated.https_first_mode_enabled').value);
    assertFalse(isChildVisible(page, '#httpsFirstModeRadioGroup'));

    // Toggling on the button should (1) expand the cr-collapse, and (2) select
    // the "balanced mode" radio button and set the pref to "balanced".
    toggleButton.click();
    await eventToPromise('transitionend', collapse);
    assertTrue(isChildVisible(page, '#httpsFirstModeRadioGroup'));
    assertEquals(
        HttpsFirstModeSetting.ENABLED_BALANCED,
        page.getPref('generated.https_first_mode_enabled').value);

    // Select the "Strict Mode" radio button.
    let radioButton = page.shadowRoot!.querySelector<HTMLElement>(
        '#httpsFirstModeEnabledStrict');
    assertTrue(!!radioButton);
    radioButton.click();
    await eventToPromise('selected-changed', radioGroup);
    assertEquals(
        HttpsFirstModeSetting.ENABLED_FULL,
        page.getPref('generated.https_first_mode_enabled').value);

    // Select the "Balanced Mode" radio button again.
    radioButton = page.shadowRoot!.querySelector<HTMLElement>(
        '#httpsFirstModeEnabledBalanced');
    assertTrue(!!radioButton);
    radioButton.click();
    await eventToPromise('selected-changed', radioGroup);
    assertEquals(
        HttpsFirstModeSetting.ENABLED_BALANCED,
        page.getPref('generated.https_first_mode_enabled').value);

    // Toggling on the button off should (1) hide the cr-collapse, and (2) fully
    // turn off HTTPS-First Mode.
    toggleButton.click();
    await eventToPromise('transitionend', collapse);
    assertFalse(isChildVisible(page, '#httpsFirstModeRadioGroup'));
    assertEquals(
        HttpsFirstModeSetting.DISABLED,
        page.getPref('generated.https_first_mode_enabled').value);
  });

  // Test that clicking the V8 security row navigates to the setting page.
  test('NavigateToV8Setting', function() {
    const link =
        page.shadowRoot!.querySelector<HTMLElement>('#v8-setting-link');
    assertTrue(!!link);
    link.click();
    assertEquals(
        routes.SITE_SETTINGS_JAVASCRIPT_JIT,
        Router.getInstance().getCurrentRoute());
  });

  // Tests that the correct Advanced Protection sublabel is used when the
  // HTTPS-First Mode setting toggle has user control disabled.
  test('HttpsFirstModeSettingAdvancedProtectionSubLabel', function() {
    const toggle = page.shadowRoot!.querySelector<SettingsToggleButtonElement>(
        '#httpsFirstModeToggle');
    assertTrue(!!toggle);
    const defaultSubLabel =
        loadTimeData.getString('httpsFirstModeSectionDescription');
    assertEquals(defaultSubLabel, toggle.subLabel);

    page.setPrefValue(
        'generated.https_first_mode_enabled', HttpsFirstModeSetting.DISABLED);
    page.set(
        'prefs.generated.https_first_mode_enabled.userControlDisabled', true);
    flush();
    const lockedSubLabel =
        loadTimeData.getString('httpsFirstModeDescriptionAdvancedProtection');
    assertEquals(lockedSubLabel, toggle.subLabel);

    page.setPrefValue(
        'generated.https_first_mode_enabled',
        HttpsFirstModeSetting.ENABLED_FULL);
    page.set(
        'prefs.generated.https_first_mode_enabled.userControlDisabled', true);
    flush();
    assertEquals(lockedSubLabel, toggle.subLabel);
  });
});

suite('SecurityPageHappinessTrackingSurveys', function() {
  let testHatsBrowserProxy: TestHatsBrowserProxy;
  let settingsPrefs: SettingsPrefsElement;
  let page: SettingsSecurityPageElement;

  suiteSetup(function() {
    settingsPrefs = document.createElement('settings-prefs');
    return CrSettingsPrefs.initialized;
  });

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;

    testHatsBrowserProxy = new TestHatsBrowserProxy();
    HatsBrowserProxyImpl.setInstance(testHatsBrowserProxy);

    page = document.createElement('settings-security-page');
    page.prefs = settingsPrefs.prefs;
    document.body.appendChild(page);
    testHatsBrowserProxy.reset();
    Router.getInstance().navigateTo(routes.SECURITY);
    return flushTasks();
  });

  teardown(function() {
    page.remove();
    Router.getInstance().navigateTo(routes.BASIC);
  });

  test('SecurityPageSwitchRouteCallsHatsProxy', async function() {
    const t1 = 10000;
    testHatsBrowserProxy.setNow(t1);
    window.dispatchEvent(new Event('focus'));

    const t2 = 20000;
    testHatsBrowserProxy.setNow(t2);
    window.dispatchEvent(new Event('blur'));

    // Switch tabs within the settings page.
    Router.getInstance().navigateTo(routes.PRIVACY);

    const args =
        await testHatsBrowserProxy.whenCalled('securityPageHatsRequest');

    // Verify that the method securityPageHatsRequest was called and the time
    // the user spent on the security page was logged correctly.
    const expectedTotalTimeInFocus = t2 - t1;
    assertEquals(expectedTotalTimeInFocus, args[2]);
  });

  test('SecurityPageBeforeUnloadCallsHatsProxy', async function() {
    // Interact with the security page.
    page.$.safeBrowsingEnhanced.click();
    await eventToPromise('selected-changed', page.$.safeBrowsingRadioGroup);

    const t1 = 10000;
    testHatsBrowserProxy.setNow(t1);
    window.dispatchEvent(new Event('focus'));

    const t2 = 20000;
    testHatsBrowserProxy.setNow(t2);
    window.dispatchEvent(new Event('blur'));

    const t3 = 60000;
    testHatsBrowserProxy.setNow(t3);
    window.dispatchEvent(new Event('focus'));

    const t4 = 80000;
    testHatsBrowserProxy.setNow(t4);
    window.dispatchEvent(new Event('blur'));

    // Fire the beforeunload event to simulate closing the page.
    window.dispatchEvent(new Event('beforeunload'));

    const args =
        await testHatsBrowserProxy.whenCalled('securityPageHatsRequest');

    // Verify the latest interaction type.
    assertEquals(SecurityPageInteraction.RADIO_BUTTON_ENHANCED_CLICK, args[0]);

    // Verify the safe browsing state on open.
    assertEquals(SafeBrowsingSetting.STANDARD, args[1]);

    // Verify the time the user spend on the security page.
    const expectedTotalTimeInFocus = t2 - t1 + t4 - t3;
    assertEquals(expectedTotalTimeInFocus, args[2]);
  });
});

suite('FlagsDisabled', function() {
  let page: SettingsSecurityPageElement;
  let testMetricsBrowserProxy: TestMetricsBrowserProxy;
  let testPrivacyBrowserProxy: TestPrivacyPageBrowserProxy;
  let openWindowProxy: TestOpenWindowProxy;

  suiteSetup(function() {
    loadTimeData.overrideValues({
      enableSecurityKeysSubpage: false,
      enableHashPrefixRealTimeLookups: false,
      enableHttpsFirstModeNewSettings: false,
      enableCertManagementUIV2: false,
      extendedReportingRemovePrefDependency: false,
      hashPrefixRealTimeLookupsSamplePing: false,
    });
    resetRouterForTesting();
  });

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;

    testMetricsBrowserProxy = new TestMetricsBrowserProxy();
    MetricsBrowserProxyImpl.setInstance(testMetricsBrowserProxy);
    testPrivacyBrowserProxy = new TestPrivacyPageBrowserProxy();
    PrivacyPageBrowserProxyImpl.setInstance(testPrivacyBrowserProxy);
    openWindowProxy = new TestOpenWindowProxy();
    OpenWindowProxyImpl.setInstance(openWindowProxy);

    page = document.createElement('settings-security-page');
    page.prefs = pagePrefs();
    document.body.appendChild(page);

    page.$.safeBrowsingEnhanced.updateCollapsed();
    page.$.safeBrowsingStandard.updateCollapsed();
    flush();
  });

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

  // <if expr="is_macosx or is_win">
  test('NativeCertificateManager', function() {
    page.shadowRoot!.querySelector<HTMLElement>(
                        '#manageCertificatesLinkRow')!.click();
    return testPrivacyBrowserProxy.whenCalled('showManageSslCertificates');
  });
  // </if>

  test('ChromeRootStorePage', async function() {
    const row =
        page.shadowRoot!.querySelector<HTMLElement>('#chromeCertificates');
    assertTrue(!!row);
    row.click();
    const url = await openWindowProxy.whenCalled('openUrl');
    assertEquals(url, loadTimeData.getString('chromeRootStoreHelpCenterURL'));
  });

  // <if expr="not chromeos_lacros">
  // TODO(crbug.com/40156980): This class directly calls
  // `CreateNSSCertDatabaseGetterForIOThread()` that causes crash at the
  // moment and is never called from Lacros-Chrome. This should be revisited
  // when there is a solution for the client certificates settings page on
  // Lacros-Chrome.
  test('LogManageCertificatesClick', async function() {
    page.shadowRoot!.querySelector<HTMLElement>(
                        '#manageCertificatesLinkRow')!.click();
    const result =
        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
    assertEquals(PrivacyElementInteractions.MANAGE_CERTIFICATES, result);
  });
  // </if>

  test('ManageSecurityKeysSubpageHidden', function() {
    assertFalse(isChildVisible(page, '#security-keys-subpage-trigger'));
  });

  // The element only exists on Windows.
  // <if expr="is_win">
  test('ManageSecurityKeysPhonesSubpageVisibleAndNavigates', function() {
    // On modern versions of Windows the security keys subpage will be disabled
    // because Windows manages that itself, but a link to the subpage for
    // managing phones as security keys will be included.
    const triggerId = '#security-keys-phones-subpage-trigger';
    assertTrue(isChildVisible(page, triggerId));
    page.shadowRoot!.querySelector<HTMLElement>(triggerId)!.click();
    flush();
    assertEquals(
        routes.SECURITY_KEYS_PHONES, Router.getInstance().getCurrentRoute());
  });
  // </if>

  // Tests the old HTTPS-Only Mode toggle UI.
  // TODO(crbug.com/349860796): Remove this test once HttpsFirstBalancedMode is
  // enabled by default.
  test('HttpsOnlyModeToggle', function() {
    // Check that the new "Secure connections" section is not shown if the
    // flag is disabled.
    const secureConnections =
        page.shadowRoot!.querySelector<HTMLElement>('secureConnectionsSection');
    assertFalse(!!secureConnections);

    // Test the old settings UI when the HttpsFirstBalancedMode flag is
    // disabled. Checks that toggling the HTTPS-Only Mode setting sets the
    // associated pref.
    const httpsOnlyModeToggle =
        page.shadowRoot!.querySelector<HTMLElement>('#httpsOnlyModeToggle');
    assertTrue(!!httpsOnlyModeToggle);

    assertEquals(
        HttpsFirstModeSetting.DISABLED,
        page.getPref('generated.https_first_mode_enabled').value);

    httpsOnlyModeToggle.click();
    assertEquals(
        HttpsFirstModeSetting.ENABLED_FULL,
        page.getPref('generated.https_first_mode_enabled').value);
  });

  // Tests that the correct Advanced Protection sublabel is used when the
  // HTTPS-Only Mode setting toggle has user control disabled.
  test('HttpsOnlyModeSettingSubLabel', function() {
    const toggle = page.shadowRoot!.querySelector<SettingsToggleButtonElement>(
        '#httpsOnlyModeToggle');
    assertTrue(!!toggle);
    const defaultSubLabel = loadTimeData.getString('httpsOnlyModeDescription');
    assertEquals(defaultSubLabel, toggle.subLabel);

    page.setPrefValue(
        'generated.https_first_mode_enabled', HttpsFirstModeSetting.DISABLED);
    page.set(
        'prefs.generated.https_first_mode_enabled.userControlDisabled', true);
    flush();
    const lockedSubLabel =
        loadTimeData.getString('httpsOnlyModeDescriptionAdvancedProtection');
    assertEquals(lockedSubLabel, toggle.subLabel);

    page.setPrefValue(
        'generated.https_first_mode_enabled',
        HttpsFirstModeSetting.ENABLED_FULL);
    page.set(
        'prefs.generated.https_first_mode_enabled.userControlDisabled', true);
    flush();
    assertEquals(lockedSubLabel, toggle.subLabel);
  });

  // TODO(crbug.com/349439367): Remove the test once
  // kExtendedReportingRemovePrefDependency is fully launched.
  test('LogSafeBrowsingExtendedToggle', async function() {
    const safeBrowsingReportingToggle =
        page.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#safeBrowsingReportingToggle');
    assertTrue(!!safeBrowsingReportingToggle);
    page.$.safeBrowsingStandard.click();
    flush();

    safeBrowsingReportingToggle.click();
    const result =
        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
    assertEquals(PrivacyElementInteractions.IMPROVE_SECURITY, result);
  });

  // TODO(crbug.com/349439367): Remove the test once
  // kExtendedReportingRemovePrefDependency is fully launched.
  test('safeBrowsingReportingToggle', async () => {
    page.$.safeBrowsingStandard.click();
    await microtasksFinished();
    assertEquals(
        SafeBrowsingSetting.STANDARD, page.prefs.generated.safe_browsing.value);

    const safeBrowsingReportingToggle =
        page.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#safeBrowsingReportingToggle');
    assertTrue(!!safeBrowsingReportingToggle);
    assertFalse(safeBrowsingReportingToggle.disabled);
    assertTrue(safeBrowsingReportingToggle.checked);

    // This could also be set to disabled, anything other than standard.
    page.$.safeBrowsingEnhanced.click();
    await microtasksFinished();
    assertEquals(
        SafeBrowsingSetting.ENHANCED, page.prefs.generated.safe_browsing.value);
    flush();
    assertTrue(safeBrowsingReportingToggle.disabled);
    assertTrue(safeBrowsingReportingToggle.checked);
    assertTrue(page.prefs.safebrowsing.scout_reporting_enabled.value);

    page.$.safeBrowsingStandard.click();
    await microtasksFinished();
    assertEquals(
        SafeBrowsingSetting.STANDARD, page.prefs.generated.safe_browsing.value);
    flush();
    assertFalse(safeBrowsingReportingToggle.disabled);
    assertTrue(safeBrowsingReportingToggle.checked);
  });

  // TODO(crbug.com/349439367): Remove the test once
  // kExtendedReportingRemovePrefDependency is fully launched.
  test('noControlSafeBrowsingReportingInEnhanced', async () => {
    const safeBrowsingReportingToggle =
        page.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#safeBrowsingReportingToggle');
    assertTrue(!!safeBrowsingReportingToggle);
    page.$.safeBrowsingStandard.click();
    assertFalse(safeBrowsingReportingToggle.disabled);
    page.$.safeBrowsingEnhanced.click();
    await eventToPromise('selected-changed', page.$.safeBrowsingRadioGroup);

    assertTrue(safeBrowsingReportingToggle.disabled);
  });

  // TODO(crbug.com/349439367): Remove the test once
  // kExtendedReportingRemovePrefDependency is fully launched.
  test('noControlSafeBrowsingReportingInDisabled', async function() {
    const safeBrowsingReportingToggle =
        page.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#safeBrowsingReportingToggle');
    assertTrue(!!safeBrowsingReportingToggle);
    page.$.safeBrowsingStandard.click();
    await microtasksFinished();

    assertFalse(safeBrowsingReportingToggle.disabled);
    page.$.safeBrowsingDisabled.click();
    await microtasksFinished();

    // Previously selected option must remain opened.
    assertTrue(page.$.safeBrowsingStandard.expanded);

    await clickConfirmOnDisableSafebrowsingDialog(page);

    assertTrue(safeBrowsingReportingToggle.disabled);
  });

  // TODO(crbug.com/349439367): Remove the test once
  // kExtendedReportingRemovePrefDependency is fully launched.
  test(
      'safeBrowsingReportingToggleVisibleWhenExtendedReportingNotDeprecated',
      async function() {
        // The safeBrowsingReportingToggle should be visible if the extended
        // reporting deprecation flag is not enabled.
        page.$.safeBrowsingStandard.click();
        flush();

        await microtasksFinished();
        assertTrue(page.$.safeBrowsingStandard.expanded);
        assertTrue(isChildVisible(page, '#safeBrowsingReportingToggle'));
      });
});

// Separate test suite for tests specifically related to Safe Browsing controls.
suite('SafeBrowsing', function() {
  let testMetricsBrowserProxy: TestMetricsBrowserProxy;
  let testPrivacyBrowserProxy: TestPrivacyPageBrowserProxy;
  let page: SettingsSecurityPageElement;
  let openWindowProxy: TestOpenWindowProxy;

  function setUpPage() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;

    testMetricsBrowserProxy = new TestMetricsBrowserProxy();
    MetricsBrowserProxyImpl.setInstance(testMetricsBrowserProxy);
    testPrivacyBrowserProxy = new TestPrivacyPageBrowserProxy();
    PrivacyPageBrowserProxyImpl.setInstance(testPrivacyBrowserProxy);
    openWindowProxy = new TestOpenWindowProxy();
    OpenWindowProxyImpl.setInstance(openWindowProxy);

    page = document.createElement('settings-security-page');
    page.prefs = pagePrefs();
    document.body.appendChild(page);
    page.$.safeBrowsingEnhanced.updateCollapsed();
    page.$.safeBrowsingStandard.updateCollapsed();
    return microtasksFinished();
  }

  async function resetPage() {
    page.remove();
    await setUpPage();
  }

  setup(function() {
    return setUpPage();
  });

  teardown(function() {
    page.remove();
    Router.getInstance().navigateTo(routes.BASIC);
  });

  // Initially specified pref option should be expanded
  test('SafeBrowsingRadio_InitialPrefOptionIsExpanded', function() {
    assertFalse(page.$.safeBrowsingEnhanced.expanded);
    assertTrue(page.$.safeBrowsingStandard.expanded);
  });

  test('PasswordsLeakDetectionSubLabel', function() {
    const toggle = page.$.passwordsLeakToggle;
    const defaultSubLabel =
        loadTimeData.getString('passwordsLeakDetectionGeneralDescription');
    const activeWhenSignedInSubLabel =
        loadTimeData.getString('passwordsLeakDetectionGeneralDescription') +
        ' ' +
        loadTimeData.getString(
            'passwordsLeakDetectionSignedOutEnabledDescription');
    assertEquals(defaultSubLabel, toggle.subLabel);

    page.set('prefs.profile.password_manager_leak_detection.value', true);
    page.set(
        'prefs.generated.password_leak_detection.userControlDisabled', true);
    flush();
    assertEquals(activeWhenSignedInSubLabel, toggle.subLabel);

    page.set('prefs.generated.password_leak_detection.value', true);
    page.set(
        'prefs.generated.password_leak_detection.userControlDisabled', false);
    flush();
    assertEquals(defaultSubLabel, toggle.subLabel);

    page.set('prefs.profile.password_manager_leak_detection.value', false);
    flush();
    assertEquals(defaultSubLabel, toggle.subLabel);
  });

  test(
      'SafeBrowsingRadio_ManuallyExpandedRemainExpandedOnRepeatSelection',
      async function() {
        page.$.safeBrowsingStandard.click();
        await microtasksFinished();
        assertEquals(
            SafeBrowsingSetting.STANDARD,
            page.prefs.generated.safe_browsing.value);
        assertTrue(page.$.safeBrowsingStandard.expanded);
        assertFalse(page.$.safeBrowsingEnhanced.expanded);

        // Expanding another radio button should not collapse already expanded
        // option.
        page.$.safeBrowsingEnhanced.$.expandButton.click();
        await microtasksFinished();
        assertTrue(page.$.safeBrowsingStandard.expanded);
        assertTrue(page.$.safeBrowsingEnhanced.expanded);

        // Clicking on already selected button should not collapse manually
        // expanded option.
        page.$.safeBrowsingStandard.click();
        // Wait one cycle and confirm nothing changed.
        await microtasksFinished();
        assertTrue(page.$.safeBrowsingStandard.expanded);
        assertTrue(page.$.safeBrowsingEnhanced.expanded);
      });

  test(
      'SafeBrowsingRadio_ManuallyExpandedRemainExpandedOnSelectedChanged',
      async function() {
        page.$.safeBrowsingStandard.click();
        await microtasksFinished();
        assertEquals(
            SafeBrowsingSetting.STANDARD,
            page.prefs.generated.safe_browsing.value);

        page.$.safeBrowsingEnhanced.$.expandButton.click();
        await microtasksFinished();
        assertTrue(page.$.safeBrowsingStandard.expanded);
        assertTrue(page.$.safeBrowsingEnhanced.expanded);

        page.$.safeBrowsingDisabled.click();
        await microtasksFinished();

        // Previously selected option must remain opened.
        assertTrue(page.$.safeBrowsingStandard.expanded);
        assertTrue(page.$.safeBrowsingEnhanced.expanded);
        await clickConfirmOnDisableSafebrowsingDialog(page);

        // The deselected option should become collapsed.
        assertFalse(page.$.safeBrowsingStandard.expanded);
        assertTrue(page.$.safeBrowsingEnhanced.expanded);
      });

  test('DisableSafebrowsingDialog_Confirm', async function() {
    page.$.safeBrowsingStandard.click();
    await microtasksFinished();
    assertEquals(
        SafeBrowsingSetting.STANDARD, page.prefs.generated.safe_browsing.value);

    page.$.safeBrowsingDisabled.click();
    await microtasksFinished();

    // Previously selected option must remain opened.
    assertTrue(page.$.safeBrowsingStandard.expanded);

    await clickConfirmOnDisableSafebrowsingDialog(page);

    assertFalse(page.$.safeBrowsingEnhanced.checked);
    assertFalse(page.$.safeBrowsingStandard.checked);
    assertTrue(page.$.safeBrowsingDisabled.checked);
    assertEquals(
        SafeBrowsingSetting.DISABLED, page.prefs.generated.safe_browsing.value);
  });

  test('DisableSafebrowsingDialog_CancelFromEnhanced', async function() {
    page.$.safeBrowsingEnhanced.click();
    await microtasksFinished();
    assertEquals(
        SafeBrowsingSetting.ENHANCED, page.prefs.generated.safe_browsing.value);

    page.$.safeBrowsingDisabled.click();
    await microtasksFinished();

    // Previously selected option must remain opened.
    assertTrue(page.$.safeBrowsingEnhanced.expanded);
    await clickCancelOnDisableSafebrowsingDialog(page);

    assertTrue(page.$.safeBrowsingEnhanced.checked);
    assertFalse(page.$.safeBrowsingStandard.checked);
    assertFalse(page.$.safeBrowsingDisabled.checked);
    assertEquals(
        SafeBrowsingSetting.ENHANCED, page.prefs.generated.safe_browsing.value);
  });

  test('DisableSafebrowsingDialog_CancelFromStandard', async function() {
    page.$.safeBrowsingStandard.click();
    await microtasksFinished();
    assertEquals(
        SafeBrowsingSetting.STANDARD, page.prefs.generated.safe_browsing.value);

    page.$.safeBrowsingDisabled.click();
    await microtasksFinished();

    // Previously selected option must remain opened.
    assertTrue(page.$.safeBrowsingStandard.expanded);
    await clickCancelOnDisableSafebrowsingDialog(page);

    assertFalse(page.$.safeBrowsingEnhanced.checked);
    assertTrue(page.$.safeBrowsingStandard.checked);
    assertFalse(page.$.safeBrowsingDisabled.checked);
    assertEquals(
        SafeBrowsingSetting.STANDARD, page.prefs.generated.safe_browsing.value);
  });

  test('noValueChangeSafeBrowsingReportingInEnhanced', async () => {
    page.$.safeBrowsingStandard.click();
    const previous = page.prefs.safebrowsing.scout_reporting_enabled.value;

    page.$.safeBrowsingEnhanced.click();
    await eventToPromise('selected-changed', page.$.safeBrowsingRadioGroup);

    assertTrue(
        page.prefs.safebrowsing.scout_reporting_enabled.value === previous);
  });

  test('noValueChangeSafeBrowsingReportingInDisabled', async function() {
    page.$.safeBrowsingStandard.click();
    const previous = page.prefs.safebrowsing.scout_reporting_enabled.value;

    page.$.safeBrowsingDisabled.click();
    await eventToPromise('selected-changed', page.$.safeBrowsingRadioGroup);

    // Previously selected option must remain opened.
    assertTrue(page.$.safeBrowsingStandard.expanded);

    await clickConfirmOnDisableSafebrowsingDialog(page);

    assertTrue(
        page.prefs.safebrowsing.scout_reporting_enabled.value === previous);
  });

  test('noValueChangePasswordLeakSwitchToEnhanced', async () => {
    page.$.safeBrowsingStandard.click();
    await microtasksFinished();
    const previous = page.prefs.profile.password_manager_leak_detection.value;

    page.$.safeBrowsingEnhanced.click();
    await eventToPromise('selected-changed', page.$.safeBrowsingRadioGroup);

    assertTrue(
        page.prefs.profile.password_manager_leak_detection.value === previous);
  });

  test('noValuePasswordLeakSwitchToDisabled', async function() {
    page.$.safeBrowsingStandard.click();
    await microtasksFinished();
    const previous = page.prefs.profile.password_manager_leak_detection.value;

    page.$.safeBrowsingDisabled.click();
    await microtasksFinished();

    // Previously selected option must remain opened.
    assertTrue(page.$.safeBrowsingStandard.expanded);

    await clickConfirmOnDisableSafebrowsingDialog(page);

    assertTrue(
        page.prefs.profile.password_manager_leak_detection.value === previous);
  });

  test('safeBrowsingUserActionRecorded', async function() {
    testMetricsBrowserProxy.resetResolver(
        'recordSafeBrowsingInteractionHistogram');
    page.$.safeBrowsingStandard.click();
    // Wait for a timeout to ensure the call count check below catches any
    // possible incorrect calls.
    await microtasksFinished();
    assertEquals(
        SafeBrowsingSetting.STANDARD, page.prefs.generated.safe_browsing.value);
    // Not logged because it is already in standard mode.
    assertEquals(
        0,
        testMetricsBrowserProxy.getCallCount(
            'recordSafeBrowsingInteractionHistogram'));

    testMetricsBrowserProxy.resetResolver(
        'recordSafeBrowsingInteractionHistogram');
    testMetricsBrowserProxy.resetResolver('recordAction');
    page.$.safeBrowsingEnhanced.click();
    await eventToPromise('selected-changed', page.$.safeBrowsingRadioGroup);
    const [enhancedClickedResult, enhancedClickedAction] = await Promise.all([
      testMetricsBrowserProxy.whenCalled(
          'recordSafeBrowsingInteractionHistogram'),
      testMetricsBrowserProxy.whenCalled('recordAction'),
    ]);
    assertEquals(
        SafeBrowsingInteractions.SAFE_BROWSING_ENHANCED_PROTECTION_CLICKED,
        enhancedClickedResult);
    assertEquals(
        'SafeBrowsing.Settings.EnhancedProtectionClicked',
        enhancedClickedAction);

    testMetricsBrowserProxy.resetResolver(
        'recordSafeBrowsingInteractionHistogram');
    testMetricsBrowserProxy.resetResolver('recordAction');
    page.$.safeBrowsingEnhanced.$.expandButton.click();
    flush();
    const [enhancedExpandedResult, enhancedExpandedAction] = await Promise.all([
      testMetricsBrowserProxy.whenCalled(
          'recordSafeBrowsingInteractionHistogram'),
      testMetricsBrowserProxy.whenCalled('recordAction'),
    ]);
    assertEquals(
        SafeBrowsingInteractions
            .SAFE_BROWSING_ENHANCED_PROTECTION_EXPAND_ARROW_CLICKED,
        enhancedExpandedResult);
    assertEquals(
        'SafeBrowsing.Settings.EnhancedProtectionExpandArrowClicked',
        enhancedExpandedAction);

    testMetricsBrowserProxy.resetResolver(
        'recordSafeBrowsingInteractionHistogram');
    testMetricsBrowserProxy.resetResolver('recordAction');
    page.$.safeBrowsingStandard.$.expandButton.click();
    flush();
    const [standardExpandedResult, standardExpandedAction] = await Promise.all([
      testMetricsBrowserProxy.whenCalled(
          'recordSafeBrowsingInteractionHistogram'),
      testMetricsBrowserProxy.whenCalled('recordAction'),
    ]);
    assertEquals(
        SafeBrowsingInteractions
            .SAFE_BROWSING_STANDARD_PROTECTION_EXPAND_ARROW_CLICKED,
        standardExpandedResult);
    assertEquals(
        'SafeBrowsing.Settings.StandardProtectionExpandArrowClicked',
        standardExpandedAction);

    testMetricsBrowserProxy.resetResolver(
        'recordSafeBrowsingInteractionHistogram');
    testMetricsBrowserProxy.resetResolver('recordAction');
    page.$.safeBrowsingDisabled.click();
    await eventToPromise('selected-changed', page.$.safeBrowsingRadioGroup);
    const [disableClickedResult, disableClickedAction] = await Promise.all([
      testMetricsBrowserProxy.whenCalled(
          'recordSafeBrowsingInteractionHistogram'),
      testMetricsBrowserProxy.whenCalled('recordAction'),
    ]);
    assertEquals(
        SafeBrowsingInteractions.SAFE_BROWSING_DISABLE_SAFE_BROWSING_CLICKED,
        disableClickedResult);
    assertEquals(
        'SafeBrowsing.Settings.DisableSafeBrowsingClicked',
        disableClickedAction);

    testMetricsBrowserProxy.resetResolver(
        'recordSafeBrowsingInteractionHistogram');
    testMetricsBrowserProxy.resetResolver('recordAction');
    page.shadowRoot!.querySelector('settings-simple-confirmation-dialog')!.$
        .cancel.click();
    flush();
    const [disableDeniedResult, disableDeniedAction] = await Promise.all([
      testMetricsBrowserProxy.whenCalled(
          'recordSafeBrowsingInteractionHistogram'),
      testMetricsBrowserProxy.whenCalled('recordAction'),
    ]);
    assertEquals(
        SafeBrowsingInteractions
            .SAFE_BROWSING_DISABLE_SAFE_BROWSING_DIALOG_DENIED,
        disableDeniedResult);
    assertEquals(
        'SafeBrowsing.Settings.DisableSafeBrowsingDialogDenied',
        disableDeniedAction);

    await flushTasks();

    page.$.safeBrowsingDisabled.click();
    await eventToPromise('selected-changed', page.$.safeBrowsingRadioGroup);
    testMetricsBrowserProxy.resetResolver(
        'recordSafeBrowsingInteractionHistogram');
    testMetricsBrowserProxy.resetResolver('recordAction');
    page.shadowRoot!.querySelector('settings-simple-confirmation-dialog')!.$
        .confirm.click();
    flush();
    const [disableConfirmedResult, disableConfirmedAction] = await Promise.all([
      testMetricsBrowserProxy.whenCalled(
          'recordSafeBrowsingInteractionHistogram'),
      testMetricsBrowserProxy.whenCalled('recordAction'),
    ]);
    assertEquals(
        SafeBrowsingInteractions
            .SAFE_BROWSING_DISABLE_SAFE_BROWSING_DIALOG_CONFIRMED,
        disableConfirmedResult);
    assertEquals(
        'SafeBrowsing.Settings.DisableSafeBrowsingDialogConfirmed',
        disableConfirmedAction);
  });

  test('securityPageShowedRecorded', async function() {
    testMetricsBrowserProxy.resetResolver(
        'recordSafeBrowsingInteractionHistogram');
    Router.getInstance().navigateTo(
        routes.SECURITY, /* dynamicParams= */ undefined,
        /* removeSearch= */ true);
    assertEquals(
        SafeBrowsingInteractions.SAFE_BROWSING_SHOWED,
        await testMetricsBrowserProxy.whenCalled(
            'recordSafeBrowsingInteractionHistogram'));
  });

  test('standardProtectionExpandedIfNoQueryParam', function() {
    // Standard protection should be pre-expanded if there is no param.
    Router.getInstance().navigateTo(routes.SECURITY);
    assertEquals(
        page.prefs.generated.safe_browsing.value, SafeBrowsingSetting.STANDARD);
    assertFalse(page.$.safeBrowsingEnhanced.expanded);
    assertTrue(page.$.safeBrowsingStandard.expanded);
  });

  test('enhancedProtectionCollapsedIfParamIsEnhanced', function() {
    // Enhanced protection should be collapsed if the param is set to
    // enhanced.
    Router.getInstance().navigateTo(
        routes.SECURITY,
        /* dynamicParams= */ new URLSearchParams('q=enhanced'));
    assertEquals(
        page.prefs.generated.safe_browsing.value, SafeBrowsingSetting.STANDARD);
    assertFalse(page.$.safeBrowsingEnhanced.expanded);
    assertFalse(page.$.safeBrowsingStandard.expanded);
  });

  test('StandardProtectionDropdown', async () => {
    loadTimeData.overrideValues({enableHashPrefixRealTimeLookups: false});
    resetRouterForTesting();

    await resetPage();
    const standardProtection = page.$.safeBrowsingStandard;
    const spSubLabel = loadTimeData.getString('safeBrowsingStandardDesc');
    assertEquals(spSubLabel, standardProtection.subLabel);

    const passwordsLeakToggle = page.$.passwordsLeakToggle;
    const passwordLeakLabel =
        loadTimeData.getString('passwordsLeakDetectionLabel');
    assertEquals(passwordLeakLabel, passwordsLeakToggle.label);

    const passwordLeakSubLabel =
        loadTimeData.getString('passwordsLeakDetectionGeneralDescription');
    assertEquals(passwordLeakSubLabel, passwordsLeakToggle.subLabel);
  });

  test('EnhancedProtectionText', async () => {
    const enhancedProtection = page.$.safeBrowsingEnhanced;
    const epSubLabel = loadTimeData.getString('safeBrowsingEnhancedDesc');
    assertEquals(epSubLabel, enhancedProtection.subLabel);

    const noProtection = page.$.safeBrowsingDisabled;
    const npSubLabel = loadTimeData.getString('safeBrowsingNoneDesc');
    assertEquals(npSubLabel, noProtection.subLabel);

    page.$.safeBrowsingEnhanced.click();
    await eventToPromise('selected-changed', page.$.safeBrowsingRadioGroup);
    // Learn more label should be visible.
    assertTrue(isChildVisible(page, '#learnMoreLabelContainer'));
  });

  test('LearnMoreLinkClickableWhenControlledByPolicy', async () => {
    page.$.safeBrowsingEnhanced.$.expandButton.click();

    // Set the page to be enterprise policy enforced.
    page.set(
        'prefs.generated.safe_browsing.enforcement',
        chrome.settingsPrivate.Enforcement.ENFORCED);
    flush();

    const learnMoreLink = page.shadowRoot!.querySelector<HTMLElement>(
        '#enhancedProtectionLearnMoreLink');

    // Confirm that the learnMoreLink element exists.
    assertNotEquals(learnMoreLink, null);

    // Confirm that the pointer-events value is auto when enterprise policy is
    // enforced.
    assertEquals(
        'auto',
        (learnMoreLink!.computedStyleMap()!.get('pointer-events') as
         CSSKeywordValue)
            .value);

    // Confirm that the correct link was clicked.
    learnMoreLink!.click();
    const url = await openWindowProxy.whenCalled('openUrl');
    assertEquals(
        url, loadTimeData.getString('enhancedProtectionHelpCenterURL'));
  });

  // <if expr="_google_chrome">
  test('StandardProtectionDropdownWithProxyString', async () => {
    loadTimeData.overrideValues({enableHashPrefixRealTimeLookups: true});
    resetRouterForTesting();

    await resetPage();
    const standardProtection = page.$.safeBrowsingStandard;
    const subLabel = loadTimeData.getString('safeBrowsingStandardDescProxy');
    assertEquals(subLabel, standardProtection.subLabel);
  });
  // </if>

  // <if expr="not _google_chrome">
  test('StandardProtectionDropdownNoProxyStringForChromium', function() {
    // If this test fails, it may be because hash-prefix real-time lookups have
    // been enabled for Chromium. The settings strings only currently support
    // Chrome, so this must be addressed to support Chromium as well.
    const standardProtection = page.$.safeBrowsingStandard;
    const subLabel = loadTimeData.getString('safeBrowsingStandardDesc');
    assertEquals(subLabel, standardProtection.subLabel);
  });
  // </if>

  test(
      'SafeBrowsingReportingToggleNotVisibleWhenExtendedReportingDeprecatedAndHprtSampled',
      async function() {
        // The safeBrowsingReportingToggle should not be visible if the extended
        // reporting deprecation flag is enabled and HPRT sampled lookup flag is
        // enabled.
        loadTimeData.overrideValues({
          extendedReportingRemovePrefDependency: true,
          hashPrefixRealTimeLookupsSamplePing: true,
        });
        resetRouterForTesting();

        await resetPage();
        page.$.safeBrowsingStandard.click();

        await microtasksFinished();
        assertTrue(page.$.safeBrowsingStandard.expanded);

        assertFalse(isChildVisible(page, '#safeBrowsingReportingToggle'));
      });

  test(
      'SafeBrowsingReportingToggleVisibleWhenExtendedReportingDeprecatedAndHprtNotSampled',
      async function() {
        // The safeBrowsingReportingToggle should be visible if the extended
        // reporting deprecation flag is enabled and HPRT sampled lookup flag is
        // disabled.
        loadTimeData.overrideValues({
          extendedReportingRemovePrefDependency: true,
          hashPrefixRealTimeLookupsSamplePing: false,
        });
        resetRouterForTesting();

        await resetPage();
        page.$.safeBrowsingStandard.click();

        await microtasksFinished();
        assertTrue(page.$.safeBrowsingStandard.expanded);

        assertTrue(isChildVisible(page, '#safeBrowsingReportingToggle'));
      });

  test(
      'SafeBrowsingReportingToggleVisibleWhenExtendedReportingNotDeprecatedAndHprtSampled',
      async function() {
        // The safeBrowsingReportingToggle should be visible if the extended
        // reporting deprecation flag is disabled and HPRT sampled lookup flag
        // is enabled.
        loadTimeData.overrideValues({
          extendedReportingRemovePrefDependency: false,
          hashPrefixRealTimeLookupsSamplePing: true,
        });
        resetRouterForTesting();

        await resetPage();
        page.$.safeBrowsingStandard.click();

        await microtasksFinished();
        assertTrue(page.$.safeBrowsingStandard.expanded);

        assertTrue(isChildVisible(page, '#safeBrowsingReportingToggle'));
      });
});

async function clickCancelOnDisableSafebrowsingDialog(
    page: SettingsSecurityPageElement) {
  const confirmationDialog =
      page.shadowRoot!.querySelector('settings-simple-confirmation-dialog');
  assertTrue(!!confirmationDialog);
  const closePromise = eventToPromise('close', confirmationDialog);
  confirmationDialog.$.cancel.click();
  flush();
  await closePromise;
  await microtasksFinished();
}

async function clickConfirmOnDisableSafebrowsingDialog(
    page: SettingsSecurityPageElement) {
  const confirmationDialog =
      page.shadowRoot!.querySelector('settings-simple-confirmation-dialog');
  assertTrue(!!confirmationDialog);
  const closePromise = eventToPromise('close', confirmationDialog);
  confirmationDialog.$.confirm.click();
  flush();
  await closePromise;
  await microtasksFinished();
}