<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Basic tests for the Migration Wizard component</title>
    <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
    <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
    <script src="head-common.js"></script>
    <script
      src="chrome://browser/content/migration/migration-wizard.mjs"
      type="module"
    ></script>
    <link
      rel="stylesheet"
      href="chrome://mochikit/content/tests/SimpleTest/test.css"
    />
    <script>
      /* import-globals-from ../head-common.js */

      "use strict";

      const { BrowserTestUtils } = ChromeUtils.importESModule(
        "resource://testing-common/BrowserTestUtils.sys.mjs"
      );

      const MIGRATOR_PROFILE_INSTANCES = [
        {
          key: "some-browser-0",
          type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
          displayName: "Some Browser 0",
          resourceTypes: ["HISTORY", "FORMDATA", "PASSWORDS", "BOOKMARKS", "EXTENSIONS"],
          profile: { id: "person-2", name: "Person 2" },
        },
        {
          key: "some-browser-1",
          type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
          displayName: "Some Browser 1",
          resourceTypes: ["HISTORY", "BOOKMARKS"],
          profile: null,
        },
      ];

      let gWiz = null;
      let gShadowRoot = null;
      let gDeck = null;

      /**
       * Returns the .resource-progress-group div for a particular resource
       * type.
       *
       * @param {string} displayedResourceType
       *   One of the constants belonging to
       *   MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.
       * @returns {Element}
       */
      function getResourceGroup(displayedResourceType) {
        return gShadowRoot.querySelector(
          `.resource-progress-group[data-resource-type="${displayedResourceType}"]`
        );
      }

      add_setup(async function() {
        gWiz = document.getElementById("test-wizard");
        gShadowRoot = gWiz.openOrClosedShadowRoot;
        gDeck = gShadowRoot.querySelector("#wizard-deck");
      });

      /**
       * Tests that the MigrationWizard:RequestState event is fired when the
       * <migration-wizard> is added to the DOM if the auto-request-state attribute
       * is set, and then ensures that the starting page is correct.
       *
       * This also tests that the MigrationWizard:RequestState is not fired automatically
       * if the auto-request-state attribute is not set, but is then fired upon calling
       * requestState().
       *
       * This uses a dynamically created <migration-wizard> instead of the one already
       * in the content div to make sure that the init event is captured.
       */
      add_task(async function test_init_event() {
        const REQUEST_STATE_EVENT = "MigrationWizard:RequestState";

        let wiz = document.createElement("migration-wizard");
        wiz.toggleAttribute("auto-request-state", true);
        let content = document.getElementById("content");
        let promise = new Promise(resolve => {
          content.addEventListener(REQUEST_STATE_EVENT, resolve, {
            once: true,
          });
        });
        content.appendChild(wiz);
        await promise;
        ok(true, `Saw ${REQUEST_STATE_EVENT} event.`);
        let shadowRoot = wiz.openOrClosedShadowRoot;
        let deck = shadowRoot.querySelector("#wizard-deck");
        is(
          deck.selectedViewName,
          "page-loading",
          "Should have the loading page selected"
        );
        wiz.remove();

        wiz.toggleAttribute("auto-request-state", false);
        let sawEvent = false;
        let handler = () => {
          sawEvent = true;
        };
        content.addEventListener(REQUEST_STATE_EVENT, handler);
        content.appendChild(wiz);
        ok(!sawEvent, `Should not have seen ${REQUEST_STATE_EVENT} event.`);
        content.removeEventListener(REQUEST_STATE_EVENT, handler);

        promise = new Promise(resolve => {
          content.addEventListener(REQUEST_STATE_EVENT, resolve, {
            once: true,
          });
        });
        wiz.requestState();
        await promise;
        ok(true, `Saw ${REQUEST_STATE_EVENT} event.`);
        wiz.remove();
      });

      /**
       * Tests that the wizard can show a list of browser and profiles.
       */
      add_task(async function test_selection() {
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: MIGRATOR_PROFILE_INSTANCES,
          showImportAll: false,
        });

        let selector = gShadowRoot.querySelector("#browser-profile-selector");
        let preamble = gShadowRoot.querySelector(".resource-selection-preamble");
        ok(!isHidden(preamble), "preamble should shown.");

        let panelList = gShadowRoot.querySelector("panel-list");
        is(panelList.childElementCount, 2, "Should have two child elements");

        let resourceTypeList = gShadowRoot.querySelector("#resource-type-list");
        let details = gShadowRoot.querySelector("details");
        ok(details.open, "Details should be open");

        // Test that the resource type checkboxes are shown or hidden depending on
        // which resourceTypes are included with the MigratorProfileInstance.
        for (let migratorInstance of MIGRATOR_PROFILE_INSTANCES) {
          selector.click();
          await new Promise(resolve => {
            gShadowRoot
              .querySelector("panel-list")
              .addEventListener("shown", resolve, { once: true });
          });
          let panelItem = gShadowRoot.querySelector(
            `panel-item[key="${migratorInstance.key}"]`
          );
          ok(panelItem, "Should find panel-item.");
          panelItem.click();

          is(
            selector.querySelector("#migrator-name").textContent,
            migratorInstance.displayName,
            "Selector should show display name"
          );
          let profileName = selector.querySelector("#profile-name");

          if (migratorInstance.profile) {
            ok(!isHidden(profileName), "Profile name element should be displayed.");
            is(
              profileName.textContent,
              migratorInstance.profile.name,
              "Selector should show profile name"
            );
          } else {
            ok(isHidden(profileName), "Profile name element should be hidden.");
            is(profileName.textContent, "");
          }

          for (let resourceType of getChoosableResourceTypes()) {
            let node = resourceTypeList.querySelector(
              `label[data-resource-type="${resourceType}"]`
            );

            if (migratorInstance.resourceTypes.includes(resourceType)) {
              ok(!isHidden(node), `Selection for ${resourceType} should be shown.`);
              ok(
                node.control.checked,
                `Checkbox for ${resourceType} should be checked.`
              );
            } else {
              ok(isHidden(node), `Selection for ${resourceType} should be hidden.`);
              ok(
                !node.control.checked,
                `Checkbox for ${resourceType} should be unchecked.`
              );
            }
          }
        }

        let selectAll = gShadowRoot.querySelector("#select-all");
        let summary = gShadowRoot.querySelector("summary");
        ok(isHidden(selectAll), "Selection for select-all should be hidden.");
        ok(isHidden(summary), "Summary should be hidden.");
        ok(!isHidden(details), "Details should be shown.");
      });

      /**
       * Tests the migration wizard with no resources
       */
      add_task(async function test_no_resources() {
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: [{
            key: "some-browser-0",
            type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
            displayName: "Some Browser 0 with no resources",
            resourceTypes: [],
            profile: { id: "person-1", name: "Person 1" },
          }],
          showImportAll: false,
        });

        let noResourcesFound = gShadowRoot.querySelector(".no-resources-found");
        let hideOnErrorEls = gShadowRoot.querySelectorAll(".hide-on-error");
        ok(
          !isHidden(noResourcesFound),
          "Error message of no reasources should be shown."
        );
        for (let hideOnErrorEl of hideOnErrorEls) {
          ok(isHidden(hideOnErrorEl), "Item should be hidden.");
        }
      });

      /**
       * Tests variant 2 of the migration wizard
       */
      add_task(async function test_selection_variant_2() {
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: MIGRATOR_PROFILE_INSTANCES,
          showImportAll: true,
        });

        let preamble = gShadowRoot.querySelector(".resource-selection-preamble");
        ok(isHidden(preamble), "preamble should be hidden.");

        let selector = gShadowRoot.querySelector("#browser-profile-selector");
        selector.click();
        await new Promise(resolve => {
          let panelList = gShadowRoot.querySelector("panel-list");
          if (panelList) {
            panelList.addEventListener("shown", resolve, { once: true });
          }
        });

        let panelItems = gShadowRoot.querySelectorAll("panel-list > panel-item");
        is(panelItems.length, 2, "Should have two panel items");

        let details = gShadowRoot.querySelector("details");
        ok(!details.open, "Details should be closed");
        details.open = true;

        for (let i = 0; i < panelItems.length; i++) {
          let migratorInstance = MIGRATOR_PROFILE_INSTANCES[i];
          let panelItem = panelItems[i];
          panelItem.click();
          for (let resourceType of getChoosableResourceTypes()) {
            let node = gShadowRoot.querySelector(
              `#resource-type-list label[data-resource-type="${resourceType}"]`
            );
            if (migratorInstance.resourceTypes.includes(resourceType)) {
              ok(!isHidden(node), `Selection for ${resourceType} should be shown.`);
              ok(
                node.control.checked,
                `Checkbox for ${resourceType} should be checked.`
              );
            } else {
              ok(isHidden(node), `Selection for ${resourceType} should be hidden.`);
              ok(
                !node.control.checked,
                `Checkbox for ${resourceType} should be unchecked.`
              );
            }
          }
        }

        let selectAll = gShadowRoot.querySelector("#select-all");
        let summary = gShadowRoot.querySelector("summary");
        ok(!isHidden(selectAll), "Selection for select-all should be shown.");
        ok(selectAll.control.checked, "Checkbox for select-all should be checked.");
        ok(!isHidden(summary), "Summary should be shown.");
        ok(!isHidden(details), "Details should be shown.");

        let selectAllCheckbox = gShadowRoot.querySelector(".select-all-checkbox");
        selectAllCheckbox.checked = true;
        selectAllCheckbox.dispatchEvent(new CustomEvent("change"));
        let resourceLabels = gShadowRoot.querySelectorAll("label[data-resource-type]");
        for (let resourceLabel of resourceLabels) {
          if (resourceLabel.hidden) {
            ok(
              !resourceLabel.control.checked,
              `Hidden checkbox for ${resourceLabel.dataset.resourceType} should be unchecked.`

            );
          } else {
            ok(
              resourceLabel.control.checked,
              `Visible checkbox for ${resourceLabel.dataset.resourceType} should be checked.`
            );
          }
        }

        let selectedDataHeader = gShadowRoot.querySelector(".selected-data-header");
        let selectedData = gShadowRoot.querySelector(".selected-data");

        let bookmarks = gShadowRoot.querySelector("#bookmarks");
        let history = gShadowRoot.querySelector("#history");

        let selectedDataUpdated = BrowserTestUtils.waitForEvent(
          gWiz,
          "MigrationWizard:ResourcesUpdated"
        );
        bookmarks.control.checked = true;
        history.control.checked = true;
        bookmarks.dispatchEvent(new CustomEvent("change"));

        ok(bookmarks.control.checked, "Bookmarks should be checked");
        ok(history.control.checked, "History should be checked");

        await selectedDataUpdated;

        is(
          selectedData.textContent,
          "Bookmarks and history",
          "Testing if selected-data reflects the selected resources."
        );

        is(
          selectedDataHeader.dataset.l10nId,
          "migration-all-available-data-label",
          "Testing if selected-data-header reflects the selected resources"
        );

        let importButton = gShadowRoot.querySelector("#import");

        ok(
          !importButton.disabled,
          "Testing if import button is enabled when at least one resource is selected."
        );

        let importButtonUpdated = BrowserTestUtils.waitForEvent(
          gWiz,
          "MigrationWizard:ResourcesUpdated"
        );

        selectAllCheckbox.checked = false;
        selectAllCheckbox.dispatchEvent(new CustomEvent("change", { bubbles: true }));
        await importButtonUpdated;

        ok(
          importButton.disabled,
          "Testing if import button is disabled when no resources are selected."
        );
      });

      /**
       * Tests variant 2 of the migration wizard when there's a single resource
       * item.
       */
      add_task(async function test_selection_variant_2_single_item() {
        let resourcesUpdated = BrowserTestUtils.waitForEvent(
          gWiz,
          "MigrationWizard:ResourcesUpdated"
        );
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: [{
            key: "some-browser-0",
            type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
            displayName: "Some Browser 0 with a single resource",
            resourceTypes: ["HISTORY"],
            profile: { id: "person-1", name: "Person 1" },
          }, {
            key: "some-browser-1",
            type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
            displayName: "Some Browser 1 with a two resources",
            resourceTypes: ["HISTORY", "BOOKMARKS"],
            profile: { id: "person-2", name: "Person 2" },
          }],
          showImportAll: true,
        });
        await resourcesUpdated;

        let selectAll = gShadowRoot.querySelector("#select-all");
        let summary = gShadowRoot.querySelector("summary");
        let details = gShadowRoot.querySelector("details");
        ok(!details.open, "Details should be closed");
        details.open = true;

        ok(isHidden(selectAll), "Selection for select-all should be hidden.");
        ok(!isHidden(summary), "Summary should be shown.");
        ok(!isHidden(details), "Details should be shown.");

        resourcesUpdated = BrowserTestUtils.waitForEvent(
          gWiz,
          "MigrationWizard:ResourcesUpdated"
        );
        let browser1Item = gShadowRoot.querySelector("panel-item[key='some-browser-1']");
        browser1Item.click();
        await resourcesUpdated;

        ok(!isHidden(selectAll), "Selection for select-all should be shown.");
        ok(!isHidden(summary), "Summary should be shown.");
        ok(!isHidden(details), "Details should be shown.");
      });

      /**
       * Tests that the Select All checkbox is checked if all non-hidden resource
       * types are checked, and unchecked otherwise.
       */
      add_task(async function test_selection_variant_2_select_all() {
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: MIGRATOR_PROFILE_INSTANCES,
          showImportAll: true,
        });

        let details = gShadowRoot.querySelector("details");
        ok(!details.open, "Details should be closed");
        details.open = true;

        let selectAll = gShadowRoot.querySelector("#select-all");
        ok(selectAll.control.checked, "Select all should be checked by default");

        let bookmarksResourceLabel = gShadowRoot.querySelector(
          "label[data-resource-type='BOOKMARKS']"
        );
        ok(bookmarksResourceLabel.control.checked, "Bookmarks should be checked");

        bookmarksResourceLabel.control.click();
        ok(!bookmarksResourceLabel.control.checked, "Bookmarks should no longer be checked");
        ok(!selectAll.control.checked, "Select all should not longer be checked");

        bookmarksResourceLabel.control.click();
        ok(bookmarksResourceLabel.control.checked, "Bookmarks should be checked again");
        ok(selectAll.control.checked, "Select all should be checked");
      });

      /**
       * Tests that the wizard can show partial progress during migration.
       */
      add_task(async function test_partial_progress() {
        const BOOKMARKS_SUCCESS_STRING = "Some bookmarks success string";
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: BOOKMARKS_SUCCESS_STRING,
            },
            // Don't include PASSWORDS to check that it's hidden.
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.HISTORY]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.LOADING,
            },
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.EXTENSIONS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.LOADING,
            },
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.FORMDATA]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.LOADING,
            },
          },
        });
        is(
          gDeck.selectedViewName,
          "page-progress",
          "Should have the progress page selected"
        );

        // Bookmarks
        let bookmarksGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS
        );
        ok(!isHidden(bookmarksGroup), "Bookmarks group should be visible");
        let progressIcon = bookmarksGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          bookmarksGroup.querySelector(".message-text").textContent,
          BOOKMARKS_SUCCESS_STRING
        );

        // Passwords
        let passwordsGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.PASSWORDS
        );
        ok(isHidden(passwordsGroup), "Passwords group should be hidden");

        // History
        let historyGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.HISTORY
        );
        ok(!isHidden(historyGroup), "History group should be visible");
        progressIcon = historyGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "loading",
          "Progress should be still be underway"
        );
        is(historyGroup.querySelector(".message-text").textContent.trim(), "");

        // Extensions
        let extensionsGroup = getResourceGroup(MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.EXTENSIONS);
        ok(!isHidden(extensionsGroup), "Extensions group should be visible");
        progressIcon = extensionsGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "loading",
          "Progress should be still be underway"
        );
        is(extensionsGroup.querySelector("a.message-text").textContent.trim(), "");
        is(extensionsGroup.querySelector("span.message-text").textContent.trim(), "");

        // Form Data
        let formDataGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.FORMDATA
        );
        ok(!isHidden(formDataGroup), "Form data group should be visible");
        progressIcon = formDataGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "loading",
          "Progress should be still be underway"
        );
        is(formDataGroup.querySelector(".message-text").textContent.trim(), "");

        // With progress still being underway, the header should be using the
        // in progress string.
        let header = gShadowRoot.querySelector("#progress-header");
        is(
          header.getAttribute("data-l10n-id"),
          "migration-wizard-progress-header",
          "Should be showing in-progress header string"
        );

        let progressPage = gShadowRoot.querySelector("div[name='page-progress']");
        let doneButton = progressPage.querySelector(".done-button");
        ok(isHidden(doneButton), "Done button should be hidden");
        let cancelButton = progressPage.querySelector(".cancel-close");
        ok(!isHidden(cancelButton), "Cancel button should be visible");
        ok(cancelButton.disabled, "Cancel button should be disabled");
      });

      /**
       * Tests that the wizard can show completed migration progress.
       */
      add_task(async function test_completed_progress() {
        const BOOKMARKS_SUCCESS_STRING = "Some bookmarks success string";
        const PASSWORDS_SUCCESS_STRING = "Some passwords success string";
        const FORMDATA_SUCCESS_STRING = "Some formdata string";
        const EXTENSIONS_SUCCESS_STRING = "Some extensions string";
        const EXTENSIONS_SUCCESS_HREF = "about:addons";
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: BOOKMARKS_SUCCESS_STRING,
            },
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.PASSWORDS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: PASSWORDS_SUCCESS_STRING,
            },
            // Don't include HISTORY to check that it's hidden.
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.EXTENSIONS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: EXTENSIONS_SUCCESS_STRING,
            },
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.FORMDATA]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: FORMDATA_SUCCESS_STRING,
            },
          },
        });
        is(
          gDeck.selectedViewName,
          "page-progress",
          "Should have the progress page selected"
        );

        // Bookmarks
        let bookmarksGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS
        );
        ok(!isHidden(bookmarksGroup), "Bookmarks group should be visible");
        let progressIcon = bookmarksGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          bookmarksGroup.querySelector(".message-text").textContent,
          BOOKMARKS_SUCCESS_STRING
        );

        // Passwords
        let passwordsGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.PASSWORDS
        );
        ok(!isHidden(passwordsGroup), "Passwords group should be visible");
        progressIcon = passwordsGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          passwordsGroup.querySelector(".message-text").textContent,
          PASSWORDS_SUCCESS_STRING
        );

        // History
        let historyGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.HISTORY
        );
        ok(isHidden(historyGroup), "History group should be hidden");

        // Extensions
        let extensionsDataGroup = getResourceGroup(MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.EXTENSIONS);
        ok(!isHidden(extensionsDataGroup), "Extensions data group should be visible");
        progressIcon = extensionsDataGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          extensionsDataGroup.querySelector("a.message-text").textContent,
          EXTENSIONS_SUCCESS_STRING
        );
        is(
          extensionsDataGroup.querySelector("a.message-text").href,
          EXTENSIONS_SUCCESS_HREF
        )
        // Form Data
        let formDataGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.FORMDATA
        );
        ok(!isHidden(formDataGroup), "Form data group should be visible");
        progressIcon = formDataGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          formDataGroup.querySelector(".message-text").textContent,
          FORMDATA_SUCCESS_STRING
        );

        // With progress being complete, the header should be using the completed
        // migration string.
        let header = gShadowRoot.querySelector("#progress-header");
        is(
          header.getAttribute("data-l10n-id"),
          "migration-wizard-progress-done-header",
          "Should be showing completed migration header string"
        );

        let progressPage = gShadowRoot.querySelector("div[name='page-progress']");
        let doneButton = progressPage.querySelector(".done-button");
        ok(!isHidden(doneButton), "Done button should be visible and enabled");
        let cancelButton = progressPage.querySelector(".cancel-close");
        ok(isHidden(cancelButton), "Cancel button should be hidden");
      });

      add_task(async function test_extension_partial_success() {
        const EXTENSIONS_INFO_STRING = "Extensions info string";
        const EXTENSIONS_INFO_HREF = "about:addons";
        const EXTENSIONS_SUPPORT_STRING = "extensions support string";
        const EXTENSIONS_SUPPORT_HREF = "about:blank";

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.EXTENSIONS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.INFO,
              message: EXTENSIONS_INFO_STRING,
              linkText: EXTENSIONS_SUPPORT_STRING,
              linkURL: EXTENSIONS_SUPPORT_HREF,
            }
          }
        });
        is(
          gDeck.selectedViewName,
          "page-progress",
          "Should have the progress page selected"
        );

        let extensionsGroup = getResourceGroup(MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.EXTENSIONS);
        ok(!isHidden(extensionsGroup), "Extensions group should be visible");
        let progressIcon = extensionsGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "info",
          "Progress should be completed, in info state"
        );
        is(
          extensionsGroup.querySelector("a.message-text").textContent,
          EXTENSIONS_INFO_STRING
        );
        is(
          extensionsGroup.querySelector("a.message-text").href,
          EXTENSIONS_INFO_HREF
        );
        is(
          extensionsGroup.querySelector(".support-text").textContent,
          EXTENSIONS_SUPPORT_STRING
        );
        is(
          extensionsGroup.querySelector(".support-text").href,
          EXTENSIONS_SUPPORT_HREF
        );

        // With progress being complete, the header should be using the completed
        // migration string.
        let header = gShadowRoot.querySelector("#progress-header");
        is(
          header.getAttribute("data-l10n-id"),
          "migration-wizard-progress-done-header",
          "Should be showing completed migration header string"
        );

        let progressPage = gShadowRoot.querySelector("div[name='page-progress']");
        let doneButton = progressPage.querySelector(".done-button");
        ok(!isHidden(doneButton), "Done button should be visible and enabled");
        let cancelButton = progressPage.querySelector(".cancel-close");
        ok(isHidden(cancelButton), "Cancel button should be hidden");
      });

      add_task(async function test_extension_error() {
        const EXTENSIONS_ERROR_STRING = "Extensions error string";
        const EXTENSIONS_SUPPORT_STRING = "extensions support string";
        const EXTENSIONS_SUPPORT_HREF = "about:blank";

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.EXTENSIONS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.WARNING,
              message: EXTENSIONS_ERROR_STRING,
              linkText: EXTENSIONS_SUPPORT_STRING,
              linkURL: EXTENSIONS_SUPPORT_HREF,
            }
          }
        });
        is(
          gDeck.selectedViewName,
          "page-progress",
          "Should have the progress page selected"
        );

        let extensionsGroup = getResourceGroup(MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.EXTENSIONS);
        ok(!isHidden(extensionsGroup), "Extensions group should be visible");
        let progressIcon = extensionsGroup.querySelector(".progress-icon");
        is(progressIcon.getAttribute("state"), "warning");
        is(
          extensionsGroup.querySelector("a.message-text").textContent,
          ""
        );
        is(
          extensionsGroup.querySelector("span.message-text").textContent,
          EXTENSIONS_ERROR_STRING
        );
        is(
          extensionsGroup.querySelector(".support-text").textContent,
          EXTENSIONS_SUPPORT_STRING
        );
        is(
          extensionsGroup.querySelector(".support-text").href,
          EXTENSIONS_SUPPORT_HREF
        );

        // With progress being complete, the header should be using the completed
        // migration string.
        let header = gShadowRoot.querySelector("#progress-header");
        is(
          header.getAttribute("data-l10n-id"),
          "migration-wizard-progress-done-with-warnings-header",
          "Should be showing completed migration header string"
        );

        let progressPage = gShadowRoot.querySelector("div[name='page-progress']");
        let doneButton = progressPage.querySelector(".done-button");
        ok(!isHidden(doneButton), "Done button should be visible and enabled");
        let cancelButton = progressPage.querySelector(".cancel-close");
        ok(isHidden(cancelButton), "Cancel button should be hidden");
      });

      /**
       * Tests that the wizard can show partial progress during file migration.
       */
      add_task(async function test_partial_file_progress() {
        const PASSWORDS_SUCCESS_STRING = "Some passwords success string";
        const TITLE = "Partial progress";

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.FILE_IMPORT_PROGRESS,
          title: "Partial progress",
          progress: {
            [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_FROM_FILE]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: PASSWORDS_SUCCESS_STRING,
            },
            [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_NEW]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.LOADING,
            },
          },
        });

        is(
          gDeck.selectedViewName,
          "page-file-import-progress",
          "Should have the file progress page selected"
        );

        let header = gShadowRoot.querySelector("#file-import-progress-header");
        is(header.textContent, TITLE, "Title is set correctly.");

        let passwordsFromFileGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_FROM_FILE
        );
        ok(!isHidden(passwordsFromFileGroup), "Passwords from file group should be visible");
        let progressIcon = passwordsFromFileGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          passwordsFromFileGroup.querySelector(".message-text").textContent,
          PASSWORDS_SUCCESS_STRING
        );

        let passwordsUpdatedGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_UPDATED
        );
        ok(isHidden(passwordsUpdatedGroup), "Passwords updated group should be hidden");

        let passwordsNewGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_NEW
        );
        ok(!isHidden(passwordsNewGroup), "Passwords new group should be visible");
        progressIcon = passwordsNewGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "loading",
          "Progress should be still be underway"
        );
        is(passwordsNewGroup.querySelector(".message-text").textContent.trim(), "");

        let progressPage = gShadowRoot.querySelector("div[name='page-file-import-progress']");
        let doneButton = progressPage.querySelector(".done-button");
        ok(isHidden(doneButton), "Done button should be hidden");
        let cancelButton = progressPage.querySelector(".cancel-close");
        ok(!isHidden(cancelButton), "Cancel button should be visible");
        ok(cancelButton.disabled, "Cancel button should be disabled");
      });

      /**
       * Tests that the wizard can show completed migration progress.
       */
      add_task(async function test_completed_file_progress() {
        const PASSWORDS_NEW_SUCCESS_STRING = "2 added";
        const PASSWORDS_UPDATED_SUCCESS_STRING = "5 updated";
        const TITLE = "Done doing file import";

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.FILE_IMPORT_PROGRESS,
          title: TITLE,
          progress: {
            [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_NEW]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: PASSWORDS_NEW_SUCCESS_STRING,
            },
            [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_UPDATED]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: PASSWORDS_UPDATED_SUCCESS_STRING,
            },
          },
        });
        is(
          gDeck.selectedViewName,
          "page-file-import-progress",
          "Should have the file progress page selected"
        );

        let header = gShadowRoot.querySelector("#file-import-progress-header");
        is(header.textContent, TITLE, "Title is set correctly.");

        let passwordsNewGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_NEW
        );
        ok(!isHidden(passwordsNewGroup), "Passwords new group should be visible");
        let progressIcon = passwordsNewGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          passwordsNewGroup.querySelector(".message-text").textContent,
          PASSWORDS_NEW_SUCCESS_STRING
        );

        let passwordsUpdatedGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_UPDATED
        );
        ok(!isHidden(passwordsUpdatedGroup), "Passwords updated group should be visible");
        progressIcon = passwordsUpdatedGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          passwordsUpdatedGroup.querySelector(".message-text").textContent,
          PASSWORDS_UPDATED_SUCCESS_STRING
        );

        let passwordsFromFileGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_FROM_FILE
        );
        ok(isHidden(passwordsFromFileGroup), "Passwords from file group should be hidden");

        let progressPage = gShadowRoot.querySelector("div[name='page-file-import-progress']");
        let doneButton = progressPage.querySelector(".done-button");
        ok(!isHidden(doneButton), "Done button should be visible and enabled");
        let cancelButton = progressPage.querySelector(".cancel-close");
        ok(isHidden(cancelButton), "Cancel button should be hidden");
      });

      /**
       * Tests that the buttons that dismiss the wizard when embedded in
       * a dialog are only visible when in dialog mode, and dispatch a
       * MigrationWizard:Close event when clicked.
       */
      add_task(async function test_dialog_mode_close() {
        gWiz.toggleAttribute("dialog-mode", true);
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: MIGRATOR_PROFILE_INSTANCES,
        });

        // For now, there's only a single .cancel-close button, so let's just test
        // that one. Let's make this test fail if there are multiple so that we can
        // then update this test to switch to the right pages to test those buttons
        // too.
        let buttons = gShadowRoot.querySelectorAll(".cancel-close:not([disabled])");
        ok(
          buttons.length,
          "This test expects at least one enabled .cancel-close button"
        );
        let button = buttons[0];
        ok(
          !isHidden(button),
          ".cancel-close button should be visible in dialog mode."
        );
        let closeEvent = BrowserTestUtils.waitForEvent(gWiz, "MigrationWizard:Close");
        synthesizeMouseAtCenter(button, {});
        await closeEvent;

        gWiz.toggleAttribute("dialog-mode", false);
        ok(
          isHidden(button),
          ".cancel-close button should be hidden when not in dialog mode."
        );
      });

      /**
       * Internet Explorer and Edge refer to bookmarks as "favorites",
       * and we change our labels to suit when either of those browsers are
       * selected as the migration source. This test tests that behavior in the
       * selection page.
       */
      add_task(async function test_ie_edge_favorites_selection() {
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: MIGRATOR_PROFILE_INSTANCES,
          showImportAll: false,
        });

        let bookmarksCheckboxLabel = gShadowRoot.querySelector("#bookmarks");
        let span = bookmarksCheckboxLabel.querySelector("span[default-data-l10n-id]");
        ok(span, "The bookmarks selection span has a default-data-l10n-id attribute");
        is(
          span.getAttribute("data-l10n-id"),
          span.getAttribute("default-data-l10n-id"),
          "Should be showing the default string for bookmarks"
        );

        // Now test when in Variant 2, for the string in the <summary>.
        let selectedDataUpdated = BrowserTestUtils.waitForEvent(
          gWiz,
          "MigrationWizard:ResourcesUpdated"
        );

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: MIGRATOR_PROFILE_INSTANCES,
          showImportAll: true,
        });

        await selectedDataUpdated;

        let summary = gShadowRoot.querySelector("summary");
        ok(
          summary.textContent.toLowerCase().includes("bookmarks"),
          "Summary should include the string 'bookmarks'"
        );

        for (let key of MigrationWizardConstants.USES_FAVORITES) {
          gWiz.setState({
            page: MigrationWizardConstants.PAGES.SELECTION,
            migrators: [{
              key,
              displayName: "Legacy Microsoft Browser",
              resourceTypes: ["BOOKMARKS"],
              profile: null,
            }],
            showImportAll: false,
          });

          is(
            span.getAttribute("data-l10n-id"),
            span.getAttribute("ie-edge-data-l10n-id"),
            "Should be showing the IE/Edge string for bookmarks"
          );

          // Now test when in Variant 2, for the string in the <summary>.
          selectedDataUpdated = BrowserTestUtils.waitForEvent(
            gWiz,
            "MigrationWizard:ResourcesUpdated"
          );

          gWiz.setState({
            page: MigrationWizardConstants.PAGES.SELECTION,
            migrators: [{
              key,
              displayName: "Legacy Microsoft Browser",
              resourceTypes: ["BOOKMARKS"],
              profile: null,
            }],
            showImportAll: true,
          });

          await selectedDataUpdated;

          ok(
            summary.textContent.toLowerCase().includes("favorites"),
            "Summary should include the string 'favorites'"
          );
        }
      });

      /**
       * Internet Explorer and Edge refer to bookmarks as "favorites",
       * and we change our labels to suit when either of those browsers are
       * selected as the migration source. This test tests that behavior in the
       * progress page
       */
      add_task(async function test_ie_edge_favorites_progress() {
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS]: {
              inProgress: false,
              message: "A string from the parent",
            },
          },
        });

        let bookmarksGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS
        );
        let span = bookmarksGroup.querySelector("span[default-data-l10n-id]");
        ok(span, "Should have found a span with default-data-l10n-id");
        is(
          span.getAttribute("data-l10n-id"),
          span.getAttribute("default-data-l10n-id"),
          "Should be using the default string."
        );


        for (let key of MigrationWizardConstants.USES_FAVORITES) {
          gWiz.setState({
            page: MigrationWizardConstants.PAGES.PROGRESS,
            key,
            progress: {
              [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS]: {
                inProgress: false,
                message: "A string from the parent",
              },
            },
          });

          is(
            span.getAttribute("data-l10n-id"),
            span.getAttribute("ie-edge-data-l10n-id"),
            "Should be showing the IE/Edge string for bookmarks"
          );
        }
      });

      /**
       * Tests that the button shown in either the browser migration success or
       * file migration success pages is a "continue" button rather than a
       * "done" button.
       */
      add_task(async function test_embedded_continue_button() {
        gWiz.toggleAttribute("dialog-mode", false);
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: "A string from the parent",
            },
          },
        });

        let progressPage = gShadowRoot.querySelector("div[name='page-progress']");
        let cancelButton = progressPage.querySelector(".cancel-close");
        ok(isHidden(cancelButton), "Cancel button should be hidden");
        let doneButton = progressPage.querySelector(".done-button");
        ok(isHidden(doneButton), "Done button should be hidden when embedding");
        let continueButton = progressPage.querySelector(".continue-button");
        ok(!isHidden(continueButton), "Continue button should be displayed");

        let content = document.getElementById("content");

        let promise = new Promise(resolve => {
          content.addEventListener("MigrationWizard:Close", resolve, {
            once: true,
          });
        });
        continueButton.click();
        await promise;
        ok(
          true,
          "Clicking on the Continue button sent the MigrationWizard:Close event."
        );

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.FILE_IMPORT_PROGRESS,
          title: "Done importing file data",
          progress: {
            [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_NEW]: {
              inProgress: false,
              message: "Some message",
            },
            [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_UPDATED]: {
              inProgress: false,
              message: "Some other",
            },
          },
        });

        progressPage = gShadowRoot.querySelector("div[name='page-file-import-progress']");
        cancelButton = progressPage.querySelector(".cancel-close");
        ok(isHidden(cancelButton), "Cancel button should be hidden");
        doneButton = progressPage.querySelector(".done-button");
        ok(isHidden(doneButton), "Done button should be hidden when embedding");
        continueButton = progressPage.querySelector(".continue-button");
        ok(!isHidden(continueButton), "Continue button should be displayed");

        promise = new Promise(resolve => {
          content.addEventListener("MigrationWizard:Close", resolve, {
            once: true,
          });
        });
        continueButton.click();
        await promise;
        ok(
          true,
          "Clicking on the Continue button sent the MigrationWizard:Close event."
        );

        gWiz.toggleAttribute("dialog-mode", true);
      });

      /**
       * Tests that if a progress update comes down which puts a resource from
       * being done to loading, that the status message is cleared.
       */
      add_task(async function test_clear_status_message_when_in_progress() {
        const STRING_TO_CLEAR = "This string should get cleared";
        gWiz.toggleAttribute("dialog-mode", false);
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: STRING_TO_CLEAR,
            },
          },
        });

        let bookmarksGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS
        );
        ok(!isHidden(bookmarksGroup), "Bookmarks group should be visible");
        let progressIcon = bookmarksGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          bookmarksGroup.querySelector(".message-text").textContent,
          STRING_TO_CLEAR
        );

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.LOADING,
              message: "",
            },
          },
        });

        ok(!isHidden(bookmarksGroup), "Bookmarks group should be visible");
        is(
          progressIcon.getAttribute("state"),
          "loading",
          "Progress should be still be underway"
        );
        is(
          bookmarksGroup.querySelector(".message-text").textContent.trim(),
          ""
        );
      });

      /**
       * Tests that if a file progress update comes down which puts a resource
       * from being done to loading, that the status message is cleared.
       *
       * This is extremely similar to the above test, except that it's for progress
       * updates for file resources.
       */
      add_task(async function test_clear_status_message_when_in_file_progress() {
        const STRING_TO_CLEAR = "This string should get cleared";
        gWiz.toggleAttribute("dialog-mode", false);
        gWiz.setState({
          page: MigrationWizardConstants.PAGES.FILE_IMPORT_PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_NEW]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.SUCCESS,
              message: STRING_TO_CLEAR,
            },
          },
        });

        let passwordsGroup = getResourceGroup(
          MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_NEW
        );
        ok(!isHidden(passwordsGroup), "Passwords group should be visible");
        let progressIcon = passwordsGroup.querySelector(".progress-icon");
        is(
          progressIcon.getAttribute("state"),
          "success",
          "Progress should be completed"
        );
        is(
          passwordsGroup.querySelector(".message-text").textContent,
          STRING_TO_CLEAR
        );

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.FILE_IMPORT_PROGRESS,
          key: "chrome",
          progress: {
            [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_NEW]: {
              value: MigrationWizardConstants.PROGRESS_VALUE.LOADING,
              message: "",
            },
          },
        });

        ok(!isHidden(passwordsGroup), "Passwords group should be visible");
        is(
          progressIcon.getAttribute("state"),
          "loading",
          "Progress should be still be underway"
        );
        is(
          passwordsGroup.querySelector(".message-text").textContent.trim(),
          ""
        );
      });

      /**
       * Tests that the migration wizard can be put into the selection page after
       * a file migrator error and show an error message.
       */
      add_task(async function test_file_migrator_error() {
        const FILE_MIGRATOR_KEY = "some-file-migrator";
        const FILE_IMPORT_ERROR_MESSAGE = "This is an error message";
        const MIGRATORS = [
          {
            key: "some-browser-0",
            type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
            displayName: "Some Browser 0",
            resourceTypes: ["HISTORY", "FORMDATA", "PASSWORDS", "BOOKMARKS"],
            profile: { id: "person-2", name: "Person 2" },
          },
          {
            key: "some-browser-1",
            type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
            displayName: "Some Browser 1",
            resourceTypes: ["HISTORY", "BOOKMARKS"],
            profile: null,
          },
          {
            key: FILE_MIGRATOR_KEY,
            type: MigrationWizardConstants.MIGRATOR_TYPES.FILE,
            displayName: "Some File Migrator",
            resourceTypes: [],
          },
        ];

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: MIGRATORS,
          showImportAll: true,
          migratorKey: "some-file-migrator",
          fileImportErrorMessage: FILE_IMPORT_ERROR_MESSAGE,
        });

        let errorMessageContainer = gShadowRoot.querySelector(".file-import-error");
        ok(!isHidden(errorMessageContainer), "Error message should be shown.");
        let errorText = gShadowRoot.querySelector("#file-import-error-message").textContent;
        is(errorText, FILE_IMPORT_ERROR_MESSAGE);

        gWiz.setState({
          page: MigrationWizardConstants.PAGES.SELECTION,
          migrators: MIGRATORS,
          showImportAll: true,
        });

        ok(isHidden(errorMessageContainer), "Error message should be hidden.");
        errorText = gShadowRoot.querySelector("#file-import-error-message").textContent;
        is(errorText, "");
      });
    </script>
  </head>
  <body>
    <p id="display"></p>
    <div id="content">
      <migration-wizard id="test-wizard" dialog-mode=""></migration-wizard>
    </div>
    <pre id="test"></pre>
  </body>
</html>
