summaryrefslogtreecommitdiffstats
path: root/browser/components/migration/tests/browser/browser_file_migration.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/migration/tests/browser/browser_file_migration.js')
-rw-r--r--browser/components/migration/tests/browser/browser_file_migration.js306
1 files changed, 306 insertions, 0 deletions
diff --git a/browser/components/migration/tests/browser/browser_file_migration.js b/browser/components/migration/tests/browser/browser_file_migration.js
new file mode 100644
index 0000000000..04241d29d5
--- /dev/null
+++ b/browser/components/migration/tests/browser/browser_file_migration.js
@@ -0,0 +1,306 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { FileMigratorBase } = ChromeUtils.importESModule(
+ "resource:///modules/FileMigrators.sys.mjs"
+);
+
+const DUMMY_FILEMIGRATOR_KEY = "dummy-file-migrator";
+const DUMMY_FILEPICKER_TITLE = "Some dummy file picker title";
+const DUMMY_FILTER_TITLE = "Some file type";
+const DUMMY_EXTENSION_PATTERN = "*.test";
+const TEST_FILE_PATH = getTestFilePath("dummy_file.csv");
+
+/**
+ * A subclass of FileMigratorBase that doesn't do anything, but
+ * is useful for testing.
+ *
+ * Notably, the `migrate` method is not overridden here. Tests that
+ * use this class should use Sinon to stub out the migrate method.
+ */
+class DummyFileMigrator extends FileMigratorBase {
+ static get key() {
+ return DUMMY_FILEMIGRATOR_KEY;
+ }
+
+ static get displayNameL10nID() {
+ return "migration-wizard-migrator-display-name-file-password-csv";
+ }
+
+ static get brandImage() {
+ return "chrome://branding/content/document.ico";
+ }
+
+ get enabled() {
+ return true;
+ }
+
+ get progressHeaderL10nID() {
+ return "migration-passwords-from-file-progress-header";
+ }
+
+ get successHeaderL10nID() {
+ return "migration-passwords-from-file-success-header";
+ }
+
+ async getFilePickerConfig() {
+ return Promise.resolve({
+ title: DUMMY_FILEPICKER_TITLE,
+ filters: [
+ {
+ title: DUMMY_FILTER_TITLE,
+ extensionPattern: DUMMY_EXTENSION_PATTERN,
+ },
+ ],
+ });
+ }
+
+ get displayedResourceTypes() {
+ return [MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.PASSWORDS];
+ }
+}
+
+const { MockFilePicker } = SpecialPowers;
+
+add_setup(async () => {
+ // We use MockFilePicker to simulate a native file picker, and prepare it
+ // to return a dummy file pointed at TEST_FILE_PATH. The file at
+ // TEST_FILE_PATH is not required (nor expected) to exist.
+ MockFilePicker.init(window);
+ registerCleanupFunction(() => {
+ MockFilePicker.cleanup();
+ });
+});
+
+/**
+ * Tests the flow of selecting a file migrator (in this case,
+ * the DummyFileMigrator), getting the file picker opened for it,
+ * and then passing the path of the selected file to the migrator.
+ */
+add_task(async function test_file_migration() {
+ let migrator = new DummyFileMigrator();
+ let sandbox = sinon.createSandbox();
+ registerCleanupFunction(() => {
+ sandbox.restore();
+ });
+
+ // First, use Sinon to insert our DummyFileMigrator as the only available
+ // file migrator.
+ sandbox.stub(MigrationUtils, "getFileMigrator").callsFake(() => {
+ return migrator;
+ });
+ sandbox.stub(MigrationUtils, "availableFileMigrators").get(() => {
+ return [migrator];
+ });
+
+ // This is the expected success state that our DummyFileMigrator will
+ // return as the final progress update to the migration wizard.
+ const SUCCESS_STATE = {
+ [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_NEW]:
+ "2 added",
+ [MigrationWizardConstants.DISPLAYED_FILE_RESOURCE_TYPES.PASSWORDS_UPDATED]:
+ "1 updated",
+ };
+
+ let migrateStub = sandbox.stub(migrator, "migrate").callsFake(filePath => {
+ Assert.equal(filePath, TEST_FILE_PATH);
+ return SUCCESS_STATE;
+ });
+
+ let dummyFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ dummyFile.initWithPath(TEST_FILE_PATH);
+ let filePickerShownPromise = new Promise(resolve => {
+ MockFilePicker.showCallback = () => {
+ Assert.ok(true, "Filepicker shown.");
+ MockFilePicker.setFiles([dummyFile]);
+ resolve();
+ };
+ });
+ MockFilePicker.returnValue = MockFilePicker.returnOK;
+
+ await withMigrationWizardDialog(async prefsWin => {
+ let dialogBody = prefsWin.document.body;
+ let wizard = dialogBody.querySelector("migration-wizard");
+ let shadow = wizard.openOrClosedShadowRoot;
+
+ let wizardDone = BrowserTestUtils.waitForEvent(
+ wizard,
+ "MigrationWizard:DoneMigration"
+ );
+
+ // Now select our DummyFileMigrator from the list.
+ let selector = shadow.querySelector("#browser-profile-selector");
+ selector.click();
+
+ info("Waiting for panel-list shown");
+ await new Promise(resolve => {
+ shadow
+ .querySelector("panel-list")
+ .addEventListener("shown", resolve, { once: true });
+ });
+
+ info("Panel list shown. Clicking on panel-item");
+ let panelItem = shadow.querySelector(
+ `panel-item[key="${DUMMY_FILEMIGRATOR_KEY}"]`
+ );
+ panelItem.click();
+
+ // Selecting a file migrator from the selector should automatically
+ // open the file picker, so we await it here. Once the file is
+ // selected, migration should begin immediately.
+
+ info("Waiting for file picker");
+ await filePickerShownPromise;
+ await wizardDone;
+ Assert.ok(migrateStub.called, "Migrate on DummyFileMigrator was called.");
+
+ // At this point, with migration having completed, we should be showing
+ // the PROGRESS page with the SUCCESS_STATE represented.
+ let deck = shadow.querySelector("#wizard-deck");
+ Assert.equal(
+ deck.selectedViewName,
+ `page-${MigrationWizardConstants.PAGES.FILE_IMPORT_PROGRESS}`
+ );
+
+ // We expect only the displayed resource types in SUCCESS_STATE are
+ // displayed now.
+ let progressGroups = shadow.querySelectorAll(
+ "div[name='page-file-import-progress'] .resource-progress-group"
+ );
+ for (let progressGroup of progressGroups) {
+ let expectedMessageText =
+ SUCCESS_STATE[progressGroup.dataset.resourceType];
+ if (expectedMessageText) {
+ let progressIcon = progressGroup.querySelector(".progress-icon");
+ Assert.stringMatches(
+ progressIcon.getAttribute("state"),
+ "success",
+ "Should be showing completed state."
+ );
+
+ let messageText =
+ progressGroup.querySelector(".message-text").textContent;
+ Assert.equal(messageText, expectedMessageText);
+ } else {
+ Assert.ok(
+ BrowserTestUtils.isHidden(progressGroup),
+ `Resource progress group for ${progressGroup.dataset.resourceType}` +
+ ` should be hidden.`
+ );
+ }
+ }
+ });
+
+ sandbox.restore();
+});
+
+/**
+ * Tests that the migration wizard will go back to the selection page and
+ * show an error message if the migration for a FileMigrator throws an
+ * exception.
+ */
+add_task(async function test_file_migration_error() {
+ let migrator = new DummyFileMigrator();
+ let sandbox = sinon.createSandbox();
+ registerCleanupFunction(() => {
+ sandbox.restore();
+ });
+
+ // First, use Sinon to insert our DummyFileMigrator as the only available
+ // file migrator.
+ sandbox.stub(MigrationUtils, "getFileMigrator").callsFake(() => {
+ return migrator;
+ });
+ sandbox.stub(MigrationUtils, "availableFileMigrators").get(() => {
+ return [migrator];
+ });
+
+ const ERROR_MESSAGE = "This is my error message";
+
+ let migrateStub = sandbox.stub(migrator, "migrate").callsFake(() => {
+ throw new Error(ERROR_MESSAGE);
+ });
+
+ let dummyFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ dummyFile.initWithPath(TEST_FILE_PATH);
+ let filePickerShownPromise = new Promise(resolve => {
+ MockFilePicker.showCallback = () => {
+ Assert.ok(true, "Filepicker shown.");
+ MockFilePicker.setFiles([dummyFile]);
+ resolve();
+ };
+ });
+ MockFilePicker.returnValue = MockFilePicker.returnOK;
+
+ await withMigrationWizardDialog(async prefsWin => {
+ let dialogBody = prefsWin.document.body;
+ let wizard = dialogBody.querySelector("migration-wizard");
+ let shadow = wizard.openOrClosedShadowRoot;
+
+ let wizardDone = BrowserTestUtils.waitForEvent(
+ wizard,
+ "MigrationWizard:DoneMigration"
+ );
+
+ // Now select our DummyFileMigrator from the list.
+ let selector = shadow.querySelector("#browser-profile-selector");
+ selector.click();
+
+ info("Waiting for panel-list shown");
+ await new Promise(resolve => {
+ shadow
+ .querySelector("panel-list")
+ .addEventListener("shown", resolve, { once: true });
+ });
+
+ info("Panel list shown. Clicking on panel-item");
+ let panelItem = shadow.querySelector(
+ `panel-item[key="${DUMMY_FILEMIGRATOR_KEY}"]`
+ );
+ panelItem.click();
+
+ // Selecting a file migrator from the selector should automatically
+ // open the file picker, so we await it here. Once the file is
+ // selected, migration should begin immediately.
+
+ info("Waiting for file picker");
+ await filePickerShownPromise;
+ await wizardDone;
+ Assert.ok(migrateStub.called, "Migrate on DummyFileMigrator was called.");
+
+ // At this point, with migration having completed, we should be showing
+ // the SELECTION page again with the ERROR_MESSAGE displayed.
+ let deck = shadow.querySelector("#wizard-deck");
+ await BrowserTestUtils.waitForMutationCondition(
+ deck,
+ { attributeFilter: ["selected-view"] },
+ () => {
+ return (
+ deck.getAttribute("selected-view") ==
+ "page-" + MigrationWizardConstants.PAGES.SELECTION
+ );
+ }
+ );
+
+ Assert.equal(
+ selector.selectedPanelItem.getAttribute("key"),
+ DUMMY_FILEMIGRATOR_KEY,
+ "Should have the file migrator selected."
+ );
+
+ let errorMessageContainer = shadow.querySelector(".file-import-error");
+ Assert.ok(
+ BrowserTestUtils.isVisible(errorMessageContainer),
+ "Should be showing the error message container"
+ );
+
+ let fileImportErrorMessage = shadow.querySelector(
+ "#file-import-error-message"
+ ).textContent;
+ Assert.equal(fileImportErrorMessage, ERROR_MESSAGE);
+ });
+
+ sandbox.restore();
+});