chromium/chrome/test/data/webui/password_manager/promo_cards_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 {PasswordsSectionElement} from 'chrome://password-manager/password_manager.js';
import {Page, PasswordManagerImpl, PromoCardsProxyImpl, Router, SyncBrowserProxyImpl, UrlParam} from 'chrome://password-manager/password_manager.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {isVisible} from 'chrome://webui-test/test_util.js';

import {TestPasswordManagerProxy} from './test_password_manager_proxy.js';
import {TestPromoCardsProxy} from './test_promo_cards_browser_proxy.js';
import {TestSyncBrowserProxy} from './test_sync_browser_proxy.js';
import {createAffiliatedDomain, createCredentialGroup, createPasswordEntry} from './test_util.js';

suite('PasswordsSectionTest', function() {
  let passwordManager: TestPasswordManagerProxy;
  let promoCardsProxy: TestPromoCardsProxy;
  let syncProxy: TestSyncBrowserProxy;

  async function createPasswordsSection(): Promise<PasswordsSectionElement> {
    const section: PasswordsSectionElement =
        document.createElement('passwords-section');
    document.body.appendChild(section);
    await passwordManager.whenCalled('getCredentialGroups');
    await flushTasks();

    return section;
  }

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    passwordManager = new TestPasswordManagerProxy();
    PasswordManagerImpl.setInstance(passwordManager);
    promoCardsProxy = new TestPromoCardsProxy();
    PromoCardsProxyImpl.setInstance(promoCardsProxy);
    syncProxy = new TestSyncBrowserProxy();
    SyncBrowserProxyImpl.setInstance(syncProxy);
    Router.getInstance().updateRouterParams(new URLSearchParams());
    return flushTasks();
  });

  test('promo card shown', async function() {
    promoCardsProxy.promo = {
      id: 'test_promo',
      title: 'Hello there',
      description: 'This is a promo card.',
    };

    const section = await createPasswordsSection();
    let promoCardElement = section.shadowRoot!.querySelector('promo-card');

    // Verify promo card is shown.
    assertTrue(!!promoCardElement);
    assertEquals(
        promoCardsProxy.promo!.title,
        promoCardElement.$.title.textContent!.trim());
    assertEquals(
        promoCardsProxy.promo!.description,
        promoCardElement.$.description.textContent!.trim());
    assertFalse(isVisible(promoCardElement.$.actionButton));
    const shownImage = promoCardElement.shadowRoot!.querySelector('img');
    assertTrue(!!shownImage);
    assertEquals(
        'chrome://password-manager/images/test_promo.svg', shownImage.src);

    // Click close button.
    promoCardElement.$.closeButton.click();
    assertEquals(
        promoCardsProxy.promo?.id,
        await promoCardsProxy.whenCalled('recordPromoDismissed'));
    await flushTasks();

    // Verify that the promo card is hidden.
    promoCardElement = section.shadowRoot!.querySelector('promo-card');
    assertFalse(!!promoCardElement);
  });

  test('password checkup promo', async function() {
    promoCardsProxy.promo = {
      id: 'password_checkup_promo',
      title: 'Checkup promo',
      description: 'Checkup promo description.',
      actionButtonText: 'Start check',
    };

    const section = await createPasswordsSection();
    let promoCardElement = section.shadowRoot!.querySelector('promo-card');

    // Verify promo card is shown.
    assertTrue(!!promoCardElement);
    assertTrue(isVisible(promoCardElement.$.actionButton));

    // Click action button button and verify we navigated to checkup page and
    // started password checkup.
    promoCardElement.$.actionButton.click();
    assertEquals(Page.CHECKUP, Router.getInstance().currentRoute.page);
    assertEquals(
        'true',
        String(Router.getInstance().currentRoute.queryParameters.get(
            UrlParam.START_CHECK)));
    await flushTasks();

    // Verify that the promo card is hidden.
    promoCardElement = section.shadowRoot!.querySelector('promo-card');
    assertFalse(!!promoCardElement);
  });

  test('shortcut promo', async function() {
    promoCardsProxy.promo = {
      id: 'password_shortcut_promo',
      title: 'Shortcut promo',
      description: 'Shortcut promo description.',
      actionButtonText: 'Add shortcut',
    };

    const section = await createPasswordsSection();
    let promoCardElement = section.shadowRoot!.querySelector('promo-card');

    // Verify promo card is shown.
    assertTrue(!!promoCardElement);
    assertTrue(isVisible(promoCardElement.$.actionButton));

    // Click action button button and verify we navigated to checkup page and
    // started password checkup.
    promoCardElement.$.actionButton.click();
    await passwordManager.whenCalled('showAddShortcutDialog');
    await flushTasks();

    // Verify that the promo card is hidden.
    promoCardElement = section.shadowRoot!.querySelector('promo-card');
    assertFalse(!!promoCardElement);
  });

  test('move passwords promo hidden if no local passwords', async function() {
    promoCardsProxy.promo = {
      id: 'move_passwords_promo',
      title: 'Move passwords promo',
      description: 'Move passwords description.',
      actionButtonText: 'Move passwords',
    };
    passwordManager.data.isOptedInAccountStorage = true;
    passwordManager.data.groups = [createCredentialGroup({
      name: 'test.com',
      credentials: [createPasswordEntry({
        username: 'user',
        id: 0,
        inProfileStore: false,
        inAccountStore: true,
      })],
    })];
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: true,
      isSyncingPasswords: false,
    };

    const section = await createPasswordsSection();
    const promoCardElement = section.shadowRoot!.querySelector('promo-card');
    assertFalse(!!promoCardElement);
  });

  test('move passwords promo hidden if butter disabled', async function() {
    promoCardsProxy.promo = {
      id: 'move_passwords_promo',
      title: 'Move passwords promo',
      description: 'Move passwords description.',
      actionButtonText: 'Move passwords',
    };
    passwordManager.data.isOptedInAccountStorage = false;
    passwordManager.data.groups = [createCredentialGroup({
      name: 'test.com',
      credentials: [createPasswordEntry(
          {username: 'user', id: 0, inProfileStore: true})],
    })];
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: true,
      isSyncingPasswords: false,
    };

    const section = await createPasswordsSection();
    const promoCardElement = section.shadowRoot!.querySelector('promo-card');
    assertFalse(!!promoCardElement);
  });

  test('move passwords promo hidden if sync issues', async function() {
    promoCardsProxy.promo = {
      id: 'move_passwords_promo',
      title: 'Move passwords promo',
      description: 'Move passwords description.',
      actionButtonText: 'Move passwords',
    };
    passwordManager.data.isOptedInAccountStorage = true;
    passwordManager.data.groups = [createCredentialGroup({
      name: 'test.com',
      credentials: [createPasswordEntry(
          {username: 'user', id: 0, inProfileStore: true})],
    })];
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: false,
      isSyncingPasswords: false,
    };

    const section = await createPasswordsSection();
    const promoCardElement = section.shadowRoot!.querySelector('promo-card');
    assertFalse(!!promoCardElement);
  });

  test('move passwords promo visible is requirements met', async function() {
    promoCardsProxy.promo = {
      id: 'move_passwords_promo',
      title: 'Move passwords promo',
      description: 'Move passwords description.',
      actionButtonText: 'Move passwords',
    };
    passwordManager.data.isOptedInAccountStorage = true;

    const password = createPasswordEntry({
      id: 1234,
      username: 'user1',
      password: 'sTr0nGp@@s',
      affiliatedDomains: [createAffiliatedDomain('test.com')],
      inProfileStore: true,
    });

    passwordManager.data.groups = [createCredentialGroup({
      name: 'test.com',
      credentials: [password],
    })];
    syncProxy.syncInfo = {
      isEligibleForAccountStorage: true,
      isSyncingPasswords: false,
    };

    passwordManager.setRequestCredentialsDetailsResponse([password]);

    const section = await createPasswordsSection();
    const promoCardElement = section.shadowRoot!.querySelector('promo-card');
    assertTrue(!!promoCardElement);
    assertTrue(isVisible(promoCardElement.$.actionButton));

    promoCardElement.$.actionButton.click();
    await flushTasks();

    const moveDialog =
        section.shadowRoot!.querySelector('move-passwords-dialog');
    assertTrue(!!moveDialog);
    assertTrue(isVisible(moveDialog.$.move));
  });

  test('screenlock promo', async function() {
    promoCardsProxy.promo = {
      id: 'screenlock_reauth_promo',
      title: 'Screenlock reauth promo',
      description: 'Screenlock reauth promo description.',
      actionButtonText: 'Enable screenlock reauth',
    };
    passwordManager.setSwitchBiometricAuthBeforeFillingStateResponse(true);

    const section = await createPasswordsSection();
    let promoCardElement = section.shadowRoot!.querySelector('promo-card');

    // Verify promo card is shown.
    assertTrue(!!promoCardElement);
    assertTrue(isVisible(promoCardElement.$.actionButton));

    // Click action button button and verify that authentication started.
    promoCardElement.$.actionButton.click();
    await passwordManager.whenCalled('switchBiometricAuthBeforeFillingState');
    await flushTasks();

    // Verify that the promo card is hidden.
    promoCardElement = section.shadowRoot!.querySelector('promo-card');
    assertFalse(isVisible(promoCardElement));
  });
});