chromium/chrome/test/data/webui/password_manager/checkup_details_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 type {CrExpandButtonElement} from 'chrome://password-manager/password_manager.js';
import {CheckupSubpage, OpenWindowProxyImpl, Page, PasswordCheckInteraction, PasswordManagerImpl, PluralStringProxyImpl, Router} from 'chrome://password-manager/password_manager.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {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 {TestPluralStringProxy} from 'chrome://webui-test/test_plural_string_proxy.js';
import {isVisible} from 'chrome://webui-test/test_util.js';

import {TestPasswordManagerProxy} from './test_password_manager_proxy.js';
import {createAffiliatedDomain, createCredentialGroup, makeInsecureCredential, makePasswordManagerPrefs} from './test_util.js';

suite('CheckupDetailsSectionTest', function() {
  const CompromiseType = chrome.passwordsPrivate.CompromiseType;

  let openWindowProxy: TestOpenWindowProxy;
  let passwordManager: TestPasswordManagerProxy;
  let pluralString: TestPluralStringProxy;

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    openWindowProxy = new TestOpenWindowProxy();
    OpenWindowProxyImpl.setInstance(openWindowProxy);
    passwordManager = new TestPasswordManagerProxy();
    PasswordManagerImpl.setInstance(passwordManager);
    pluralString = new TestPluralStringProxy();
    PluralStringProxyImpl.setInstance(pluralString);
    Router.getInstance().navigateTo(Page.CHECKUP);
    return flushTasks();
  });

  [CheckupSubpage.COMPROMISED, CheckupSubpage.REUSED, CheckupSubpage.WEAK]
      .forEach(
          type => test(`Title shown correctly for ${type}`, async function() {
            Router.getInstance().navigateTo(Page.CHECKUP_DETAILS, type);
            passwordManager.data.insecureCredentials = [
              makeInsecureCredential({
                types: [
                  CompromiseType.LEAKED,
                  CompromiseType.REUSED,
                  CompromiseType.WEAK,
                ],
              }),
              makeInsecureCredential({
                types: [
                  CompromiseType.PHISHED,
                  CompromiseType.REUSED,
                  CompromiseType.WEAK,
                ],
              }),
            ];

            const section = document.createElement('checkup-details-section');
            document.body.appendChild(section);
            await passwordManager.whenCalled('getInsecureCredentials');
            const params = await pluralString.whenCalled('getPluralString');
            await flushTasks();

            assertEquals(type + 'Passwords', params.messageName);
            assertEquals(2, params.itemCount);

            if (type === CheckupSubpage.COMPROMISED) {
              // getPluralString() should be called 2 times: 1 for page title,
              // and 1 more for page subtitle.
              assertEquals(2, pluralString.getCallCount('getPluralString'));
            } else {
              assertEquals(
                  loadTimeData.getString(`${type}PasswordsTitle`),
                  section.$.subtitle.textContent!.trim());
            }
            assertEquals(
                loadTimeData.getString(`${type}PasswordsDescription`),
                section.$.description.textContent!.trim());
          }));

  test('Compromised issues shown correctly', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    passwordManager.data.insecureCredentials = [
      makeInsecureCredential({
        url: 'test.com',
        username: 'viking',
        types: [
          CompromiseType.LEAKED,
        ],
        elapsedMinSinceCompromise: 1,
      }),
      makeInsecureCredential({
        url: 'example.com',
        username: 'justUser',
        types: [
          CompromiseType.PHISHED,
        ],
        elapsedMinSinceCompromise: 10,
      }),
      makeInsecureCredential({
        url: 'www.bestSite.com',
        username: 'random',
        types: [
          CompromiseType.LEAKED,
          CompromiseType.PHISHED,
        ],
        elapsedMinSinceCompromise: 100,
      }),
    ];
    passwordManager.data.groups = [
      createCredentialGroup({
        name: 'Affiliation.com',
        credentials: passwordManager.data.insecureCredentials,
      }),
    ];

    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await passwordManager.whenCalled('getCredentialGroups');
    const params = await pluralString.whenCalled('getPluralString');
    await flushTasks();

    assertEquals('compromisedPasswords', params.messageName);
    assertEquals(3, params.itemCount);

    const listItemElements =
        section.shadowRoot!.querySelectorAll('checkup-list-item');
    assertEquals(
        listItemElements.length,
        passwordManager.data.insecureCredentials.length);

    const expectedType = [
      loadTimeData.getString('leakedPassword'),
      loadTimeData.getString('phishedPassword'),
      loadTimeData.getString('phishedAndLeakedPassword'),
    ];

    for (let index = 0; index < listItemElements.length; ++index) {
      const expectedCredential =
          passwordManager.data.insecureCredentials[index]!;
      const listItemElement = listItemElements[index];

      assertTrue(!!listItemElement);
      assertEquals(
          passwordManager.data.groups[0]?.name,
          listItemElement.$.shownUrl.textContent!.trim());
      assertEquals(
          expectedCredential.username,
          listItemElement.$.username.textContent!.trim());
      const compromiseType =
          listItemElement.shadowRoot!.querySelector('#compromiseType');

      assertTrue(!!compromiseType);
      assertTrue(isVisible(compromiseType));
      assertEquals(expectedType[index]!, compromiseType.textContent!.trim());

      const elapsedTime =
          listItemElement.shadowRoot!.querySelector('#elapsedTime');
      assertTrue(!!elapsedTime);
      assertTrue(isVisible(elapsedTime));
      assertEquals(
          expectedCredential.compromisedInfo?.elapsedTimeSinceCompromise,
          elapsedTime.textContent!.trim());
    }
  });

  test('Weak issues shown correctly', async function() {
    Router.getInstance().navigateTo(Page.CHECKUP_DETAILS, CheckupSubpage.WEAK);
    passwordManager.data.insecureCredentials = [makeInsecureCredential({
      url: 'test.com',
      username: 'viking',
      types: [
        CompromiseType.WEAK,
      ],
      elapsedMinSinceCompromise: 1,
    })];
    passwordManager.data.groups = [
      createCredentialGroup({
        name: 'Best test site',
        credentials: passwordManager.data.insecureCredentials,
      }),
    ];

    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await passwordManager.whenCalled('getCredentialGroups');
    const params = await pluralString.whenCalled('getPluralString');
    await flushTasks();

    assertEquals('weakPasswords', params.messageName);
    assertEquals(1, params.itemCount);

    const listItemElements =
        section.shadowRoot!.querySelectorAll('checkup-list-item');
    assertEquals(1, listItemElements.length);
    const weakItem = listItemElements[0];

    assertTrue(!!weakItem);
    assertEquals(
        passwordManager.data.groups[0]!.name,
        weakItem.$.shownUrl.textContent!.trim());
    assertEquals('viking', weakItem.$.username.textContent!.trim());

    assertFalse(!!weakItem.shadowRoot!.querySelector('#compromiseType'));
    assertFalse(!!weakItem.shadowRoot!.querySelector('#elapsedTime'));
  });

  test('Muted compromised issues shown correctly', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    passwordManager.data.insecureCredentials = [
      makeInsecureCredential({
        url: 'test.com',
        username: 'viking',
        types: [
          CompromiseType.LEAKED,
        ],
        elapsedMinSinceCompromise: 1,
        isMuted: false,
      }),
      makeInsecureCredential({
        url: 'example.com',
        username: 'admin',
        types: [
          CompromiseType.PHISHED,
        ],
        elapsedMinSinceCompromise: 1,
        isMuted: false,
      }),
      makeInsecureCredential({
        url: 'example.com',
        username: 'justUser',
        types: [
          CompromiseType.PHISHED,
        ],
        elapsedMinSinceCompromise: 10,
        isMuted: true,
      }),
    ];
    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');

    const params = await pluralString.whenCalled('getPluralString');
    await flushTasks();

    assertEquals('compromisedPasswords', params.messageName);
    assertEquals(2, params.itemCount);

    const dismissedButton =
        section.shadowRoot!.querySelector<CrExpandButtonElement>(
            '#expandMutedCompromisedCredentialsButton');
    assertTrue(!!dismissedButton);
    assertTrue(isVisible(dismissedButton));

    const mutedCredentialsList =
        section.shadowRoot!.querySelector('#mutedCredentialsList');
    assertTrue(!!mutedCredentialsList);

    const listItemElements =
        mutedCredentialsList.querySelectorAll<HTMLElement>('checkup-list-item');
    assertEquals(1, listItemElements.length);
    assertTrue(!!listItemElements[0]);
    assertFalse(isVisible(listItemElements[0]));

    dismissedButton.click();
    await dismissedButton.updateComplete;

    assertTrue(isVisible(listItemElements[0]));
  });

  test('Reused issues shown correctly', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.REUSED);
    const insecurePasswords = [
      makeInsecureCredential({url: 'Some app', username: 'viking', id: 0}),
      makeInsecureCredential({url: 'example.com', username: 'user', id: 1}),
      makeInsecureCredential({url: 'test.com', username: 'Lalala', id: 2}),
      makeInsecureCredential(
          {url: 'accounts.google.com', username: 'corporateEmail', id: 3}),
      makeInsecureCredential(
          {url: 'super.secure.com', username: 'admin', id: 4}),
    ];
    passwordManager.data.groups = insecurePasswords.map(
        entry => createCredentialGroup(
            {name: entry.affiliatedDomains[0]!.name, credentials: [entry]}));
    passwordManager.data.credentialWithReusedPassword = [
      {entries: insecurePasswords.slice(0, 3).sort(() => Math.random() - 0.5)},
      {entries: insecurePasswords.slice(3, 5).sort(() => Math.random() - 0.5)},
    ];

    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await passwordManager.whenCalled('getCredentialsWithReusedPassword');
    await pluralString.whenCalled('getPluralString');
    // getPluralString() should be called 3 times: 1 for title, and 2 more for
    // each reused password.
    assertEquals(3, pluralString.getCallCount('getPluralString'));
    await flushTasks();

    const listItemElements =
        section.shadowRoot!.querySelectorAll('checkup-list-item');
    assertEquals(insecurePasswords.length, listItemElements.length);

    for (let index = 0; index < listItemElements.length; ++index) {
      const expectedCredential = insecurePasswords[index]!;
      const listItemElement = listItemElements[index];

      assertTrue(!!listItemElement);
      assertEquals(
          expectedCredential.affiliatedDomains[0]!.name,
          listItemElement.$.shownUrl.textContent!.trim());
      assertEquals(
          expectedCredential.username,
          listItemElement.$.username.textContent!.trim());
      const leakType = listItemElement.shadowRoot!.querySelector('#leakType');
      assertFalse(!!leakType);

      const elapsedTime =
          listItemElement.shadowRoot!.querySelector('#elapsedTime');
      assertFalse(!!elapsedTime);
    }
  });

  test('Show/Hide action button works', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    passwordManager.data.insecureCredentials = [
      makeInsecureCredential({
        id: 0,
        url: 'test.com',
        username: 'viking',
        types: [
          CompromiseType.LEAKED,
        ],
      }),
    ];

    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await flushTasks();

    const listItem = section.shadowRoot!.querySelector('checkup-list-item');
    assertTrue(!!listItem);
    assertTrue(isVisible(listItem));
    assertEquals('password', listItem.$.insecurePassword.type);

    assertFalse(isVisible(section.$.moreActionsMenu));

    // Click more actions button
    listItem.$.more.click();

    assertTrue(isVisible(section.$.menuShowPassword));
    assertEquals(
        loadTimeData.getString('showPassword'),
        section.$.menuShowPassword.textContent?.trim());

    const credentialWithPassword = passwordManager.data.insecureCredentials[0]!;
    credentialWithPassword.password = 'pAssWoRd';
    passwordManager.setRequestCredentialsDetailsResponse(
        [credentialWithPassword]);

    section.$.menuShowPassword.click();
    await passwordManager.whenCalled('requestCredentialsDetails');

    assertEquals('text', listItem.$.insecurePassword.type);
    assertEquals(
        credentialWithPassword.password, listItem.$.insecurePassword.value);

    listItem.$.more.click();
    assertTrue(isVisible(section.$.menuShowPassword));
    assertEquals(
        loadTimeData.getString('hidePassword'),
        section.$.menuShowPassword.textContent?.trim());
    section.$.menuShowPassword.click();

    assertEquals('password', listItem.$.insecurePassword.type);
  });

  test('Mute button works', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    passwordManager.data.insecureCredentials = [
      makeInsecureCredential({
        id: 0,
        url: 'test.com',
        username: 'viking',
        types: [
          CompromiseType.LEAKED,
        ],
      }),
    ];

    const section = document.createElement('checkup-details-section');
    section.prefs = makePasswordManagerPrefs();
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await flushTasks();

    const listItem = section.shadowRoot!.querySelector('checkup-list-item');
    assertTrue(!!listItem);
    assertTrue(isVisible(listItem));

    // Click more actions button
    listItem.$.more.click();

    const muteButton =
        section.shadowRoot!.querySelector<HTMLElement>('#menuMuteUnmuteButton');
    assertTrue(!!muteButton);
    assertTrue(isVisible(muteButton));
    assertEquals(
        loadTimeData.getString('muteCompromisedPassword'),
        muteButton.textContent?.trim());

    muteButton.click();
    await passwordManager.whenCalled('muteInsecureCredential');
  });

  test('Unmute button works', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    passwordManager.data.insecureCredentials = [
      makeInsecureCredential({
        id: 0,
        url: 'test.com',
        username: 'viking',
        types: [
          CompromiseType.LEAKED,
        ],
        isMuted: true,
      }),
    ];

    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await flushTasks();

    // Expand dismissed compromised credentials.
    const expandButton = section.shadowRoot!.querySelector<HTMLElement>(
        '#expandMutedCompromisedCredentialsButton');
    assertTrue(!!expandButton);
    assertTrue(isVisible(expandButton));
    expandButton.click();
    await flushTasks();

    const listItem = section.shadowRoot!.querySelector('checkup-list-item');
    assertTrue(!!listItem);
    assertFalse(isVisible(section.$.moreActionsMenu));

    // Click more actions button
    listItem.$.more.click();

    const unMuteButton =
        section.shadowRoot!.querySelector<HTMLElement>('#menuMuteUnmuteButton');
    assertTrue(!!unMuteButton);
    assertTrue(isVisible(unMuteButton));
    assertEquals(
        loadTimeData.getString('unmuteCompromisedPassword'),
        unMuteButton.textContent?.trim());

    unMuteButton.click();
    await passwordManager.whenCalled('unmuteInsecureCredential');
  });

  test('Mute button disabled by pref', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    passwordManager.data.insecureCredentials = [
      makeInsecureCredential({
        id: 0,
        url: 'test.com',
        username: 'viking',
        types: [
          CompromiseType.LEAKED,
        ],
      }),
    ];

    const section = document.createElement('checkup-details-section');
    section.prefs = makePasswordManagerPrefs();
    section.prefs.profile.password_dismiss_compromised_alert.value = false;
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await flushTasks();

    const listItem = section.shadowRoot!.querySelector('checkup-list-item');
    assertTrue(!!listItem);
    assertTrue(isVisible(listItem));

    // Click more actions button
    listItem.$.more.click();

    const muteButton = section.shadowRoot!.querySelector<HTMLButtonElement>(
        '#menuMuteUnmuteButton');

    assertTrue(!!muteButton);
    assertTrue(isVisible(muteButton));
    assertTrue(muteButton.disabled);
  });

  [CheckupSubpage.COMPROMISED, CheckupSubpage.REUSED, CheckupSubpage.WEAK]
      .forEach(
          type => test(`Change password click for ${type}`, async function() {
            Router.getInstance().navigateTo(Page.CHECKUP_DETAILS, type);

            const insecureCredential = makeInsecureCredential({
              id: Math.floor(Math.random() * 1000),
              url: 'test.com',
              username: 'viking',
              types: [
                CompromiseType.LEAKED,
                CompromiseType.WEAK,
                CompromiseType.REUSED,
              ],
            });
            passwordManager.data.insecureCredentials = [insecureCredential];
            passwordManager.data.credentialWithReusedPassword =
                [{entries: [insecureCredential]}];

            const section = document.createElement('checkup-details-section');
            document.body.appendChild(section);
            await passwordManager.whenCalled('getInsecureCredentials');
            if (type === CheckupSubpage.REUSED) {
              await passwordManager.whenCalled(
                  'getCredentialsWithReusedPassword');
            }
            await pluralString.whenCalled('getPluralString');
            await flushTasks();

            const listItemElements =
                section.shadowRoot!.querySelectorAll('checkup-list-item');
            assertEquals(1, listItemElements.length);
            assertTrue(!!listItemElements[0]);
            assertTrue(isVisible(listItemElements[0]));


            // Verify that 'Already change password?' link is hidden.
            const alreadyChange =
                listItemElements[0].shadowRoot!.querySelector<HTMLElement>(
                    '#alreadyChanged');
            assertTrue(!!alreadyChange);
            assertTrue(alreadyChange.hidden);

            const changePassword =
                listItemElements[0].shadowRoot!.querySelector<HTMLElement>(
                    '#changePasswordButton');
            assertTrue(!!changePassword);

            changePassword.click();
            const url = await openWindowProxy.whenCalled('openUrl');
            assertEquals(url, insecureCredential.changePasswordUrl);
            await flushTasks();

            // Verify that 'Already change password?' link is visible.
            assertFalse(alreadyChange.hidden);
          }));

  [CheckupSubpage.COMPROMISED, CheckupSubpage.REUSED, CheckupSubpage.WEAK]
      .forEach(
          type => test(`Change password in app for ${type}`, async function() {
            Router.getInstance().navigateTo(Page.CHECKUP_DETAILS, type);

            const insecureCredential = makeInsecureCredential({
              url: 'test.com',
              username: 'viking',
              types: [
                CompromiseType.LEAKED,
                CompromiseType.WEAK,
                CompromiseType.REUSED,
              ],
            });
            insecureCredential.changePasswordUrl = undefined;
            passwordManager.data.insecureCredentials = [insecureCredential];
            passwordManager.data.credentialWithReusedPassword =
                [{entries: [insecureCredential]}];

            const section = document.createElement('checkup-details-section');
            document.body.appendChild(section);
            await passwordManager.whenCalled('getInsecureCredentials');
            if (type === CheckupSubpage.REUSED) {
              await passwordManager.whenCalled(
                  'getCredentialsWithReusedPassword');
            }
            await pluralString.whenCalled('getPluralString');
            await flushTasks();

            const listItemElements =
                section.shadowRoot!.querySelectorAll('checkup-list-item');
            assertEquals(1, listItemElements.length);
            assertTrue(!!listItemElements[0]);
            assertTrue(isVisible(listItemElements[0]));

            // Verify that 'Change password' button is hidden.
            const changePassword =
                listItemElements[0].shadowRoot!.querySelector(
                    '#changePasswordButton');
            assertFalse(!!changePassword);

            const changeInAppString =
                listItemElements[0].shadowRoot!.querySelector(
                    '#changePasswordInApp');
            assertTrue(!!changeInAppString);
            assertTrue(isVisible(changeInAppString));
            assertEquals(
                loadTimeData.getString('changePasswordInApp'),
                changeInAppString.textContent?.trim());
          }));

  test('Edit action button works', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    const credential = makeInsecureCredential({
      id: 0,
      url: 'test.com',
      username: 'viking',
      password: 'pass',
      types: [
        CompromiseType.LEAKED,
      ],
    });
    credential.affiliatedDomains = [createAffiliatedDomain('test.com')];
    passwordManager.data.insecureCredentials = [credential];

    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await flushTasks();

    const listItem = section.shadowRoot!.querySelector('checkup-list-item');
    assertTrue(!!listItem);

    // Click more actions button.
    listItem.$.more.click();
    // Set up response for requestCredentialsDetails() to simulate successful
    // reauth.
    passwordManager.setRequestCredentialsDetailsResponse([credential]);

    section.$.menuEditPassword.click();
    await passwordManager.whenCalled('requestCredentialsDetails');
    await flushTasks();

    const editDialog =
        listItem.shadowRoot!.querySelector('edit-password-dialog');
    assertTrue(!!editDialog);
    assertTrue(editDialog.$.dialog.open);
  });

  test('No edit if auth failed', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    const credential = makeInsecureCredential({
      id: 0,
      url: 'test.com',
      username: 'viking',
      password: 'pass',
      types: [
        CompromiseType.LEAKED,
      ],
    });
    credential.affiliatedDomains = [createAffiliatedDomain('test.com')];
    passwordManager.data.insecureCredentials = [credential];

    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await flushTasks();

    const listItem = section.shadowRoot!.querySelector('checkup-list-item');
    assertTrue(!!listItem);

    // Click more actions button.
    listItem.$.more.click();

    section.$.menuEditPassword.click();
    await passwordManager.whenCalled('requestCredentialsDetails');
    await flushTasks();

    const editDialog =
        listItem.shadowRoot!.querySelector('edit-password-dialog');
    assertFalse(!!editDialog);
  });

  test('Edit dialog shown during already change flow', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    const credential = makeInsecureCredential({
      id: 0,
      url: 'test.com',
      username: 'viking',
      password: 'pass',
      types: [
        CompromiseType.LEAKED,
      ],
    });
    credential.affiliatedDomains = [createAffiliatedDomain('test.com')];
    passwordManager.data.insecureCredentials = [credential];

    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await flushTasks();

    const listItem = section.shadowRoot!.querySelector('checkup-list-item');
    assertTrue(!!listItem);

    // Click 'Change password'
    const changePassword = listItem.shadowRoot!.querySelector<HTMLElement>(
        '#changePasswordButton');
    assertTrue(!!changePassword);
    changePassword.click();

    // Click 'Already change password?'
    const alreadyChange =
        listItem.shadowRoot!.querySelector<HTMLElement>('#alreadyChanged');
    assertTrue(!!alreadyChange);
    alreadyChange.click();
    await flushTasks();

    // Verify edit disclaimer dialog is shown.
    const editDisclaimer =
        listItem.shadowRoot!.querySelector('edit-password-disclaimer-dialog');
    assertTrue(!!editDisclaimer);
    assertTrue(editDisclaimer.$.dialog.open);

    // Set up response for requestCredentialsDetails() to simulate successful
    // reauth and click 'Edit'.
    passwordManager.setRequestCredentialsDetailsResponse([credential]);
    editDisclaimer.$.edit.click();

    await passwordManager.whenCalled('requestCredentialsDetails');
    await flushTasks();

    const editDialog =
        listItem.shadowRoot!.querySelector('edit-password-dialog');
    assertTrue(!!editDialog);
    assertTrue(editDialog.$.dialog.open);
  });

  test('Delete insecure password', async function() {
    Router.getInstance().navigateTo(
        Page.CHECKUP_DETAILS, CheckupSubpage.COMPROMISED);
    const credential = makeInsecureCredential({
      id: 0,
      url: 'test.com',
      username: 'viking',
      types: [
        CompromiseType.LEAKED,
      ],
    });
    credential.affiliatedDomains = [createAffiliatedDomain('test.com')];
    passwordManager.data.insecureCredentials = [credential];

    const section = document.createElement('checkup-details-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getInsecureCredentials');
    await flushTasks();

    const listItem = section.shadowRoot!.querySelector('checkup-list-item');
    assertTrue(!!listItem);

    // Click more actions button.
    listItem.$.more.click();

    section.$.menuDeletePassword.click();
    await flushTasks();

    const deleteDialog =
        listItem.shadowRoot!.querySelector('delete-password-disclaimer-dialog');
    assertTrue(!!deleteDialog);
    assertTrue(deleteDialog.$.dialog.open);

    // Change password URL gets linkified.
    assertTrue(isVisible(deleteDialog.$.link));
    assertFalse(isVisible(deleteDialog.$.text));

    // Click 'Delete password'.
    deleteDialog.$.delete.click();
    const interaction =
        await passwordManager.whenCalled('recordPasswordCheckInteraction');
    const params = await passwordManager.whenCalled('removeCredential');
    assertEquals(params.id, credential.id);
    assertEquals(params.fromStores, credential.storedIn);
    assertEquals(PasswordCheckInteraction.REMOVE_PASSWORD, interaction);
  });
});