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

// Copyright 2023 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 {DeletePasskeyDialogElement, EditPasskeyDialogElement, PasskeyDetailsCardElement} from 'chrome://password-manager/password_manager.js';
import {Page, PasswordManagerImpl, PasswordViewPageInteractions, Router} from 'chrome://password-manager/password_manager.js';
import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {eventToPromise, isVisible} from 'chrome://webui-test/test_util.js';

import {TestPasswordManagerProxy} from './test_password_manager_proxy.js';
import {createAffiliatedDomain, createPasswordEntry} from './test_util.js';

suite('PasskeyDetailsCardTest', function() {
  let passwordManager: TestPasswordManagerProxy;
  let passkey: chrome.passwordsPrivate.PasswordUiEntry;
  let card: PasskeyDetailsCardElement;

  setup(async function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    passwordManager = new TestPasswordManagerProxy();
    PasswordManagerImpl.setInstance(passwordManager);
    Router.getInstance().navigateTo(Page.PASSWORDS);
    await flushTasks();

    passkey = createPasswordEntry({
      url: 'test.com',
      username: 'reimu',
      isPasskey: true,
      displayName: 'Reimu Hakurei',
      note: 'Remember the milk',
      affiliatedDomains: [createAffiliatedDomain('test.com')],
    });

    card = document.createElement('passkey-details-card');
    card.passkey = passkey;
    document.body.appendChild(card);
    await flushTasks();
  });

  test('Content displayed properly', async function() {
    assertEquals(passkey.username, card.$.usernameValue.value);
    assertEquals(passkey.displayName, card.$.displayNameValue.value);
    assertEquals(
        // 1/12/70 is the date that matches the creation time set by
        // `createPasswordEntry`.
        card.i18n('passkeyManagementInfoLabel', '1/12/70'),
        card.$.infoLabel.innerText.trim());
    assertTrue(isVisible(card.$.editButton));
    assertTrue(isVisible(card.$.deleteButton));

    const domains =
        card.shadowRoot!.querySelectorAll<HTMLAnchorElement>('a.site-link');
    assertEquals(domains.length, 1);
    assertEquals(
        passkey.affiliatedDomains![0]!.name, domains[0]!.textContent!.trim());
    assertEquals(passkey.affiliatedDomains![0]!.url, domains[0]!.href);
  });

  test('Clicking edit button opens an edit dialog', async function() {
    card.$.editButton.click();
    await eventToPromise('cr-dialog-open', card);
    await passwordManager.whenCalled('extendAuthValidity');
    assertEquals(
        PasswordViewPageInteractions.PASSKEY_EDIT_BUTTON_CLICKED,
        await passwordManager.whenCalled('recordPasswordViewInteraction'));
    await flushTasks();

    const editDialog = card.shadowRoot!.querySelector<EditPasskeyDialogElement>(
        'edit-passkey-dialog');
    assertTrue(!!editDialog);
    assertTrue(editDialog.$.dialog.open);

    // Close the dialog and verify it leaves the DOM.
    const editTemplate =
        card.shadowRoot!.querySelector('#editPasskeyTemplate')!;
    const domChange = eventToPromise('dom-change', editTemplate);
    editDialog.$.dialog.close();
    await passwordManager.whenCalled('extendAuthValidity');
    await domChange;
    assertEquals(card.shadowRoot!.querySelector('edit-passkey-dialog'), null);
  });

  test('Clicking delete button opens a delete dialog', async function() {
    card.$.deleteButton.click();
    await eventToPromise('cr-dialog-open', card);
    await passwordManager.whenCalled('extendAuthValidity');
    assertEquals(
        PasswordViewPageInteractions.PASSKEY_DELETE_BUTTON_CLICKED,
        await passwordManager.whenCalled('recordPasswordViewInteraction'));
    await flushTasks();

    const deleteDialog =
        card.shadowRoot!.querySelector<DeletePasskeyDialogElement>(
            'delete-passkey-dialog');
    assertTrue(!!deleteDialog);
    assertTrue(deleteDialog.$.dialog.open);

    // Close the dialog and verify it leaves the DOM.
    const deleteTemplate =
        card.shadowRoot!.querySelector('#deletePasskeyTemplate')!;
    const domChange = eventToPromise('dom-change', deleteTemplate);
    deleteDialog.$.dialog.close();
    await passwordManager.whenCalled('extendAuthValidity');
    await domChange;
    assertEquals(card.shadowRoot!.querySelector('delete-passkey-dialog'), null);
  });
});