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

// 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.

// clang-format off
import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import type {SafetyCheckExtensionsElement, SafetyCheckBrowserProxy, SettingsSafetyCheckChildElement, SettingsSafetyCheckExtensionsChildElement, SettingsSafetyCheckPageElement, SettingsSafetyCheckPasswordsChildElement, SettingsSafetyCheckSafeBrowsingChildElement ,SettingsSafetyCheckUpdatesChildElement} from 'chrome://settings/settings.js';
import {SafetyCheckExtensionsBrowserProxyImpl, HatsBrowserProxyImpl, LifetimeBrowserProxyImpl, MetricsBrowserProxyImpl, OpenWindowProxyImpl, PasswordCheckReferrer, PasswordManagerImpl, Router, routes, PasswordManagerPage, SafetyCheckBrowserProxyImpl, SafetyCheckCallbackConstants, SafetyCheckExtensionsStatus, SafetyCheckIconStatus, SafetyCheckInteractions, SafetyCheckParentStatus, SafetyCheckPasswordsStatus, SafetyCheckSafeBrowsingStatus, SafetyCheckUpdatesStatus, TrustSafetyInteraction} from 'chrome://settings/settings.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
import {TestOpenWindowProxy} from 'chrome://webui-test/test_open_window_proxy.js';

import {TestExtensionBrowserProxy} from './test_extensions_browser_proxy.js';
import {TestHatsBrowserProxy} from './test_hats_browser_proxy.js';
import {TestLifetimeBrowserProxy} from './test_lifetime_browser_proxy.js';
import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js';
import {TestPasswordManagerProxy} from './test_password_manager_proxy.js';
import {assertSafetyCheckChild} from './safety_check_test_utils.js';

// clang-format on

const testDisplayString = 'Test display string';
const passwordsString = 'Password Manager';

/**
 * Fire a safety check parent event.
 */
function fireSafetyCheckParentEvent(state: SafetyCheckParentStatus) {
  const event = {
    newState: state,
    displayString: testDisplayString,
  };
  webUIListenerCallback(SafetyCheckCallbackConstants.PARENT_CHANGED, event);
}

/**
 * Fire a safety check updates event.
 */
function fireSafetyCheckUpdatesEvent(state: SafetyCheckUpdatesStatus) {
  const event = {
    newState: state,
    displayString: testDisplayString,
  };
  webUIListenerCallback(SafetyCheckCallbackConstants.UPDATES_CHANGED, event);
}

/**
 * Fire a safety check passwords event.
 */
function fireSafetyCheckPasswordsEvent(state: SafetyCheckPasswordsStatus) {
  const event = {
    newState: state,
    displayString: testDisplayString,
    passwordsButtonString: null,
  };
  webUIListenerCallback(SafetyCheckCallbackConstants.PASSWORDS_CHANGED, event);
}

/**
 * Fire a safety check safe browsing event.
 */
function fireSafetyCheckSafeBrowsingEvent(
    state: SafetyCheckSafeBrowsingStatus) {
  const event = {
    newState: state,
    displayString: testDisplayString,
  };
  webUIListenerCallback(
      SafetyCheckCallbackConstants.SAFE_BROWSING_CHANGED, event);
}

/**
 * Fire a safety check extensions event.
 */
function fireSafetyCheckExtensionsEvent(state: SafetyCheckExtensionsStatus) {
  const event = {
    newState: state,
    displayString: testDisplayString,
  };
  webUIListenerCallback(SafetyCheckCallbackConstants.EXTENSIONS_CHANGED, event);
}

class TestSafetyCheckBrowserProxy extends TestBrowserProxy implements
    SafetyCheckBrowserProxy {
  private parentRanDisplayString_ = '';

  constructor() {
    super([
      'getParentRanDisplayString',
      'runSafetyCheck',
    ]);
  }

  runSafetyCheck() {
    this.methodCalled('runSafetyCheck');
  }

  setParentRanDisplayString(s: string) {
    this.parentRanDisplayString_ = s;
  }

  getParentRanDisplayString() {
    this.methodCalled('getParentRanDisplayString');
    return Promise.resolve(this.parentRanDisplayString_);
  }
}

suite('SafetyCheckPageUiTests', function() {
  let metricsBrowserProxy: TestMetricsBrowserProxy;
  let safetyCheckBrowserProxy: TestSafetyCheckBrowserProxy;
  let page: SettingsSafetyCheckPageElement;

  setup(function() {
    metricsBrowserProxy = new TestMetricsBrowserProxy();
    MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);

    safetyCheckBrowserProxy = new TestSafetyCheckBrowserProxy();
    safetyCheckBrowserProxy.setParentRanDisplayString('Dummy string');
    SafetyCheckBrowserProxyImpl.setInstance(safetyCheckBrowserProxy);

    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-safety-check-page');
    document.body.appendChild(page);
    flush();
  });

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

  /** Tests parent element and collapse.from start to completion */
  test('testParentAndCollapse', async function() {
    // Before the check, only the text button is present.
    assertTrue(!!page.shadowRoot!.querySelector('#safetyCheckParentButton'));
    assertFalse(!!page.shadowRoot!.querySelector('cr-icon-button'));
    // Collapse is not opened.
    const collapse = page.shadowRoot!.querySelector('cr-collapse')!;
    assertFalse(collapse.opened);

    // User starts check.
    page.shadowRoot!.querySelector<HTMLElement>(
                        '#safetyCheckParentButton')!.click();
    // Ensure UMA is logged.
    assertEquals(
        SafetyCheckInteractions.RUN_SAFETY_CHECK,
        await metricsBrowserProxy.whenCalled(
            'recordSafetyCheckInteractionHistogram'));
    assertEquals(
        'Settings.SafetyCheck.Start',
        await metricsBrowserProxy.whenCalled('recordAction'));
    // Ensure the browser proxy call is done.
    await safetyCheckBrowserProxy.whenCalled('runSafetyCheck');

    // Mock all incoming messages that indicate safety check is running.
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.CHECKING);
    fireSafetyCheckPasswordsEvent(SafetyCheckPasswordsStatus.CHECKING);
    fireSafetyCheckSafeBrowsingEvent(SafetyCheckSafeBrowsingStatus.CHECKING);
    fireSafetyCheckExtensionsEvent(SafetyCheckExtensionsStatus.CHECKING);
    fireSafetyCheckParentEvent(SafetyCheckParentStatus.CHECKING);

    flush();
    // Only the icon button is present.
    assertFalse(!!page.shadowRoot!.querySelector('#safetyCheckParentButton'));
    assertTrue(!!page.shadowRoot!.querySelector('cr-icon-button'));
    // Collapse is opened.
    assertTrue(collapse.opened);

    // Mock all incoming messages that indicate safety check completion.
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.UPDATED);
    fireSafetyCheckPasswordsEvent(SafetyCheckPasswordsStatus.SAFE);
    fireSafetyCheckSafeBrowsingEvent(
        SafetyCheckSafeBrowsingStatus.ENABLED_STANDARD);
    fireSafetyCheckExtensionsEvent(
        SafetyCheckExtensionsStatus.NO_BLOCKLISTED_EXTENSIONS);
    fireSafetyCheckParentEvent(SafetyCheckParentStatus.AFTER);

    flush();
    // Only the icon button is present.
    assertFalse(!!page.shadowRoot!.querySelector('#safetyCheckParentButton'));
    assertTrue(!!page.shadowRoot!.querySelector('cr-icon-button'));
    // Collapse is opened.
    assertTrue(page.shadowRoot!.querySelector('cr-collapse')!.opened);

    // Ensure the automatic browser proxy calls are started.
    return safetyCheckBrowserProxy.whenCalled('getParentRanDisplayString');
  });

  test('HappinessTrackingSurveysTest', async function() {
    const testHatsBrowserProxy = new TestHatsBrowserProxy();
    HatsBrowserProxyImpl.setInstance(testHatsBrowserProxy);
    page.shadowRoot!.querySelector<HTMLElement>(
                        '#safetyCheckParentButton')!.click();
    const interaction =
        await testHatsBrowserProxy.whenCalled('trustSafetyInteractionOccurred');
    assertEquals(TrustSafetyInteraction.RAN_SAFETY_CHECK, interaction);
  });
});

suite('SafetyCheckChildTests', function() {
  let page: SettingsSafetyCheckChildElement;

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

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

  test('testIconStatusRunning', function() {
    page.iconStatus = SafetyCheckIconStatus.RUNNING;
    flush();
    const statusIconElem =
        page.shadowRoot!.querySelector<HTMLElement>('#statusIcon');
    assertTrue(!!statusIconElem);
    assertTrue(statusIconElem!.classList.contains('icon-blue'));
    assertFalse(statusIconElem!.classList.contains('icon-red'));
    assertEquals('Running', statusIconElem!.getAttribute('aria-label'));
  });

  test('testIconStatusSafe', function() {
    page.iconStatus = SafetyCheckIconStatus.SAFE;
    flush();
    const statusIconElem =
        page.shadowRoot!.querySelector<HTMLElement>('#statusIcon');
    assertTrue(!!statusIconElem);
    assertTrue(statusIconElem!.classList.contains('icon-blue'));
    assertFalse(statusIconElem!.classList.contains('icon-red'));
    assertEquals('Passed', statusIconElem!.getAttribute('aria-label'));
  });

  test('testIconStatusInfo', function() {
    page.iconStatus = SafetyCheckIconStatus.INFO;
    flush();
    const statusIconElem =
        page.shadowRoot!.querySelector<HTMLElement>('#statusIcon');
    assertTrue(!!statusIconElem);
    assertFalse(statusIconElem!.classList.contains('icon-blue'));
    assertFalse(statusIconElem!.classList.contains('icon-red'));
    assertEquals('Info', statusIconElem!.getAttribute('aria-label'));
  });

  test('testIconStatusWarning', function() {
    page.iconStatus = SafetyCheckIconStatus.WARNING;
    flush();
    const statusIconElem =
        page.shadowRoot!.querySelector<HTMLElement>('#statusIcon');
    assertTrue(!!statusIconElem);
    assertFalse(statusIconElem!.classList.contains('icon-blue'));
    assertTrue(statusIconElem!.classList.contains('icon-red'));
    assertEquals('Warning', statusIconElem!.getAttribute('aria-label'));
  });

  test('testLabelText', function() {
    page.label = 'Main label test text';
    flush();
    const label = page.shadowRoot!.querySelector('#label');
    assertTrue(!!label);
    assertEquals('Main label test text', label!.textContent!.trim());
  });

  test('testSubLabelText', function() {
    page.subLabel = 'Sub label test text';
    flush();
    const subLabel = page.shadowRoot!.querySelector('#subLabel');
    assertTrue(!!subLabel);
    assertEquals('Sub label test text', subLabel!.textContent!.trim());
  });

  test('testSubLabelNoText', function() {
    // sublabel not set -> empty sublabel in element
    const subLabel = page.shadowRoot!.querySelector('#subLabel');
    assertTrue(!!subLabel);
    assertEquals('', subLabel!.textContent!.trim());
  });

  test('testButtonWithoutClass', function() {
    page.buttonLabel = 'Button label';
    page.buttonAriaLabel = 'Aria label';
    flush();
    const button = page.shadowRoot!.querySelector('#button');
    assertTrue(!!button);
    assertEquals('Button label', button!.textContent!.trim());
    assertEquals('Aria label', button!.getAttribute('aria-label'));
    assertFalse(button!.classList.contains('action-button'));
  });

  test('testButtonWithClass', function() {
    page.buttonLabel = 'Button label';
    page.buttonAriaLabel = 'Aria label';
    page.buttonClass = 'action-button';
    flush();
    const button = page.shadowRoot!.querySelector('#button');
    assertTrue(!!button);
    assertEquals('Button label', button!.textContent!.trim());
    assertEquals('Aria label', button!.getAttribute('aria-label'));
    assertTrue(button!.classList.contains('action-button'));
  });

  test('testNoButton', function() {
    // Button label not set -> no button.
    assertFalse(!!page.shadowRoot!.querySelector('#button'));
  });

  test('testManagedIcon', function() {
    page.managedIcon = 'cr20:domain';
    flush();
    assertTrue(!!page.shadowRoot!.querySelector('#managedIcon'));
  });

  test('testNoManagedIcon', function() {
    // Managed icon not set -> no managed icon.
    assertFalse(!!page.shadowRoot!.querySelector('#managedIcon'));
  });

  test('testRowClickableIndicator', function() {
    page.rowClickable = true;
    flush();
    assertTrue(!!page.shadowRoot!.querySelector('#rowClickableIndicator'));
    assertEquals(
        'cr:arrow-right',
        page.shadowRoot!.querySelector('#rowClickableIndicator')!.getAttribute(
            'iron-icon'));
  });

  test('testExternalRowClickableIndicator', function() {
    page.rowClickable = true;
    page.external = true;
    flush();
    assertTrue(!!page.shadowRoot!.querySelector('#rowClickableIndicator'));
    assertEquals(
        'cr:open-in-new',
        page.shadowRoot!.querySelector('#rowClickableIndicator')!.getAttribute(
            'iron-icon'));
  });

  test('testNoRowClickableIndicator', function() {
    // rowClickable not set -> no RowClickableIndicator.
    assertFalse(!!page.shadowRoot!.querySelector('#rowClickableIndicator'));
  });
});

suite('SafetyCheckUpdatesChildUiTests', function() {
  let lifetimeBrowserProxy: TestLifetimeBrowserProxy;
  let metricsBrowserProxy: TestMetricsBrowserProxy;
  let page: SettingsSafetyCheckUpdatesChildElement;

  setup(function() {
    lifetimeBrowserProxy = new TestLifetimeBrowserProxy();
    LifetimeBrowserProxyImpl.setInstance(lifetimeBrowserProxy);
    metricsBrowserProxy = new TestMetricsBrowserProxy();
    MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);

    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-safety-check-updates-child');
    document.body.appendChild(page);
    flush();
  });

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

  test('checkingUiTest', function() {
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.CHECKING);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.RUNNING,
      label: 'Updates',
      sublabel: testDisplayString,
    });
  });

  test('updatedUiTest', function() {
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.UPDATED);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.SAFE,
      label: 'Updates',
      sublabel: testDisplayString,
    });
  });

  test('updatingUiTest', function() {
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.UPDATING);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.RUNNING,
      label: 'Updates',
      sublabel: testDisplayString,
    });
  });

  test('relaunchUiTest', async function() {
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.RELAUNCH);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Updates',
      sublabel: testDisplayString,
      buttonLabel: page.i18n('aboutRelaunch'),
      buttonAriaLabel: page.i18n('safetyCheckUpdatesButtonAriaLabel'),
      buttonClass: 'action-button',
    });

    // User clicks the relaunch button.
    page.shadowRoot!
        .querySelector<SettingsSafetyCheckChildElement>('#safetyCheckChild')!
        .shadowRoot!.querySelector<HTMLElement>('#button')!.click();
    // Ensure UMA is logged.
    assertEquals(
        SafetyCheckInteractions.UPDATES_RELAUNCH,
        await metricsBrowserProxy.whenCalled(
            'recordSafetyCheckInteractionHistogram'));
    assertEquals(
        'Settings.SafetyCheck.RelaunchAfterUpdates',
        await metricsBrowserProxy.whenCalled('recordAction'));
    // Ensure the browser proxy call is done.
    return lifetimeBrowserProxy.whenCalled('relaunch');
  });

  test('disabledByAdminUiTest', function() {
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.DISABLED_BY_ADMIN);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Updates',
      sublabel: testDisplayString,
      managedIcon: true,
    });
  });

  test('failedOfflineUiTest', function() {
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.FAILED_OFFLINE);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Updates',
      sublabel: testDisplayString,
    });
  });

  test('failedUiTest', function() {
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.FAILED);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.WARNING,
      label: 'Updates',
      sublabel: testDisplayString,
    });
  });

  test('unknownUiTest', function() {
    fireSafetyCheckUpdatesEvent(SafetyCheckUpdatesStatus.UNKNOWN);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Updates',
      sublabel: testDisplayString,
    });
  });

  test('updateToRollbackVersionDisallowedUiTest', () => {
    fireSafetyCheckUpdatesEvent(
        SafetyCheckUpdatesStatus.UPDATE_TO_ROLLBACK_VERSION_DISALLOWED);
    flush();
    assertSafetyCheckChild({
      page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Updates',
      sublabel: testDisplayString,
    });
  });
});

suite('SafetyCheckPasswordsChildUiTests', function() {
  let metricsBrowserProxy: TestMetricsBrowserProxy;
  let passwordManager: TestPasswordManagerProxy;
  let page: SettingsSafetyCheckPasswordsChildElement;

  setup(function() {
    metricsBrowserProxy = new TestMetricsBrowserProxy();
    MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);

    passwordManager = new TestPasswordManagerProxy();
    PasswordManagerImpl.setInstance(passwordManager);

    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-safety-check-passwords-child');
    document.body.appendChild(page);
    flush();
  });

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

  test('passwordCheckingUiTest', function() {
    fireSafetyCheckPasswordsEvent(SafetyCheckPasswordsStatus.CHECKING);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.RUNNING,
      label: passwordsString,
      sublabel: testDisplayString,
    });
  });

  test('passwordSafeUiTest', async function() {
    fireSafetyCheckPasswordsEvent(SafetyCheckPasswordsStatus.SAFE);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.SAFE,
      label: passwordsString,
      sublabel: testDisplayString,
      rowClickable: true,
    });

    // User clicks the row.
    page.shadowRoot!
        .querySelector<SettingsSafetyCheckChildElement>(
            '#safetyCheckChild')!.click();
    // Ensure UMA is logged.
    assertEquals(
        SafetyCheckInteractions.PASSWORDS_CARET_NAVIGATION,
        await metricsBrowserProxy.whenCalled(
            'recordSafetyCheckInteractionHistogram'));
    assertEquals(
        'Settings.SafetyCheck.ManagePasswordsThroughCaretNavigation',
        await metricsBrowserProxy.whenCalled('recordAction'));
    // Ensure the Password Check page is shown.
    const param = await passwordManager.whenCalled('showPasswordManager');
    assertEquals(PasswordManagerPage.CHECKUP, param);
  });

  test('passwordCompromisedUiTest', async function() {
    fireSafetyCheckPasswordsEvent(SafetyCheckPasswordsStatus.COMPROMISED);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.WARNING,
      label: passwordsString,
      sublabel: testDisplayString,
      buttonLabel: 'Review',
      buttonAriaLabel: 'Review passwords',
      buttonClass: 'action-button',
    });

    const passwordManager = new TestPasswordManagerProxy();
    PasswordManagerImpl.setInstance(passwordManager);

    // User clicks the manage passwords button.
    page.shadowRoot!
        .querySelector<SettingsSafetyCheckChildElement>('#safetyCheckChild')!
        .shadowRoot!.querySelector<HTMLElement>('#button')!.click();
    // Ensure UMA is logged.
    assertEquals(
        SafetyCheckInteractions.PASSWORDS_MANAGE_COMPROMISED_PASSWORDS,
        await metricsBrowserProxy.whenCalled(
            'recordSafetyCheckInteractionHistogram'));
    assertEquals(
        'Settings.SafetyCheck.ManagePasswords',
        await metricsBrowserProxy.whenCalled('recordAction'));
    // Ensure the Password Check page is shown.
    const param = await passwordManager.whenCalled('showPasswordManager');
    assertEquals(PasswordManagerPage.CHECKUP, param);

    // Ensure correct referrer sent to password check.
    const referrer =
        await passwordManager.whenCalled('recordPasswordCheckReferrer');
    assertEquals(PasswordCheckReferrer.SAFETY_CHECK, referrer);
  });

  test('passwordWeakUiTest', async function() {
    fireSafetyCheckPasswordsEvent(
        SafetyCheckPasswordsStatus.WEAK_PASSWORDS_EXIST);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: passwordsString,
      sublabel: testDisplayString,
      rowClickable: true,
    });

    // User clicks the manage passwords button.
    page.shadowRoot!
        .querySelector<SettingsSafetyCheckChildElement>(
            '#safetyCheckChild')!.click();
    // Ensure UMA is logged.
    assertEquals(
        SafetyCheckInteractions.PASSWORDS_MANAGE_WEAK_PASSWORDS,
        await metricsBrowserProxy.whenCalled(
            'recordSafetyCheckInteractionHistogram'));
    assertEquals(
        'Settings.SafetyCheck.ManageWeakPasswords',
        await metricsBrowserProxy.whenCalled('recordAction'));
    // Ensure the Password Check page is shown.
    const param = await passwordManager.whenCalled('showPasswordManager');
    assertEquals(PasswordManagerPage.CHECKUP, param);
  });

  test('passwordInfoStatesUiTest', function() {
    // Iterate over all states
    for (const state of Object.values(SafetyCheckPasswordsStatus)
             .filter(v => Number.isInteger(v))) {
      fireSafetyCheckPasswordsEvent(state as SafetyCheckPasswordsStatus);
      flush();

      // Check that icon status is the correct one for this password status.
      switch (state) {
        case SafetyCheckPasswordsStatus.OFFLINE:
        case SafetyCheckPasswordsStatus.NO_PASSWORDS:
        case SafetyCheckPasswordsStatus.SIGNED_OUT:
        case SafetyCheckPasswordsStatus.FEATURE_UNAVAILABLE:
          assertSafetyCheckChild({
            page: page,
            iconStatus: SafetyCheckIconStatus.INFO,
            label: passwordsString,
            sublabel: testDisplayString,
          });
          break;
        case SafetyCheckPasswordsStatus.QUOTA_LIMIT:
        case SafetyCheckPasswordsStatus.ERROR:
          assertSafetyCheckChild({
            page: page,
            iconStatus: SafetyCheckIconStatus.INFO,
            label: passwordsString,
            sublabel: testDisplayString,
            rowClickable: true,
          });
          break;
        default:
          // Not covered by this test.
          break;
      }
    }
  });
});

suite('SafetyCheckSafeBrowsingChildUiTests', function() {
  let metricsBrowserProxy: TestMetricsBrowserProxy;
  let page: SettingsSafetyCheckSafeBrowsingChildElement;

  setup(function() {
    metricsBrowserProxy = new TestMetricsBrowserProxy();
    MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);

    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-safety-check-safe-browsing-child');
    document.body.appendChild(page);
    flush();
  });

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

  test('safeBrowsingCheckingUiTest', function() {
    fireSafetyCheckSafeBrowsingEvent(SafetyCheckSafeBrowsingStatus.CHECKING);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.RUNNING,
      label: 'Safe Browsing',
      sublabel: testDisplayString,
    });
  });

  test('safeBrowsingEnabledStandardUiTest', async function() {
    fireSafetyCheckSafeBrowsingEvent(
        SafetyCheckSafeBrowsingStatus.ENABLED_STANDARD);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.SAFE,
      label: 'Safe Browsing',
      sublabel: testDisplayString,
      rowClickable: true,
    });

    // User clicks the row.
    page.shadowRoot!
        .querySelector<SettingsSafetyCheckChildElement>(
            '#safetyCheckChild')!.click();
    // Ensure UMA is logged.
    assertEquals(
        SafetyCheckInteractions.SAFE_BROWSING_CARET_NAVIGATION,
        await metricsBrowserProxy.whenCalled(
            'recordSafetyCheckInteractionHistogram'));
    assertEquals(
        'Settings.SafetyCheck.ManageSafeBrowsingThroughCaretNavigation',
        await metricsBrowserProxy.whenCalled('recordAction'));
    // Ensure the correct Settings page is shown.
    assertEquals(routes.SECURITY, Router.getInstance().getCurrentRoute());
  });

  test('safeBrowsingEnabledStandardAvailableEnhancedUiTest', function() {
    fireSafetyCheckSafeBrowsingEvent(
        SafetyCheckSafeBrowsingStatus.ENABLED_STANDARD_AVAILABLE_ENHANCED);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.SAFE,
      label: 'Safe Browsing',
      sublabel: testDisplayString,
      rowClickable: true,
    });
  });

  test('safeBrowsingEnabledEnhancedUiTest', function() {
    fireSafetyCheckSafeBrowsingEvent(
        SafetyCheckSafeBrowsingStatus.ENABLED_ENHANCED);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.SAFE,
      label: 'Safe Browsing',
      sublabel: testDisplayString,
      rowClickable: true,
    });
  });

  test('safeBrowsingDisabledUiTest', async function() {
    fireSafetyCheckSafeBrowsingEvent(SafetyCheckSafeBrowsingStatus.DISABLED);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Safe Browsing',
      sublabel: testDisplayString,
      buttonLabel: 'Manage',
      buttonAriaLabel: 'Manage Safe Browsing',
      buttonClass: 'action-button',
    });

    // User clicks the manage safe browsing button.
    page.shadowRoot!
        .querySelector<SettingsSafetyCheckChildElement>('#safetyCheckChild')!
        .shadowRoot!.querySelector<HTMLElement>('#button')!.click();
    // Ensure UMA is logged.
    assertEquals(
        SafetyCheckInteractions.SAFE_BROWSING_MANAGE,
        await metricsBrowserProxy.whenCalled(
            'recordSafetyCheckInteractionHistogram'));
    assertEquals(
        'Settings.SafetyCheck.ManageSafeBrowsing',
        await metricsBrowserProxy.whenCalled('recordAction'));
    // Ensure the correct Settings page is shown.
    assertEquals(routes.SECURITY, Router.getInstance().getCurrentRoute());
  });

  test('safeBrowsingDisabledByAdminUiTest', function() {
    fireSafetyCheckSafeBrowsingEvent(
        SafetyCheckSafeBrowsingStatus.DISABLED_BY_ADMIN);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Safe Browsing',
      sublabel: testDisplayString,
      managedIcon: true,
      rowClickable: true,
    });
  });

  test('safeBrowsingDisabledByExtensionUiTest', function() {
    fireSafetyCheckSafeBrowsingEvent(
        SafetyCheckSafeBrowsingStatus.DISABLED_BY_EXTENSION);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Safe Browsing',
      sublabel: testDisplayString,
      managedIcon: true,
      rowClickable: true,
    });
  });
});

suite('SafetyCheckExtensionsUiTests', function() {
  let page: SafetyCheckExtensionsElement;
  let browserProxy: TestExtensionBrowserProxy;
  let openWindowProxy: TestOpenWindowProxy;

  setup(function() {
    browserProxy = new TestExtensionBrowserProxy();
    SafetyCheckExtensionsBrowserProxyImpl.setInstance(browserProxy);
    openWindowProxy = new TestOpenWindowProxy();
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    OpenWindowProxyImpl.setInstance(openWindowProxy);
    page = document.createElement('safety-check-extensions');
    document.body.appendChild(page);
    flush();
  });

  test('extensionsReviewUiTest', async function() {
    // Make sure that clicking the Safety Check Review button navigates
    // the user to the extensions page.
    const safetyCheck = page.$.safetyCheckChild.shadowRoot!;
    assertTrue(!!safetyCheck);
    safetyCheck.querySelector<HTMLElement>('#button')!.click();
    const url = await openWindowProxy.whenCalled('openUrl');
    assertEquals('chrome://extensions', url);
  });
});


suite('SafetyCheckExtensionsChildUiTests', function() {
  let metricsBrowserProxy: TestMetricsBrowserProxy;
  let openWindowProxy: TestOpenWindowProxy;
  let page: SettingsSafetyCheckExtensionsChildElement;

  setup(function() {
    metricsBrowserProxy = new TestMetricsBrowserProxy();
    MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
    openWindowProxy = new TestOpenWindowProxy();
    OpenWindowProxyImpl.setInstance(openWindowProxy);

    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    page = document.createElement('settings-safety-check-extensions-child');
    document.body.appendChild(page);
    flush();
  });

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

  /** @return {!Promise} */
  async function expectExtensionsButtonClickActions() {
    // User clicks review extensions button.
    page.shadowRoot!
        .querySelector<SettingsSafetyCheckChildElement>('#safetyCheckChild')!
        .shadowRoot!.querySelector<HTMLElement>('#button')!.click();
    // Ensure UMA is logged.
    assertEquals(
        SafetyCheckInteractions.EXTENSIONS_REVIEW,
        await metricsBrowserProxy.whenCalled(
            'recordSafetyCheckInteractionHistogram'));
    assertEquals(
        'Settings.SafetyCheck.ReviewExtensions',
        await metricsBrowserProxy.whenCalled('recordAction'));
    // Ensure the browser proxy call is done.
    assertEquals(
        'chrome://extensions', await openWindowProxy.whenCalled('openUrl'));
  }

  test('extensionsCheckingUiTest', function() {
    fireSafetyCheckExtensionsEvent(SafetyCheckExtensionsStatus.CHECKING);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.RUNNING,
      label: 'Extensions',
      sublabel: testDisplayString,
    });
  });

  test('extensionsErrorUiTest', function() {
    fireSafetyCheckExtensionsEvent(SafetyCheckExtensionsStatus.ERROR);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Extensions',
      sublabel: testDisplayString,
      rowClickable: true,
    });
  });

  test('extensionsSafeUiTest', async function() {
    fireSafetyCheckExtensionsEvent(
        SafetyCheckExtensionsStatus.NO_BLOCKLISTED_EXTENSIONS);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.SAFE,
      label: 'Extensions',
      sublabel: testDisplayString,
      rowClickable: true,
    });

    // User clicks the row.
    page.shadowRoot!
        .querySelector<SettingsSafetyCheckChildElement>(
            '#safetyCheckChild')!.click();
    // Ensure UMA is logged.
    assertEquals(
        SafetyCheckInteractions.EXTENSIONS_CARET_NAVIGATION,
        await metricsBrowserProxy.whenCalled(
            'recordSafetyCheckInteractionHistogram'));
    assertEquals(
        'Settings.SafetyCheck.ReviewExtensionsThroughCaretNavigation',
        await metricsBrowserProxy.whenCalled('recordAction'));
    // Ensure the browser proxy call is done.
    const url = await openWindowProxy.whenCalled('openUrl');
    assertEquals('chrome://extensions', url);
  });

  test('extensionsBlocklistedOffUiTest', async function() {
    fireSafetyCheckExtensionsEvent(
        SafetyCheckExtensionsStatus.BLOCKLISTED_ALL_DISABLED);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.SAFE,
      label: 'Extensions',
      sublabel: testDisplayString,
      rowClickable: true,
    });

    // User clicks the row.
    page.shadowRoot!
        .querySelector<SettingsSafetyCheckChildElement>(
            '#safetyCheckChild')!.click();
    // Ensure the browser proxy call is done.
    const url = await openWindowProxy.whenCalled('openUrl');
    assertEquals('chrome://extensions', url);
  });

  test('extensionsBlocklistedOnAllUserUiTest', function() {
    fireSafetyCheckExtensionsEvent(
        SafetyCheckExtensionsStatus.BLOCKLISTED_REENABLED_ALL_BY_USER);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.WARNING,
      label: 'Extensions',
      sublabel: testDisplayString,
      buttonLabel: 'Review',
      buttonAriaLabel: 'Review extensions',
      buttonClass: 'action-button',
    });
    return expectExtensionsButtonClickActions();
  });

  test('extensionsBlocklistedOnUserAdminUiTest', function() {
    fireSafetyCheckExtensionsEvent(
        SafetyCheckExtensionsStatus.BLOCKLISTED_REENABLED_SOME_BY_USER);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.WARNING,
      label: 'Extensions',
      sublabel: testDisplayString,
      buttonLabel: 'Review',
      buttonAriaLabel: 'Review extensions',
      buttonClass: 'action-button',
      managedIcon: false,
    });
    return expectExtensionsButtonClickActions();
  });

  test('extensionsBlocklistedOnAllAdminUiTest', function() {
    fireSafetyCheckExtensionsEvent(
        SafetyCheckExtensionsStatus.BLOCKLISTED_REENABLED_ALL_BY_ADMIN);
    flush();
    assertSafetyCheckChild({
      page: page,
      iconStatus: SafetyCheckIconStatus.INFO,
      label: 'Extensions',
      sublabel: testDisplayString,
      managedIcon: true,
      rowClickable: true,
    });
  });
});