Bug 1425224 - Use manifest.ExtensionURL in devtools.panels.create API schema. r=mixedpuppy
authorLuca Greco <lgreco@mozilla.com>
Thu, 14 Dec 2017 18:20:59 +0100
changeset 449360 36585f7098f7bf8429a725e66aa4d15ee8791d96
parent 449359 f94505f76fa48b98c6e4bc38756ea2f5d0177f44
child 449361 b91ce5ed4d3597cf627b49c96def71ba63f1cc7d
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmixedpuppy
bugs1425224
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1425224 - Use manifest.ExtensionURL in devtools.panels.create API schema. r=mixedpuppy MozReview-Commit-ID: AR6j1fC0PmJ
browser/components/extensions/schemas/devtools_panels.json
browser/components/extensions/test/browser/browser_ext_devtools_panel.js
--- a/browser/components/extensions/schemas/devtools_panels.json
+++ b/browser/components/extensions/schemas/devtools_panels.json
@@ -329,22 +329,25 @@
         "parameters": [
           {
             "name": "title",
             "type": "string",
             "description": "Title that is displayed next to the extension icon in the Developer Tools toolbar."
           },
           {
             "name": "iconPath",
-            "type": "string",
-            "description": "Path of the panel's icon relative to the extension directory."
+            "description": "Path of the panel's icon relative to the extension directory, or an empty string to use the default extension icon as the panel icon.",
+            "choices": [
+              {"type": "string", "enum": [""]},
+              {"$ref": "manifest.ExtensionURL"}
+            ]
           },
           {
             "name": "pagePath",
-            "type": "string",
+            "$ref": "manifest.ExtensionURL",
             "description": "Path of the panel's HTML page relative to the extension directory."
           },
           {
             "name": "callback",
             "type": "function",
             "optional": true,
             "description": "A function that is called when the panel is created.",
             "parameters": [
--- a/browser/components/extensions/test/browser/browser_ext_devtools_panel.js
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_panel.js
@@ -425,8 +425,140 @@ add_task(async function test_devtools_pa
 
   await gDevTools.closeToolbox(target);
   await target.destroy();
 
   await extension.unload();
 
   await BrowserTestUtils.removeTab(tab);
 });
+
+add_task(async function test_devtools_page_invalid_panel_urls() {
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
+
+  async function devtools_page() {
+    const matchInvalidPanelURL = /must be a relative URL/;
+    const matchInvalidIconURL = /be one of \[""\], or match the format "strictRelativeUrl"/;
+
+    const test_cases = [
+      // Invalid panel urls (validated by the schema wrappers, throws on invalid urls).
+      {panel: "about:about", icon: "icon.png", expectError: matchInvalidPanelURL},
+      {panel: "about:addons", icon: "icon.png", expectError: matchInvalidPanelURL},
+      {panel: "http://mochi.test:8888", icon: "icon.png", expectError: matchInvalidPanelURL},
+      // Invalid icon urls (validated inside the API method because of the empty icon string
+      // which have to be resolved to the default icon, reject the returned promise).
+      {panel: "panel.html", icon: "about:about", expectError: matchInvalidIconURL},
+      {panel: "panel.html", icon: "http://mochi.test:8888", expectError: matchInvalidIconURL},
+      // Valid panel urls
+      {panel: "panel.html", icon: "icon.png"},
+      {panel: "./panel.html", icon: "icon.png"},
+      {panel: "/panel.html", icon: "icon.png"},
+      {panel: "/panel.html", icon: ""},
+    ];
+
+    browser.test.onMessage.addListener(async msg => {
+      if (msg !== "start_test_panel_create") {
+        return;
+      }
+
+      for (let {panel, icon, expectError} of test_cases) {
+        browser.test.log(`Testing devtools.panels.create for ${JSON.stringify({panel, icon})}`);
+
+        if (expectError) {
+          // Verify that invalid panel urls throw.
+          browser.test.assertThrows(
+            () => browser.devtools.panels.create("Test Panel", icon, panel),
+            expectError,
+            "Got the expected rejection on creating a devtools panel with " +
+            `panel url ${panel} and icon ${icon}`
+          );
+        } else {
+          // Verify that with valid panel and icon urls the panel is created and loaded
+          // as expected.
+          try {
+            const pane = await browser.devtools.panels.create("Test Panel", icon, panel);
+
+            // Wait the panel to be loaded.
+            const oncePanelLoaded = new Promise(resolve => {
+              pane.onShown.addListener(paneWin => {
+                browser.test.assertTrue(
+                  paneWin.location.href.endsWith("/panel.html"),
+                  `The panel has loaded the expected extension URL with ${panel}`);
+                resolve();
+              });
+            });
+
+            // Ask the privileged code to select the last created panel.
+            browser.test.sendMessage("select-devtools-panel");
+            await oncePanelLoaded;
+          } catch (err) {
+            browser.test.fail("Unexpected failure on creating a devtools panel with " +
+                              `panel url ${panel} and icon ${icon}`);
+          }
+        }
+      }
+
+      browser.test.sendMessage("test_invalid_devtools_panel_urls_done");
+    });
+
+    browser.test.sendMessage("devtools_page_ready");
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      devtools_page: "devtools_page.html",
+      icons: {
+        "32": "icon.png",
+      },
+    },
+    files: {
+      "devtools_page.html": `<!DOCTYPE html>
+        <html>
+         <head>
+           <meta charset="utf-8">
+         </head>
+         <body>
+           <script src="devtools_page.js"></script>
+         </body>
+        </html>`,
+      "devtools_page.js": devtools_page,
+      "panel.html":  `<!DOCTYPE html>
+        <html>
+         <head>
+           <meta charset="utf-8">
+         </head>
+         <body>
+           DEVTOOLS PANEL
+         </body>
+        </html>`,
+      "icon.png": imageBuffer,
+      "default-icon.png": imageBuffer,
+    },
+  });
+
+  await extension.startup();
+
+  let target = gDevTools.getTargetForTab(tab);
+
+  let toolbox = await gDevTools.showToolbox(target, "webconsole");
+
+  extension.onMessage("select-devtools-panel", () => {
+    const toolboxAdditionalTools = toolbox.getAdditionalTools();
+    const lastTool = toolboxAdditionalTools[toolboxAdditionalTools.length - 1];
+
+    gDevTools.showToolbox(target, lastTool.id);
+  });
+
+  info("developer toolbox opened");
+
+  await extension.awaitMessage("devtools_page_ready");
+
+  extension.sendMessage("start_test_panel_create");
+
+  await extension.awaitMessage("test_invalid_devtools_panel_urls_done");
+
+  await gDevTools.closeToolbox(target);
+  await target.destroy();
+
+  await extension.unload();
+
+  await BrowserTestUtils.removeTab(tab);
+});