new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/addons/test-devtools-webextension-nobg/manifest.json
@@ -0,0 +1,10 @@
+{
+ "manifest_version": 2,
+ "name": "test-devtools-webextension-nobg",
+ "version": "1.0",
+ "applications": {
+ "gecko": {
+ "id": "test-devtools-webextension-nobg@mozilla.org"
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/addons/test-devtools-webextension/bg.js
@@ -0,0 +1,20 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* eslint-env browser */
+/* global browser */
+
+"use strict";
+
+document.body.innerText = "Background Page Body Test Content";
+
+// This function are called from the webconsole test:
+// browser_addons_debug_webextension.js
+
+function myWebExtensionAddonFunction() { // eslint-disable-line no-unused-vars
+ console.log("Background page function called", browser.runtime.getManifest());
+}
+
+function myWebExtensionShowPopup() { // eslint-disable-line no-unused-vars
+ console.log("readyForOpenPopup");
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/addons/test-devtools-webextension/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "test-devtools-webextension",
+ "version": "1.0",
+ "applications": {
+ "gecko": {
+ "id": "test-devtools-webextension@mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["bg.js"]
+ },
+ "browser_action": {
+ "default_title": "WebExtension Popup Debugging",
+ "default_popup": "popup.html"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/addons/test-devtools-webextension/popup.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <script src="popup.js"></script>
+ </head>
+ <body>
+ Background Page Body Test Content
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/addons/test-devtools-webextension/popup.js
@@ -0,0 +1,13 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* eslint-env browser */
+/* global browser */
+
+"use strict";
+
+// This function is called from the webconsole test:
+// browser_addons_debug_webextension.js
+function myWebExtensionPopupAddonFunction() { // eslint-disable-line no-unused-vars
+ console.log("Popup page function called", browser.runtime.getManifest());
+}
--- a/devtools/client/aboutdebugging/test/browser.ini
+++ b/devtools/client/aboutdebugging/test/browser.ini
@@ -2,23 +2,29 @@
tags = devtools
subsuite = devtools
support-files =
head.js
addons/unpacked/bootstrap.js
addons/unpacked/install.rdf
addons/bad/manifest.json
addons/bug1273184.xpi
+ addons/test-devtools-webextension/*
+ addons/test-devtools-webextension-nobg/*
service-workers/empty-sw.html
service-workers/empty-sw.js
service-workers/push-sw.html
service-workers/push-sw.js
!/devtools/client/framework/test/shared-head.js
[browser_addons_debug_bootstrapped.js]
+[browser_addons_debug_webextension.js]
+[browser_addons_debug_webextension_inspector.js]
+[browser_addons_debug_webextension_nobg.js]
+[browser_addons_debug_webextension_popup.js]
[browser_addons_debugging_initial_state.js]
[browser_addons_install.js]
[browser_addons_reload.js]
[browser_addons_toggle_debug.js]
[browser_page_not_found.js]
[browser_service_workers.js]
[browser_service_workers_not_compatible.js]
[browser_service_workers_push.js]
--- a/devtools/client/aboutdebugging/test/browser_addons_debug_bootstrapped.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_bootstrapped.js
@@ -21,18 +21,21 @@ add_task(function* () {
// Enable Browser toolbox test script execution via env variable
["devtools.browser-toolbox.allow-unsafe-script", true],
]};
SpecialPowers.pushPrefEnv(options, resolve);
});
let { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
- yield installAddon(document, "addons/unpacked/install.rdf", ADDON_NAME,
- "test-devtools");
+ yield installAddon({
+ document,
+ path: "addons/unpacked/install.rdf",
+ name: ADDON_NAME,
+ });
// Retrieve the DEBUG button for the addon
let names = [...document.querySelectorAll("#addons .target-name")];
let name = names.filter(element => element.textContent === ADDON_NAME)[0];
ok(name, "Found the addon in the list");
let targetElement = name.parentNode.parentNode;
let debugBtn = targetElement.querySelector(".debug-button");
ok(debugBtn, "Found its debug button");
@@ -70,11 +73,11 @@ add_task(function* () {
debugBtn.click();
yield onCustomMessage;
ok(true, "Received the notification message from the bootstrap.js function");
yield onToolboxClose;
ok(true, "Addon toolbox closed");
- yield uninstallAddon(document, ADDON_ID, ADDON_NAME);
+ yield uninstallAddon({document, id: ADDON_ID, name: ADDON_NAME});
yield closeAboutDebugging(tab);
});
copy from devtools/client/aboutdebugging/test/browser_addons_debug_bootstrapped.js
copy to devtools/client/aboutdebugging/test/browser_addons_debug_webextension.js
--- a/devtools/client/aboutdebugging/test/browser_addons_debug_bootstrapped.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension.js
@@ -1,80 +1,74 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
requestLongerTimeout(2);
-const ADDON_ID = "test-devtools@mozilla.org";
-const ADDON_NAME = "test-devtools";
+const ADDON_ID = "test-devtools-webextension@mozilla.org";
+const ADDON_NAME = "test-devtools-webextension";
+const ADDON_MANIFEST_PATH = "addons/test-devtools-webextension/manifest.json";
-const { BrowserToolboxProcess } = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
+const {
+ BrowserToolboxProcess
+} = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
-add_task(function* () {
- yield new Promise(resolve => {
- let options = {"set": [
- // Force enabling of addons debugging
- ["devtools.chrome.enabled", true],
- ["devtools.debugger.remote-enabled", true],
- // Disable security prompt
- ["devtools.debugger.prompt-connection", false],
- // Enable Browser toolbox test script execution via env variable
- ["devtools.browser-toolbox.allow-unsafe-script", true],
- ]};
- SpecialPowers.pushPrefEnv(options, resolve);
- });
-
- let { tab, document } = yield openAboutDebugging("addons");
- yield waitForInitialAddonList(document);
- yield installAddon(document, "addons/unpacked/install.rdf", ADDON_NAME,
- "test-devtools");
-
- // Retrieve the DEBUG button for the addon
- let names = [...document.querySelectorAll("#addons .target-name")];
- let name = names.filter(element => element.textContent === ADDON_NAME)[0];
- ok(name, "Found the addon in the list");
- let targetElement = name.parentNode.parentNode;
- let debugBtn = targetElement.querySelector(".debug-button");
- ok(debugBtn, "Found its debug button");
+/**
+ * This test file ensures that the webextension addon developer toolbox:
+ * - when the debug button is clicked on a webextension, the opened toolbox
+ * has a working webconsole with the background page as default target;
+ */
+add_task(function* testWebExtensionsToolboxWebConsole() {
+ let {
+ tab, document, debugBtn,
+ } = yield setupTestAboutDebuggingWebExtension(ADDON_NAME, ADDON_MANIFEST_PATH);
// Wait for a notification sent by a script evaluated the test addon via
// the web console.
let onCustomMessage = new Promise(done => {
- Services.obs.addObserver(function listener() {
- Services.obs.removeObserver(listener, "addon-console-works");
- done();
- }, "addon-console-works", false);
+ Services.obs.addObserver(function listener(message, topic) {
+ let apiMessage = message.wrappedJSObject;
+ if (!apiMessage.originAttributes ||
+ apiMessage.originAttributes.addonId != ADDON_ID) {
+ return;
+ }
+ Services.obs.removeObserver(listener, "console-api-log-event");
+ done(apiMessage.arguments);
+ }, "console-api-log-event", false);
});
// Be careful, this JS function is going to be executed in the addon toolbox,
// which lives in another process. So do not try to use any scope variable!
let env = Cc["@mozilla.org/process/environment;1"]
.getService(Ci.nsIEnvironment);
let testScript = function () {
/* eslint-disable no-undef */
toolbox.selectTool("webconsole")
.then(console => {
let { jsterm } = console.hud;
- return jsterm.execute("myBootstrapAddonFunction()");
+ return jsterm.execute("myWebExtensionAddonFunction()");
})
.then(() => toolbox.destroy());
/* eslint-enable no-undef */
};
env.set("MOZ_TOOLBOX_TEST_SCRIPT", "new " + testScript);
registerCleanupFunction(() => {
env.set("MOZ_TOOLBOX_TEST_SCRIPT", "");
});
let onToolboxClose = BrowserToolboxProcess.once("close");
debugBtn.click();
- yield onCustomMessage;
- ok(true, "Received the notification message from the bootstrap.js function");
+ let args = yield onCustomMessage;
+ ok(true, "Received console message from the background page function as expected");
+ is(args[0], "Background page function called", "Got the expected console message");
+ is(args[1] && args[1].name, ADDON_NAME,
+ "Got the expected manifest from WebExtension API");
yield onToolboxClose;
ok(true, "Addon toolbox closed");
- yield uninstallAddon(document, ADDON_ID, ADDON_NAME);
+ yield uninstallAddon({document, id: ADDON_ID, name: ADDON_NAME});
yield closeAboutDebugging(tab);
});
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_inspector.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
+requestLongerTimeout(2);
+
+const ADDON_ID = "test-devtools-webextension@mozilla.org";
+const ADDON_NAME = "test-devtools-webextension";
+const ADDON_PATH = "addons/test-devtools-webextension/manifest.json";
+
+const {
+ BrowserToolboxProcess
+} = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
+
+/**
+ * This test file ensures that the webextension addon developer toolbox:
+ * - the webextension developer toolbox has a working Inspector panel, with the
+ * background page as default target;
+ */
+add_task(function* testWebExtensionsToolboxInspector() {
+ let {
+ tab, document, debugBtn,
+ } = yield setupTestAboutDebuggingWebExtension(ADDON_NAME, ADDON_PATH);
+
+ // Be careful, this JS function is going to be executed in the addon toolbox,
+ // which lives in another process. So do not try to use any scope variable!
+ let env = Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment);
+ let testScript = function () {
+ /* eslint-disable no-undef */
+ toolbox.selectTool("inspector")
+ .then(inspector => {
+ return inspector.walker.querySelector(inspector.walker.rootNode, "body");
+ })
+ .then((nodeActor) => {
+ if (!nodeActor) {
+ throw new Error("nodeActor not found");
+ }
+
+ dump("Got a nodeActor\n");
+
+ if (!(nodeActor.inlineTextChild)) {
+ throw new Error("inlineTextChild not found");
+ }
+
+ dump("Got a nodeActor with an inline text child\n");
+
+ let expectedValue = "Background Page Body Test Content";
+ let actualValue = nodeActor.inlineTextChild._form.nodeValue;
+
+ if (String(actualValue).trim() !== String(expectedValue).trim()) {
+ throw new Error(
+ `mismatched inlineTextchild value: "${actualValue}" !== "${expectedValue}"`
+ );
+ }
+
+ dump("Got the expected inline text content in the selected node\n");
+ return Promise.resolve();
+ })
+ .then(() => toolbox.destroy())
+ .catch((error) => {
+ dump("Error while running code in the browser toolbox process:\n");
+ dump(error + "\n");
+ dump("stack:\n" + error.stack + "\n");
+ });
+ /* eslint-enable no-undef */
+ };
+ env.set("MOZ_TOOLBOX_TEST_SCRIPT", "new " + testScript);
+ registerCleanupFunction(() => {
+ env.set("MOZ_TOOLBOX_TEST_SCRIPT", "");
+ });
+
+ let onToolboxClose = BrowserToolboxProcess.once("close");
+ debugBtn.click();
+ yield onToolboxClose;
+
+ ok(true, "Addon toolbox closed");
+
+ yield uninstallAddon({document, id: ADDON_ID, name: ADDON_NAME});
+ yield closeAboutDebugging(tab);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_nobg.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
+requestLongerTimeout(2);
+
+const ADDON_NOBG_ID = "test-devtools-webextension-nobg@mozilla.org";
+const ADDON_NOBG_NAME = "test-devtools-webextension-nobg";
+const ADDON_NOBG_PATH = "addons/test-devtools-webextension-nobg/manifest.json";
+
+const {
+ BrowserToolboxProcess
+} = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
+
+/**
+ * This test file ensures that the webextension addon developer toolbox:
+ * - the webextension developer toolbox is connected to a fallback page when the
+ * background page is not available (and in the fallback page document body contains
+ * the expected message, which warns the user that the current page is not a real
+ * webextension context);
+ */
+add_task(function* testWebExtensionsToolboxNoBackgroundPage() {
+ let {
+ tab, document, debugBtn,
+ } = yield setupTestAboutDebuggingWebExtension(ADDON_NOBG_NAME, ADDON_NOBG_PATH);
+
+ // Be careful, this JS function is going to be executed in the addon toolbox,
+ // which lives in another process. So do not try to use any scope variable!
+ let env = Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment);
+ let testScript = function () {
+ /* eslint-disable no-undef */
+ toolbox.selectTool("inspector")
+ .then(inspector => {
+ return inspector.walker.querySelector(inspector.walker.rootNode, "body");
+ })
+ .then((nodeActor) => {
+ if (!nodeActor) {
+ throw new Error("nodeActor not found");
+ }
+
+ dump("Got a nodeActor\n");
+
+ if (!(nodeActor.inlineTextChild)) {
+ throw new Error("inlineTextChild not found");
+ }
+
+ dump("Got a nodeActor with an inline text child\n");
+
+ let expectedValue = "Your addon does not have any document opened yet.";
+ let actualValue = nodeActor.inlineTextChild._form.nodeValue;
+
+ if (actualValue !== expectedValue) {
+ throw new Error(
+ `mismatched inlineTextchild value: "${actualValue}" !== "${expectedValue}"`
+ );
+ }
+
+ dump("Got the expected inline text content in the selected node\n");
+ return Promise.resolve();
+ })
+ .then(() => toolbox.destroy())
+ .catch((error) => {
+ dump("Error while running code in the browser toolbox process:\n");
+ dump(error + "\n");
+ dump("stack:\n" + error.stack + "\n");
+ });
+ /* eslint-enable no-undef */
+ };
+ env.set("MOZ_TOOLBOX_TEST_SCRIPT", "new " + testScript);
+ registerCleanupFunction(() => {
+ env.set("MOZ_TOOLBOX_TEST_SCRIPT", "");
+ });
+
+ let onToolboxClose = BrowserToolboxProcess.once("close");
+ debugBtn.click();
+ yield onToolboxClose;
+
+ ok(true, "Addon toolbox closed");
+
+ yield uninstallAddon({document, id: ADDON_NOBG_ID, name: ADDON_NOBG_NAME});
+ yield closeAboutDebugging(tab);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_popup.js
@@ -0,0 +1,180 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
+requestLongerTimeout(2);
+
+const ADDON_ID = "test-devtools-webextension@mozilla.org";
+const ADDON_NAME = "test-devtools-webextension";
+const ADDON_MANIFEST_PATH = "addons/test-devtools-webextension/manifest.json";
+
+const {
+ BrowserToolboxProcess
+} = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
+
+/**
+ * This test file ensures that the webextension addon developer toolbox:
+ * - when the debug button is clicked on a webextension, the opened toolbox
+ * has a working webconsole with the background page as default target;
+ * - the webextension developer toolbox has a working Inspector panel, with the
+ * background page as default target;
+ * - the webextension developer toolbox is connected to a fallback page when the
+ * background page is not available (and in the fallback page document body contains
+ * the expected message, which warns the user that the current page is not a real
+ * webextension context);
+ * - the webextension developer toolbox has a frame list menu and the noautohide toolbar
+ * toggle button, and they can be used to switch the current target to the extension
+ * popup page.
+ */
+
+/**
+ * Returns the widget id for an extension with the passed id.
+ */
+function makeWidgetId(id) {
+ id = id.toLowerCase();
+ return id.replace(/[^a-z0-9_-]/g, "_");
+}
+
+add_task(function* testWebExtensionsToolboxSwitchToPopup() {
+ let {
+ tab, document, debugBtn,
+ } = yield setupTestAboutDebuggingWebExtension(ADDON_NAME, ADDON_MANIFEST_PATH);
+
+ let onReadyForOpenPopup = new Promise(done => {
+ Services.obs.addObserver(function listener(message, topic) {
+ let apiMessage = message.wrappedJSObject;
+ if (!apiMessage.originAttributes ||
+ apiMessage.originAttributes.addonId != ADDON_ID) {
+ return;
+ }
+
+ if (apiMessage.arguments[0] == "readyForOpenPopup") {
+ Services.obs.removeObserver(listener, "console-api-log-event");
+ done();
+ }
+ }, "console-api-log-event", false);
+ });
+
+ // Be careful, this JS function is going to be executed in the addon toolbox,
+ // which lives in another process. So do not try to use any scope variable!
+ let env = Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment);
+ let testScript = function () {
+ /* eslint-disable no-undef */
+
+ let jsterm;
+
+ toolbox.selectTool("webconsole")
+ .then(console => {
+ dump(`Clicking the noautohide button\n`);
+ toolbox.doc.getElementById("command-button-noautohide").click();
+ dump(`Clicked the noautohide button\n`);
+
+ let waitForFrameListUpdate = new Promise((done) => {
+ toolbox.target.once("frame-update", () => {
+ done(console);
+ });
+ });
+
+ jsterm = console.hud.jsterm;
+ jsterm.execute("myWebExtensionShowPopup()");
+
+ // Wait the initial frame update (which list the background page).
+ return waitForFrameListUpdate;
+ })
+ .then((console) => {
+ // Wait the new frame update (once the extension popup has been opened).
+ return new Promise((done) => {
+ toolbox.target.once("frame-update", done);
+ });
+ })
+ .then(() => {
+ dump(`Clicking the frame list button\n`);
+ let btn = toolbox.doc.getElementById("command-button-frames");
+ let menu = toolbox.showFramesMenu({target: btn});
+ dump(`Clicked the frame list button\n`);
+ return menu.once("open").then(() => {
+ return menu;
+ });
+ })
+ .then(frameMenu => {
+ let frames = frameMenu.items;
+
+ if (frames.length != 2) {
+ throw Error(`Number of frames found is wrong: ${frames.length} != 2`);
+ }
+
+ let popupFrameBtn = frames.filter((frame) => {
+ return frame.label.endsWith("popup.html");
+ }).pop();
+
+ if (!popupFrameBtn) {
+ throw Error("Extension Popup frame not found in the listed frames");
+ }
+
+ let waitForNavigated = toolbox.target.once("navigate");
+
+ popupFrameBtn.click();
+
+ return waitForNavigated;
+ })
+ .then(() => {
+ return jsterm.execute("myWebExtensionPopupAddonFunction()");
+ })
+ .then(() => toolbox.destroy())
+ .catch((error) => {
+ dump("Error while running code in the browser toolbox process:\n");
+ dump(error + "\n");
+ dump("stack:\n" + error.stack + "\n");
+ });
+ /* eslint-enable no-undef */
+ };
+ env.set("MOZ_TOOLBOX_TEST_SCRIPT", "new " + testScript);
+ registerCleanupFunction(() => {
+ env.set("MOZ_TOOLBOX_TEST_SCRIPT", "");
+ });
+
+ // Wait for a notification sent by a script evaluated the test addon via
+ // the web console.
+ let onPopupCustomMessage = new Promise(done => {
+ Services.obs.addObserver(function listener(message, topic) {
+ let apiMessage = message.wrappedJSObject;
+ if (!apiMessage.originAttributes ||
+ apiMessage.originAttributes.addonId != ADDON_ID) {
+ return;
+ }
+
+ if (apiMessage.arguments[0] == "Popup page function called") {
+ Services.obs.removeObserver(listener, "console-api-log-event");
+ done(apiMessage.arguments);
+ }
+ }, "console-api-log-event", false);
+ });
+
+ let onToolboxClose = BrowserToolboxProcess.once("close");
+
+ debugBtn.click();
+
+ yield onReadyForOpenPopup;
+
+ let browserActionId = makeWidgetId(ADDON_ID) + "-browser-action";
+ let browserActionEl = window.document.getElementById(browserActionId);
+
+ ok(browserActionEl, "Got the browserAction button from the browser UI");
+ browserActionEl.click();
+ info("Clicked on the browserAction button");
+
+ let args = yield onPopupCustomMessage;
+ ok(true, "Received console message from the popup page function as expected");
+ is(args[0], "Popup page function called", "Got the expected console message");
+ is(args[1] && args[1].name, ADDON_NAME,
+ "Got the expected manifest from WebExtension API");
+
+ yield onToolboxClose;
+
+ ok(true, "Addon toolbox closed");
+
+ yield uninstallAddon({document, id: ADDON_ID, name: ADDON_NAME});
+ yield closeAboutDebugging(tab);
+});
--- a/devtools/client/aboutdebugging/test/browser_addons_debugging_initial_state.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debugging_initial_state.js
@@ -45,26 +45,29 @@ function* testCheckboxState(testData) {
]};
SpecialPowers.pushPrefEnv(options, resolve);
});
let { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
info("Install a test addon.");
- yield installAddon(document, "addons/unpacked/install.rdf", ADDON_NAME,
- "test-devtools");
+ yield installAddon({
+ document,
+ path: "addons/unpacked/install.rdf",
+ name: ADDON_NAME,
+ });
info("Test checkbox checked state.");
let addonDebugCheckbox = document.querySelector("#enable-addon-debugging");
is(addonDebugCheckbox.checked, testData.expected,
"Addons debugging checkbox should be in expected state.");
info("Test debug buttons disabled state.");
let debugButtons = [...document.querySelectorAll("#addons .debug-button")];
ok(debugButtons.every(b => b.disabled != testData.expected),
"Debug buttons should be in the expected state");
info("Uninstall test addon installed earlier.");
- yield uninstallAddon(document, ADDON_ID, ADDON_NAME);
+ yield uninstallAddon({document, id: ADDON_ID, name: ADDON_NAME});
yield closeAboutDebugging(tab);
}
--- a/devtools/client/aboutdebugging/test/browser_addons_install.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_install.js
@@ -5,21 +5,24 @@
const ADDON_ID = "test-devtools@mozilla.org";
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,
- "test-devtools");
+ yield installAddon({
+ document,
+ path: "addons/unpacked/install.rdf",
+ name: ADDON_NAME,
+ });
// Install the add-on, and verify that it disappears in the about:debugging UI
- yield uninstallAddon(document, ADDON_ID, ADDON_NAME);
+ yield uninstallAddon({document, id: ADDON_ID, name: ADDON_NAME});
yield closeAboutDebugging(tab);
});
add_task(function* () {
let { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
--- a/devtools/client/aboutdebugging/test/browser_addons_reload.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_reload.js
@@ -104,18 +104,21 @@ class TempWebExt {
remove() {
return this.tmpDir.remove(true);
}
}
add_task(function* reloadButtonReloadsAddon() {
const { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
- yield installAddon(document, "addons/unpacked/install.rdf",
- ADDON_NAME, ADDON_NAME);
+ yield installAddon({
+ document,
+ path: "addons/unpacked/install.rdf",
+ name: ADDON_NAME,
+ });
const reloadButton = getReloadButton(document, ADDON_NAME);
is(reloadButton.disabled, false, "Reload button should not be disabled");
is(reloadButton.title, "", "Reload button should not have a tooltip");
const onInstalled = promiseAddonEvent("onInstalled");
const onBootstrapInstallCalled = new Promise(done => {
Services.obs.addObserver(function listener() {
--- a/devtools/client/aboutdebugging/test/browser_addons_toggle_debug.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_toggle_debug.js
@@ -18,18 +18,21 @@ add_task(function* () {
]};
SpecialPowers.pushPrefEnv(options, resolve);
});
let { tab, document } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
info("Install a test addon.");
- yield installAddon(document, "addons/unpacked/install.rdf", ADDON_NAME,
- "test-devtools");
+ yield installAddon({
+ document,
+ path: "addons/unpacked/install.rdf",
+ name: ADDON_NAME,
+ });
let addonDebugCheckbox = document.querySelector("#enable-addon-debugging");
ok(!addonDebugCheckbox.checked, "Addons debugging should be disabled.");
info("Check all debug buttons are disabled.");
let debugButtons = [...document.querySelectorAll("#addons .debug-button")];
ok(debugButtons.every(b => b.disabled), "Debug buttons should be disabled");
@@ -51,12 +54,12 @@ add_task(function* () {
addonDebugCheckbox.click();
yield onAddonsMutation;
info("Check all debug buttons are disabled again.");
debugButtons = [...document.querySelectorAll("#addons .debug-button")];
ok(debugButtons.every(b => b.disabled), "Debug buttons should be disabled");
info("Uninstall addon installed earlier.");
- yield uninstallAddon(document, ADDON_ID, ADDON_NAME);
+ yield uninstallAddon({document, id: ADDON_ID, name: ADDON_NAME});
yield closeAboutDebugging(tab);
});
--- a/devtools/client/aboutdebugging/test/head.js
+++ b/devtools/client/aboutdebugging/test/head.js
@@ -1,27 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-env browser */
/* exported openAboutDebugging, changeAboutDebuggingHash, closeAboutDebugging,
installAddon, uninstallAddon, waitForMutation, assertHasTarget,
getServiceWorkerList, getTabList, openPanel, waitForInitialAddonList,
waitForServiceWorkerRegistered, unregisterServiceWorker,
- waitForDelayedStartupFinished */
+ waitForDelayedStartupFinished, setupTestAboutDebuggingWebExtension */
/* import-globals-from ../../framework/test/shared-head.js */
"use strict";
// Load the shared-head file first.
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
this);
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
+const { Management } = Cu.import("resource://gre/modules/Extension.jsm", {});
+
DevToolsUtils.testing = true;
registerCleanupFunction(() => {
DevToolsUtils.testing = false;
});
function* openAboutDebugging(page, win) {
info("opening about:debugging");
@@ -143,55 +145,70 @@ function getServiceWorkerList(document)
* @param {DOMDocument} document #tabs section container document
* @return {DOMNode} target list or container element
*/
function getTabList(document) {
return document.querySelector("#tabs .target-list") ||
document.querySelector("#tabs.targets");
}
-function* installAddon(document, path, name, evt) {
+function* installAddon({document, path, name, isWebExtension}) {
// Mock the file picker to select a test addon
let MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(null);
let file = getSupportsFile(path);
MockFilePicker.returnFiles = [file.file];
let addonList = getAddonList(document);
let addonListMutation = waitForMutation(addonList, { childList: true });
- // Wait for a message sent by the addon's bootstrap.js file
- let onAddonInstalled = new Promise(done => {
- Services.obs.addObserver(function listener() {
- Services.obs.removeObserver(listener, evt);
+ let onAddonInstalled;
+
+ if (isWebExtension) {
+ onAddonInstalled = new Promise(done => {
+ Management.on("startup", function listener(event, extension) {
+ if (extension.name != name) {
+ return;
+ }
- done();
- }, evt, false);
- });
+ Management.off("startup", listener);
+ done();
+ });
+ });
+ } else {
+ // Wait for a "test-devtools" message sent by the addon's bootstrap.js file
+ onAddonInstalled = new Promise(done => {
+ Services.obs.addObserver(function listener() {
+ Services.obs.removeObserver(listener, "test-devtools");
+
+ done();
+ }, "test-devtools", false);
+ });
+ }
// Trigger the file picker by clicking on the button
document.getElementById("load-addon-from-file").click();
yield onAddonInstalled;
ok(true, "Addon installed and running its bootstrap.js file");
// Check that the addon appears in the UI
yield addonListMutation;
let names = [...addonList.querySelectorAll(".target-name")];
names = names.map(element => element.textContent);
ok(names.includes(name),
"The addon name appears in the list of addons: " + names);
}
-function* uninstallAddon(document, addonId, addonName) {
+function* uninstallAddon({document, id, name}) {
let addonList = getAddonList(document);
let addonListMutation = waitForMutation(addonList, { childList: true });
// Now uninstall this addon
yield new Promise(done => {
- AddonManager.getAddonByID(addonId, addon => {
+ AddonManager.getAddonByID(id, addon => {
let listener = {
onUninstalled: function (uninstalledAddon) {
if (uninstalledAddon != addon) {
return;
}
AddonManager.removeAddonListener(listener);
done();
@@ -201,17 +218,17 @@ function* uninstallAddon(document, addon
addon.uninstall();
});
});
// Ensure that the UI removes the addon from the list
yield addonListMutation;
let names = [...addonList.querySelectorAll(".target-name")];
names = names.map(element => element.textContent);
- ok(!names.includes(addonName),
+ ok(!names.includes(name),
"After uninstall, the addon name disappears from the list of addons: "
+ names);
}
/**
* Returns a promise that will resolve when the add-on list has been updated.
*
* @param {Node} document
@@ -307,8 +324,46 @@ function waitForDelayedStartupFinished(w
Services.obs.addObserver(function observer(subject, topic) {
if (win == subject) {
Services.obs.removeObserver(observer, topic);
resolve();
}
}, "browser-delayed-startup-finished", false);
});
}
+
+/**
+ * open the about:debugging page and install an addon
+ */
+function* setupTestAboutDebuggingWebExtension(name, path) {
+ yield new Promise(resolve => {
+ let options = {"set": [
+ // Force enabling of addons debugging
+ ["devtools.chrome.enabled", true],
+ ["devtools.debugger.remote-enabled", true],
+ // Disable security prompt
+ ["devtools.debugger.prompt-connection", false],
+ // Enable Browser toolbox test script execution via env variable
+ ["devtools.browser-toolbox.allow-unsafe-script", true],
+ ]};
+ SpecialPowers.pushPrefEnv(options, resolve);
+ });
+
+ let { tab, document } = yield openAboutDebugging("addons");
+ yield waitForInitialAddonList(document);
+
+ yield installAddon({
+ document,
+ path,
+ name,
+ isWebExtension: true,
+ });
+
+ // Retrieve the DEBUG button for the addon
+ let names = [...document.querySelectorAll("#addons .target-name")];
+ let nameEl = names.filter(element => element.textContent === name)[0];
+ ok(name, "Found the addon in the list");
+ let targetElement = nameEl.parentNode.parentNode;
+ let debugBtn = targetElement.querySelector(".debug-button");
+ ok(debugBtn, "Found its debug button");
+
+ return { tab, document, debugBtn };
+}