# HG changeset patch # User Luca Greco # Date 1513272059 -3600 # Thu Dec 14 18:20:59 2017 +0100 # Node ID aca965dcf4386ed4bf92f5ac7da70f9d8fa84907 # Parent b346d072341c92572930db2a923f439256d2d978 Bug 1425224 - Use manifest.ExtensionURL in devtools.panels.create API schema. r=mixedpuppy a=gchang MozReview-Commit-ID: AR6j1fC0PmJ diff --git a/browser/components/extensions/schemas/devtools_panels.json b/browser/components/extensions/schemas/devtools_panels.json --- a/browser/components/extensions/schemas/devtools_panels.json +++ b/browser/components/extensions/schemas/devtools_panels.json @@ -331,22 +331,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": [ diff --git a/browser/components/extensions/test/browser/browser_ext_devtools_panel.js b/browser/components/extensions/test/browser/browser_ext_devtools_panel.js --- a/browser/components/extensions/test/browser/browser_ext_devtools_panel.js +++ b/browser/components/extensions/test/browser/browser_ext_devtools_panel.js @@ -304,8 +304,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": ` + + + + + + + + `, + "devtools_page.js": devtools_page, + "panel.html": ` + + + + + + DEVTOOLS PANEL + + `, + "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); +});