chromium/chrome/test/data/webui/password_manager/settings_section_test.ts

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

import 'chrome://password-manager/password_manager.js';

import {OpenWindowProxyImpl, PASSWORD_MANAGER_ACCOUNT_STORE_TOGGLE_ELEMENT_ID, PasswordManagerImpl, SyncBrowserProxyImpl, TrustedVaultBannerState} from 'chrome://password-manager/password_manager.js';
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 {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {TestOpenWindowProxy} from 'chrome://webui-test/test_open_window_proxy.js';
import {$$, eventToPromise, isVisible} from 'chrome://webui-test/test_util.js';

import {TestPasswordManagerProxy} from './test_password_manager_proxy.js';
import {TestSyncBrowserProxy} from './test_sync_browser_proxy.js';
import {createBlockedSiteEntry, createCredentialGroup, createPasswordEntry, makePasswordManagerPrefs} from './test_util.js';

// clang-format off
// <if expr="is_win or is_macosx">
import type { PrefToggleButtonElement} from 'chrome://password-manager/password_manager.js';
import {PasskeysBrowserProxyImpl} from 'chrome://password-manager/password_manager.js';

import {TestPasskeysBrowserProxy} from './test_passkeys_browser_proxy.js';
// </if>
// clang-format on

/**
 * Helper method that validates a that elements in the exception list match
 * the expected data.
 * @param nodes The nodes that will be checked.
 * @param blockedSiteList The expected data.
 */
function assertBlockedSiteList(
    nodes: NodeListOf<HTMLElement>,
    blockedSiteList: chrome.passwordsPrivate.ExceptionEntry[]) {
  assertEquals(blockedSiteList.length, nodes.length);
  for (let index = 0; index < blockedSiteList.length; ++index) {
    const node = nodes[index]!;
    const blockedSite = blockedSiteList[index]!;
    assertEquals(blockedSite.urls.shown, node.textContent!.trim());
  }
}

suite('SettingsSectionTest', function() {
  let passwordManager: TestPasswordManagerProxy;
  let openWindowProxy: TestOpenWindowProxy;
  let syncProxy: TestSyncBrowserProxy;
  // <if expr="is_win or is_macosx">
  let passkeysProxy: TestPasskeysBrowserProxy;
  // </if>

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    passwordManager = new TestPasswordManagerProxy();
    PasswordManagerImpl.setInstance(passwordManager);
    openWindowProxy = new TestOpenWindowProxy();
    OpenWindowProxyImpl.setInstance(openWindowProxy);
    syncProxy = new TestSyncBrowserProxy();
    SyncBrowserProxyImpl.setInstance(syncProxy);
    // <if expr="is_win or is_macosx">
    passkeysProxy = new TestPasskeysBrowserProxy();
    PasskeysBrowserProxyImpl.setInstance(passkeysProxy);
    // </if>
  });

  test('pref value displayed in the UI', async function() {
    const settings = document.createElement('settings-section');
    settings.prefs = makePasswordManagerPrefs();
    settings.prefs.credentials_enable_service.value = false;
    document.body.appendChild(settings);
    await flushTasks();

    assertFalse(settings.$.passwordToggle.checked);
    assertTrue(settings.$.autosigninToggle.checked);
  });

  test('clicking the toggle updates corresponding pref', async function() {
    const settings = document.createElement('settings-section');
    settings.prefs = makePasswordManagerPrefs();
    document.body.appendChild(settings);
    await flushTasks();

    assertTrue(settings.getPref('credentials_enable_service').value);
    assertTrue(settings.$.passwordToggle.checked);

    settings.$.passwordToggle.click();
    assertFalse(settings.getPref('credentials_enable_service').value);
    assertFalse(settings.$.passwordToggle.checked);
  });

  test('enforcement disables toggle', async function() {
    const settings = document.createElement('settings-section');
    settings.prefs = makePasswordManagerPrefs();
    settings.prefs.credentials_enable_service.enforcement =
        chrome.settingsPrivate.Enforcement.ENFORCED;
    document.body.appendChild(settings);
    await flushTasks();

    assertTrue(settings.getPref('credentials_enable_service').value);
    assertTrue(settings.$.passwordToggle.checked);
    settings.$.passwordToggle.click();
    assertTrue(settings.getPref('credentials_enable_service').value);
  });

  test('extension control includes icon', async function() {
    const settings = document.createElement('settings-section');
    settings.prefs = makePasswordManagerPrefs();
    settings.prefs.credentials_enable_service.extensionId = 'test';
    settings.prefs.credentials_enable_service.controlledByName =
        'test extension';
    document.body.appendChild(settings);
    await flushTasks();

    assertTrue(settings.$.passwordToggle.checked);
    assertTrue(
        !!settings.shadowRoot!.querySelector('extension-controlled-indicator'));
  });

  test('no extension control icon by default', async function() {
    const settings = document.createElement('settings-section');
    settings.prefs = makePasswordManagerPrefs();
    document.body.appendChild(settings);
    await flushTasks();

    assertTrue(settings.$.passwordToggle.checked);
    settings.$.passwordToggle.click();
    assertFalse(!!settings.$.passwordToggle.shadowRoot!.querySelector(
        'extension-controlled-indicator'));
  });

  test('pref updated externally', async function() {
    const settings = document.createElement('settings-section');
    settings.prefs = makePasswordManagerPrefs();
    document.body.appendChild(settings);
    await flushTasks();

    assertTrue(settings.$.autosigninToggle.checked);
    settings.set('prefs.credentials_enable_autosignin.value', false);

    assertFalse(settings.$.autosigninToggle.checked);
  });

  // <if expr="is_win or is_macosx">
  // Tests that biometric auth pref is visible, and clicking on it triggers
  // biometric auth validation instead of directly updating the pref value.
  test('biometric auth prefs when feature is available', async function() {
    loadTimeData.overrideValues(
        {biometricAuthenticationForFillingToggleVisible: true});

    const settings = document.createElement('settings-section');
    settings.prefs = makePasswordManagerPrefs();
    settings.prefs.password_manager.biometric_authentication_filling.value =
        false;
    document.body.appendChild(settings);
    await flushTasks();

    const biometricAuthenticationToggle =
        settings.shadowRoot!.querySelector<PrefToggleButtonElement>(
            '#biometricAuthenticationToggle');
    assertTrue(!!biometricAuthenticationToggle);
    assertFalse(biometricAuthenticationToggle.checked);
    assertFalse(
        settings.getPref('password_manager.biometric_authentication_filling')
            .value);

    biometricAuthenticationToggle.click();

    // Pref settings should not change until authentication succeeds.
    await passwordManager.whenCalled('switchBiometricAuthBeforeFillingState');
    assertFalse(biometricAuthenticationToggle.checked);
    assertFalse(
        settings.getPref('password_manager.biometric_authentication_filling')
            .value);
  });

  // Tests that biometric auth pref is not shown, if biometric auth is
  // unavailable.
  test('biometric auth prefs when feature is unavailable', async function() {
    loadTimeData.overrideValues(
        {biometricAuthenticationForFillingToggleVisible: false});
    const settings = document.createElement('settings-section');
    settings.prefs = makePasswordManagerPrefs();
    document.body.appendChild(settings);
    await flushTasks();
    assertFalse(!!settings.shadowRoot!.querySelector<PrefToggleButtonElement>(
        '#biometricAuthenticationToggle'));
  });
  // </if>

  test('settings section shows blockedSites', async function() {
    passwordManager.data.blockedSites = [
      createBlockedSiteEntry('test.com', 0),
      createBlockedSiteEntry('test2.com', 1),
    ];
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await flushTasks();
    await passwordManager.whenCalled('getBlockedSitesList');

    assertTrue(isVisible(settings.$.blockedSitesList));
    assertBlockedSiteList(
        settings.$.blockedSitesList.querySelectorAll<HTMLElement>(
            '.blocked-site-content'),
        passwordManager.data.blockedSites);
  });

  test('blockedSites can be deleted', async function() {
    const blockedId = 1;
    passwordManager.data.blockedSites =
        [createBlockedSiteEntry('test.com', blockedId)];
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await flushTasks();
    await passwordManager.whenCalled('getBlockedSitesList');
    assertTrue(isVisible(settings.$.blockedSitesList));

    settings.$.blockedSitesList
        .querySelector<HTMLElement>('#removeBlockedValueButton')!.click();
    const removedId = await passwordManager.whenCalled('removeBlockedSite');
    assertEquals(blockedId, removedId);
  });

  test('blockedSites listener updates the list', async function() {
    passwordManager.data.blockedSites = [createBlockedSiteEntry('test.com', 1)];
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await flushTasks();
    await passwordManager.whenCalled('getBlockedSitesList');
    // Check that only one entry is shown.
    assertTrue(isVisible(settings.$.blockedSitesList));
    assertEquals(
        settings.$.blockedSitesList
            .querySelectorAll<HTMLElement>('.blocked-site-content')
            .length,
        1);

    passwordManager.data.blockedSites.push(
        createBlockedSiteEntry('test2.com', 2));
    passwordManager.listeners.blockedSitesListChangedListener!
        (passwordManager.data.blockedSites);
    await flushTasks();
    // Check that two entries are shown.
    assertTrue(isVisible(settings.$.blockedSitesList));
    assertEquals(
        settings.$.blockedSitesList
            .querySelectorAll<HTMLElement>('.blocked-site-content')
            .length,
        2);
  });

  // Add Shortcut banner is shown and clickable.
  test('showAddShortcutBanner', async function() {
    loadTimeData.overrideValues({canAddShortcut: true});

    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await flushTasks();

    const addShortcutBanner =
        settings.shadowRoot!.querySelector<HTMLElement>('#addShortcutBanner');
    assertTrue(!!addShortcutBanner);
    assertTrue(isVisible(addShortcutBanner));
    addShortcutBanner.click();
    await passwordManager.whenCalled('showAddShortcutDialog');
  });

  // Add Shortcut banner is shown and clickable.
  test('addShortcutBanner hidden', async function() {
    loadTimeData.overrideValues({canAddShortcut: false});

    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await flushTasks();

    assertFalse(!!settings.shadowRoot!.querySelector('#addShortcutBanner'));
  });

  test(
      'import visible when policy disabled and controlled by extension',
      async function() {
        const settings = document.createElement('settings-section');
        settings.prefs = makePasswordManagerPrefs();
        settings.prefs.credentials_enable_service.value = false;
        settings.prefs.credentials_enable_service.enforcement =
            chrome.settingsPrivate.Enforcement.ENFORCED;
        settings.prefs.credentials_enable_service.controlledBy =
            chrome.settingsPrivate.ControlledBy.EXTENSION;
        document.body.appendChild(settings);
        await flushTasks();

        assertTrue(!!settings.shadowRoot!.querySelector('passwords-importer'));
      });

  test(
      'import hidden when policy disabled and not controlled by extension',
      async function() {
        const settings = document.createElement('settings-section');
        settings.prefs = makePasswordManagerPrefs();
        settings.prefs.credentials_enable_service.value = false;
        settings.prefs.credentials_enable_service.enforcement =
            chrome.settingsPrivate.Enforcement.ENFORCED;
        settings.prefs.credentials_enable_service.controlledBy =
            chrome.settingsPrivate.ControlledBy.DEVICE_POLICY;
        document.body.appendChild(settings);
        await flushTasks();

        assertFalse(!!settings.shadowRoot!.querySelector('passwords-importer'));
      });

  test('import visible when policy enabled', async function() {
    const settings = document.createElement('settings-section');
    settings.prefs = makePasswordManagerPrefs();
    settings.prefs.credentials_enable_service.value = true;
    document.body.appendChild(settings);
    await flushTasks();

    assertTrue(!!settings.shadowRoot!.querySelector('passwords-importer'));
  });

  test('Password exporter element', async function() {
    // Exporter should not be present if there are no saved passwords.
    passwordManager.data.passwords = [];
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await passwordManager.whenCalled('getSavedPasswordList');
    assertFalse(!!settings.shadowRoot!.querySelector('passwords-exporter'));

    // Exporter should appear when saved passwords are observed.
    passwordManager.data.passwords.push(
        createPasswordEntry({username: 'user1', id: 1}));
    passwordManager.listeners.savedPasswordListChangedListener!
        (passwordManager.data.passwords);
    flush();
    assertTrue(!!settings.shadowRoot!.querySelector('passwords-exporter'));
  });

  test('trustedVaultBannerVisibilityChangesWithState', async function() {
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    webUIListenerCallback(
        'trusted-vault-banner-state-changed',
        TrustedVaultBannerState.NOT_SHOWN);
    flush();
    assertTrue(settings.$.trustedVaultBanner.hidden);

    webUIListenerCallback(
        'trusted-vault-banner-state-changed',
        TrustedVaultBannerState.OFFER_OPT_IN);
    flush();
    assertFalse(settings.$.trustedVaultBanner.hidden);
    assertEquals(
        settings.i18n('trustedVaultBannerSubLabelOfferOptIn'),
        settings.$.trustedVaultBanner.subLabel);

    webUIListenerCallback(
        'trusted-vault-banner-state-changed', TrustedVaultBannerState.OPTED_IN);
    flush();
    assertFalse(settings.$.trustedVaultBanner.hidden);
    assertEquals(
        settings.i18n('trustedVaultBannerSubLabelOptedIn'),
        settings.$.trustedVaultBanner.subLabel);
  });

  test('trustedVaultBannerOpensOptInPage', async function() {
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    webUIListenerCallback(
        'trusted-vault-banner-state-changed',
        TrustedVaultBannerState.OFFER_OPT_IN);
    flush();
    assertFalse(settings.$.trustedVaultBanner.hidden);

    settings.$.trustedVaultBanner.click();
    const url = await openWindowProxy.whenCalled('openUrl');
    assertEquals(url, loadTimeData.getString('trustedVaultOptInUrl'));
  });

  test('trustedVaultBannerOpensLearnMorePage', async function() {
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    webUIListenerCallback(
        'trusted-vault-banner-state-changed', TrustedVaultBannerState.OPTED_IN);
    flush();
    assertFalse(settings.$.trustedVaultBanner.hidden);

    settings.$.trustedVaultBanner.click();
    const url = await openWindowProxy.whenCalled('openUrl');
    assertEquals(url, loadTimeData.getString('trustedVaultLearnMoreUrl'));
  });

  test('account storage toggle when feature is available', async function() {
    passwordManager.data.isOptedInAccountStorage = false;
    syncProxy.accountInfo = {
      email: '[email protected]',
    };
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: true,
      isSyncingPasswords: false,
    };

    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await syncProxy.whenCalled('getSyncInfo');
    await syncProxy.whenCalled('getAccountInfo');
    await flushTasks();
    await flushTasks();

    const accountStorageToggle = settings.$.accountStorageToggle;
    assertFalse(accountStorageToggle.hidden);
    assertFalse(accountStorageToggle.hasAttribute('checked'));
    accountStorageToggle.click();

    // Toggle should not change until authentication succeeds.
    await passwordManager.whenCalled('optInForAccountStorage');
    assertFalse(accountStorageToggle.hasAttribute('checked'));

    // Assert that password section subscribed as a listener to opt in state and
    // opt out from account storage.
    assertTrue(!!passwordManager.listeners.accountStorageOptInStateListener);
    passwordManager.data.isOptedInAccountStorage = true;
    // Imitate listener notification after successful identification.
    passwordManager.listeners.accountStorageOptInStateListener(true);
    await flushTasks();

    assertTrue(accountStorageToggle.checked);
  });

  // Tests that account storage toggle is not shown, if it should not be shown.
  test(
      'account storage pref toggle when feature is unavailable',
      async function() {
        syncProxy.syncInfo = {
          isEligibleForAccountStorage: false,
          isSyncingPasswords: false,
        };
        const settings = document.createElement('settings-section');
        document.body.appendChild(settings);
        await syncProxy.whenCalled('getSyncInfo');
        await flushTasks();

        assertTrue(settings.$.accountStorageToggle.hidden);
      });

  // <if expr="is_win or is_macosx">
  test('managePasskeysNotShownWithoutPasskeys', async function() {
    passkeysProxy.passkeysPresent = false;
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await passkeysProxy.whenCalled('passkeysHasPasskeys');
    flush();
    assertFalse(!!settings.shadowRoot!.querySelector('#managePasskeysRow'));
  });

  test('managePasskeysShownWhenNeeded', async function() {
    passkeysProxy.passkeysPresent = true;
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await passkeysProxy.whenCalled('passkeysHasPasskeys');
    flush();
    const managePasskeysRow =
        settings.shadowRoot!.querySelector<HTMLElement>('#managePasskeysRow');
    assertTrue(!!managePasskeysRow);

    managePasskeysRow.click();
    await passkeysProxy.whenCalled('passkeysManagePasskeys');
  });
  // </if>

  test('blockedSites section hidden when no blocked sites', async function() {
    passwordManager.data.blockedSites = [];
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await flushTasks();
    await passwordManager.whenCalled('getBlockedSitesList');

    assertFalse(isVisible(settings.$.blockedSitesList));
  });

  test('Move passwords to account button is visible', async function() {
    passwordManager.data.isOptedInAccountStorage = true;
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: true,
      isSyncingPasswords: false,
    };

    const group = createCredentialGroup({
      name: 'test.com',
      credentials: [
        createPasswordEntry({
          id: 0,
          username: 'test1',
          inProfileStore: true,
          inAccountStore: false,
        }),
      ],
    });

    passwordManager.data.groups = [group];
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await passwordManager.whenCalled('getSavedPasswordList');
    await flushTasks();

    assertTrue(!!settings.shadowRoot!.getElementById('movePasswordsButton'));
  });

  test('Move passwords to account button is not visible', async function() {
    passwordManager.data.isOptedInAccountStorage = true;
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: true,
      isSyncingPasswords: false,
    };

    const group = createCredentialGroup({
      name: 'test.com',
      credentials: [
        createPasswordEntry({
          id: 0,
          username: 'test1',
          inProfileStore: false,
          inAccountStore: true,
        }),
      ],
    });

    passwordManager.data.groups = [group];
    const settings = document.createElement('settings-section');
    document.body.appendChild(settings);
    await passwordManager.whenCalled('getSavedPasswordList');
    await flushTasks();

    assertFalse(!!settings.shadowRoot!.getElementById('movePasswordsButton'));
  });

  test(
      'clicking save passwords in account opens move passwords dialog',
      async function() {
        passwordManager.data.isOptedInAccountStorage = true;
        syncProxy.syncInfo = {
          isEligibleForAccountStorage: true,
          isSyncingPasswords: false,
        };

        const group = createCredentialGroup({
          name: 'test.com',
          credentials: [
            createPasswordEntry({
              id: 0,
              username: 'test1',
              inProfileStore: true,
              inAccountStore: false,
            }),
          ],
        });

        passwordManager.data.groups = [group];
        passwordManager.setRequestCredentialsDetailsResponse(
            passwordManager.data.groups[0]!.entries);

        const settings = document.createElement('settings-section');
        document.body.appendChild(settings);
        await passwordManager.whenCalled('getSavedPasswordList');
        await flushTasks();

        const movePasswordsButton =
            settings.shadowRoot!.getElementById('movePasswordsButton');
        assertTrue(!!movePasswordsButton);
        assertTrue(isVisible(movePasswordsButton));

        movePasswordsButton!.click();
        await flushTasks();

        const moveDialog =
            settings.shadowRoot!.querySelector('move-passwords-dialog');
        assertTrue(!!moveDialog);
        const dialog = moveDialog!.shadowRoot!.querySelector('#dialog');
        assertTrue(!!dialog);
      });

  test('Account storage iph', async function() {
    loadTimeData.overrideValues({canAddShortcut: false});
    passwordManager.data.isOptedInAccountStorage = false;
    syncProxy.accountInfo = {
      email: '[email protected]',
    };
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: true,
      isSyncingPasswords: false,
    };

    const section = document.createElement('settings-section');
    document.body.appendChild(section);
    await flushTasks();

    assertDeepEquals(
        section.getSortedAnchorStatusesForTesting(),
        [
          [PASSWORD_MANAGER_ACCOUNT_STORE_TOGGLE_ELEMENT_ID, true],
        ],
    );
  });

  test('Change Password Manager PIN is not available ', async function() {
    const section = document.createElement('settings-section');
    document.body.appendChild(section);
    await flushTasks();

    assertFalse(isVisible($$(section, '#changePasswordManagerPinRow')));
  });

  test('Change Password Manager PIN is available', async function() {
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: false,
      isSyncingPasswords: true,
    };
    passwordManager.data.isPasswordManagerPinAvailable = true;

    const section = document.createElement('settings-section');
    document.body.appendChild(section);
    await flushTasks();

    const changePasswordManagerPinRow =
        $$(section, '#changePasswordManagerPinRow');

    assertTrue(!!changePasswordManagerPinRow);

    changePasswordManagerPinRow.click();
    await passwordManager.whenCalled('changePasswordManagerPin');
  });

  test(
      'Change PIN and Disconnect Enclave rows hides with sync',
      async function() {
        syncProxy.syncInfo = {
          isEligibleForAccountStorage: false,
          isSyncingPasswords: true,
        };
        passwordManager.data.isPasswordManagerPinAvailable = true;
        passwordManager.data.isConnectedToCloudAuthenticator = true;

        const section = document.createElement('settings-section');
        document.body.appendChild(section);
        await flushTasks();
        await passwordManager.whenCalled('isPasswordManagerPinAvailable');

        assertTrue(isVisible($$(section, '#changePasswordManagerPinRow')));
        assertTrue(isVisible($$(section, '#disconnectCloudAuthenticatorRow')));

        webUIListenerCallback('sync-info-changed', {
          isEligibleForAccountStorage: false,
          isSyncingPasswords: false,
        });
        await flushTasks();
        await passwordManager.whenCalled('isPasswordManagerPinAvailable');
        await passwordManager.whenCalled('isConnectedToCloudAuthenticator');

        assertFalse(isVisible($$(section, '#changePasswordManagerPinRow')));
        assertFalse(isVisible($$(section, '#disconnectCloudAuthenticatorRow')));
      });

  test('After successful PIN Change toast is shown', async function() {
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: false,
      isSyncingPasswords: true,
    };
    passwordManager.data.isPasswordManagerPinAvailable = true;

    const section = document.createElement('settings-section');
    document.body.appendChild(section);
    await flushTasks();

    const changePasswordManagerPinRow =
        $$(section, '#changePasswordManagerPinRow');

    assertTrue(!!changePasswordManagerPinRow);

    changePasswordManagerPinRow.click();

    await passwordManager.whenCalled('changePasswordManagerPin');
    assertFalse(section.$.toast.open);

    passwordManager.data.changePasswordManagerPinSuccesful = false;
    changePasswordManagerPinRow.click();

    await passwordManager.whenCalled('changePasswordManagerPin');
    assertFalse(section.$.toast.open);

    passwordManager.data.changePasswordManagerPinSuccesful = true;
    changePasswordManagerPinRow.click();

    await passwordManager.whenCalled('changePasswordManagerPin');
    assertTrue(section.$.toast.open);
    assertEquals(
        loadTimeData.getString('passwordManagerPinChanged'),
        section.$.toast.textContent!.trim());
  });

  test('Disconnect Cloud Authenticator', async function() {
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: false,
      isSyncingPasswords: true,
    };
    passwordManager.data.isConnectedToCloudAuthenticator = true;
    passwordManager.data.disconnectCloudAuthenticatorSuccessful = true;

    const section = document.createElement('settings-section');
    document.body.appendChild(section);
    await flushTasks();

    const disconnectCloudAuthenticatorRow =
        $$(section, '#disconnectCloudAuthenticatorRow');
    assertTrue(!!disconnectCloudAuthenticatorRow);

    const disconnectButton =
        disconnectCloudAuthenticatorRow.querySelector<HTMLElement>(
            '#disconnectCloudAuthenticatorButton');
    assertTrue(!!disconnectButton);
    disconnectButton.click();

    await eventToPromise('cr-dialog-open', section);
    const dialog = $$(section, '#disconnectCloudAuthenticatorDialog');
    assertTrue(!!dialog);

    const confirmButton = $$(dialog, '#confirmButton')!;
    assertTrue(isVisible(confirmButton));

    confirmButton.click();
    await passwordManager.whenCalled('disconnectCloudAuthenticator');

    assertTrue(section.$.toast.open);
    assertEquals(
        loadTimeData.getString('disconnectCloudAuthenticatorToastMessage'),
        section.$.toast.textContent!.trim());
  });

  test('enableWebAuthnGpmPin shows full-data-reset row', async function() {
    loadTimeData.overrideValues({enableWebAuthnGpmPin: true});

    const section = document.createElement('settings-section');
    document.body.appendChild(section);
    await flushTasks();

    assertTrue(isVisible($$(section, 'full-data-reset')));
  });

  test(
      'disabled enableWebAuthnGpmPin hides full-data-reset row',
      async function() {
        loadTimeData.overrideValues({enableWebAuthnGpmPin: false});

        const section = document.createElement('settings-section');
        document.body.appendChild(section);
        await flushTasks();

        assertFalse(isVisible($$(section, 'full-data-reset')));
      });
});