Bug 1390464 - Add windowId parameter in sidebarAction methods r=mixedpuppy

MozReview-Commit-ID: eSJnVzpNvO

--HG--
extra : rebase_source : 5837207b8375649c5ebc24e27a6dcc6894d6d40b
This commit is contained in:
Oriol Brufau 2018-01-28 20:46:24 +01:00
Родитель 263541211d
Коммит 2b62ae8f00
3 изменённых файлов: 338 добавлений и 178 удалений

Просмотреть файл

@ -4,6 +4,10 @@
ChromeUtils.import("resource://gre/modules/ExtensionParent.jsm"); ChromeUtils.import("resource://gre/modules/ExtensionParent.jsm");
var {
ExtensionError,
} = ExtensionUtils;
var { var {
IconDetails, IconDetails,
} = ExtensionParent; } = ExtensionParent;
@ -50,8 +54,13 @@ this.sidebarAction = class extends ExtensionAPI {
}; };
this.globals = Object.create(this.defaults); this.globals = Object.create(this.defaults);
this.tabContext = new TabContext(tab => Object.create(this.globals), this.tabContext = new TabContext(target => {
extension); let window = target.ownerGlobal;
if (target === window) {
return Object.create(this.globals);
}
return Object.create(this.tabContext.get(window));
}, extension);
// We need to ensure our elements are available before session restore. // We need to ensure our elements are available before session restore.
this.windowOpenListener = (window) => { this.windowOpenListener = (window) => {
@ -248,16 +257,18 @@ this.sidebarAction = class extends ExtensionAPI {
/** /**
* Update the broadcaster and menuitem when the extension changes the icon, * Update the broadcaster and menuitem when the extension changes the icon,
* title, url, etc. If it only changes a parameter for a single * title, url, etc. If it only changes a parameter for a single tab, `target`
* tab, `tab` will be that tab. Otherwise it will be null. * will be that tab. If it only changes a parameter for a single window,
* `target` will be that window. Otherwise `target` will be null.
* *
* @param {XULElement|null} nativeTab * @param {XULElement|ChromeWindow|null} target
* Browser tab, may be null. * Browser tab or browser chrome window, may be null.
*/ */
updateOnChange(nativeTab) { updateOnChange(target) {
if (nativeTab) { if (target) {
if (nativeTab.selected) { let window = target.ownerGlobal;
this.updateWindow(nativeTab.ownerGlobal); if (target === window || target.selected) {
this.updateWindow(window);
} }
} else { } else {
for (let window of windowTracker.browserWindows()) { for (let window of windowTracker.browserWindows()) {
@ -267,46 +278,71 @@ this.sidebarAction = class extends ExtensionAPI {
} }
/** /**
* Set a default or tab specific property. * Gets the target object and its associated values corresponding to
* the `details` parameter of the various get* and set* API methods.
* *
* @param {XULElement|null} nativeTab * @param {Object} details
* Webextension tab object, may be null. * An object with optional `tabId` or `windowId` properties.
* @throws if both `tabId` and `windowId` are specified, or if they are invalid.
* @returns {Object}
* An object with two properties: `target` and `values`.
* - If a `tabId` was specified, `target` will be the corresponding
* XULElement tab. If a `windowId` was specified, `target` will be
* the corresponding ChromeWindow. Otherwise it will be `null`.
* - `values` will contain the icon, title and panel associated with
* the target.
*/
getContextData({tabId, windowId}) {
if (tabId != null && windowId != null) {
throw new ExtensionError("Only one of tabId and windowId can be specified.");
}
let target, values;
if (tabId != null) {
target = tabTracker.getTab(tabId);
values = this.tabContext.get(target);
} else if (windowId != null) {
target = windowTracker.getWindow(windowId);
values = this.tabContext.get(target);
} else {
target = null;
values = this.globals;
}
return {target, values};
}
/**
* Set a global, window specific or tab specific property.
*
* @param {Object} details
* An object with optional `tabId` or `windowId` properties.
* @param {string} prop * @param {string} prop
* String property to retrieve ["icon", "title", or "panel"]. * String property to set ["icon", "title", or "panel"].
* @param {string} value * @param {string} value
* Value for property. * Value for property.
*/ */
setProperty(nativeTab, prop, value) { setProperty(details, prop, value) {
let values; let {target, values} = this.getContextData(details);
if (nativeTab === null) {
values = this.globals;
} else {
values = this.tabContext.get(nativeTab);
}
if (value === null) { if (value === null) {
delete values[prop]; delete values[prop];
} else { } else {
values[prop] = value; values[prop] = value;
} }
this.updateOnChange(nativeTab); this.updateOnChange(target);
} }
/** /**
* Retrieve a property from the tab or globals if tab is null. * Retrieve the value of a global, window specific or tab specific property.
* *
* @param {XULElement|null} nativeTab * @param {Object} details
* Browser tab object, may be null. * An object with optional `tabId` or `windowId` properties.
* @param {string} prop * @param {string} prop
* String property to retrieve ["icon", "title", or "panel"] * String property to retrieve ["icon", "title", or "panel"]
* @returns {string} value * @returns {string} value
* Value for prop. * Value of prop.
*/ */
getProperty(nativeTab, prop) { getProperty(details, prop) {
if (nativeTab === null) { return this.getContextData(details).values[prop];
return this.globals[prop];
}
return this.tabContext.get(nativeTab)[prop];
} }
/** /**
@ -360,40 +396,25 @@ this.sidebarAction = class extends ExtensionAPI {
let {extension} = context; let {extension} = context;
const sidebarAction = this; const sidebarAction = this;
function getTab(tabId) {
if (tabId !== null) {
return tabTracker.getTab(tabId);
}
return null;
}
return { return {
sidebarAction: { sidebarAction: {
async setTitle(details) { async setTitle(details) {
let nativeTab = getTab(details.tabId); sidebarAction.setProperty(details, "title", details.title);
sidebarAction.setProperty(nativeTab, "title", details.title);
}, },
getTitle(details) { getTitle(details) {
let nativeTab = getTab(details.tabId); return sidebarAction.getProperty(details, "title");
let title = sidebarAction.getProperty(nativeTab, "title");
return Promise.resolve(title);
}, },
async setIcon(details) { async setIcon(details) {
let nativeTab = getTab(details.tabId);
let icon = IconDetails.normalize(details, extension, context); let icon = IconDetails.normalize(details, extension, context);
if (!Object.keys(icon).length) { if (!Object.keys(icon).length) {
icon = null; icon = null;
} }
sidebarAction.setProperty(nativeTab, "icon", icon); sidebarAction.setProperty(details, "icon", icon);
}, },
async setPanel(details) { async setPanel(details) {
let nativeTab = getTab(details.tabId);
let url; let url;
// Clear the url when given null or empty string. // Clear the url when given null or empty string.
if (!details.panel) { if (!details.panel) {
@ -405,14 +426,11 @@ this.sidebarAction = class extends ExtensionAPI {
} }
} }
sidebarAction.setProperty(nativeTab, "panel", url); sidebarAction.setProperty(details, "panel", url);
}, },
getPanel(details) { getPanel(details) {
let nativeTab = getTab(details.tabId); return sidebarAction.getProperty(details, "panel");
let panel = sidebarAction.getProperty(nativeTab, "panel");
return Promise.resolve(panel);
}, },
open() { open() {

Просмотреть файл

@ -74,6 +74,12 @@
"type": "integer", "type": "integer",
"optional": true, "optional": true,
"description": "Sets the sidebar title for the tab specified by tabId. Automatically resets when the tab is closed." "description": "Sets the sidebar title for the tab specified by tabId. Automatically resets when the tab is closed."
},
"windowId": {
"type": "integer",
"optional": true,
"minimum": -2,
"description": "Sets the sidebar title for the window specified by windowId."
} }
} }
} }
@ -92,7 +98,13 @@
"tabId": { "tabId": {
"type": "integer", "type": "integer",
"optional": true, "optional": true,
"description": "Specify the tab to get the title from. If no tab is specified, the non-tab-specific title is returned." "description": "Specify the tab to get the title from. If no tab nor window is specified, the global title is returned."
},
"windowId": {
"type": "integer",
"optional": true,
"minimum": -2,
"description": "Specify the window to get the title from. If no tab nor window is specified, the global title is returned."
} }
} }
} }
@ -137,6 +149,12 @@
"type": "integer", "type": "integer",
"optional": true, "optional": true,
"description": "Sets the sidebar icon for the tab specified by tabId. Automatically resets when the tab is closed." "description": "Sets the sidebar icon for the tab specified by tabId. Automatically resets when the tab is closed."
},
"windowId": {
"type": "integer",
"optional": true,
"minimum": -2,
"description": "Sets the sidebar icon for the window specified by windowId."
} }
} }
} }
@ -158,6 +176,12 @@
"minimum": 0, "minimum": 0,
"description": "Sets the sidebar url for the tab specified by tabId. Automatically resets when the tab is closed." "description": "Sets the sidebar url for the tab specified by tabId. Automatically resets when the tab is closed."
}, },
"windowId": {
"type": "integer",
"optional": true,
"minimum": -2,
"description": "Sets the sidebar url for the window specified by windowId."
},
"panel": { "panel": {
"choices": [ "choices": [
{"type": "string"}, {"type": "string"},
@ -182,7 +206,13 @@
"tabId": { "tabId": {
"type": "integer", "type": "integer",
"optional": true, "optional": true,
"description": "Specify the tab to get the sidebar from. If no tab is specified, the non-tab-specific sidebar is returned." "description": "Specify the tab to get the panel from. If no tab nor window is specified, the global panel is returned."
},
"windowId": {
"type": "integer",
"optional": true,
"minimum": -2,
"description": "Specify the window to get the panel from. If no tab nor window is specified, the global panel is returned."
} }
} }
} }

Просмотреть файл

@ -11,22 +11,19 @@ SpecialPowers.pushPrefEnv({
async function runTests(options) { async function runTests(options) {
async function background(getTests) { async function background(getTests) {
async function checkDetails(expecting, tabId) { async function checkDetails(expecting, details) {
let title = await browser.sidebarAction.getTitle({tabId}); let title = await browser.sidebarAction.getTitle(details);
browser.test.assertEq(expecting.title, title, browser.test.assertEq(expecting.title, title,
"expected value from getTitle"); "expected value from getTitle in " + JSON.stringify(details));
let panel = await browser.sidebarAction.getPanel({tabId}); let panel = await browser.sidebarAction.getPanel(details);
browser.test.assertEq(expecting.panel, panel, browser.test.assertEq(expecting.panel, panel,
"expected value from getPanel"); "expected value from getPanel in " + JSON.stringify(details));
} }
let expectDefaults = expecting => {
return checkDetails(expecting);
};
let tabs = []; let tabs = [];
let tests = getTests(tabs, expectDefaults); let windows = [];
let tests = getTests(tabs, windows);
{ {
let tabId = 0xdeadbeef; let tabId = 0xdeadbeef;
@ -49,15 +46,21 @@ async function runTests(options) {
function nextTest() { function nextTest() {
let test = tests.shift(); let test = tests.shift();
test(async expecting => { test(async (expectTab, expectWindow, expectGlobal, expectDefault) => {
expectGlobal = {...expectDefault, ...expectGlobal};
expectWindow = {...expectGlobal, ...expectWindow};
expectTab = {...expectWindow, ...expectTab};
// Check that the API returns the expected values, and then // Check that the API returns the expected values, and then
// run the next test. // run the next test.
let tabs = await browser.tabs.query({active: true, currentWindow: true}); let [{windowId, id: tabId}] = await browser.tabs.query({active: true, currentWindow: true});
await checkDetails(expecting, tabs[0].id); await checkDetails(expectTab, {tabId});
await checkDetails(expectWindow, {windowId});
await checkDetails(expectGlobal, {});
// Check that the actual icon has the expected values, then // Check that the actual icon has the expected values, then
// run the next test. // run the next test.
browser.test.sendMessage("nextTest", expecting, tests.length); browser.test.sendMessage("nextTest", expectTab, windowId, tests.length);
}); });
} }
@ -69,9 +72,9 @@ async function runTests(options) {
nextTest(); nextTest();
}); });
browser.tabs.query({active: true, currentWindow: true}, resultTabs => { let [{id, windowId}] = await browser.tabs.query({active: true, currentWindow: true});
tabs[0] = resultTabs[0].id; tabs.push(id);
}); windows.push(windowId);
} }
let extension = ExtensionTestUtils.loadExtension({ let extension = ExtensionTestUtils.loadExtension({
@ -84,7 +87,8 @@ async function runTests(options) {
}); });
let sidebarActionId; let sidebarActionId;
function checkDetails(details) { function checkDetails(details, windowId) {
let {document} = Services.wm.getOuterWindowWithId(windowId);
if (!sidebarActionId) { if (!sidebarActionId) {
sidebarActionId = `${makeWidgetId(extension.id)}-sidebar-action`; sidebarActionId = `${makeWidgetId(extension.id)}-sidebar-action`;
} }
@ -103,8 +107,8 @@ async function runTests(options) {
} }
let awaitFinish = new Promise(resolve => { let awaitFinish = new Promise(resolve => {
extension.onMessage("nextTest", (expecting, testsRemaining) => { extension.onMessage("nextTest", (expecting, windowId, testsRemaining) => {
checkDetails(expecting); checkDetails(expecting, windowId);
if (testsRemaining) { if (testsRemaining) {
extension.sendMessage("runNextTest"); extension.sendMessage("runNextTest");
@ -149,7 +153,7 @@ add_task(async function testTabSwitchContext() {
"files": { "files": {
"default.html": sidebar, "default.html": sidebar,
"default-2.html": sidebar, "global.html": sidebar,
"2.html": sidebar, "2.html": sidebar,
"_locales/en/messages.json": { "_locales/en/messages.json": {
@ -165,40 +169,29 @@ add_task(async function testTabSwitchContext() {
}, },
"default.png": imageBuffer, "default.png": imageBuffer,
"default-2.png": imageBuffer, "global.png": imageBuffer,
"1.png": imageBuffer, "1.png": imageBuffer,
"2.png": imageBuffer, "2.png": imageBuffer,
}, },
getTests: function(tabs, expectDefaults) { getTests: function(tabs) {
let details = [ let details = [
{"icon": browser.runtime.getURL("default.png"), {"icon": browser.runtime.getURL("default.png"),
"panel": browser.runtime.getURL("default.html"), "panel": browser.runtime.getURL("default.html"),
"title": "Default Title", "title": "Default Title",
}, },
{"icon": browser.runtime.getURL("1.png"), {"icon": browser.runtime.getURL("1.png"),
"panel": browser.runtime.getURL("default.html"),
"title": "Default Title",
}, },
{"icon": browser.runtime.getURL("2.png"), {"icon": browser.runtime.getURL("2.png"),
"panel": browser.runtime.getURL("2.html"), "panel": browser.runtime.getURL("2.html"),
"title": "Title 2", "title": "Title 2",
}, },
{"icon": browser.runtime.getURL("1.png"), {"icon": browser.runtime.getURL("global.png"),
"panel": browser.runtime.getURL("default-2.html"), "panel": browser.runtime.getURL("global.html"),
"title": "Default Title 2", "title": "Global Title",
},
{"icon": browser.runtime.getURL("1.png"),
"panel": browser.runtime.getURL("default-2.html"),
"title": "Default Title 2",
},
{"icon": browser.runtime.getURL("default-2.png"),
"panel": browser.runtime.getURL("default-2.html"),
"title": "Default Title 2",
}, },
{"icon": browser.runtime.getURL("1.png"), {"icon": browser.runtime.getURL("1.png"),
"panel": browser.runtime.getURL("2.html"), "panel": browser.runtime.getURL("2.html"),
"title": "Default Title 2",
}, },
]; ];
@ -206,23 +199,20 @@ add_task(async function testTabSwitchContext() {
async expect => { async expect => {
browser.test.log("Initial state, expect default properties."); browser.test.log("Initial state, expect default properties.");
await expectDefaults(details[0]); expect(null, null, null, details[0]);
expect(details[0]);
}, },
async expect => { async expect => {
browser.test.log("Change the icon in the current tab. Expect default properties excluding the icon."); browser.test.log("Change the icon in the current tab. Expect default properties excluding the icon.");
await browser.sidebarAction.setIcon({tabId: tabs[0], path: "1.png"}); await browser.sidebarAction.setIcon({tabId: tabs[0], path: "1.png"});
await expectDefaults(details[0]); expect(details[1], null, null, details[0]);
expect(details[1]);
}, },
async expect => { async expect => {
browser.test.log("Create a new tab. Expect default properties."); browser.test.log("Create a new tab. Expect default properties.");
let tab = await browser.tabs.create({active: true, url: "about:blank?0"}); let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
tabs.push(tab.id); tabs.push(tab.id);
await expectDefaults(details[0]); expect(null, null, null, details[0]);
expect(details[0]);
}, },
async expect => { async expect => {
browser.test.log("Change properties. Expect new properties."); browser.test.log("Change properties. Expect new properties.");
@ -232,8 +222,7 @@ add_task(async function testTabSwitchContext() {
browser.sidebarAction.setPanel({tabId, panel: "2.html"}), browser.sidebarAction.setPanel({tabId, panel: "2.html"}),
browser.sidebarAction.setTitle({tabId, title: "Title 2"}), browser.sidebarAction.setTitle({tabId, title: "Title 2"}),
]); ]);
await expectDefaults(details[0]); expect(details[2], null, null, details[0]);
expect(details[2]);
}, },
expect => { expect => {
browser.test.log("Navigate to a new page. Expect no changes."); browser.test.log("Navigate to a new page. Expect no changes.");
@ -243,7 +232,7 @@ add_task(async function testTabSwitchContext() {
browser.tabs.onUpdated.addListener(function listener(tabId, changed) { browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
if (tabId == tabs[1] && changed.url) { if (tabId == tabs[1] && changed.url) {
browser.tabs.onUpdated.removeListener(listener); browser.tabs.onUpdated.removeListener(listener);
expect(details[2]); expect(details[2], null, null, details[0]);
} }
}); });
@ -252,53 +241,51 @@ add_task(async function testTabSwitchContext() {
async expect => { async expect => {
browser.test.log("Switch back to the first tab. Expect previously set properties."); browser.test.log("Switch back to the first tab. Expect previously set properties.");
await browser.tabs.update(tabs[0], {active: true}); await browser.tabs.update(tabs[0], {active: true});
expect(details[1]); expect(details[1], null, null, details[0]);
}, },
async expect => { async expect => {
browser.test.log("Change default values, expect those changes reflected."); browser.test.log("Change global values, expect those changes reflected.");
await Promise.all([ await Promise.all([
browser.sidebarAction.setIcon({path: "default-2.png"}), browser.sidebarAction.setIcon({path: "global.png"}),
browser.sidebarAction.setPanel({panel: "default-2.html"}), browser.sidebarAction.setPanel({panel: "global.html"}),
browser.sidebarAction.setTitle({title: "Default Title 2"}), browser.sidebarAction.setTitle({title: "Global Title"}),
]); ]);
await expectDefaults(details[3]); expect(details[1], null, details[3], details[0]);
expect(details[3]);
}, },
async expect => { async expect => {
browser.test.log("Switch back to tab 2. Expect former value, unaffected by changes to defaults in previous step."); browser.test.log("Switch back to tab 2. Expect former tab values, and new global values from previous step.");
await browser.tabs.update(tabs[1], {active: true}); await browser.tabs.update(tabs[1], {active: true});
await expectDefaults(details[3]); expect(details[2], null, details[3], details[0]);
expect(details[2]);
}, },
async expect => { async expect => {
browser.test.log("Delete tab, switch back to tab 1. Expect previous results again."); browser.test.log("Delete tab, switch back to tab 1. Expect previous results again.");
await browser.tabs.remove(tabs[1]); await browser.tabs.remove(tabs[1]);
expect(details[4]); expect(details[1], null, details[3], details[0]);
}, },
async expect => { async expect => {
browser.test.log("Create a new tab. Expect new default properties."); browser.test.log("Create a new tab. Expect new global properties.");
let tab = await browser.tabs.create({active: true, url: "about:blank?2"}); let tab = await browser.tabs.create({active: true, url: "about:blank?2"});
tabs.push(tab.id); tabs.push(tab.id);
expect(details[5]); expect(null, null, details[3], details[0]);
}, },
async expect => { async expect => {
browser.test.log("Delete tab."); browser.test.log("Delete tab.");
await browser.tabs.remove(tabs[2]); await browser.tabs.remove(tabs[2]);
expect(details[4]); expect(details[1], null, details[3], details[0]);
}, },
async expect => { async expect => {
browser.test.log("Change tab panel."); browser.test.log("Change tab panel.");
let tabId = tabs[0]; let tabId = tabs[0];
await browser.sidebarAction.setPanel({tabId, panel: "2.html"}); await browser.sidebarAction.setPanel({tabId, panel: "2.html"});
expect(details[6]); expect(details[4], null, details[3], details[0]);
}, },
async expect => { async expect => {
browser.test.log("Revert tab panel."); browser.test.log("Revert tab panel.");
let tabId = tabs[0]; let tabId = tabs[0];
await browser.sidebarAction.setPanel({tabId, panel: null}); await browser.sidebarAction.setPanel({tabId, panel: null});
expect(details[4]); expect(details[1], null, details[3], details[0]);
}, },
]; ];
}, },
@ -323,53 +310,44 @@ add_task(async function testDefaultTitle() {
"icon.png": imageBuffer, "icon.png": imageBuffer,
}, },
getTests: function(tabs, expectGlobals) { getTests: function(tabs) {
let details = [ let details = [
{"title": "Foo Extension", {"title": "Foo Extension",
"panel": browser.runtime.getURL("sidebar.html"), "panel": browser.runtime.getURL("sidebar.html"),
"icon": browser.runtime.getURL("icon.png")}, "icon": browser.runtime.getURL("icon.png")},
{"title": "Foo Title", {"title": "Foo Title"},
"panel": browser.runtime.getURL("sidebar.html"), {"title": "Bar Title"},
"icon": browser.runtime.getURL("icon.png")},
{"title": "Bar Title",
"panel": browser.runtime.getURL("sidebar.html"),
"icon": browser.runtime.getURL("icon.png")},
]; ];
return [ return [
async expect => { async expect => {
browser.test.log("Initial state. Expect default extension title."); browser.test.log("Initial state. Expect default extension title.");
await expectGlobals(details[0]); expect(null, null, null, details[0]);
expect(details[0]);
}, },
async expect => { async expect => {
browser.test.log("Change the tab title. Expect new title."); browser.test.log("Change the tab title. Expect new title.");
browser.sidebarAction.setTitle({tabId: tabs[0], title: "Foo Title"}); browser.sidebarAction.setTitle({tabId: tabs[0], title: "Foo Title"});
await expectGlobals(details[0]); expect(details[1], null, null, details[0]);
expect(details[1]);
}, },
async expect => { async expect => {
browser.test.log("Change the global title. Expect same properties."); browser.test.log("Change the global title. Expect same properties.");
browser.sidebarAction.setTitle({title: "Bar Title"}); browser.sidebarAction.setTitle({title: "Bar Title"});
await expectGlobals(details[2]); expect(details[1], null, details[2], details[0]);
expect(details[1]);
}, },
async expect => { async expect => {
browser.test.log("Clear the tab title. Expect new global title."); browser.test.log("Clear the tab title. Expect new global title.");
browser.sidebarAction.setTitle({tabId: tabs[0], title: null}); browser.sidebarAction.setTitle({tabId: tabs[0], title: null});
await expectGlobals(details[2]); expect(null, null, details[2], details[0]);
expect(details[2]);
}, },
async expect => { async expect => {
browser.test.log("Clear the global title. Expect default title."); browser.test.log("Clear the global title. Expect default title.");
browser.sidebarAction.setTitle({title: null}); browser.sidebarAction.setTitle({title: null});
await expectGlobals(details[0]); expect(null, null, null, details[0]);
expect(details[0]);
}, },
async expect => { async expect => {
browser.test.assertRejects( browser.test.assertRejects(
@ -377,8 +355,7 @@ add_task(async function testDefaultTitle() {
/Access denied for URL about:addons/, /Access denied for URL about:addons/,
"unable to set panel to about:addons"); "unable to set panel to about:addons");
await expectGlobals(details[0]); expect(null, null, null, details[0]);
expect(details[0]);
}, },
]; ];
}, },
@ -401,57 +378,66 @@ add_task(async function testPropertyRemoval() {
files: { files: {
"default.html": sidebar, "default.html": sidebar,
"p1.html": sidebar, "global.html": sidebar,
"p2.html": sidebar, "global2.html": sidebar,
"p3.html": sidebar, "window.html": sidebar,
"tab.html": sidebar,
"default.png": imageBuffer, "default.png": imageBuffer,
"i1.png": imageBuffer, "global.png": imageBuffer,
"i2.png": imageBuffer, "global2.png": imageBuffer,
"i3.png": imageBuffer, "window.png": imageBuffer,
"tab.png": imageBuffer,
}, },
getTests: function(tabs, expectGlobals) { getTests: function(tabs, windows) {
let defaultIcon = "chrome://browser/content/extension.svg"; let defaultIcon = "chrome://browser/content/extension.svg";
let details = [ let details = [
{"icon": browser.runtime.getURL("default.png"), {"icon": browser.runtime.getURL("default.png"),
"panel": browser.runtime.getURL("default.html"), "panel": browser.runtime.getURL("default.html"),
"title": "Default Title"}, "title": "Default Title"},
{"icon": browser.runtime.getURL("i1.png"), {"icon": browser.runtime.getURL("global.png"),
"panel": browser.runtime.getURL("p1.html"), "panel": browser.runtime.getURL("global.html"),
"title": "t1"}, "title": "global"},
{"icon": browser.runtime.getURL("i2.png"), {"icon": browser.runtime.getURL("window.png"),
"panel": browser.runtime.getURL("p2.html"), "panel": browser.runtime.getURL("window.html"),
"title": "t2"}, "title": "window"},
{"icon": browser.runtime.getURL("tab.png"),
"panel": browser.runtime.getURL("tab.html"),
"title": "tab"},
{"icon": defaultIcon, {"icon": defaultIcon,
"panel": browser.runtime.getURL("p1.html"),
"title": ""}, "title": ""},
{"icon": browser.runtime.getURL("i3.png"), {"icon": browser.runtime.getURL("global2.png"),
"panel": browser.runtime.getURL("p3.html"), "panel": browser.runtime.getURL("global2.html"),
"title": "t3"}, "title": "global2"},
]; ];
return [ return [
async expect => { async expect => {
browser.test.log("Initial state, expect default properties."); browser.test.log("Initial state, expect default properties.");
await expectGlobals(details[0]); expect(null, null, null, details[0]);
expect(details[0]);
}, },
async expect => { async expect => {
browser.test.log("Set global values, expect the new values."); browser.test.log("Set global values, expect the new values.");
browser.sidebarAction.setIcon({path: "i1.png"}); browser.sidebarAction.setIcon({path: "global.png"});
browser.sidebarAction.setPanel({panel: "p1.html"}); browser.sidebarAction.setPanel({panel: "global.html"});
browser.sidebarAction.setTitle({title: "t1"}); browser.sidebarAction.setTitle({title: "global"});
await expectGlobals(details[1]); expect(null, null, details[1], details[0]);
expect(details[1]); },
async expect => {
browser.test.log("Set window values, expect the new values.");
let windowId = windows[0];
browser.sidebarAction.setIcon({windowId, path: "window.png"});
browser.sidebarAction.setPanel({windowId, panel: "window.html"});
browser.sidebarAction.setTitle({windowId, title: "window"});
expect(null, details[2], details[1], details[0]);
}, },
async expect => { async expect => {
browser.test.log("Set tab values, expect the new values."); browser.test.log("Set tab values, expect the new values.");
let tabId = tabs[0]; let tabId = tabs[0];
browser.sidebarAction.setIcon({tabId, path: "i2.png"}); browser.sidebarAction.setIcon({tabId, path: "tab.png"});
browser.sidebarAction.setPanel({tabId, panel: "p2.html"}); browser.sidebarAction.setPanel({tabId, panel: "tab.html"});
browser.sidebarAction.setTitle({tabId, title: "t2"}); browser.sidebarAction.setTitle({tabId, title: "tab"});
await expectGlobals(details[1]); expect(details[3], details[2], details[1], details[0]);
expect(details[2]);
}, },
async expect => { async expect => {
browser.test.log("Set empty tab values."); browser.test.log("Set empty tab values.");
@ -459,33 +445,159 @@ add_task(async function testPropertyRemoval() {
browser.sidebarAction.setIcon({tabId, path: ""}); browser.sidebarAction.setIcon({tabId, path: ""});
browser.sidebarAction.setPanel({tabId, panel: ""}); browser.sidebarAction.setPanel({tabId, panel: ""});
browser.sidebarAction.setTitle({tabId, title: ""}); browser.sidebarAction.setTitle({tabId, title: ""});
await expectGlobals(details[1]); expect(details[4], details[2], details[1], details[0]);
expect(details[3]);
}, },
async expect => { async expect => {
browser.test.log("Remove tab values, expect global values."); browser.test.log("Remove tab values, expect window values.");
let tabId = tabs[0]; let tabId = tabs[0];
browser.sidebarAction.setIcon({tabId, path: null}); browser.sidebarAction.setIcon({tabId, path: null});
browser.sidebarAction.setPanel({tabId, panel: null}); browser.sidebarAction.setPanel({tabId, panel: null});
browser.sidebarAction.setTitle({tabId, title: null}); browser.sidebarAction.setTitle({tabId, title: null});
await expectGlobals(details[1]); expect(null, details[2], details[1], details[0]);
expect(details[1]); },
async expect => {
browser.test.log("Remove window values, expect global values.");
let windowId = windows[0];
browser.sidebarAction.setIcon({windowId, path: null});
browser.sidebarAction.setPanel({windowId, panel: null});
browser.sidebarAction.setTitle({windowId, title: null});
expect(null, null, details[1], details[0]);
}, },
async expect => { async expect => {
browser.test.log("Change global values, expect the new values."); browser.test.log("Change global values, expect the new values.");
browser.sidebarAction.setIcon({path: "i3.png"}); browser.sidebarAction.setIcon({path: "global2.png"});
browser.sidebarAction.setPanel({panel: "p3.html"}); browser.sidebarAction.setPanel({panel: "global2.html"});
browser.sidebarAction.setTitle({title: "t3"}); browser.sidebarAction.setTitle({title: "global2"});
await expectGlobals(details[4]); expect(null, null, details[5], details[0]);
expect(details[4]);
}, },
async expect => { async expect => {
browser.test.log("Remove global values, expect defaults."); browser.test.log("Remove global values, expect defaults.");
browser.sidebarAction.setIcon({path: null}); browser.sidebarAction.setIcon({path: null});
browser.sidebarAction.setPanel({panel: null}); browser.sidebarAction.setPanel({panel: null});
browser.sidebarAction.setTitle({title: null}); browser.sidebarAction.setTitle({title: null});
await expectGlobals(details[0]); expect(null, null, null, details[0]);
expect(details[0]); },
];
},
});
});
add_task(async function testMultipleWindows() {
await runTests({
manifest: {
"name": "Foo Extension",
"sidebar_action": {
"default_icon": "default.png",
"default_panel": "default.html",
"default_title": "Default Title",
},
"permissions": ["tabs"],
},
files: {
"default.html": sidebar,
"window1.html": sidebar,
"window2.html": sidebar,
"default.png": imageBuffer,
"window1.png": imageBuffer,
"window2.png": imageBuffer,
},
getTests: function(tabs, windows) {
let details = [
{"icon": browser.runtime.getURL("default.png"),
"panel": browser.runtime.getURL("default.html"),
"title": "Default Title"},
{"icon": browser.runtime.getURL("window1.png"),
"panel": browser.runtime.getURL("window1.html"),
"title": "window1"},
{"icon": browser.runtime.getURL("window2.png"),
"panel": browser.runtime.getURL("window2.html"),
"title": "window2"},
{"title": "tab"},
];
return [
async expect => {
browser.test.log("Initial state, expect default properties.");
expect(null, null, null, details[0]);
},
async expect => {
browser.test.log("Set window values, expect the new values.");
let windowId = windows[0];
browser.sidebarAction.setIcon({windowId, path: "window1.png"});
browser.sidebarAction.setPanel({windowId, panel: "window1.html"});
browser.sidebarAction.setTitle({windowId, title: "window1"});
expect(null, details[1], null, details[0]);
},
async expect => {
browser.test.log("Create a new tab, expect window values.");
let tab = await browser.tabs.create({active: true});
tabs.push(tab.id);
expect(null, details[1], null, details[0]);
},
async expect => {
browser.test.log("Set a tab title, expect it.");
await browser.sidebarAction.setTitle({tabId: tabs[1], title: "tab"});
expect(details[3], details[1], null, details[0]);
},
async expect => {
browser.test.log("Open a new window, expect default values.");
let {id} = await browser.windows.create();
windows.push(id);
expect(null, null, null, details[0]);
},
async expect => {
browser.test.log("Set window values, expect the new values.");
let windowId = windows[1];
browser.sidebarAction.setIcon({windowId, path: "window2.png"});
browser.sidebarAction.setPanel({windowId, panel: "window2.html"});
browser.sidebarAction.setTitle({windowId, title: "window2"});
expect(null, details[2], null, details[0]);
},
async expect => {
browser.test.log("Move tab from old window to the new one. Tab-specific data"
+ " is cleared (bug 1451176) and inheritance is from the new window");
await browser.tabs.move(tabs[1], {windowId: windows[1], index: -1});
await browser.tabs.update(tabs[1], {active: true});
expect(null, details[2], null, details[0]);
},
async expect => {
browser.test.log("Close the tab, expect window values.");
await browser.tabs.remove(tabs[1]);
expect(null, details[2], null, details[0]);
},
async expect => {
browser.test.log("Close the new window and go back to the previous one.");
await browser.windows.remove(windows[1]);
expect(null, details[1], null, details[0]);
},
async expect => {
browser.test.log("Assert failures for bad parameters. Expect no change");
let calls = {
setIcon: {path: "default.png"},
setPanel: {panel: "default.html"},
setTitle: {title: "Default Title"},
getPanel: {},
getTitle: {},
};
for (let [method, arg] of Object.entries(calls)) {
browser.test.assertThrows(
() => browser.sidebarAction[method]({...arg, windowId: -3}),
/-3 is too small \(must be at least -2\)/,
method + " with invalid windowId",
);
await browser.test.assertRejects(
browser.sidebarAction[method]({...arg, tabId: tabs[0], windowId: windows[0]}),
/Only one of tabId and windowId can be specified/,
method + " with both tabId and windowId",
);
}
expect(null, details[1], null, details[0]);
}, },
]; ];
}, },