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

// Copyright 2016 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 {dashToCamelCase, flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import type {BrowserProfile, ImportDataBrowserProxy, SettingsCheckboxElement, SettingsImportDataDialogElement} from 'chrome://settings/lazy_load.js';
import {ImportDataBrowserProxyImpl, ImportDataStatus} from 'chrome://settings/lazy_load.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';

// clang-format on

class TestImportDataBrowserProxy extends TestBrowserProxy implements
    ImportDataBrowserProxy {
  private browserProfiles_: BrowserProfile[] = [];

  constructor() {
    super([
      'initializeImportDialog',
      'importFromBookmarksFile',
      'importData',
    ]);
  }

  setBrowserProfiles(browserProfiles: BrowserProfile[]) {
    this.browserProfiles_ = browserProfiles;
  }

  initializeImportDialog() {
    this.methodCalled('initializeImportDialog');
    return Promise.resolve(this.browserProfiles_.slice());
  }

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

  importData(browserProfileIndex: number, types: {[type: string]: boolean}) {
    this.methodCalled('importData', [browserProfileIndex, types]);
  }
}

suite('ImportDataDialog', function() {
  const browserProfiles: BrowserProfile[] = [
    {
      autofillFormData: true,
      favorites: true,
      history: true,
      index: 0,
      name: 'Mozilla Firefox',
      passwords: true,
      profileName: '',
      search: true,
    },
    {
      autofillFormData: true,
      favorites: true,
      history: false,  // Emulate unsupported import option
      index: 1,
      name: 'Mozilla Firefox',
      passwords: true,
      profileName: 'My profile',
      search: true,
    },
    {
      autofillFormData: false,
      favorites: true,
      history: false,
      index: 2,
      name: 'Bookmarks HTML File',
      passwords: false,
      profileName: '',
      search: false,
    },
  ];

  function createBooleanPref(name: string): chrome.settingsPrivate.PrefObject {
    return {
      key: name,
      type: chrome.settingsPrivate.PrefType.BOOLEAN,
      value: true,
    };
  }

  const prefs: {[key: string]: chrome.settingsPrivate.PrefObject} = {};
  ['import_dialog_history',
   'import_dialog_bookmarks',
   'import_dialog_saved_passwords',
   'import_dialog_search_engine',
   'import_dialog_autofill_form_data',
  ].forEach(function(name) {
    prefs[name] = createBooleanPref(name);
  });

  let dialog: SettingsImportDataDialogElement;
  let browserProxy: TestImportDataBrowserProxy;

  setup(async function() {
    browserProxy = new TestImportDataBrowserProxy();
    browserProxy.setBrowserProfiles(browserProfiles);
    ImportDataBrowserProxyImpl.setInstance(browserProxy);
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    dialog = document.createElement('settings-import-data-dialog');
    dialog.set('prefs', prefs);
    document.body.appendChild(dialog);
    await browserProxy.whenCalled('initializeImportDialog');
    assertTrue(dialog.$.dialog.open);
    flush();
  });

  async function ensureSettingsCheckboxCheckedStatus(
      prefName: string, checked: boolean) {
    const id = dashToCamelCase(prefName.replace(/_/g, '-'));
    const settingsCheckbox =
        dialog.shadowRoot!.querySelector<SettingsCheckboxElement>(`#${id}`)!;

    if (settingsCheckbox.checked !== checked) {
      // Use click operation to produce a 'change' event.
      settingsCheckbox.$.checkbox.click();
      await settingsCheckbox.$.checkbox.updateComplete;
    }
  }

  function simulateBrowserProfileChange(index: number) {
    dialog.$.browserSelect.selectedIndex = index;
    dialog.$.browserSelect.dispatchEvent(new CustomEvent('change'));
  }

  test('Initialization', function() {
    assertFalse(dialog.$.import.hidden);
    assertFalse(dialog.$.import.disabled);
    assertFalse(dialog.$.cancel.hidden);
    assertFalse(dialog.$.cancel.disabled);
    assertTrue(dialog.$.done.hidden);
    assertTrue(dialog.$.successIcon.parentElement!.hidden);

    // Check that the displayed text correctly combines browser name and profile
    // name (if any).
    const expectedText = [
      'Mozilla Firefox',
      'Mozilla Firefox - My profile',
      'Bookmarks HTML File',
    ];

    Array.from(dialog.$.browserSelect.options).forEach((option, i) => {
      assertEquals(expectedText[i], option.textContent!.trim());
    });
  });

  test('ImportButton', async function() {
    assertFalse(dialog.$.import.disabled);

    // Flip all prefs to false.
    for (const key of Object.keys(prefs)) {
      await ensureSettingsCheckboxCheckedStatus(key, false);
    }
    assertTrue(dialog.$.import.disabled);

    // Change browser selection to "Import from Bookmarks HTML file".
    simulateBrowserProfileChange(2);
    assertTrue(dialog.$.import.disabled);

    // Ensure everything except |import_dialog_bookmarks| is ignored.
    await ensureSettingsCheckboxCheckedStatus('import_dialog_history', true);
    assertTrue(dialog.$.import.disabled);

    await ensureSettingsCheckboxCheckedStatus('import_dialog_bookmarks', true);
    assertFalse(dialog.$.import.disabled);
  });

  function assertInProgressButtons() {
    assertFalse(dialog.$.import.hidden);
    assertTrue(dialog.$.import.disabled);
    assertFalse(dialog.$.cancel.hidden);
    assertTrue(dialog.$.cancel.disabled);
    assertTrue(dialog.$.done.hidden);
    const spinner = dialog.shadowRoot!.querySelector('paper-spinner-lite')!;
    assertTrue(spinner.active);
    assertFalse(spinner.hidden);
  }

  function assertSucceededButtons() {
    assertTrue(dialog.$.import.hidden);
    assertTrue(dialog.$.cancel.hidden);
    assertFalse(dialog.$.done.hidden);
    const spinner = dialog.shadowRoot!.querySelector('paper-spinner-lite')!;
    assertFalse(spinner.active);
    assertTrue(spinner.hidden);
  }

  function simulateImportStatusChange(status: ImportDataStatus) {
    webUIListenerCallback('import-data-status-changed', status);
  }

  test('ImportFromBookmarksFile', async function() {
    simulateBrowserProfileChange(2);
    dialog.$.import.click();
    await browserProxy.whenCalled('importFromBookmarksFile');
    simulateImportStatusChange(ImportDataStatus.IN_PROGRESS);
    assertInProgressButtons();

    simulateImportStatusChange(ImportDataStatus.SUCCEEDED);
    assertSucceededButtons();

    assertFalse(dialog.$.successIcon.parentElement!.hidden);
    assertFalse(
        dialog.shadowRoot!.querySelector(
                              'settings-toggle-button')!.parentElement!.hidden);
  });

  test('ImportFromBrowserProfile', async function() {
    await ensureSettingsCheckboxCheckedStatus('import_dialog_bookmarks', false);
    await ensureSettingsCheckboxCheckedStatus(
        'import_dialog_search_engine', true);

    const expectedIndex = 0;
    simulateBrowserProfileChange(expectedIndex);
    dialog.$.import.click();

    const [actualIndex, types] = await browserProxy.whenCalled('importData');

    assertEquals(expectedIndex, actualIndex);
    assertFalse(types['import_dialog_bookmarks']);
    assertTrue(types['import_dialog_search_engine']);

    simulateImportStatusChange(ImportDataStatus.IN_PROGRESS);
    assertInProgressButtons();

    simulateImportStatusChange(ImportDataStatus.SUCCEEDED);
    assertSucceededButtons();

    assertFalse(dialog.$.successIcon.parentElement!.hidden);
    assertTrue(
        dialog.shadowRoot!.querySelector(
                              'settings-toggle-button')!.parentElement!.hidden);
  });

  test('ImportFromBrowserProfileWithUnsupportedOption', async function() {
    // Flip all prefs to true.
    for (const key of Object.keys(prefs)) {
      await ensureSettingsCheckboxCheckedStatus(key, true);
    }

    const expectedIndex = 1;
    simulateBrowserProfileChange(expectedIndex);
    dialog.$.import.click();

    const [actualIndex, types] = await browserProxy.whenCalled('importData');
    assertEquals(expectedIndex, actualIndex);

    Object.keys(prefs).forEach(function(prefName) {
      // import_dialog_history is unsupported and hidden
      assertEquals(prefName !== 'import_dialog_history', types[prefName]);
    });
  });

  test('ImportError', function() {
    simulateImportStatusChange(ImportDataStatus.FAILED);
    assertFalse(dialog.$.dialog.open);
  });
});