Bug 1451513 Part 3: Make loading the mochitest extension more robust
A couple of changes to ensure that the mochitest harness doesn't try to
start executing changes before the mochitest extension is loaded:
1. Fix the marionette driver to wait for an installed extension to
be started before returning from Addon:install
2. Wait for extension API onStartup() handlers to finish before
considering a webextension started.
MozReview-Commit-ID: 8YEdNn6s5qh
--- a/testing/marionette/addon.js
+++ b/testing/marionette/addon.js
@@ -18,48 +18,26 @@ const ERRORS = {
[-3]: "ERROR_CORRUPT_FILE: The file appears to be corrupt.",
[-4]: "ERROR_FILE_ACCESS: There was an error accessing the filesystem.",
[-5]: "ERROR_SIGNEDSTATE_REQUIRED: The addon must be signed and isn't.",
};
async function installAddon(file) {
let install = await AddonManager.getInstallForFile(file);
- return new Promise(resolve => {
- if (install.error) {
- throw new UnknownError(ERRORS[install.error]);
- }
-
- let addonId = install.addon.id;
-
- let success = install => {
- if (install.addon.id === addonId) {
- install.removeListener(listener);
- resolve(install.addon);
- }
- };
+ if (install.error) {
+ throw new UnknownError(ERRORS[install.error]);
+ }
- let fail = install => {
- if (install.addon.id === addonId) {
- install.removeListener(listener);
- throw new UnknownError(ERRORS[install.error]);
- }
- };
-
- let listener = {
- onDownloadCancelled: fail,
- onDownloadFailed: fail,
- onInstallCancelled: fail,
- onInstallFailed: fail,
- onInstallEnded: success,
- };
-
- install.addListener(listener);
- install.install();
- });
+ try {
+ let addon = await install.install();
+ return addon;
+ } catch (ex) {
+ throw new UnknownError(ERRORS[install.error]);
+ }
}
/** Installs addons by path and uninstalls by ID. */
class Addon {
/**
* Install a Firefox addon.
*
* If the addon is restartless, it can be used right away. Otherwise a
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -1773,19 +1773,21 @@ class Extension extends ExtensionData {
this.updatePermissions(this.startupReason);
// The "startup" Management event sent on the extension instance itself
// is emitted just before the Management "startup" event,
// and it is used to run code that needs to be executed before
// any of the "startup" listeners.
this.emit("startup", this);
- Management.emit("startup", this);
- await this.runManifest(this.manifest);
+ await Promise.all([
+ Management.emit("startup", this),
+ this.runManifest(this.manifest),
+ ]);
Management.emit("ready", this);
this.emit("ready");
TelemetryStopwatch.finish("WEBEXT_EXTENSION_STARTUP_MS", this);
} catch (errors) {
for (let e of [].concat(errors)) {
dump(`Extension error: ${e.message || e} ${e.filename || e.fileName}:${e.lineNumber} :: ${e.stack || new Error().stack}\n`);
Cu.reportError(e);