summaryrefslogtreecommitdiffstats
path: root/browser/components/migration/tests/unit/test_Chrome_extensions.js
blob: 7aa7a9419411cb7aa591fb79cb96128a071c6469 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const { AMBrowserExtensionsImport, AddonManager } = ChromeUtils.importESModule(
  "resource://gre/modules/AddonManager.sys.mjs"
);
const { AddonTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/AddonTestUtils.sys.mjs"
);
const { ChromeMigrationUtils } = ChromeUtils.importESModule(
  "resource:///modules/ChromeMigrationUtils.sys.mjs"
);
const { ChromeProfileMigrator } = ChromeUtils.importESModule(
  "resource:///modules/ChromeProfileMigrator.sys.mjs"
);

AddonTestUtils.init(this);
AddonTestUtils.overrideCertDB();
AddonTestUtils.createAppInfo(
  "xpcshell@tests.mozilla.org",
  "XPCShell",
  "42",
  "42"
);

const TEST_SERVER = AddonTestUtils.createHttpServer({ hosts: ["example.com"] });

const PROFILE = {
  id: "Default",
  name: "Person 1",
};

const IMPORTED_ADDON_1 = {
  name: "A Firefox extension",
  version: "1.0",
  browser_specific_settings: { gecko: { id: "some-ff@extension" } },
};

// Setup chrome user data path for all platforms.
ChromeMigrationUtils.getDataPath = () => {
  return Promise.resolve(
    do_get_file("Library/Application Support/Google/Chrome/").path
  );
};

const mockAddonRepository = ({ addons = [] } = {}) => {
  return {
    async getMappedAddons(browserID, extensionIDs) {
      Assert.equal(browserID, "chrome", "expected browser ID");
      // Sort extension IDs to have a predictable order.
      extensionIDs.sort();
      Assert.deepEqual(
        extensionIDs,
        ["fake-extension-1", "fake-extension-2"],
        "expected an array of 2 extension IDs"
      );
      return Promise.resolve({
        addons,
        matchedIDs: [],
        unmatchedIDs: [],
      });
    },
  };
};

add_setup(async function setup() {
  await AddonTestUtils.promiseStartupManager();

  // Create a Firefox XPI that we can use during the import.
  const xpi = AddonTestUtils.createTempWebExtensionFile({
    manifest: IMPORTED_ADDON_1,
  });
  TEST_SERVER.registerFile(`/addons/addon-1.xpi`, xpi);

  // Override the `AddonRepository` in `AMBrowserExtensionsImport` with our own
  // mock so that we control the add-ons that are mapped to the list of Chrome
  // extension IDs.
  const addons = [
    {
      id: IMPORTED_ADDON_1.browser_specific_settings.gecko.id,
      name: IMPORTED_ADDON_1.name,
      version: IMPORTED_ADDON_1.version,
      sourceURI: Services.io.newURI(`http://example.com/addons/addon-1.xpi`),
      icons: {},
    },
  ];
  AMBrowserExtensionsImport._addonRepository = mockAddonRepository({ addons });

  registerCleanupFunction(() => {
    // Clear the add-on repository override.
    AMBrowserExtensionsImport._addonRepository = null;
  });
});

add_task(
  { pref_set: [["browser.migrate.chrome.extensions.enabled", true]] },
  async function test_import_extensions() {
    const migrator = await MigrationUtils.getMigrator("chrome");
    Assert.ok(
      await migrator.isSourceAvailable(),
      "Sanity check the source exists"
    );

    let promiseTopic = TestUtils.topicObserved(
      "webextension-imported-addons-pending"
    );
    await promiseMigration(
      migrator,
      MigrationUtils.resourceTypes.EXTENSIONS,
      PROFILE,
      true
    );
    await promiseTopic;
    // When this property is `true`, the UI should show a badge on the appmenu
    // button, and the user can finalize the import later.
    Assert.ok(
      AMBrowserExtensionsImport.canCompleteOrCancelInstalls,
      "expected some add-ons to have been imported"
    );

    // Let's actually complete the import programatically below.
    promiseTopic = TestUtils.topicObserved(
      "webextension-imported-addons-complete"
    );
    await AMBrowserExtensionsImport.completeInstalls();
    await Promise.all([
      AddonTestUtils.promiseInstallEvent("onInstallEnded"),
      promiseTopic,
    ]);

    // The add-on should be installed and therefore it can be uninstalled.
    const addon = await AddonManager.getAddonByID(
      IMPORTED_ADDON_1.browser_specific_settings.gecko.id
    );
    await addon.uninstall();
  }
);

/**
 * Test that, for now at least, the extension resource type is only made
 * available for Chrome and none of the derivitive browsers.
 */
add_task(
  { pref_set: [["browser.migrate.chrome.extensions.enabled", true]] },
  async function test_only_chrome_migrates_extensions() {
    for (const key of MigrationUtils.availableMigratorKeys) {
      let migrator = await MigrationUtils.getMigrator(key);

      if (migrator instanceof ChromeProfileMigrator && key != "chrome") {
        info("Testing migrator with key " + key);
        Assert.ok(
          await migrator.isSourceAvailable(),
          "First check the source exists"
        );
        let resourceTypes = await migrator.getMigrateData(PROFILE);
        Assert.ok(
          !(resourceTypes & MigrationUtils.resourceTypes.EXTENSIONS),
          "Should not offer the extension resource type"
        );
      }
    }
  }
);