Bug 1231128 Display errors when temporary add-on install fails
MozReview-Commit-ID: BG81hWHLGQ2
--- a/devtools/client/aboutdebugging/aboutdebugging.css
+++ b/devtools/client/aboutdebugging/aboutdebugging.css
@@ -75,16 +75,37 @@ button {
flex: 1;
}
.addons-controls {
display: flex;
flex-direction: row;
}
+.addons-install-error {
+ background-color: #f3b0b0;
+ padding: 5px 10px;
+ margin: 5px 4px 5px 0px;
+}
+
+.addons-install-error .warning {
+ background-image: url(chrome://devtools/skin/images/alerticon-warning.png);
+ background-size: 13px 12px;
+ margin-right: 10px;
+ display: inline-block;
+ width: 13px;
+ height: 12px;
+}
+
+@media (min-resolution: 1.1dppx) {
+ .addons-install-error .warning {
+ background-image: url(chrome://devtools/skin/images/alerticon-warning@2x.png);
+ }
+}
+
.addons-options {
flex: 1;
}
.addons-debugging-label {
display: inline-block;
margin: 0 5px 5px 0;
}
--- a/devtools/client/aboutdebugging/components/addons-controls.js
+++ b/devtools/client/aboutdebugging/components/addons-controls.js
@@ -6,33 +6,42 @@
/* globals AddonManager */
"use strict";
loader.lazyImporter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
const { Cc, Ci } = require("chrome");
-const { createClass, DOM: dom } =
+const { createFactory, createClass, DOM: dom } =
require("devtools/client/shared/vendor/react");
const Services = require("Services");
+const AddonsInstallError = createFactory(require("./addons-install-error"));
+
const Strings = Services.strings.createBundle(
"chrome://devtools/locale/aboutdebugging.properties");
const MORE_INFO_URL = "https://developer.mozilla.org/docs/Tools" +
"/about:debugging#Enabling_add-on_debugging";
module.exports = createClass({
displayName: "AddonsControls",
+ getInitialState() {
+ return {
+ installError: null,
+ };
+ },
+
render() {
let { debugDisabled } = this.props;
- return dom.div({ className: "addons-controls" },
+ return dom.div({ className: "addons-top" },
+ dom.div({ className: "addons-controls" },
dom.div({ className: "addons-options" },
dom.input({
id: "enable-addon-debugging",
type: "checkbox",
checked: !debugDisabled,
onChange: this.onEnableAddonDebuggingChange,
}),
dom.label({
@@ -44,40 +53,41 @@ module.exports = createClass({
dom.a({ href: MORE_INFO_URL, target: "_blank" },
Strings.GetStringFromName("addonDebugging.moreInfo")),
")"
),
dom.button({
id: "load-addon-from-file",
onClick: this.loadAddonFromFile,
}, Strings.GetStringFromName("loadTemporaryAddon"))
- );
+ ),
+ AddonsInstallError({ error: this.state.installError }));
},
onEnableAddonDebuggingChange(event) {
let enabled = event.target.checked;
Services.prefs.setBoolPref("devtools.chrome.enabled", enabled);
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", enabled);
},
loadAddonFromFile() {
+ this.setState({ installError: null });
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window,
Strings.GetStringFromName("selectAddonFromFile2"),
Ci.nsIFilePicker.modeOpen);
let res = fp.show();
if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
return;
}
let file = fp.file;
// AddonManager.installTemporaryAddon accepts either
// addon directory or final xpi file.
if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
file = file.parent;
}
- try {
- AddonManager.installTemporaryAddon(file);
- } catch (e) {
- window.alert("Error while installing the addon:\n" + e.message + "\n");
- throw e;
- }
+
+ AddonManager.installTemporaryAddon(file)
+ .catch(e => {
+ this.setState({ installError: e.message });
+ });
},
});
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/components/addons-install-error.js
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env browser */
+"use strict";
+
+const { createClass, DOM: dom } = require("devtools/client/shared/vendor/react");
+
+module.exports = createClass({
+ displayName: "AddonsInstallError",
+
+ render() {
+ if (!this.props.error) {
+ return null;
+ }
+ let text = `There was an error during installation: ${this.props.error}`;
+ return dom.div({ className: "addons-install-error" },
+ dom.div({ className: "warning" }),
+ dom.span({}, text));
+ }
+});
--- a/devtools/client/aboutdebugging/components/moz.build
+++ b/devtools/client/aboutdebugging/components/moz.build
@@ -1,16 +1,17 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'aboutdebugging.js',
'addon-target.js',
'addons-controls.js',
+ 'addons-install-error.js',
'addons-tab.js',
'tab-header.js',
'tab-menu-entry.js',
'tab-menu.js',
'target-list.js',
'worker-target.js',
'workers-tab.js',
)
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/addons/bad/manifest.json
@@ -0,0 +1,1 @@
+this is not valid json
--- a/devtools/client/aboutdebugging/test/browser.ini
+++ b/devtools/client/aboutdebugging/test/browser.ini
@@ -1,15 +1,16 @@
[DEFAULT]
tags = devtools
subsuite = devtools
support-files =
head.js
addons/unpacked/bootstrap.js
addons/unpacked/install.rdf
+ addons/bad/manifest.json
service-workers/empty-sw.html
service-workers/empty-sw.js
service-workers/push-sw.html
service-workers/push-sw.js
[browser_addons_debugging_initial_state.js]
[browser_addons_install.js]
[browser_addons_toggle_debug.js]
--- a/devtools/client/aboutdebugging/test/browser_addons_install.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_install.js
@@ -23,8 +23,35 @@ add_task(function* () {
names = [...document.querySelectorAll("#addons .target-name")];
names = names.map(element => element.textContent);
ok(!names.includes(ADDON_NAME),
"After uninstall, the addon name disappears from the list of addons: "
+ names);
yield closeAboutDebugging(tab);
});
+
+add_task(function* () {
+ let { tab, document } = yield openAboutDebugging("addons");
+
+ // Start an observer that looks for the install error before
+ // actually doing the install
+ let top = document.querySelector(".addons-top");
+ let promise = waitForMutation(top, { childList: true });
+
+ // Mock the file picker to select a test addon
+ let MockFilePicker = SpecialPowers.MockFilePicker;
+ MockFilePicker.init(null);
+ let file = getSupportsFile("addons/bad/manifest.json");
+ MockFilePicker.returnFiles = [file.file];
+
+ // Trigger the file picker by clicking on the button
+ document.getElementById("load-addon-from-file").click();
+
+ // Now wait for the install error to appear.
+ yield promise;
+
+ // And check that it really is there.
+ let err = document.querySelector(".addons-install-error");
+ isnot(err, null, "Addon install error message appeared");
+
+ yield closeAboutDebugging(tab);
+});