Bug 1246030 - Allow reloading an add-on in about:debugging. r=ochameau

MozReview-Commit-ID: Lh2iwPgmlhU

--HG--
extra : transplant_source : %D4zhF%D7F%CA%07UIC%E8yB%E05%7B%EB%F6t
This commit is contained in:
Kumar McMillan 2016-03-31 12:01:02 -05:00
parent aa3b208dcd
commit 7814d5af7a
11 changed files with 140 additions and 13 deletions

View File

@ -25,6 +25,19 @@ module.exports = createClass({
BrowserToolboxProcess.init({ addonID: target.addonID });
},
reload() {
let { client, target } = this.props;
// This function sometimes returns a partial promise that only
// implements then().
client.request({
to: target.addonActor,
type: "reload"
}).then(() => {}, error => {
throw new Error(
"Error reloading addon " + target.addonID + ": " + error);
});
},
render() {
let { target, debugDisabled } = this.props;
@ -41,7 +54,11 @@ module.exports = createClass({
className: "debug-button",
onClick: this.debug,
disabled: debugDisabled,
}, Strings.GetStringFromName("debug"))
}, Strings.GetStringFromName("debug")),
dom.button({
className: "reload-button",
onClick: this.reload
}, Strings.GetStringFromName("reload"))
);
}
});

View File

@ -60,17 +60,21 @@ module.exports = createClass({
},
updateAddonsList() {
AddonManager.getAllAddons(addons => {
let extensions = addons.filter(addon => addon.isDebuggable).map(addon => {
return {
name: addon.name,
icon: addon.iconURL || ExtensionIcon,
addonID: addon.id
};
});
this.props.client.listAddons()
.then(({addons}) => {
let extensions = addons.filter(addon => addon.debuggable).map(addon => {
return {
name: addon.name,
icon: addon.iconURL || ExtensionIcon,
addonID: addon.id,
addonActor: addon.actor
};
});
this.setState({ extensions });
});
this.setState({ extensions });
}, error => {
throw new Error("Client error while listing addons: " + error);
});
},
/**

View File

@ -14,6 +14,7 @@ support-files =
[browser_addons_debug_bootstrapped.js]
[browser_addons_debugging_initial_state.js]
[browser_addons_install.js]
[browser_addons_reload.js]
[browser_addons_toggle_debug.js]
[browser_service_workers.js]
[browser_service_workers_push.js]

View File

@ -22,6 +22,7 @@ add_task(function* () {
});
let { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
yield installAddon(document, "addons/unpacked/install.rdf", ADDON_NAME,
"test-devtools");

View File

@ -47,6 +47,7 @@ function* testCheckboxState(testData) {
});
let { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
info("Install a test addon.");
yield installAddon(document, "addons/unpacked/install.rdf", ADDON_NAME,

View File

@ -7,6 +7,7 @@ const ADDON_NAME = "test-devtools";
add_task(function* () {
let { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
// Install this add-on, and verify that it appears in the about:debugging UI
yield installAddon(document, "addons/unpacked/install.rdf", ADDON_NAME,
@ -20,6 +21,7 @@ add_task(function* () {
add_task(function* () {
let { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
// Start an observer that looks for the install error before
// actually doing the install

View File

@ -0,0 +1,65 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const ADDON_ID = "test-devtools@mozilla.org";
const ADDON_NAME = "test-devtools";
/**
* Returns a promise that resolves when the given add-on event is fired. The
* resolved value is an array of arguments passed for the event.
*/
function promiseAddonEvent(event) {
return new Promise(resolve => {
let listener = {
[event]: function(...args) {
AddonManager.removeAddonListener(listener);
resolve(args);
}
};
AddonManager.addAddonListener(listener);
});
}
add_task(function* () {
const { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
yield installAddon(document, "addons/unpacked/install.rdf",
ADDON_NAME, ADDON_NAME);
// Retrieve the Reload button.
const names = [...document.querySelectorAll("#addons .target-name")];
const name = names.filter(element => element.textContent === ADDON_NAME)[0];
ok(name, "Found " + ADDON_NAME + " add-on in the list");
const targetElement = name.parentNode.parentNode;
const reloadButton = targetElement.querySelector(".reload-button");
ok(reloadButton, "Found its reload button");
const onDisabled = promiseAddonEvent("onDisabled");
const onEnabled = promiseAddonEvent("onEnabled");
const onBootstrapInstallCalled = new Promise(done => {
Services.obs.addObserver(function listener() {
Services.obs.removeObserver(listener, ADDON_NAME, false);
ok(true, "Add-on was installed: " + ADDON_NAME);
done();
}, ADDON_NAME, false);
});
reloadButton.click();
const [disabledAddon] = yield onDisabled;
ok(disabledAddon.name === ADDON_NAME,
"Add-on was disabled: " + disabledAddon.name);
const [enabledAddon] = yield onEnabled;
ok(enabledAddon.name === ADDON_NAME,
"Add-on was re-enabled: " + enabledAddon.name);
yield onBootstrapInstallCalled;
info("Uninstall addon installed earlier.");
yield uninstallAddon(document, ADDON_ID, ADDON_NAME);
yield closeAboutDebugging(tab);
});

View File

@ -20,6 +20,7 @@ add_task(function* () {
});
let { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
info("Install a test addon.");
yield installAddon(document, "addons/unpacked/install.rdf", ADDON_NAME,

View File

@ -5,7 +5,8 @@
/* eslint-disable mozilla/no-cpows-in-tests */
/* exported openAboutDebugging, closeAboutDebugging, installAddon,
uninstallAddon, waitForMutation, assertHasTarget,
waitForServiceWorkerRegistered, unregisterServiceWorker */
waitForInitialAddonList, waitForServiceWorkerRegistered,
unregisterServiceWorker */
/* global sendAsyncMessage */
"use strict";
@ -155,6 +156,30 @@ function* uninstallAddon(document, addonId, addonName) {
+ names);
}
/**
* Returns a promise that will resolve when the add-on list has been updated.
*
* @param {Node} document
* @return {Promise}
*/
function waitForInitialAddonList(document) {
const addonListContainer = document.querySelector("#addons .targets");
let addonCount = addonListContainer.querySelectorAll(".target");
addonCount = addonCount ? [...addonCount].length : -1;
info("Waiting for add-ons to load. Current add-on count: " + addonCount);
// This relies on the network speed of the actor responding to the
// listAddons() request and also the speed of openAboutDebugging().
let result;
if (addonCount > 0) {
info("Actually, the add-ons have already loaded");
result = Promise.resolve();
} else {
result = waitForMutation(addonListContainer, { childList: true });
}
return result;
}
/**
* Returns a promise that will resolve after receiving a mutation matching the
* provided mutation options on the provided target.

View File

@ -16,6 +16,7 @@ addonDebugging.moreInfo = more info
loadTemporaryAddon = Load Temporary Add-on
extensions = Extensions
selectAddonFromFile2 = Select Manifest File or Package (.xpi)
reload = Reload
workers = Workers
serviceWorkers = Service Workers

View File

@ -83,6 +83,7 @@ BrowserAddonActor.prototype = {
id: this.id,
name: this._addon.name,
url: this.url,
iconURL: this._addon.iconURL,
debuggable: this._addon.isDebuggable,
consoleActor: this._consoleActor.actorID,
@ -155,6 +156,13 @@ BrowserAddonActor.prototype = {
return { type: "detached" };
},
onReload: function BAA_onReload() {
return this._addon.reload()
.then(() => {
return {}; // send an empty response
});
},
preNest: function() {
let e = Services.wm.getEnumerator(null);
while (e.hasMoreElements()) {
@ -249,7 +257,8 @@ BrowserAddonActor.prototype = {
BrowserAddonActor.prototype.requestTypes = {
"attach": BrowserAddonActor.prototype.onAttach,
"detach": BrowserAddonActor.prototype.onDetach
"detach": BrowserAddonActor.prototype.onDetach,
"reload": BrowserAddonActor.prototype.onReload
};
/**