--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
#
# Modifying this file will now automatically clobber the buildbot machines \o/
#
# Are you updating CLOBBER because you think it's needed for your WebIDL
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
-bug 1313485 - OS X bustage requires clobber to fix
+Bug 1277704 - jemalloc may need a clobber
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -368,16 +368,19 @@ AccessibleWrap::CreateMaiInterfaces(void
if (IsLink())
interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
if (!nsAccUtils::MustPrune(this)) { // These interfaces require children
// Table interface.
if (AsTable())
interfacesBits |= 1 << MAI_INTERFACE_TABLE;
+ if (AsTableCell())
+ interfacesBits |= 1 << MAI_INTERFACE_TABLE_CELL;
+
// Selection interface.
if (IsSelect()) {
interfacesBits |= 1 << MAI_INTERFACE_SELECTION;
}
}
return interfacesBits;
}
@@ -1125,16 +1128,19 @@ GetInterfacesForProxy(ProxyAccessible* a
interfaces |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
if (aInterfaces & Interfaces::VALUE)
interfaces |= 1 << MAI_INTERFACE_VALUE;
if (aInterfaces & Interfaces::TABLE)
interfaces |= 1 << MAI_INTERFACE_TABLE;
+ if (aInterfaces & Interfaces::TABLECELL)
+ interfaces |= 1 << MAI_INTERFACE_TABLE_CELL;
+
if (aInterfaces & Interfaces::IMAGE)
interfaces |= 1 << MAI_INTERFACE_IMAGE;
if (aInterfaces & Interfaces::DOCUMENT)
interfaces |= 1 << MAI_INTERFACE_DOCUMENT;
if (aInterfaces & Interfaces::SELECTION) {
interfaces |= 1 << MAI_INTERFACE_SELECTION;
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -623,18 +623,16 @@ function promiseTabLoadEvent(tab, url)
info(`Skipping spurious load event for ${loadedUrl}`);
return false;
}
info("Tab event received: load");
return true;
}
- // Create two promises: one resolved from the content process when the page
- // loads and one that is rejected if we take too long to load the url.
let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
if (url)
BrowserTestUtils.loadURI(tab.linkedBrowser, url);
return loaded;
}
--- a/browser/base/content/test/plugins/head.js
+++ b/browser/base/content/test/plugins/head.js
@@ -85,18 +85,16 @@ function promiseTabLoadEvent(tab, url) {
info(`Skipping spurious load event for ${loadedUrl}`);
return false;
}
info("Tab event received: load");
return true;
}
- // Create two promises: one resolved from the content process when the page
- // loads and one that is rejected if we take too long to load the url.
let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
if (url)
BrowserTestUtils.loadURI(tab.linkedBrowser, url);
return loaded;
}
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -4,16 +4,17 @@
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
Cu.import("resource://gre/modules/MatchPattern.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var {
EventManager,
+ ExtensionError,
IconDetails,
} = ExtensionUtils;
// Map[Extension -> Map[ID -> MenuItem]]
// Note: we want to enumerate all the menu items so
// this cannot be a weak map.
var gContextMenuMap = new Map();
@@ -321,17 +322,17 @@ MenuItem.prototype = {
return;
}
let menuMap = gContextMenuMap.get(this.extension);
if (!menuMap.has(parentId)) {
throw new Error("Could not find any MenuItem with id: " + parentId);
}
for (let item = menuMap.get(parentId); item; item = item.parent) {
if (item === this) {
- throw new Error("MenuItem cannot be an ancestor (or self) of its new parent.");
+ throw new ExtensionError("MenuItem cannot be an ancestor (or self) of its new parent.");
}
}
},
set parentId(parentId) {
this.ensureValidParentId(parentId);
if (this.parent) {
--- a/browser/components/extensions/test/browser/.eslintrc.js
+++ b/browser/components/extensions/test/browser/.eslintrc.js
@@ -24,9 +24,13 @@ module.exports = { // eslint-disable-li
"closeContextMenu": true,
"closeExtensionContextMenu": true,
"focusWindow": true,
"makeWidgetId": true,
"openContextMenu": true,
"openExtensionContextMenu": true,
"CustomizableUI": true,
},
+
+ "rules": {
+ "no-shadow": 0,
+ },
};
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
@@ -1,45 +1,31 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
function* runTests(options) {
- function background(getTests) {
- // Gets the current details of the browser action, and returns a
- // promise that resolves to an object containing them.
- function getDetails(tabId) {
- return Promise.all([
- browser.browserAction.getTitle({tabId}),
- browser.browserAction.getPopup({tabId}),
- browser.browserAction.getBadgeText({tabId}),
- browser.browserAction.getBadgeBackgroundColor({tabId})]
- ).then(details => {
- return Promise.resolve({title: details[0],
- popup: details[1],
- badge: details[2],
- badgeBackgroundColor: details[3]});
- });
- }
+ async function background(getTests) {
+ async function checkDetails(expecting, tabId) {
+ let title = await browser.browserAction.getTitle({tabId});
+ browser.test.assertEq(expecting.title, title,
+ "expected value from getTitle");
- function checkDetails(expecting, tabId) {
- return getDetails(tabId).then(details => {
- browser.test.assertEq(expecting.title, details.title,
- "expected value from getTitle");
-
- browser.test.assertEq(expecting.popup, details.popup,
- "expected value from getPopup");
+ let popup = await browser.browserAction.getPopup({tabId});
+ browser.test.assertEq(expecting.popup, popup,
+ "expected value from getPopup");
- browser.test.assertEq(expecting.badge, details.badge,
- "expected value from getBadge");
+ let badge = await browser.browserAction.getBadgeText({tabId});
+ browser.test.assertEq(expecting.badge, badge,
+ "expected value from getBadge");
- browser.test.assertEq(String(expecting.badgeBackgroundColor),
- String(details.badgeBackgroundColor),
- "expected value from getBadgeBackgroundColor");
- });
+ let badgeBackgroundColor = await browser.browserAction.getBadgeBackgroundColor({tabId});
+ browser.test.assertEq(String(expecting.badgeBackgroundColor),
+ String(badgeBackgroundColor),
+ "expected value from getBadgeBackgroundColor");
}
let expectDefaults = expecting => {
return checkDetails(expecting);
};
let tabs = [];
let tests = getTests(tabs, expectDefaults);
@@ -52,49 +38,37 @@ function* runTests(options) {
() => browser.browserAction.setTitle({tabId, title: "foo"}),
() => browser.browserAction.setIcon({tabId, path: "foo.png"}),
() => browser.browserAction.setPopup({tabId, popup: "foo.html"}),
() => browser.browserAction.setBadgeText({tabId, text: "foo"}),
() => browser.browserAction.setBadgeBackgroundColor({tabId, color: [0xff, 0, 0, 0xff]}),
];
for (let call of calls) {
- let checkError = e => {
- browser.test.assertTrue(e.message.includes(`Invalid tab ID: ${tabId}`),
- `Expected invalid tab ID error, got ${e}`);
- };
- try {
- call().then(() => {
- browser.test.fail(`Expected call to fail: ${call}`);
- }, e => {
- checkError(e);
- });
- } catch (e) {
- checkError(e);
- }
+ await browser.test.assertRejects(
+ new Promise(resolve => resolve(call())),
+ RegExp(`Invalid tab ID: ${tabId}`),
+ "Expected invalid tab ID error");
}
}
// Runs the next test in the `tests` array, checks the results,
// and passes control back to the outer test scope.
function nextTest() {
let test = tests.shift();
- test(expecting => {
+ test(async expecting => {
// Check that the API returns the expected values, and then
// run the next test.
- new Promise(resolve => {
- return browser.tabs.query({active: true, currentWindow: true}, resolve);
- }).then(tabs => {
- return checkDetails(expecting, tabs[0].id);
- }).then(() => {
- // Check that the actual icon has the expected values, then
- // run the next test.
- browser.test.sendMessage("nextTest", expecting, tests.length);
- });
+ let tabs = await browser.tabs.query({active: true, currentWindow: true});
+ await checkDetails(expecting, tabs[0].id);
+
+ // Check that the actual icon has the expected values, then
+ // run the next test.
+ browser.test.sendMessage("nextTest", expecting, tests.length);
});
}
browser.test.onMessage.addListener((msg) => {
if (msg != "runNextTest") {
browser.test.fail("Expecting 'runNextTest' message");
}
@@ -236,117 +210,110 @@ add_task(function* testTabSwitchContext(
{"icon": browser.runtime.getURL("default-2.png"),
"popup": browser.runtime.getURL("default-2.html"),
"title": "Default Title 2",
"badge": "d2",
"badgeBackgroundColor": [0, 0xff, 0, 0xff]},
];
return [
- expect => {
+ async expect => {
browser.test.log("Initial state, expect default properties.");
- expectDefaults(details[0]).then(() => {
- expect(details[0]);
- });
+
+ await expectDefaults(details[0]);
+ expect(details[0]);
},
- expect => {
+ async expect => {
browser.test.log("Change the icon in the current tab. Expect default properties excluding the icon.");
browser.browserAction.setIcon({tabId: tabs[0], path: "1.png"});
- expectDefaults(details[0]).then(() => {
- expect(details[1]);
- });
+
+ await expectDefaults(details[0]);
+ expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Create a new tab. Expect default properties.");
- browser.tabs.create({active: true, url: "about:blank?0"}, tab => {
- tabs.push(tab.id);
- expectDefaults(details[0]).then(() => {
- expect(details[0]);
- });
- });
+ let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
+ tabs.push(tab.id);
+
+ await expectDefaults(details[0]);
+ expect(details[0]);
},
- expect => {
+ async expect => {
browser.test.log("Change properties. Expect new properties.");
let tabId = tabs[1];
browser.browserAction.setIcon({tabId, path: "2.png"});
browser.browserAction.setPopup({tabId, popup: "2.html"});
browser.browserAction.setTitle({tabId, title: "Title 2"});
browser.browserAction.setBadgeText({tabId, text: "2"});
browser.browserAction.setBadgeBackgroundColor({tabId, color: "#ff0000"});
browser.browserAction.disable(tabId);
- expectDefaults(details[0]).then(() => {
- expect(details[2]);
- });
+ await expectDefaults(details[0]);
+ expect(details[2]);
},
expect => {
browser.test.log("Navigate to a new page. Expect no changes.");
// TODO: This listener should not be necessary, but the |tabs.update|
// callback currently fires too early in e10s windows.
browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
if (tabId == tabs[1] && changed.url) {
browser.tabs.onUpdated.removeListener(listener);
expect(details[2]);
}
});
browser.tabs.update(tabs[1], {url: "about:blank?1"});
},
- expect => {
+ async expect => {
browser.test.log("Switch back to the first tab. Expect previously set properties.");
- browser.tabs.update(tabs[0], {active: true}, () => {
- expect(details[1]);
- });
+ await browser.tabs.update(tabs[0], {active: true});
+ expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Change default values, expect those changes reflected.");
browser.browserAction.setIcon({path: "default-2.png"});
browser.browserAction.setPopup({popup: "default-2.html"});
browser.browserAction.setTitle({title: "Default Title 2"});
browser.browserAction.setBadgeText({text: "d2"});
browser.browserAction.setBadgeBackgroundColor({color: [0, 0xff, 0, 0xff]});
browser.browserAction.disable();
- expectDefaults(details[3]).then(() => {
- expect(details[3]);
- });
+
+ await expectDefaults(details[3]);
+ expect(details[3]);
},
- expect => {
+ async expect => {
browser.test.log("Re-enable by default. Expect enabled.");
browser.browserAction.enable();
- expectDefaults(details[4]).then(() => {
- expect(details[4]);
- });
+
+ await expectDefaults(details[4]);
+ expect(details[4]);
},
- expect => {
+ async expect => {
browser.test.log("Switch back to tab 2. Expect former value, unaffected by changes to defaults in previous step.");
- browser.tabs.update(tabs[1], {active: true}, () => {
- expectDefaults(details[3]).then(() => {
- expect(details[2]);
- });
- });
+ await browser.tabs.update(tabs[1], {active: true});
+
+ await expectDefaults(details[3]);
+ expect(details[2]);
},
- expect => {
+ async expect => {
browser.test.log("Delete tab, switch back to tab 1. Expect previous results again.");
- browser.tabs.remove(tabs[1], () => {
- expect(details[4]);
- });
+ await browser.tabs.remove(tabs[1]);
+ expect(details[4]);
},
- expect => {
+ async expect => {
browser.test.log("Create a new tab. Expect new default properties.");
- browser.tabs.create({active: true, url: "about:blank?2"}, tab => {
- tabs.push(tab.id);
- expect(details[5]);
- });
+ let tab = await browser.tabs.create({active: true, url: "about:blank?2"});
+ tabs.push(tab.id);
+ expect(details[5]);
},
- expect => {
+ async expect => {
browser.test.log("Delete tab.");
- browser.tabs.remove(tabs[2], () => {
- expect(details[4]);
- });
+ await browser.tabs.remove(tabs[2]);
+ expect(details[4]);
},
];
},
});
});
add_task(function* testDefaultTitle() {
yield runTests({
@@ -386,46 +353,46 @@ add_task(function* testDefaultTitle() {
{"title": "",
"popup": "",
"badge": "",
"badgeBackgroundColor": DEFAULT_BADGE_COLOR,
"icon": browser.runtime.getURL("icon.png")},
];
return [
- expect => {
+ async expect => {
browser.test.log("Initial state. Expect extension title as default title.");
- expectDefaults(details[0]).then(() => {
- expect(details[0]);
- });
+
+ await expectDefaults(details[0]);
+ expect(details[0]);
},
- expect => {
+ async expect => {
browser.test.log("Change the title. Expect new title.");
browser.browserAction.setTitle({tabId: tabs[0], title: "Foo Title"});
- expectDefaults(details[0]).then(() => {
- expect(details[1]);
- });
+
+ await expectDefaults(details[0]);
+ expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Change the default. Expect same properties.");
browser.browserAction.setTitle({title: "Bar Title"});
- expectDefaults(details[2]).then(() => {
- expect(details[1]);
- });
+
+ await expectDefaults(details[2]);
+ expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Clear the title. Expect new default title.");
browser.browserAction.setTitle({tabId: tabs[0], title: ""});
- expectDefaults(details[2]).then(() => {
- expect(details[2]);
- });
+
+ await expectDefaults(details[2]);
+ expect(details[2]);
},
- expect => {
+ async expect => {
browser.test.log("Set default title to null string. Expect null string from API, extension title in UI.");
browser.browserAction.setTitle({title: ""});
- expectDefaults(details[3]).then(() => {
- expect(details[3]);
- });
+
+ await expectDefaults(details[3]);
+ expect(details[3]);
},
];
},
});
});
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon_permissions.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon_permissions.js
@@ -15,24 +15,20 @@ add_task(function* testInvalidIconSizes(
let tabId = tabs[0].id;
let promises = [];
for (let api of ["pageAction", "browserAction"]) {
// helper function to run setIcon and check if it fails
let assertSetIconThrows = function(detail, error, message) {
detail.tabId = tabId;
promises.push(
- browser[api].setIcon(detail).then(
- () => {
- browser.test.fail("Expected an error on invalid icon size.");
- browser.test.notifyFail("setIcon with invalid icon size");
- },
- error => {
- browser.test.succeed("setIcon with invalid icon size");
- }));
+ browser.test.assertRejects(
+ browser[api].setIcon(detail),
+ /must be an integer/,
+ "setIcon with invalid icon size"));
};
let imageData = new ImageData(1, 1);
// test invalid icon size inputs
for (let type of ["path", "imageData"]) {
let img = type == "imageData" ? imageData : "test.png";
@@ -143,24 +139,20 @@ add_task(function* testSecureURLsDenied(
let urls = ["chrome://browser/content/browser.xul",
"javascript:true"];
let promises = [];
for (let url of urls) {
for (let api of ["pageAction", "browserAction"]) {
promises.push(
- browser[api].setIcon({tabId, path: url}).then(
- () => {
- browser.test.fail(`Load of '${url}' succeeded. Expected failure.`);
- browser.test.notifyFail("setIcon security tests");
- },
- error => {
- browser.test.succeed(`Load of '${url}' failed. Expected failure. ${error}`);
- }));
+ browser.test.assertRejects(
+ browser[api].setIcon({tabId, path: url}),
+ /Illegal URL/,
+ `Load of '${url}' should fail.`));
}
}
Promise.all(promises).then(() => {
browser.test.notifyPass("setIcon security tests");
});
});
},
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus.js
@@ -47,17 +47,17 @@ add_task(function* () {
gBrowser.selectedTab = tab1;
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["contextMenus"],
},
- background: function() {
+ background: async function() {
// A generic onclick callback function.
function genericOnClick(info, tab) {
browser.test.sendMessage("onclick", {info, tab});
}
browser.contextMenus.onClicked.addListener((info, tab) => {
browser.test.sendMessage("browser.contextMenus.onClicked", {info, tab});
});
@@ -117,24 +117,22 @@ add_task(function* () {
});
browser.contextMenus.remove(parentToDel);
browser.contextMenus.create({
title: "Without onclick property",
id: "ext-without-onclick",
});
- browser.contextMenus.update(parent, {parentId: child2}).then(
- () => {
- browser.test.notifyFail("contextmenus");
- },
- () => {
- browser.test.notifyPass("contextmenus");
- }
- );
+ await browser.test.assertRejects(
+ browser.contextMenus.update(parent, {parentId: child2}),
+ /cannot be an ancestor/,
+ "Should not be able to reparent an item as descendent of itself");
+
+ browser.test.notifyPass("contextmenus");
},
});
yield extension.startup();
yield extension.awaitFinish("contextmenus");
let expectedClickInfo = {
menuItemId: "ext-image",
--- a/browser/components/extensions/test/browser/browser_ext_incognito_popup.js
+++ b/browser/components/extensions/test/browser/browser_ext_incognito_popup.js
@@ -9,91 +9,92 @@ add_task(function* testIncognitoPopup()
"browser_action": {
"default_popup": "popup.html",
},
"page_action": {
"default_popup": "popup.html",
},
},
- background() {
+ background: async function() {
let resolveMessage;
browser.runtime.onMessage.addListener(msg => {
if (resolveMessage && msg.message == "popup-details") {
resolveMessage(msg);
}
});
let awaitPopup = windowId => {
return new Promise(resolve => {
resolveMessage = resolve;
}).then(msg => {
browser.test.assertEq(windowId, msg.windowId, "Got popup message from correct window");
return msg;
});
};
- let testWindow = window => {
- return browser.tabs.query({active: true, windowId: window.id}).then(([tab]) => {
- return browser.pageAction.show(tab.id);
- }).then(() => {
- browser.test.sendMessage("click-pageAction");
+ let testWindow = async window => {
+ let [tab] = await browser.tabs.query({active: true, windowId: window.id});
+
+ await browser.pageAction.show(tab.id);
+ browser.test.sendMessage("click-pageAction");
- return awaitPopup(window.id);
- }).then(msg => {
- browser.test.assertEq(window.incognito, msg.incognito, "Correct incognito status in pageAction popup");
+ let msg = await awaitPopup(window.id);
+ browser.test.assertEq(window.incognito, msg.incognito, "Correct incognito status in pageAction popup");
- browser.test.sendMessage("click-browserAction");
+ browser.test.sendMessage("click-browserAction");
- return awaitPopup(window.id);
- }).then(msg => {
- browser.test.assertEq(window.incognito, msg.incognito, "Correct incognito status in browserAction popup");
- });
+ msg = await awaitPopup(window.id);
+ browser.test.assertEq(window.incognito, msg.incognito, "Correct incognito status in browserAction popup");
};
const URL = "http://example.com/incognito";
let windowReady = new Promise(resolve => {
browser.tabs.onUpdated.addListener(function listener(tabId, changed, tab) {
if (changed.status == "complete" && tab.url == URL) {
browser.tabs.onUpdated.removeListener(listener);
resolve();
}
});
});
- browser.windows.getCurrent().then(window => {
- return testWindow(window);
- }).then(() => {
- return browser.windows.create({incognito: true, url: URL});
- }).then(window => {
- return windowReady.then(() => {
- return testWindow(window);
- }).then(() => {
- return browser.windows.remove(window.id);
- });
- }).then(() => {
+ try {
+ {
+ let window = await browser.windows.getCurrent();
+
+ await testWindow(window);
+ }
+
+ {
+ let window = await browser.windows.create({incognito: true, url: URL});
+ await windowReady;
+
+ await testWindow(window);
+
+ await browser.windows.remove(window.id);
+ }
+
browser.test.notifyPass("incognito");
- }).catch(error => {
+ } catch (error) {
browser.test.fail(`Error: ${error} :: ${error.stack}`);
browser.test.notifyFail("incognito");
- });
+ }
},
files: {
"popup.html": '<html><head><meta charset="utf-8"><script src="popup.js"></script></head></html>',
- "popup.js": function() {
- browser.windows.getCurrent().then(win => {
- browser.runtime.sendMessage({
- message: "popup-details",
- windowId: win.id,
- incognito: browser.extension.inIncognitoContext,
- });
- window.close();
+ "popup.js": async function() {
+ let win = await browser.windows.getCurrent();
+ browser.runtime.sendMessage({
+ message: "popup-details",
+ windowId: win.id,
+ incognito: browser.extension.inIncognitoContext,
});
+ window.close();
},
},
});
extension.onMessage("click-browserAction", () => {
clickBrowserAction(extension, Services.wm.getMostRecentWindow("navigator:browser"));
});
--- a/browser/components/extensions/test/browser/browser_ext_legacy_extension_context_contentscript.js
+++ b/browser/components/extensions/test/browser/browser_ext_legacy_extension_context_contentscript.js
@@ -22,27 +22,29 @@ function promiseAddonStartup(extension)
* tab info.
*/
add_task(function* test_legacy_extension_context_contentscript_connection() {
function backgroundScript() {
// Extract the assigned uuid from the background page url and send it
// in a test message.
let uuid = window.location.hostname;
- browser.test.onMessage.addListener(msg => {
+ browser.test.onMessage.addListener(async msg => {
if (msg == "open-test-tab") {
- browser.tabs.create({url: "http://example.com/"})
- .then(tab => browser.test.sendMessage("get-expected-sender-info", {
- uuid, tab,
- }));
+ let tab = await browser.tabs.create({url: "http://example.com/"});
+ browser.test.sendMessage("get-expected-sender-info",
+ {uuid, tab});
} else if (msg == "close-current-tab") {
- browser.tabs.query({active: true})
- .then(tabs => browser.tabs.remove(tabs[0].id))
- .then(() => browser.test.sendMessage("current-tab-closed", true))
- .catch(() => browser.test.sendMessage("current-tab-closed", false));
+ try {
+ let [tab] = await browser.tabs.query({active: true});
+ await browser.tabs.remove(tab.id);
+ browser.test.sendMessage("current-tab-closed", true);
+ } catch (e) {
+ browser.test.sendMessage("current-tab-closed", false);
+ }
}
});
browser.test.sendMessage("ready");
}
function contentScript() {
browser.runtime.sendMessage("webextension -> legacy_extension message", (reply) => {
--- a/browser/components/extensions/test/browser/browser_ext_optionsPage_privileges.js
+++ b/browser/components/extensions/test/browser/browser_ext_optionsPage_privileges.js
@@ -12,26 +12,27 @@ add_task(function* test_tab_options_priv
browser.test.log(`Error: ${error} :: ${error.stack}`);
browser.test.notifyFail("options-ui-privileges");
});
}
});
browser.runtime.openOptionsPage();
}
- function optionsScript() {
- browser.tabs.query({url: "http://example.com/"}).then(tabs => {
- browser.test.assertEq("http://example.com/", tabs[0].url, "Got the expect tab");
- return browser.tabs.getCurrent();
- }).then(tab => {
+ async function optionsScript() {
+ try {
+ let [tab] = await browser.tabs.query({url: "http://example.com/"});
+ browser.test.assertEq("http://example.com/", tab.url, "Got the expect tab");
+
+ tab = await browser.tabs.getCurrent();
browser.runtime.sendMessage({msgName: "removeTabId", tabId: tab.id});
- }).catch(error => {
+ } catch (error) {
browser.test.log(`Error: ${error} :: ${error.stack}`);
browser.test.notifyFail("options-ui-privileges");
- });
+ }
}
const ID = "options_privileges@tests.mozilla.org";
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "temporary",
manifest: {
applications: {gecko: {id: ID}},
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_context.js
@@ -74,108 +74,105 @@ add_task(function* testTabSwitchContext(
browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
if (tabId == details.id && changed.url == details.url) {
browser.tabs.onUpdated.removeListener(listener);
resolve();
}
});
});
};
+
return [
expect => {
browser.test.log("Initial state. No icon visible.");
expect(null);
},
- expect => {
+ async expect => {
browser.test.log("Show the icon on the first tab, expect default properties.");
- browser.pageAction.show(tabs[0]).then(() => {
- expect(details[0]);
- });
+ await browser.pageAction.show(tabs[0]);
+ expect(details[0]);
},
expect => {
browser.test.log("Change the icon. Expect default properties excluding the icon.");
browser.pageAction.setIcon({tabId: tabs[0], path: "1.png"});
expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Create a new tab. No icon visible.");
- browser.tabs.create({active: true, url: "about:blank?0"}, tab => {
- tabs.push(tab.id);
- expect(null);
- });
+ let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
+ tabs.push(tab.id);
+ expect(null);
},
expect => {
browser.test.log("Await tab load. No icon visible.");
expect(null);
},
- expect => {
+ async expect => {
browser.test.log("Change properties. Expect new properties.");
let tabId = tabs[1];
- browser.pageAction.show(tabId).then(() => {
- browser.pageAction.setIcon({tabId, path: "2.png"});
- browser.pageAction.setPopup({tabId, popup: "2.html"});
- browser.pageAction.setTitle({tabId, title: "Title 2"});
+ await browser.pageAction.show(tabId);
- expect(details[2]);
- });
+ browser.pageAction.setIcon({tabId, path: "2.png"});
+ browser.pageAction.setPopup({tabId, popup: "2.html"});
+ browser.pageAction.setTitle({tabId, title: "Title 2"});
+
+ expect(details[2]);
},
- expect => {
+ async expect => {
browser.test.log("Change the hash. Expect same properties.");
- promiseTabLoad({id: tabs[1], url: "about:blank?0#ref"}).then(() => {
- expect(details[2]);
- });
+ let promise = promiseTabLoad({id: tabs[1], url: "about:blank?0#ref"});
+ browser.tabs.update(tabs[1], {url: "about:blank?0#ref"});
+ await promise;
- browser.tabs.update(tabs[1], {url: "about:blank?0#ref"});
+ expect(details[2]);
},
expect => {
browser.test.log("Clear the title. Expect default title.");
browser.pageAction.setTitle({tabId: tabs[1], title: ""});
expect(details[3]);
},
- expect => {
+ async expect => {
browser.test.log("Navigate to a new page. Expect icon hidden.");
// TODO: This listener should not be necessary, but the |tabs.update|
// callback currently fires too early in e10s windows.
- promiseTabLoad({id: tabs[1], url: "about:blank?1"}).then(() => {
- expect(null);
- });
+ let promise = promiseTabLoad({id: tabs[1], url: "about:blank?1"});
browser.tabs.update(tabs[1], {url: "about:blank?1"});
- },
- expect => {
- browser.test.log("Show the icon. Expect default properties again.");
- browser.pageAction.show(tabs[1]).then(() => {
- expect(details[0]);
- });
+
+ await promise;
+ expect(null);
},
- expect => {
+ async expect => {
+ browser.test.log("Show the icon. Expect default properties again.");
+
+ await browser.pageAction.show(tabs[1]);
+ expect(details[0]);
+ },
+ async expect => {
browser.test.log("Switch back to the first tab. Expect previously set properties.");
- browser.tabs.update(tabs[0], {active: true}, () => {
- expect(details[1]);
- });
+ await browser.tabs.update(tabs[0], {active: true});
+ expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Hide the icon on tab 2. Switch back, expect hidden.");
- browser.pageAction.hide(tabs[1]).then(() => {
- browser.tabs.update(tabs[1], {active: true}, () => {
- expect(null);
- });
- });
+ await browser.pageAction.hide(tabs[1]);
+
+ await browser.tabs.update(tabs[1], {active: true});
+ expect(null);
},
- expect => {
+ async expect => {
browser.test.log("Switch back to tab 1. Expect previous results again.");
- browser.tabs.remove(tabs[1], () => {
- expect(details[1]);
- });
+ await browser.tabs.remove(tabs[1]);
+ expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Hide the icon. Expect hidden.");
- browser.pageAction.hide(tabs[0]).then(() => {
- expect(null);
- });
+
+ await browser.pageAction.hide(tabs[0]);
+ expect(null);
},
];
},
});
});
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_popup.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_popup.js
@@ -34,17 +34,17 @@ add_task(function* testPageActionPopup()
"data/popup-b.html": scriptPage("popup-b.js"),
"data/popup-b.js": function() {
browser.runtime.sendMessage("from-popup-b");
},
"data/background.html": scriptPage("background.js"),
- "data/background.js": function() {
+ "data/background.js": async function() {
let tabId;
let sendClick;
let tests = [
() => {
sendClick({expectEvent: false, expectPopup: "a"});
},
() => {
@@ -110,17 +110,17 @@ add_task(function* testPageActionPopup()
} else {
browser.test.fail("unexpected click event");
}
expect.event = false;
browser.test.sendMessage("next-test");
});
- browser.test.onMessage.addListener((msg) => {
+ browser.test.onMessage.addListener(msg => {
if (msg == "close-popup") {
browser.runtime.sendMessage("close-popup");
return;
}
if (msg != "next-test") {
browser.test.fail("Expecting 'next-test' message");
}
@@ -128,23 +128,21 @@ add_task(function* testPageActionPopup()
if (tests.length) {
let test = tests.shift();
test();
} else {
browser.test.notifyPass("pageaction-tests-done");
}
});
- browser.tabs.query({active: true, currentWindow: true}, tabs => {
- tabId = tabs[0].id;
+ let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+ tabId = tab.id;
- browser.pageAction.show(tabId).then(() => {
- browser.test.sendMessage("next-test");
- });
- });
+ await browser.pageAction.show(tabId);
+ browser.test.sendMessage("next-test");
},
},
});
extension.onMessage("send-click", () => {
clickPageAction(extension);
});
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_title.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_title.js
@@ -79,106 +79,100 @@ add_task(function* testTabSwitchContext(
});
});
};
return [
expect => {
browser.test.log("Initial state. No icon visible.");
expect(null);
},
- expect => {
+ async expect => {
browser.test.log("Show the icon on the first tab, expect default properties.");
- browser.pageAction.show(tabs[0]).then(() => {
- expect(details[0]);
- });
+ await browser.pageAction.show(tabs[0]);
+ expect(details[0]);
},
expect => {
browser.test.log("Change the icon. Expect default properties excluding the icon.");
browser.pageAction.setIcon({tabId: tabs[0], path: "1.png"});
expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Create a new tab. No icon visible.");
- browser.tabs.create({active: true, url: "about:blank?0"}, tab => {
- tabs.push(tab.id);
- expect(null);
- });
+ let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
+ tabs.push(tab.id);
+ expect(null);
},
expect => {
browser.test.log("Await tab load. No icon visible.");
expect(null);
},
- expect => {
+ async expect => {
browser.test.log("Change properties. Expect new properties.");
let tabId = tabs[1];
- browser.pageAction.show(tabId).then(() => {
- browser.pageAction.setIcon({tabId, path: "2.png"});
- browser.pageAction.setPopup({tabId, popup: "2.html"});
- browser.pageAction.setTitle({tabId, title: "Title 2"});
- expect(details[2]);
- });
+ await browser.pageAction.show(tabId);
+ browser.pageAction.setIcon({tabId, path: "2.png"});
+ browser.pageAction.setPopup({tabId, popup: "2.html"});
+ browser.pageAction.setTitle({tabId, title: "Title 2"});
+
+ expect(details[2]);
},
- expect => {
+ async expect => {
browser.test.log("Change the hash. Expect same properties.");
- promiseTabLoad({id: tabs[1], url: "about:blank?0#ref"}).then(() => {
- expect(details[2]);
- });
+ let promise = promiseTabLoad({id: tabs[1], url: "about:blank?0#ref"});
browser.tabs.update(tabs[1], {url: "about:blank?0#ref"});
+
+ await promise;
+ expect(details[2]);
},
expect => {
browser.test.log("Clear the title. Expect default title.");
browser.pageAction.setTitle({tabId: tabs[1], title: ""});
expect(details[3]);
},
- expect => {
+ async expect => {
browser.test.log("Navigate to a new page. Expect icon hidden.");
// TODO: This listener should not be necessary, but the |tabs.update|
// callback currently fires too early in e10s windows.
- promiseTabLoad({id: tabs[1], url: "about:blank?1"}).then(() => {
- expect(null);
- });
+ let promise = promiseTabLoad({id: tabs[1], url: "about:blank?1"});
browser.tabs.update(tabs[1], {url: "about:blank?1"});
- },
- expect => {
- browser.test.log("Show the icon. Expect default properties again.");
- browser.pageAction.show(tabs[1]).then(() => {
- expect(details[0]);
- });
+
+ await promise;
+ expect(null);
},
- expect => {
+ async expect => {
+ browser.test.log("Show the icon. Expect default properties again.");
+ await browser.pageAction.show(tabs[1]);
+ expect(details[0]);
+ },
+ async expect => {
browser.test.log("Switch back to the first tab. Expect previously set properties.");
- browser.tabs.update(tabs[0], {active: true}, () => {
- expect(details[1]);
- });
+ await browser.tabs.update(tabs[0], {active: true});
+ expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Hide the icon on tab 2. Switch back, expect hidden.");
- browser.pageAction.hide(tabs[1]).then(() => {
- browser.tabs.update(tabs[1], {active: true}, () => {
- expect(null);
- });
- });
+ await browser.pageAction.hide(tabs[1]);
+ await browser.tabs.update(tabs[1], {active: true});
+ expect(null);
},
- expect => {
+ async expect => {
browser.test.log("Switch back to tab 1. Expect previous results again.");
- browser.tabs.remove(tabs[1], () => {
- expect(details[1]);
- });
+ await browser.tabs.remove(tabs[1]);
+ expect(details[1]);
},
- expect => {
+ async expect => {
browser.test.log("Hide the icon. Expect hidden.");
- browser.pageAction.hide(tabs[0]).then(() => {
- expect(null);
- });
+ await browser.pageAction.hide(tabs[0]);
+ expect(null);
},
];
},
});
});
add_task(function* testDefaultTitle() {
yield runTests({
@@ -206,21 +200,20 @@ add_task(function* testDefaultTitle() {
"icon": browser.runtime.getURL("icon.png")},
];
return [
expect => {
browser.test.log("Initial state. No icon visible.");
expect(null);
},
- expect => {
+ async expect => {
browser.test.log("Show the icon on the first tab, expect extension title as default title.");
- browser.pageAction.show(tabs[0]).then(() => {
- expect(details[0]);
- });
+ await browser.pageAction.show(tabs[0]);
+ expect(details[0]);
},
expect => {
browser.test.log("Change the title. Expect new title.");
browser.pageAction.setTitle({tabId: tabs[0], title: "Foo Title"});
expect(details[1]);
},
expect => {
browser.test.log("Clear the title. Expect extension title.");
--- a/browser/components/extensions/test/browser/browser_ext_popup_sendMessage.js
+++ b/browser/components/extensions/test/browser/browser_ext_popup_sendMessage.js
@@ -15,55 +15,54 @@ add_task(function* test_popup_sendMessag
"page_action": {
"default_popup": "popup.html",
"browser_style": true,
},
},
files: {
"popup.html": scriptPage("popup.js"),
- "popup.js": function() {
- browser.runtime.onMessage.addListener(msg => {
+ "popup.js": async function() {
+ browser.runtime.onMessage.addListener(async msg => {
if (msg == "popup-ping") {
return Promise.resolve("popup-pong");
}
});
- browser.runtime.sendMessage("background-ping").then(response => {
- browser.test.sendMessage("background-ping-response", response);
- });
+ let response = await browser.runtime.sendMessage("background-ping");
+ browser.test.sendMessage("background-ping-response", response);
},
},
- background() {
- browser.tabs.query({active: true, currentWindow: true}).then(([tab]) => {
- return browser.pageAction.show(tab.id);
- }).then(() => {
- browser.test.sendMessage("page-action-ready");
- });
+ async background() {
+ browser.runtime.onMessage.addListener(async msg => {
+ if (msg == "background-ping") {
+ let response = await browser.runtime.sendMessage("popup-ping");
- browser.runtime.onMessage.addListener(msg => {
- if (msg == "background-ping") {
- browser.runtime.sendMessage("popup-ping").then(response => {
- browser.test.sendMessage("popup-ping-response", response);
- });
+ browser.test.sendMessage("popup-ping-response", response);
- return new Promise(resolve => {
+ await new Promise(resolve => {
// Wait long enough that we're relatively sure the docShells have
// been swapped. Note that this value is fairly arbitrary. The load
// event that triggers the swap should happen almost immediately
// after the message is sent. The extra quarter of a second gives us
// enough leeway that we can expect to respond after the swap in the
// vast majority of cases.
setTimeout(resolve, 250);
- }).then(() => {
- return "background-pong";
});
+
+ return "background-pong";
}
});
+
+ let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+
+ await browser.pageAction.show(tab.id);
+
+ browser.test.sendMessage("page-action-ready");
},
});
yield extension.startup();
{
clickBrowserAction(extension);
--- a/browser/components/extensions/test/browser/browser_ext_popup_shutdown.js
+++ b/browser/components/extensions/test/browser/browser_ext_popup_shutdown.js
@@ -1,19 +1,18 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
let getExtension = () => {
return ExtensionTestUtils.loadExtension({
- background() {
- browser.tabs.query({active: true, currentWindow: true}, tabs => {
- browser.pageAction.show(tabs[0].id)
- .then(() => { browser.test.sendMessage("pageAction ready"); });
- });
+ background: async function() {
+ let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+ await browser.pageAction.show(tab.id);
+ browser.test.sendMessage("pageAction ready");
},
manifest: {
"browser_action": {
"default_popup": "popup.html",
"browser_style": false,
},
--- a/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
@@ -56,17 +56,17 @@ add_tasks(function* test_inline_options(
let extension = yield loadExtension(Object.assign({}, extraOptions, {
manifest: {
applications: {gecko: {id: "inline_options@tests.mozilla.org"}},
"options_ui": {
"page": "options.html",
},
},
- background: function() {
+ background: async function() {
let _optionsPromise;
let awaitOptions = () => {
browser.test.assertFalse(_optionsPromise, "Should not be awaiting options already");
return new Promise(resolve => {
_optionsPromise = {resolve};
});
};
@@ -77,76 +77,73 @@ add_tasks(function* test_inline_options(
_optionsPromise.resolve(sender.tab);
_optionsPromise = null;
} else {
browser.test.fail("Saw unexpected options page load");
}
}
});
- let firstTab, optionsTab;
- browser.tabs.query({currentWindow: true, active: true}).then(tabs => {
- firstTab = tabs[0].id;
+ try {
+ let [firstTab] = await browser.tabs.query({currentWindow: true, active: true});
browser.test.log("Open options page. Expect fresh load.");
- return Promise.all([
+
+ let [, optionsTab] = await Promise.all([
browser.runtime.openOptionsPage(),
awaitOptions(),
]);
- }).then(([, tab]) => {
- browser.test.assertEq("about:addons", tab.url, "Tab contains AddonManager");
- browser.test.assertTrue(tab.active, "Tab is active");
- browser.test.assertTrue(tab.id != firstTab, "Tab is a new tab");
- optionsTab = tab.id;
+ browser.test.assertEq("about:addons", optionsTab.url, "Tab contains AddonManager");
+ browser.test.assertTrue(optionsTab.active, "Tab is active");
+ browser.test.assertTrue(optionsTab.id != firstTab.id, "Tab is a new tab");
+
browser.test.assertEq(0, browser.extension.getViews({type: "popup"}).length, "viewType is not popup");
browser.test.assertEq(1, browser.extension.getViews({type: "tab"}).length, "viewType is tab");
- browser.test.assertEq(1, browser.extension.getViews({windowId: tab.windowId}).length, "windowId matches");
+ browser.test.assertEq(1, browser.extension.getViews({windowId: optionsTab.windowId}).length, "windowId matches");
+
let views = browser.extension.getViews();
browser.test.assertEq(2, views.length, "Expected the options page and the background page");
browser.test.assertTrue(views.includes(window), "One of the views is the background page");
browser.test.assertTrue(views.some(w => w.iAmOption), "One of the views is the options page");
browser.test.log("Switch tabs.");
- return browser.tabs.update(firstTab, {active: true});
- }).then(() => {
+ await browser.tabs.update(firstTab.id, {active: true});
+
browser.test.log("Open options page again. Expect tab re-selected, no new load.");
- return browser.runtime.openOptionsPage();
- }).then(() => {
- return browser.tabs.query({currentWindow: true, active: true});
- }).then(([tab]) => {
- browser.test.assertEq(optionsTab, tab.id, "Tab is the same as the previous options tab");
+ await browser.runtime.openOptionsPage();
+ let [tab] = await browser.tabs.query({currentWindow: true, active: true});
+
+ browser.test.assertEq(optionsTab.id, tab.id, "Tab is the same as the previous options tab");
browser.test.assertEq("about:addons", tab.url, "Tab contains AddonManager");
browser.test.log("Ping options page.");
- return browser.runtime.sendMessage("ping");
- }).then((pong) => {
+ let pong = await browser.runtime.sendMessage("ping");
browser.test.assertEq("pong", pong, "Got pong.");
browser.test.log("Remove options tab.");
- return browser.tabs.remove(optionsTab);
- }).then(() => {
+ await browser.tabs.remove(optionsTab.id);
+
browser.test.log("Open options page again. Expect fresh load.");
- return Promise.all([
+ [, tab] = await Promise.all([
browser.runtime.openOptionsPage(),
awaitOptions(),
]);
- }).then(([, tab]) => {
browser.test.assertEq("about:addons", tab.url, "Tab contains AddonManager");
browser.test.assertTrue(tab.active, "Tab is active");
- browser.test.assertTrue(tab.id != optionsTab, "Tab is a new tab");
+ browser.test.assertTrue(tab.id != optionsTab.id, "Tab is a new tab");
- return browser.tabs.remove(tab.id);
- }).then(() => {
+ await browser.tabs.remove(tab.id);
+
browser.test.notifyPass("options-ui");
- }).catch(error => {
- browser.test.log(`Error: ${error} :: ${error.stack}`);
+ } catch (error) {
+ browser.test.fail(`Error: ${error} :: ${error.stack}`);
browser.test.notifyFail("options-ui");
- });
+ }
},
}));
yield extension.awaitFinish("options-ui");
yield extension.unload();
yield BrowserTestUtils.removeTab(tab);
});
@@ -160,17 +157,17 @@ add_tasks(function* test_tab_options(ext
manifest: {
applications: {gecko: {id: "tab_options@tests.mozilla.org"}},
"options_ui": {
"page": "options.html",
"open_in_tab": true,
},
},
- background: function() {
+ background: async function() {
let _optionsPromise;
let awaitOptions = () => {
browser.test.assertFalse(_optionsPromise, "Should not be awaiting options already");
return new Promise(resolve => {
_optionsPromise = {resolve};
});
};
@@ -183,77 +180,73 @@ add_tasks(function* test_tab_options(ext
} else {
browser.test.fail("Saw unexpected options page load");
}
}
});
let optionsURL = browser.extension.getURL("options.html");
- let firstTab, optionsTab;
- browser.tabs.query({currentWindow: true, active: true}).then(tabs => {
- firstTab = tabs[0].id;
+ try {
+ let [firstTab] = await browser.tabs.query({currentWindow: true, active: true});
browser.test.log("Open options page. Expect fresh load.");
- return Promise.all([
+ let [, optionsTab] = await Promise.all([
browser.runtime.openOptionsPage(),
awaitOptions(),
]);
- }).then(([, tab]) => {
- browser.test.assertEq(optionsURL, tab.url, "Tab contains options.html");
- browser.test.assertTrue(tab.active, "Tab is active");
- browser.test.assertTrue(tab.id != firstTab, "Tab is a new tab");
+ browser.test.assertEq(optionsURL, optionsTab.url, "Tab contains options.html");
+ browser.test.assertTrue(optionsTab.active, "Tab is active");
+ browser.test.assertTrue(optionsTab.id != firstTab.id, "Tab is a new tab");
- optionsTab = tab.id;
browser.test.assertEq(0, browser.extension.getViews({type: "popup"}).length, "viewType is not popup");
browser.test.assertEq(1, browser.extension.getViews({type: "tab"}).length, "viewType is tab");
- browser.test.assertEq(1, browser.extension.getViews({windowId: tab.windowId}).length, "windowId matches");
+ browser.test.assertEq(1, browser.extension.getViews({windowId: optionsTab.windowId}).length, "windowId matches");
+
let views = browser.extension.getViews();
browser.test.assertEq(2, views.length, "Expected the options page and the background page");
browser.test.assertTrue(views.includes(window), "One of the views is the background page");
browser.test.assertTrue(views.some(w => w.iAmOption), "One of the views is the options page");
browser.test.log("Switch tabs.");
- return browser.tabs.update(firstTab, {active: true});
- }).then(() => {
+ await browser.tabs.update(firstTab.id, {active: true});
+
browser.test.log("Open options page again. Expect tab re-selected, no new load.");
- return browser.runtime.openOptionsPage();
- }).then(() => {
- return browser.tabs.query({currentWindow: true, active: true});
- }).then(([tab]) => {
- browser.test.assertEq(optionsTab, tab.id, "Tab is the same as the previous options tab");
+ await browser.runtime.openOptionsPage();
+ let [tab] = await browser.tabs.query({currentWindow: true, active: true});
+
+ browser.test.assertEq(optionsTab.id, tab.id, "Tab is the same as the previous options tab");
browser.test.assertEq(optionsURL, tab.url, "Tab contains options.html");
// Unfortunately, we can't currently do this, since onMessage doesn't
// currently support responses when there are multiple listeners.
//
// browser.test.log("Ping options page.");
// return new Promise(resolve => browser.runtime.sendMessage("ping", resolve));
browser.test.log("Remove options tab.");
- return browser.tabs.remove(optionsTab);
- }).then(() => {
+ await browser.tabs.remove(optionsTab.id);
+
browser.test.log("Open options page again. Expect fresh load.");
- return Promise.all([
+ [, tab] = await Promise.all([
browser.runtime.openOptionsPage(),
awaitOptions(),
]);
- }).then(([, tab]) => {
browser.test.assertEq(optionsURL, tab.url, "Tab contains options.html");
browser.test.assertTrue(tab.active, "Tab is active");
- browser.test.assertTrue(tab.id != optionsTab, "Tab is a new tab");
+ browser.test.assertTrue(tab.id != optionsTab.id, "Tab is a new tab");
- return browser.tabs.remove(tab.id);
- }).then(() => {
+ await browser.tabs.remove(tab.id);
+
browser.test.notifyPass("options-ui-tab");
- }).catch(error => {
- browser.test.log(`Error: ${error} :: ${error.stack}`);
+ } catch (error) {
+ browser.test.fail(`Error: ${error} :: ${error.stack}`);
browser.test.notifyFail("options-ui-tab");
- });
+ }
},
}));
yield extension.awaitFinish("options-ui-tab");
yield extension.unload();
yield BrowserTestUtils.removeTab(tab);
});
@@ -261,34 +254,23 @@ add_tasks(function* test_tab_options(ext
add_tasks(function* test_options_no_manifest(extraOptions) {
info(`Test with no manifest key (${JSON.stringify(extraOptions)})`);
let extension = yield loadExtension(Object.assign({}, extraOptions, {
manifest: {
applications: {gecko: {id: "no_options@tests.mozilla.org"}},
},
- background: function() {
+ async background() {
browser.test.log("Try to open options page when not specified in the manifest.");
- browser.runtime.openOptionsPage().then(
- () => {
- browser.test.fail("Opening options page without one specified in the manifest generated an error");
- browser.test.notifyFail("options-no-manifest");
- },
- error => {
- let expected = "No `options_ui` declared";
- browser.test.assertTrue(
- error.message.includes(expected),
- `Got expected error (got: '${error.message}', expected: '${expected}'`);
- }
- ).then(() => {
- browser.test.notifyPass("options-no-manifest");
- }).catch(error => {
- browser.test.log(`Error: ${error} :: ${error.stack}`);
- browser.test.notifyFail("options-no-manifest");
- });
+ await browser.test.assertRejects(
+ browser.runtime.openOptionsPage(),
+ /No `options_ui` declared/,
+ "Expected error from openOptionsPage()");
+
+ browser.test.notifyPass("options-no-manifest");
},
}));
yield extension.awaitFinish("options-no-manifest");
yield extension.unload();
});
--- a/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage_uninstall.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage_uninstall.js
@@ -43,17 +43,17 @@ add_task(function* test_inline_options_u
let extension = yield loadExtension({
manifest: {
applications: {gecko: {id: "inline_options_uninstall@tests.mozilla.org"}},
"options_ui": {
"page": "options.html",
},
},
- background: function() {
+ background: async function() {
let _optionsPromise;
let awaitOptions = () => {
browser.test.assertFalse(_optionsPromise, "Should not be awaiting options already");
return new Promise(resolve => {
_optionsPromise = {resolve};
});
};
@@ -64,34 +64,33 @@ add_task(function* test_inline_options_u
_optionsPromise.resolve(sender.tab);
_optionsPromise = null;
} else {
browser.test.fail("Saw unexpected options page load");
}
}
});
- let firstTab;
- browser.tabs.query({currentWindow: true, active: true}).then(tabs => {
- firstTab = tabs[0].id;
+ try {
+ let [firstTab] = await browser.tabs.query({currentWindow: true, active: true});
browser.test.log("Open options page. Expect fresh load.");
- return Promise.all([
+ let [, tab] = await Promise.all([
browser.runtime.openOptionsPage(),
awaitOptions(),
]);
- }).then(([, tab]) => {
+
browser.test.assertEq("about:addons", tab.url, "Tab contains AddonManager");
browser.test.assertTrue(tab.active, "Tab is active");
- browser.test.assertTrue(tab.id != firstTab, "Tab is a new tab");
+ browser.test.assertTrue(tab.id != firstTab.id, "Tab is a new tab");
browser.test.sendMessage("options-ui-open");
- }).catch(error => {
+ } catch (error) {
browser.test.fail(`Error: ${error} :: ${error.stack}`);
- });
+ }
},
});
yield extension.awaitMessage("options-ui-open");
yield extension.unload();
is(gBrowser.selectedBrowser.currentURI.spec, "about:addons",
"Add-on manager tab should still be open");
--- a/browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
@@ -25,71 +25,62 @@ function* makeAndInstallXPI(id, backgrou
let loadTab = yield loadPromise;
yield BrowserTestUtils.removeTab(loadTab);
return addon;
}
add_task(function* test_setuninstallurl_badargs() {
- function backgroundScript() {
- let promises = [
- browser.runtime.setUninstallURL("this is not a url")
- .then(() => {
- browser.test.notifyFail("setUninstallURL should have failed with bad url");
- })
- .catch(error => {
- browser.test.assertTrue(/Invalid URL/.test(error.message), "error message indicates malformed url");
- }),
+ async function background() {
+ await browser.test.assertRejects(
+ browser.runtime.setUninstallURL("this is not a url"),
+ /Invalid URL/,
+ "setUninstallURL with an invalid URL should fail");
- browser.runtime.setUninstallURL("file:///etc/passwd")
- .then(() => {
- browser.test.notifyFail("setUninstallURL should have failed with non-http[s] url");
- })
- .catch(error => {
- browser.test.assertTrue(/must have the scheme http or https/.test(error.message), "error message indicates bad scheme");
- }),
- ];
+ await browser.test.assertRejects(
+ browser.runtime.setUninstallURL("file:///etc/passwd"),
+ /must have the scheme http or https/,
+ "setUninstallURL with an illegal URL should fail");
- Promise.all(promises)
- .then(() => browser.test.notifyPass("setUninstallURL bad params"));
+ browser.test.notifyPass("setUninstallURL bad params");
}
let extension = ExtensionTestUtils.loadExtension({
- background: "(" + backgroundScript.toString() + ")()",
+ background,
});
yield extension.startup();
yield extension.awaitFinish();
yield extension.unload();
});
// Test the documented behavior of setUninstallURL() that passing an
// empty string is equivalent to not setting an uninstall URL
// (i.e., no new tab is opened upon uninstall)
add_task(function* test_setuninstall_empty_url() {
- function backgroundScript() {
- browser.runtime.setUninstallURL("")
- .then(() => browser.tabs.create({url: "http://example.com/addon_loaded"}));
+ async function backgroundScript() {
+ await browser.runtime.setUninstallURL("");
+ browser.tabs.create({url: "http://example.com/addon_loaded"});
}
let addon = yield makeAndInstallXPI("test_uinstallurl2@tests.mozilla.org",
backgroundScript,
"http://example.com/addon_loaded");
addon.uninstall(true);
info("uninstalled");
// no need to explicitly check for the absence of a new tab,
// BrowserTestUtils will eventually complain if one is opened.
});
add_task(function* test_setuninstallurl() {
- function backgroundScript() {
- browser.runtime.setUninstallURL("http://example.com/addon_uninstalled")
- .then(() => browser.tabs.create({url: "http://example.com/addon_loaded"}));
+ async function backgroundScript() {
+ await browser.runtime.setUninstallURL("http://example.com/addon_uninstalled");
+ browser.tabs.create({url: "http://example.com/addon_loaded"});
}
let addon = yield makeAndInstallXPI("test_uinstallurl@tests.mozilla.org",
backgroundScript,
"http://example.com/addon_loaded");
// look for a new tab with the uninstall url.
let uninstallPromise = BrowserTestUtils.waitForNewTab(gBrowser, "http://example.com/addon_uninstalled");
--- a/browser/components/extensions/test/browser/browser_ext_tabs_audio.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_audio.js
@@ -3,27 +3,17 @@
"use strict";
add_task(function* () {
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank?1");
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank?2");
gBrowser.selectedTab = tab1;
- function background() {
- // Wrap API methods in promise-based variants.
- let promiseTabs = {};
- Object.keys(browser.tabs).forEach(method => {
- promiseTabs[method] = (...args) => {
- return new Promise(resolve => {
- browser.tabs[method](...args, resolve);
- });
- };
- });
-
+ async function background() {
function promiseUpdated(tabId, attr) {
return new Promise(resolve => {
let onUpdated = (tabId_, changeInfo, tab) => {
if (tabId == tabId_ && attr in changeInfo) {
browser.tabs.onUpdated.removeListener(onUpdated);
resolve({changeInfo, tab});
}
@@ -42,134 +32,129 @@ add_task(function* () {
function changeTab(tabId, attr, on) {
return new Promise((resolve, reject) => {
deferred[tabId] = {resolve, reject};
browser.test.sendMessage("change-tab", tabId, attr, on);
});
}
- let windowId;
- let tabIds;
- promiseTabs.query({lastFocusedWindow: true}).then(tabs => {
+ try {
+ let tabs = await browser.tabs.query({lastFocusedWindow: true});
browser.test.assertEq(tabs.length, 3, "We have three tabs");
for (let tab of tabs) {
// Note: We want to check that these are actual boolean values, not
// just that they evaluate as false.
browser.test.assertEq(false, tab.mutedInfo.muted, "Tab is not muted");
browser.test.assertEq(undefined, tab.mutedInfo.reason, "Tab has no muted info reason");
browser.test.assertEq(false, tab.audible, "Tab is not audible");
}
- windowId = tabs[0].windowId;
- tabIds = [tabs[1].id, tabs[2].id];
+ let windowId = tabs[0].windowId;
+ let tabIds = [tabs[1].id, tabs[2].id];
browser.test.log("Test initial queries for muted and audible return no tabs");
- return Promise.all([
- promiseTabs.query({windowId, audible: false}),
- promiseTabs.query({windowId, audible: true}),
- promiseTabs.query({windowId, muted: true}),
- promiseTabs.query({windowId, muted: false}),
- ]);
- }).then(([silent, audible, muted, nonMuted]) => {
+ let silent = await browser.tabs.query({windowId, audible: false});
+ let audible = await browser.tabs.query({windowId, audible: true});
+ let muted = await browser.tabs.query({windowId, muted: true});
+ let nonMuted = await browser.tabs.query({windowId, muted: false});
+
browser.test.assertEq(3, silent.length, "Three silent tabs");
browser.test.assertEq(0, audible.length, "No audible tabs");
browser.test.assertEq(0, muted.length, "No muted tabs");
browser.test.assertEq(3, nonMuted.length, "Three non-muted tabs");
browser.test.log("Toggle muted and audible externally on one tab each, and check results");
- return Promise.all([
+ [muted, audible] = await Promise.all([
promiseUpdated(tabIds[0], "mutedInfo"),
promiseUpdated(tabIds[1], "audible"),
changeTab(tabIds[0], "muted", true),
changeTab(tabIds[1], "audible", true),
]);
- }).then(([muted, audible]) => {
+
for (let obj of [muted.changeInfo, muted.tab]) {
browser.test.assertEq(true, obj.mutedInfo.muted, "Tab is muted");
browser.test.assertEq("user", obj.mutedInfo.reason, "Tab was muted by the user");
}
browser.test.assertEq(true, audible.changeInfo.audible, "Tab audible state changed");
browser.test.assertEq(true, audible.tab.audible, "Tab is audible");
browser.test.log("Re-check queries. Expect one audible and one muted tab");
- return Promise.all([
- promiseTabs.query({windowId, audible: false}),
- promiseTabs.query({windowId, audible: true}),
- promiseTabs.query({windowId, muted: true}),
- promiseTabs.query({windowId, muted: false}),
- ]);
- }).then(([silent, audible, muted, nonMuted]) => {
+ silent = await browser.tabs.query({windowId, audible: false});
+ audible = await browser.tabs.query({windowId, audible: true});
+ muted = await browser.tabs.query({windowId, muted: true});
+ nonMuted = await browser.tabs.query({windowId, muted: false});
+
browser.test.assertEq(2, silent.length, "Two silent tabs");
browser.test.assertEq(1, audible.length, "One audible tab");
browser.test.assertEq(1, muted.length, "One muted tab");
browser.test.assertEq(2, nonMuted.length, "Two non-muted tabs");
browser.test.assertEq(true, muted[0].mutedInfo.muted, "Tab is muted");
browser.test.assertEq("user", muted[0].mutedInfo.reason, "Tab was muted by the user");
browser.test.assertEq(true, audible[0].audible, "Tab is audible");
browser.test.log("Toggle muted internally on two tabs, and check results");
- return Promise.all([
+ [nonMuted, muted] = await Promise.all([
promiseUpdated(tabIds[0], "mutedInfo"),
promiseUpdated(tabIds[1], "mutedInfo"),
- promiseTabs.update(tabIds[0], {muted: false}),
- promiseTabs.update(tabIds[1], {muted: true}),
+ browser.tabs.update(tabIds[0], {muted: false}),
+ browser.tabs.update(tabIds[1], {muted: true}),
]);
- }).then(([unmuted, muted]) => {
- for (let obj of [unmuted.changeInfo, unmuted.tab]) {
+
+ for (let obj of [nonMuted.changeInfo, nonMuted.tab]) {
browser.test.assertEq(false, obj.mutedInfo.muted, "Tab is not muted");
}
for (let obj of [muted.changeInfo, muted.tab]) {
browser.test.assertEq(true, obj.mutedInfo.muted, "Tab is muted");
}
- for (let obj of [unmuted.changeInfo, unmuted.tab, muted.changeInfo, muted.tab]) {
+ for (let obj of [nonMuted.changeInfo, nonMuted.tab, muted.changeInfo, muted.tab]) {
browser.test.assertEq("extension", obj.mutedInfo.reason, "Mute state changed by extension");
// FIXME: browser.runtime.id is currently broken.
browser.test.assertEq(browser.i18n.getMessage("@@extension_id"),
obj.mutedInfo.extensionId,
"Mute state changed by extension");
}
browser.test.log("Test that mutedInfo is preserved by sessionstore");
- return changeTab(tabIds[1], "duplicate").then(promiseTabs.get);
- }).then(tab => {
+ let tab = await changeTab(tabIds[1], "duplicate").then(browser.tabs.get);
+
browser.test.assertEq(true, tab.mutedInfo.muted, "Tab is muted");
browser.test.assertEq("extension", tab.mutedInfo.reason, "Mute state changed by extension");
// FIXME: browser.runtime.id is currently broken.
browser.test.assertEq(browser.i18n.getMessage("@@extension_id"),
tab.mutedInfo.extensionId,
"Mute state changed by extension");
browser.test.log("Unmute externally, and check results");
- return Promise.all([
+ [nonMuted] = await Promise.all([
promiseUpdated(tabIds[1], "mutedInfo"),
changeTab(tabIds[1], "muted", false),
- promiseTabs.remove(tab.id),
+ browser.tabs.remove(tab.id),
]);
- }).then(([unmuted]) => {
- for (let obj of [unmuted.changeInfo, unmuted.tab]) {
+
+ for (let obj of [nonMuted.changeInfo, nonMuted.tab]) {
browser.test.assertEq(false, obj.mutedInfo.muted, "Tab is not muted");
browser.test.assertEq("user", obj.mutedInfo.reason, "Mute state changed by user");
}
browser.test.notifyPass("tab-audio");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("tab-audio");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_captureVisibleTab.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_captureVisibleTab.js
@@ -21,103 +21,95 @@ function* runTest(options) {
</html>
`;
let url = `data:text/html,${encodeURIComponent(html)}`;
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url, true);
tab.linkedBrowser.fullZoom = options.fullZoom;
- function background(options) {
- // Wrap API methods in promise-based variants.
- let promiseTabs = {};
- Object.keys(browser.tabs).forEach(method => {
- promiseTabs[method] = (...args) => {
- return new Promise(resolve => {
- browser.tabs[method](...args, resolve);
- });
- };
- });
-
+ async function background(options) {
browser.test.log(`Test color ${options.color} at fullZoom=${options.fullZoom}`);
- promiseTabs.query({currentWindow: true, active: true}).then(([tab]) => {
- return Promise.all([
- promiseTabs.captureVisibleTab(tab.windowId, {format: "jpeg", quality: 95}),
- promiseTabs.captureVisibleTab(tab.windowId, {format: "png", quality: 95}),
- promiseTabs.captureVisibleTab(tab.windowId, {quality: 95}),
- promiseTabs.captureVisibleTab(tab.windowId),
- ]).then(([jpeg, png, ...pngs]) => {
- browser.test.assertTrue(pngs.every(url => url == png), "All PNGs are identical");
+ try {
+ let [tab] = await browser.tabs.query({currentWindow: true, active: true});
- browser.test.assertTrue(jpeg.startsWith("data:image/jpeg;base64,"), "jpeg is JPEG");
- browser.test.assertTrue(png.startsWith("data:image/png;base64,"), "png is PNG");
+ let [jpeg, png, ...pngs] = await Promise.all([
+ browser.tabs.captureVisibleTab(tab.windowId, {format: "jpeg", quality: 95}),
+ browser.tabs.captureVisibleTab(tab.windowId, {format: "png", quality: 95}),
+ browser.tabs.captureVisibleTab(tab.windowId, {quality: 95}),
+ browser.tabs.captureVisibleTab(tab.windowId),
+ ]);
+
+ browser.test.assertTrue(pngs.every(url => url == png), "All PNGs are identical");
+
+ browser.test.assertTrue(jpeg.startsWith("data:image/jpeg;base64,"), "jpeg is JPEG");
+ browser.test.assertTrue(png.startsWith("data:image/png;base64,"), "png is PNG");
- let promises = [jpeg, png].map(url => new Promise(resolve => {
- let img = new Image();
- img.src = url;
- img.onload = () => resolve(img);
- }));
- return Promise.all(promises);
- }).then(([jpeg, png]) => {
- let tabDims = `${tab.width}\u00d7${tab.height}`;
+ let promises = [jpeg, png].map(url => new Promise(resolve => {
+ let img = new Image();
+ img.src = url;
+ img.onload = () => resolve(img);
+ }));
- let images = {jpeg, png};
- for (let format of Object.keys(images)) {
- let img = images[format];
+ [jpeg, png] = await Promise.all(promises);
+ let tabDims = `${tab.width}\u00d7${tab.height}`;
- let dims = `${img.width}\u00d7${img.height}`;
- browser.test.assertEq(tabDims, dims, `${format} dimensions are correct`);
+ let images = {jpeg, png};
+ for (let format of Object.keys(images)) {
+ let img = images[format];
- let canvas = document.createElement("canvas");
- canvas.width = img.width;
- canvas.height = img.height;
- canvas.mozOpaque = true;
+ let dims = `${img.width}\u00d7${img.height}`;
+ browser.test.assertEq(tabDims, dims, `${format} dimensions are correct`);
- let ctx = canvas.getContext("2d");
- ctx.drawImage(img, 0, 0);
+ let canvas = document.createElement("canvas");
+ canvas.width = img.width;
+ canvas.height = img.height;
+ canvas.mozOpaque = true;
- // Check the colors of the first and last pixels of the image, to make
- // sure we capture the entire frame, and scale it correctly.
- let coords = [
- {x: 0, y: 0,
- color: options.color},
- {x: img.width - 1,
- y: img.height - 1,
- color: options.color},
- {x: img.width / 2 | 0,
- y: img.height / 2 | 0,
- color: options.neutral},
- ];
+ let ctx = canvas.getContext("2d");
+ ctx.drawImage(img, 0, 0);
- for (let {x, y, color} of coords) {
- let imageData = ctx.getImageData(x, y, 1, 1).data;
+ // Check the colors of the first and last pixels of the image, to make
+ // sure we capture the entire frame, and scale it correctly.
+ let coords = [
+ {x: 0, y: 0,
+ color: options.color},
+ {x: img.width - 1,
+ y: img.height - 1,
+ color: options.color},
+ {x: img.width / 2 | 0,
+ y: img.height / 2 | 0,
+ color: options.neutral},
+ ];
- if (format == "png") {
- browser.test.assertEq(`rgba(${color},255)`, `rgba(${[...imageData]})`, `${format} image color is correct at (${x}, ${y})`);
- } else {
- // Allow for some deviation in JPEG version due to lossy compression.
- const SLOP = 3;
+ for (let {x, y, color} of coords) {
+ let imageData = ctx.getImageData(x, y, 1, 1).data;
- browser.test.log(`Testing ${format} image color at (${x}, ${y}), have rgba(${[...imageData]}), expecting approx. rgba(${color},255)`);
+ if (format == "png") {
+ browser.test.assertEq(`rgba(${color},255)`, `rgba(${[...imageData]})`, `${format} image color is correct at (${x}, ${y})`);
+ } else {
+ // Allow for some deviation in JPEG version due to lossy compression.
+ const SLOP = 3;
- browser.test.assertTrue(Math.abs(color[0] - imageData[0]) <= SLOP, `${format} image color.red is correct at (${x}, ${y})`);
- browser.test.assertTrue(Math.abs(color[1] - imageData[1]) <= SLOP, `${format} image color.green is correct at (${x}, ${y})`);
- browser.test.assertTrue(Math.abs(color[2] - imageData[2]) <= SLOP, `${format} image color.blue is correct at (${x}, ${y})`);
- browser.test.assertEq(255, imageData[3], `${format} image color.alpha is correct at (${x}, ${y})`);
- }
+ browser.test.log(`Testing ${format} image color at (${x}, ${y}), have rgba(${[...imageData]}), expecting approx. rgba(${color},255)`);
+
+ browser.test.assertTrue(Math.abs(color[0] - imageData[0]) <= SLOP, `${format} image color.red is correct at (${x}, ${y})`);
+ browser.test.assertTrue(Math.abs(color[1] - imageData[1]) <= SLOP, `${format} image color.green is correct at (${x}, ${y})`);
+ browser.test.assertTrue(Math.abs(color[2] - imageData[2]) <= SLOP, `${format} image color.blue is correct at (${x}, ${y})`);
+ browser.test.assertEq(255, imageData[3], `${format} image color.alpha is correct at (${x}, ${y})`);
}
}
+ }
- browser.test.notifyPass("captureVisibleTab");
- });
- }).catch(e => {
+ browser.test.notifyPass("captureVisibleTab");
+ } catch (e) {
browser.test.fail(`Error: ${e} :: ${e.stack}`);
browser.test.notifyFail("captureVisibleTab");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["<all_urls>"],
},
background: `(${background})(${JSON.stringify(options)})`,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_cookieStoreId.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_cookieStoreId.js
@@ -37,107 +37,93 @@ add_task(function* () {
background: function() {
function testTab(data, tab) {
browser.test.assertTrue(data.success, "we want a success");
browser.test.assertTrue(!!tab, "we have a tab");
browser.test.assertEq(data.expectedCookieStoreId, tab.cookieStoreId, "tab should have the correct cookieStoreId");
}
- function runTest(data) {
- // Tab Creation
- browser.tabs.create({windowId: data.privateTab ? this.privateWindowId : this.defaultWindowId,
- cookieStoreId: data.cookieStoreId})
+ async function runTest(data) {
+ try {
+ // Tab Creation
+ let tab;
+ try {
+ tab = await browser.tabs.create({
+ windowId: data.privateTab ? this.privateWindowId : this.defaultWindowId,
+ cookieStoreId: data.cookieStoreId,
+ });
+
+ browser.test.assertTrue(!data.failure, "we want a success");
+ } catch (error) {
+ browser.test.assertTrue(!!data.failure, "we want a failure");
- // Tests for tab creation
- .then((tab) => {
- testTab(data, tab);
- return tab;
- }, (error) => {
- browser.test.assertTrue(!!data.failure, "we want a failure");
- if (data.failure == "illegal") {
- browser.test.assertTrue(/Illegal cookieStoreId/.test(error.message),
- "runtime.lastError should report the expected error message");
- } else if (data.failure == "defaultToPrivate") {
- browser.test.assertTrue("Illegal to set private cookieStorageId in a non private window",
- error.message,
- "runtime.lastError should report the expected error message");
- } else if (data.failure == "privateToDefault") {
- browser.test.assertTrue("Illegal to set non private cookieStorageId in a private window",
- error.message,
- "runtime.lastError should report the expected error message");
- } else if (data.failure == "exist") {
- browser.test.assertTrue(/No cookie store exists/.test(error.message),
- "runtime.lastError should report the expected error message");
- } else {
- browser.test.fail("The test is broken");
+ if (data.failure == "illegal") {
+ browser.test.assertTrue(/Illegal cookieStoreId/.test(error.message),
+ "runtime.lastError should report the expected error message");
+ } else if (data.failure == "defaultToPrivate") {
+ browser.test.assertTrue("Illegal to set private cookieStorageId in a non private window",
+ error.message,
+ "runtime.lastError should report the expected error message");
+ } else if (data.failure == "privateToDefault") {
+ browser.test.assertTrue("Illegal to set non private cookieStorageId in a private window",
+ error.message,
+ "runtime.lastError should report the expected error message");
+ } else if (data.failure == "exist") {
+ browser.test.assertTrue(/No cookie store exists/.test(error.message),
+ "runtime.lastError should report the expected error message");
+ } else {
+ browser.test.fail("The test is broken");
+ }
+
+ browser.test.sendMessage("test-done");
+ return;
}
- return null;
- })
+ // Tests for tab creation
+ testTab(data, tab);
- // Tests for tab querying
- .then((tab) => {
- if (tab) {
- return browser.tabs.query({windowId: data.privateTab ? this.privateWindowId : this.defaultWindowId,
- cookieStoreId: data.cookieStoreId})
- .then((tabs) => {
- browser.test.assertTrue(tabs.length >= 1, "Tab found!");
- testTab(data, tabs[0]);
- return tab;
- });
- }
- })
+ {
+ // Tests for tab querying
+ let [tab] = await browser.tabs.query({
+ windowId: data.privateTab ? this.privateWindowId : this.defaultWindowId,
+ cookieStoreId: data.cookieStoreId,
+ });
- .then((tab) => {
- if (tab) {
- return browser.cookies.getAllCookieStores()
- .then(stores => {
- let store = stores.find(store => store.id === tab.cookieStoreId);
- browser.test.assertTrue(!!store, "We have a store for this tab.");
- return tab;
- });
+ browser.test.assertTrue(tab != undefined, "Tab found!");
+ testTab(data, tab);
}
- })
+
+ let stores = await browser.cookies.getAllCookieStores();
- .then((tab) => {
- if (tab) {
- return browser.tabs.remove(tab.id);
- }
- })
+ let store = stores.find(store => store.id === tab.cookieStoreId);
+ browser.test.assertTrue(!!store, "We have a store for this tab.");
+
+ await browser.tabs.remove(tab.id);
- .then(() => {
browser.test.sendMessage("test-done");
- }, () => {
- browser.test.fail("An exception has ben thrown");
- });
+ } catch (e) {
+ browser.test.fail("An exception has been thrown");
+ }
}
- function initialize() {
- browser.windows.create({incognito: true})
- .then((win) => {
- this.privateWindowId = win.id;
- return browser.windows.create({incognito: false});
- })
- .then((win) => {
- this.defaultWindowId = win.id;
- })
- .then(() => {
- browser.test.sendMessage("ready");
- });
+ async function initialize() {
+ let win = await browser.windows.create({incognito: true});
+ this.privateWindowId = win.id;
+
+ win = await browser.windows.create({incognito: false});
+ this.defaultWindowId = win.id;
+
+ browser.test.sendMessage("ready");
}
- function shutdown() {
- browser.windows.remove(this.privateWindowId)
- .then(() => {
- browser.windows.remove(this.defaultWindowId);
- })
- .then(() => {
- browser.test.sendMessage("gone");
- });
+ async function shutdown() {
+ await browser.windows.remove(this.privateWindowId);
+ await browser.windows.remove(this.defaultWindowId);
+ browser.test.sendMessage("gone");
}
// Waiting for messages
browser.test.onMessage.addListener((msg, data) => {
if (msg == "be-ready") {
initialize();
} else if (msg == "test") {
runTest(data);
--- a/browser/components/extensions/test/browser/browser_ext_tabs_create.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_create.js
@@ -85,17 +85,17 @@ add_task(function* () {
result: {index: 1, active: false},
},
{
create: {windowId: activeWindow},
result: {windowId: activeWindow},
},
];
- function nextTest() {
+ async function nextTest() {
if (!tests.length) {
browser.test.notifyPass("tabs.create");
return;
}
let test = tests.shift();
let expected = Object.assign({}, DEFAULTS, test.result);
@@ -114,43 +114,39 @@ add_task(function* () {
let createdPromise = new Promise(resolve => {
let onCreated = tab => {
browser.test.assertTrue("id" in tab, `Expected tabs.onCreated callback to receive tab object`);
resolve();
};
browser.tabs.onCreated.addListener(onCreated);
});
- let tabId;
- Promise.all([
+ let [tab] = await Promise.all([
browser.tabs.create(test.create),
createdPromise,
- ]).then(([tab]) => {
- tabId = tab.id;
+ ]);
+ let tabId = tab.id;
- for (let key of Object.keys(expected)) {
- if (key === "url") {
- // FIXME: This doesn't get updated until later in the load cycle.
- continue;
- }
-
- browser.test.assertEq(expected[key], tab[key], `Expected value for tab.${key}`);
+ for (let key of Object.keys(expected)) {
+ if (key === "url") {
+ // FIXME: This doesn't get updated until later in the load cycle.
+ continue;
}
- return updatedPromise;
- }).then(updated => {
- browser.test.assertEq(tabId, updated.tabId, `Expected value for tab.id`);
- browser.test.assertEq(expected.url, updated.url, `Expected value for tab.url`);
+ browser.test.assertEq(expected[key], tab[key], `Expected value for tab.${key}`);
+ }
- return browser.tabs.remove(tabId);
- }).then(() => {
- return browser.tabs.update(activeTab, {active: true});
- }).then(() => {
- nextTest();
- });
+ let updated = await updatedPromise;
+ browser.test.assertEq(tabId, updated.tabId, `Expected value for tab.id`);
+ browser.test.assertEq(expected.url, updated.url, `Expected value for tab.url`);
+
+ await browser.tabs.remove(tabId);
+ await browser.tabs.update(activeTab, {active: true});
+
+ nextTest();
}
nextTest();
}
browser.tabs.query({active: true, currentWindow: true}, tabs => {
activeTab = tabs[0].id;
activeWindow = tabs[0].windowId;
--- a/browser/components/extensions/test/browser/browser_ext_tabs_detectLanguage.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_detectLanguage.js
@@ -3,48 +3,44 @@
"use strict";
add_task(function* testDetectLanguage() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
- background() {
+ background: async function() {
const BASE_PATH = "browser/browser/components/extensions/test/browser";
function loadTab(url) {
return browser.tabs.create({url});
}
- loadTab(`http://example.co.jp/${BASE_PATH}/file_language_ja.html`).then(tab => {
- return browser.tabs.detectLanguage(tab.id).then(lang => {
- browser.test.assertEq("ja", lang, "Japanese document should be detected as Japanese");
- return browser.tabs.remove(tab.id);
- });
- }).then(() => {
- return loadTab(`http://example.co.jp/${BASE_PATH}/file_language_fr_en.html`);
- }).then(tab => {
- return browser.tabs.detectLanguage(tab.id).then(lang => {
- browser.test.assertEq("fr", lang, "French/English document should be detected as primarily French");
- return browser.tabs.remove(tab.id);
- });
- }).then(() => {
- return loadTab(`http://example.co.jp/${BASE_PATH}/file_language_tlh.html`);
- }).then(tab => {
- return browser.tabs.detectLanguage(tab.id).then(lang => {
- browser.test.assertEq("und", lang, "Klingon document should not be detected, should return 'und'");
- return browser.tabs.remove(tab.id);
- });
- }).then(() => {
+ try {
+ let tab = await loadTab(`http://example.co.jp/${BASE_PATH}/file_language_ja.html`);
+ let lang = await browser.tabs.detectLanguage(tab.id);
+ browser.test.assertEq("ja", lang, "Japanese document should be detected as Japanese");
+ await browser.tabs.remove(tab.id);
+
+ tab = await loadTab(`http://example.co.jp/${BASE_PATH}/file_language_fr_en.html`);
+ lang = await browser.tabs.detectLanguage(tab.id);
+ browser.test.assertEq("fr", lang, "French/English document should be detected as primarily French");
+ await browser.tabs.remove(tab.id);
+
+ tab = await loadTab(`http://example.co.jp/${BASE_PATH}/file_language_tlh.html`);
+ lang = await browser.tabs.detectLanguage(tab.id);
+ browser.test.assertEq("und", lang, "Klingon document should not be detected, should return 'und'");
+ await browser.tabs.remove(tab.id);
+
browser.test.notifyPass("detectLanguage");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`Error: ${e} :: ${e.stack}`);
browser.test.notifyFail("detectLanguage");
- });
+ }
},
});
yield extension.startup();
yield extension.awaitFinish("detectLanguage");
yield extension.unload();
--- a/browser/components/extensions/test/browser/browser_ext_tabs_duplicate.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_duplicate.js
@@ -36,17 +36,17 @@ add_task(function* testDuplicateTab() {
yield extension.unload();
while (gBrowser.tabs[0].linkedBrowser.currentURI.spec === "http://example.net/") {
yield BrowserTestUtils.removeTab(gBrowser.tabs[0]);
}
});
add_task(function* testDuplicateTabLazily() {
- function background() {
+ async function background() {
let tabLoadComplete = new Promise(resolve => {
browser.test.onMessage.addListener((message, tabId, result) => {
if (message == "duplicate-tab-done") {
resolve(tabId);
}
});
});
@@ -56,42 +56,38 @@ add_task(function* testDuplicateTabLazil
if (tabId == tabId_ && changed.status == "complete") {
browser.tabs.onUpdated.removeListener(listener);
resolve();
}
});
});
}
- let startTabId;
- let url = "http://example.com/browser/browser/components/extensions/test/browser/file_dummy.html";
- browser.tabs.create({url}, tab => {
- startTabId = tab.id;
+ try {
+ let url = "http://example.com/browser/browser/components/extensions/test/browser/file_dummy.html";
+ let tab = await browser.tabs.create({url});
+ let startTabId = tab.id;
- awaitLoad(startTabId).then(() => {
- browser.test.sendMessage("duplicate-tab", startTabId);
+ await awaitLoad(startTabId);
+ browser.test.sendMessage("duplicate-tab", startTabId);
- tabLoadComplete.then(unloadedTabId => {
- browser.tabs.get(startTabId, loadedtab => {
- browser.test.assertEq("Dummy test page", loadedtab.title, "Title should be returned for loaded pages");
- browser.test.assertEq("complete", loadedtab.status, "Tab status should be complete for loaded pages");
- });
+ let unloadedTabId = await tabLoadComplete;
+ let loadedtab = await browser.tabs.get(startTabId);
+ browser.test.assertEq("Dummy test page", loadedtab.title, "Title should be returned for loaded pages");
+ browser.test.assertEq("complete", loadedtab.status, "Tab status should be complete for loaded pages");
- browser.tabs.get(unloadedTabId, unloadedtab => {
- browser.test.assertEq("Dummy test page", unloadedtab.title, "Title should be returned after page has been unloaded");
- });
+ let unloadedtab = await browser.tabs.get(unloadedTabId);
+ browser.test.assertEq("Dummy test page", unloadedtab.title, "Title should be returned after page has been unloaded");
- browser.tabs.remove([tab.id, unloadedTabId]);
- browser.test.notifyPass("tabs.hasCorrectTabTitle");
- });
- }).catch(e => {
- browser.test.fail(`${e} :: ${e.stack}`);
- browser.test.notifyFail("tabs.hasCorrectTabTitle");
- });
- });
+ await browser.tabs.remove([tab.id, unloadedTabId]);
+ browser.test.notifyPass("tabs.hasCorrectTabTitle");
+ } catch (e) {
+ browser.test.fail(`${e} :: ${e.stack}`);
+ browser.test.notifyFail("tabs.hasCorrectTabTitle");
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_events.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_events.js
@@ -1,14 +1,14 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* testTabEvents() {
- function background() {
+ async function background() {
let events = [];
browser.tabs.onCreated.addListener(tab => {
events.push({type: "onCreated", tab});
});
browser.tabs.onAttached.addListener((tabId, info) => {
events.push(Object.assign({type: "onAttached", tabId}, info));
});
@@ -20,136 +20,131 @@ add_task(function* testTabEvents() {
browser.tabs.onRemoved.addListener((tabId, info) => {
events.push(Object.assign({type: "onRemoved", tabId}, info));
});
browser.tabs.onMoved.addListener((tabId, info) => {
events.push(Object.assign({type: "onMoved", tabId}, info));
});
- function expectEvents(names) {
+ async function expectEvents(names) {
browser.test.log(`Expecting events: ${names.join(", ")}`);
- return new Promise(resolve => {
- setTimeout(resolve, 0);
- }).then(() => {
- browser.test.assertEq(names.length, events.length, "Got expected number of events");
- for (let [i, name] of names.entries()) {
- browser.test.assertEq(name, i in events && events[i].type,
- `Got expected ${name} event`);
- }
- return events.splice(0);
- });
+ await new Promise(resolve => setTimeout(resolve, 0));
+
+ browser.test.assertEq(names.length, events.length, "Got expected number of events");
+ for (let [i, name] of names.entries()) {
+ browser.test.assertEq(name, i in events && events[i].type,
+ `Got expected ${name} event`);
+ }
+ return events.splice(0);
}
- browser.test.log("Create second browser window");
- let windowId;
- Promise.all([
- browser.windows.getCurrent(),
- browser.windows.create({url: "about:blank"}),
- ]).then(windows => {
- windowId = windows[0].id;
+ try {
+ browser.test.log("Create second browser window");
+
+ let windows = await Promise.all([
+ browser.windows.getCurrent(),
+ browser.windows.create({url: "about:blank"}),
+ ]);
+
+ let windowId = windows[0].id;
let otherWindowId = windows[1].id;
- let initialTab;
- return expectEvents(["onCreated"]).then(([created]) => {
- initialTab = created.tab;
+ let [created] = await expectEvents(["onCreated"]);
+ let initialTab = created.tab;
+
- browser.test.log("Create tab in window 1");
- return browser.tabs.create({windowId, index: 0, url: "about:blank"});
- }).then(tab => {
- let oldIndex = tab.index;
- browser.test.assertEq(0, oldIndex, "Tab has the expected index");
+ browser.test.log("Create tab in window 1");
+ let tab = await browser.tabs.create({windowId, index: 0, url: "about:blank"});
+ let oldIndex = tab.index;
+ browser.test.assertEq(0, oldIndex, "Tab has the expected index");
+
+ [created] = await expectEvents(["onCreated"]);
+ browser.test.assertEq(tab.id, created.tab.id, "Got expected tab ID");
+ browser.test.assertEq(oldIndex, created.tab.index, "Got expected tab index");
+
- return expectEvents(["onCreated"]).then(([created]) => {
- browser.test.assertEq(tab.id, created.tab.id, "Got expected tab ID");
- browser.test.assertEq(oldIndex, created.tab.index, "Got expected tab index");
+ browser.test.log("Move tab to window 2");
+ await browser.tabs.move([tab.id], {windowId: otherWindowId, index: 0});
- browser.test.log("Move tab to window 2");
- return browser.tabs.move([tab.id], {windowId: otherWindowId, index: 0});
- }).then(() => {
- return expectEvents(["onDetached", "onAttached"]);
- }).then(([detached, attached]) => {
- browser.test.assertEq(oldIndex, detached.oldPosition, "Expected old index");
- browser.test.assertEq(windowId, detached.oldWindowId, "Expected old window ID");
+ let [detached, attached] = await expectEvents(["onDetached", "onAttached"]);
+ browser.test.assertEq(oldIndex, detached.oldPosition, "Expected old index");
+ browser.test.assertEq(windowId, detached.oldWindowId, "Expected old window ID");
+
+ browser.test.assertEq(0, attached.newPosition, "Expected new index");
+ browser.test.assertEq(otherWindowId, attached.newWindowId, "Expected new window ID");
+
- browser.test.assertEq(0, attached.newPosition, "Expected new index");
- browser.test.assertEq(otherWindowId, attached.newWindowId, "Expected new window ID");
+ browser.test.log("Move tab within the same window");
+ let [moved] = await browser.tabs.move([tab.id], {index: 1});
+ browser.test.assertEq(1, moved.index, "Expected new index");
+
+ [moved] = await expectEvents(["onMoved"]);
+ browser.test.assertEq(tab.id, moved.tabId, "Expected tab ID");
+ browser.test.assertEq(0, moved.fromIndex, "Expected old index");
+ browser.test.assertEq(1, moved.toIndex, "Expected new index");
+ browser.test.assertEq(otherWindowId, moved.windowId, "Expected window ID");
- browser.test.log("Move tab within the same window");
- return browser.tabs.move([tab.id], {index: 1});
- }).then(([moved]) => {
- browser.test.assertEq(1, moved.index, "Expected new index");
+
+ browser.test.log("Remove tab");
+ await browser.tabs.remove(tab.id);
+ let [removed] = await expectEvents(["onRemoved"]);
- return expectEvents(["onMoved"]);
- }).then(([moved]) => {
- browser.test.assertEq(tab.id, moved.tabId, "Expected tab ID");
- browser.test.assertEq(0, moved.fromIndex, "Expected old index");
- browser.test.assertEq(1, moved.toIndex, "Expected new index");
- browser.test.assertEq(otherWindowId, moved.windowId, "Expected window ID");
+ browser.test.assertEq(tab.id, removed.tabId, "Expected removed tab ID");
+ browser.test.assertEq(otherWindowId, removed.windowId, "Expected removed tab window ID");
+ // Note: We want to test for the actual boolean value false here.
+ browser.test.assertEq(false, removed.isWindowClosing, "Expected isWindowClosing value");
+
- browser.test.log("Remove tab");
- return browser.tabs.remove(tab.id);
- }).then(() => {
- return expectEvents(["onRemoved"]);
- }).then(([removed]) => {
- browser.test.assertEq(tab.id, removed.tabId, "Expected removed tab ID");
- browser.test.assertEq(otherWindowId, removed.windowId, "Expected removed tab window ID");
- // Note: We want to test for the actual boolean value false here.
- browser.test.assertEq(false, removed.isWindowClosing, "Expected isWindowClosing value");
+ browser.test.log("Close second window");
+ await browser.windows.remove(otherWindowId);
+ [removed] = await expectEvents(["onRemoved"]);
+ browser.test.assertEq(initialTab.id, removed.tabId, "Expected removed tab ID");
+ browser.test.assertEq(otherWindowId, removed.windowId, "Expected removed tab window ID");
+ browser.test.assertEq(true, removed.isWindowClosing, "Expected isWindowClosing value");
+
- browser.test.log("Close second window");
- return browser.windows.remove(otherWindowId);
- }).then(() => {
- return expectEvents(["onRemoved"]);
- }).then(([removed]) => {
- browser.test.assertEq(initialTab.id, removed.tabId, "Expected removed tab ID");
- browser.test.assertEq(otherWindowId, removed.windowId, "Expected removed tab window ID");
- browser.test.assertEq(true, removed.isWindowClosing, "Expected isWindowClosing value");
+ browser.test.log("Create additional tab in window 1");
+ tab = await browser.tabs.create({windowId, url: "about:blank"});
+ await expectEvents(["onCreated"]);
+
+
+ browser.test.log("Create a new window, adopting the new tab");
+ // We have to explicitly wait for the event here, since its timing is
+ // not predictable.
+ let promiseAttached = new Promise(resolve => {
+ browser.tabs.onAttached.addListener(function listener(tabId) {
+ browser.tabs.onAttached.removeListener(listener);
+ resolve();
});
});
- }).then(() => {
- browser.test.log("Create additional tab in window 1");
- return browser.tabs.create({windowId, url: "about:blank"});
- }).then(tab => {
- return expectEvents(["onCreated"]).then(() => {
- browser.test.log("Create a new window, adopting the new tab");
- // We have to explicitly wait for the event here, since its timing is
- // not predictable.
- let promiseAttached = new Promise(resolve => {
- browser.tabs.onAttached.addListener(function listener(tabId) {
- browser.tabs.onAttached.removeListener(listener);
- resolve();
- });
- });
+ let [window] = await Promise.all([
+ browser.windows.create({tabId: tab.id}),
+ promiseAttached,
+ ]);
+
+ [detached, attached] = await expectEvents(["onDetached", "onAttached"]);
+
+ browser.test.assertEq(tab.id, detached.tabId, "Expected onDetached tab ID");
- return Promise.all([
- browser.windows.create({tabId: tab.id}),
- promiseAttached,
- ]);
- }).then(([window]) => {
- return expectEvents(["onDetached", "onAttached"]).then(([detached, attached]) => {
- browser.test.assertEq(tab.id, detached.tabId, "Expected onDetached tab ID");
+ browser.test.assertEq(tab.id, attached.tabId, "Expected onAttached tab ID");
+ browser.test.assertEq(0, attached.newPosition, "Expected onAttached new index");
+ browser.test.assertEq(window.id, attached.newWindowId,
+ "Expected onAttached new window id");
- browser.test.assertEq(tab.id, attached.tabId, "Expected onAttached tab ID");
- browser.test.assertEq(0, attached.newPosition, "Expected onAttached new index");
- browser.test.assertEq(window.id, attached.newWindowId,
- "Expected onAttached new window id");
+ browser.test.log("Close the new window");
+ await browser.windows.remove(window.id);
- browser.test.log("Close the new window");
- return browser.windows.remove(window.id);
- });
- });
- }).then(() => {
browser.test.notifyPass("tabs-events");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("tabs-events");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
background,
@@ -171,26 +166,24 @@ add_task(function* testTabEventsSize() {
});
browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status == "complete") {
sendSizeMessages(tab, "on-updated");
}
});
- browser.test.onMessage.addListener((msg, arg) => {
+ browser.test.onMessage.addListener(async (msg, arg) => {
if (msg === "create-tab") {
- browser.tabs.create({url: "http://example.com/"}).then(tab => {
- sendSizeMessages(tab, "create");
- browser.test.sendMessage("created-tab-id", tab.id);
- });
+ let tab = await browser.tabs.create({url: "http://example.com/"});
+ sendSizeMessages(tab, "create");
+ browser.test.sendMessage("created-tab-id", tab.id);
} else if (msg === "update-tab") {
- browser.tabs.update(arg, {url: "http://example.org/"}).then(tab => {
- sendSizeMessages(tab, "update");
- });
+ let tab = await browser.tabs.update(arg, {url: "http://example.org/"});
+ sendSizeMessages(tab, "update");
} else if (msg === "remove-tab") {
browser.tabs.remove(arg);
browser.test.sendMessage("tab-removed");
}
});
browser.test.sendMessage("ready");
}
@@ -233,19 +226,17 @@ add_task(function* testTabEventsSize() {
yield extension.awaitMessage("tab-removed");
}
yield extension.unload();
SpecialPowers.clearUserPref(RESOLUTION_PREF);
});
add_task(function* testTabRemovalEvent() {
- function background() {
- let removalTabId;
-
+ async function background() {
function awaitLoad(tabId) {
return new Promise(resolve => {
browser.tabs.onUpdated.addListener(function listener(tabId_, changed, tab) {
if (tabId == tabId_ && changed.status == "complete") {
browser.tabs.onUpdated.removeListener(listener);
resolve();
}
});
@@ -257,27 +248,26 @@ add_task(function* testTabRemovalEvent()
chrome.tabs.query({}, tabs => {
for (let tab of tabs) {
browser.test.assertTrue(tab.id != tabId, "Tab query should not include removed tabId");
}
browser.test.notifyPass("tabs-events");
});
});
- let url = "http://example.com/browser/browser/components/extensions/test/browser/context.html";
- browser.tabs.create({url: url})
- .then(tab => {
- removalTabId = tab.id;
- return awaitLoad(tab.id);
- }).then(() => {
- return browser.tabs.remove(removalTabId);
- }).catch(e => {
+ try {
+ let url = "http://example.com/browser/browser/components/extensions/test/browser/context.html";
+ let tab = await browser.tabs.create({url: url});
+ await awaitLoad(tab.id);
+
+ await browser.tabs.remove(tab.id);
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("tabs-events");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
@@ -31,22 +31,23 @@ add_task(function* testExecuteScript() {
let messageManagersSize = countMM(MessageChannel.messageManagers);
let responseManagersSize = countMM(MessageChannel.responseManagers);
const BASE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/";
const URL = BASE + "file_iframe_document.html";
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URL, true);
- function background() {
- browser.tabs.query({active: true, currentWindow: true}).then(tabs => {
- return browser.webNavigation.getAllFrames({tabId: tabs[0].id});
- }).then(frames => {
+ async function background() {
+ try {
+ let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+ let frames = await browser.webNavigation.getAllFrames({tabId: tab.id});
+
browser.test.log(`FRAMES: ${frames[1].frameId} ${JSON.stringify(frames)}\n`);
- return Promise.all([
+ await Promise.all([
browser.tabs.executeScript({
code: "42",
}).then(result => {
browser.test.assertEq(1, result.length, "Expected one callback result");
browser.test.assertEq(42, result[0], "Expected callback result");
}),
browser.tabs.executeScript({
@@ -122,30 +123,30 @@ add_task(function* testExecuteScript() {
let details = {
frame_id: Number.MAX_SAFE_INTEGER,
matchesHost: ["http://mochi.test/", "http://example.com/"],
};
browser.test.assertEq(`No window matching ${JSON.stringify(details)}`,
error.message, "Got expected error");
}),
- browser.tabs.create({url: "http://example.net/", active: false}).then(tab => {
- return browser.tabs.executeScript(tab.id, {
+ browser.tabs.create({url: "http://example.net/", active: false}).then(async tab => {
+ await browser.tabs.executeScript(tab.id, {
code: "42",
}).then(result => {
browser.test.fail("Expected error when trying to execute on invalid domain");
}, error => {
let details = {
matchesHost: ["http://mochi.test/", "http://example.com/"],
};
browser.test.assertEq(`No window matching ${JSON.stringify(details)}`,
error.message, "Got expected error");
- }).then(() => {
- return browser.tabs.remove(tab.id);
});
+
+ await browser.tabs.remove(tab.id);
}),
browser.tabs.executeScript({
code: "Promise.resolve(42)",
}).then(result => {
browser.test.assertEq(42, result[0], "Got expected promise resolution value as result");
}),
@@ -173,37 +174,37 @@ add_task(function* testExecuteScript() {
browser.tabs.executeScript({
code: "location.href;",
frameId: frames[1].frameId,
}).then(result => {
browser.test.assertEq(1, result.length, "Expected one result");
browser.test.assertEq("http://mochi.test:8888/", result[0], "Result for frameId[1] is correct");
}),
- browser.tabs.create({url: "http://example.com/"}).then(tab => {
- return browser.tabs.executeScript(tab.id, {code: "location.href"}).then(result => {
- browser.test.assertEq("http://example.com/", result[0], "Script executed correctly in new tab");
+ browser.tabs.create({url: "http://example.com/"}).then(async tab => {
+ let result = await browser.tabs.executeScript(tab.id, {code: "location.href"});
- return browser.tabs.remove(tab.id);
- });
+ browser.test.assertEq("http://example.com/", result[0], "Script executed correctly in new tab");
+
+ await browser.tabs.remove(tab.id);
}),
new Promise(resolve => {
browser.runtime.onMessage.addListener(message => {
browser.test.assertEq("script ran", message, "Expected runtime message");
resolve();
});
}),
]);
- }).then(() => {
+
browser.test.notifyPass("executeScript");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`Error: ${e} :: ${e.stack}`);
browser.test.notifyFail("executeScript");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["http://mochi.test/", "http://example.com/", "webNavigation"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_bad.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_bad.js
@@ -1,16 +1,16 @@
"use strict";
// This is a pretty terrible hack, but it's the best we can do until we
// support |executeScript| callbacks and |lastError|.
function* testHasNoPermission(params) {
let contentSetup = params.contentSetup || (() => Promise.resolve());
- function background(contentSetup) {
+ async function background(contentSetup) {
browser.runtime.onMessage.addListener((msg, sender) => {
browser.test.assertEq(msg, "second script ran", "second script ran");
browser.test.notifyPass("executeScript");
});
browser.test.onMessage.addListener(msg => {
browser.test.assertEq(msg, "execute-script");
@@ -25,19 +25,19 @@ function* testHasNoPermission(params) {
// it, but it's just about the best we can do until we
// support callbacks for executeScript.
browser.tabs.executeScript(tabs[1].id, {
file: "second-script.js",
});
});
});
- contentSetup().then(() => {
- browser.test.sendMessage("ready");
- });
+ await contentSetup();
+
+ browser.test.sendMessage("ready");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: params.manifest,
background: `(${background})(${contentSetup})`,
files: {
@@ -127,83 +127,76 @@ add_task(function* testBadPermissions()
});
info("Test active tab, page action, no click");
yield testHasNoPermission({
manifest: {
"permissions": ["http://example.com/", "activeTab"],
"page_action": {},
},
- contentSetup() {
- return new Promise(resolve => {
- browser.tabs.query({active: true, currentWindow: true}, tabs => {
- browser.pageAction.show(tabs[0].id).then(() => {
- resolve();
- });
- });
- });
+ async contentSetup() {
+ let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+ await browser.pageAction.show(tab.id);
},
});
yield BrowserTestUtils.removeTab(tab2);
yield BrowserTestUtils.removeTab(tab1);
});
add_task(function* testBadURL() {
- function background() {
- browser.tabs.query({currentWindow: true}, tabs => {
- let promises = [
- new Promise(resolve => {
- browser.tabs.executeScript({
- file: "http://example.com/script.js",
- }, result => {
- browser.test.assertEq(undefined, result, "Result value");
-
- browser.test.assertTrue(browser.extension.lastError instanceof Error,
- "runtime.lastError is Error");
-
- browser.test.assertTrue(browser.runtime.lastError instanceof Error,
- "runtime.lastError is Error");
-
- browser.test.assertEq(
- "Files to be injected must be within the extension",
- browser.extension.lastError && browser.extension.lastError.message,
- "extension.lastError value");
-
- browser.test.assertEq(
- "Files to be injected must be within the extension",
- browser.runtime.lastError && browser.runtime.lastError.message,
- "runtime.lastError value");
-
- resolve();
- });
- }),
-
+ async function background() {
+ let promises = [
+ new Promise(resolve => {
browser.tabs.executeScript({
file: "http://example.com/script.js",
- }).catch(error => {
- browser.test.assertTrue(error instanceof Error, "Error is Error");
+ }, result => {
+ browser.test.assertEq(undefined, result, "Result value");
+
+ browser.test.assertTrue(browser.extension.lastError instanceof Error,
+ "runtime.lastError is Error");
- browser.test.assertEq(null, browser.extension.lastError,
- "extension.lastError value");
+ browser.test.assertTrue(browser.runtime.lastError instanceof Error,
+ "runtime.lastError is Error");
- browser.test.assertEq(null, browser.runtime.lastError,
- "runtime.lastError value");
+ browser.test.assertEq(
+ "Files to be injected must be within the extension",
+ browser.extension.lastError && browser.extension.lastError.message,
+ "extension.lastError value");
browser.test.assertEq(
"Files to be injected must be within the extension",
- error && error.message,
- "error value");
- }),
- ];
+ browser.runtime.lastError && browser.runtime.lastError.message,
+ "runtime.lastError value");
+
+ resolve();
+ });
+ }),
+
+ browser.tabs.executeScript({
+ file: "http://example.com/script.js",
+ }).catch(error => {
+ browser.test.assertTrue(error instanceof Error, "Error is Error");
- Promise.all(promises).then(() => {
- browser.test.notifyPass("executeScript-lastError");
- });
- });
+ browser.test.assertEq(null, browser.extension.lastError,
+ "extension.lastError value");
+
+ browser.test.assertEq(null, browser.runtime.lastError,
+ "runtime.lastError value");
+
+ browser.test.assertEq(
+ "Files to be injected must be within the extension",
+ error && error.message,
+ "error value");
+ }),
+ ];
+
+ await Promise.all(promises);
+
+ browser.test.notifyPass("executeScript-lastError");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["<all_urls>"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_good.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_good.js
@@ -2,33 +2,33 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
requestLongerTimeout(2);
function* testHasPermission(params) {
let contentSetup = params.contentSetup || (() => Promise.resolve());
- function background(contentSetup) {
+ async function background(contentSetup) {
browser.runtime.onMessage.addListener((msg, sender) => {
browser.test.assertEq(msg, "script ran", "script ran");
browser.test.notifyPass("executeScript");
});
browser.test.onMessage.addListener(msg => {
browser.test.assertEq(msg, "execute-script");
browser.tabs.executeScript({
file: "script.js",
});
});
- contentSetup().then(() => {
- browser.test.sendMessage("ready");
- });
+ await contentSetup();
+
+ browser.test.sendMessage("ready");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: params.manifest,
background: `(${background})(${contentSetup})`,
files: {
@@ -117,57 +117,46 @@ add_task(function* testGoodPermissions()
});
info("Test activeTab permission with a page action click");
yield testHasPermission({
manifest: {
"permissions": ["activeTab"],
"page_action": {},
},
- contentSetup() {
- return new Promise(resolve => {
- browser.tabs.query({active: true, currentWindow: true}, tabs => {
- browser.pageAction.show(tabs[0].id).then(() => {
- resolve();
- });
- });
- });
+ contentSetup: async () => {
+ let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+ await browser.pageAction.show(tab.id);
},
setup: clickPageAction,
tearDown: closePageAction,
});
info("Test activeTab permission with a browser action w/popup click");
yield testHasPermission({
manifest: {
"permissions": ["activeTab"],
"browser_action": {"default_popup": "_blank.html"},
},
- setup: extension => {
- return clickBrowserAction(extension).then(() => {
- return awaitExtensionPanel(extension, window, "_blank.html");
- });
+ setup: async extension => {
+ await clickBrowserAction(extension);
+ return awaitExtensionPanel(extension, window, "_blank.html");
},
tearDown: closeBrowserAction,
});
info("Test activeTab permission with a page action w/popup click");
yield testHasPermission({
manifest: {
"permissions": ["activeTab"],
"page_action": {"default_popup": "_blank.html"},
},
- contentSetup() {
- return new Promise(resolve => {
- browser.tabs.query({active: true, currentWindow: true}, tabs => {
- browser.pageAction.show(tabs[0].id).then(() => {
- resolve();
- });
- });
- });
+ contentSetup: async () => {
+ let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+ await browser.pageAction.show(tab.id);
},
setup: clickPageAction,
tearDown: closePageAction,
});
info("Test activeTab permission with a context menu click");
yield testHasPermission({
manifest: {
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_runAt.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_runAt.js
@@ -12,91 +12,86 @@
*
* And since we can't actually rely on that timing, it retries any attempts that
* fail to load as early as expected, but don't load at any illegal time.
*/
add_task(function* testExecuteScript() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank", true);
- function background() {
+ async function background() {
let tab;
const BASE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/";
const URL = BASE + "file_iframe_document.sjs";
const MAX_TRIES = 10;
- let tries = 0;
+
+ try {
+ [tab] = await browser.tabs.query({active: true, currentWindow: true});
- function again() {
- if (tries++ == MAX_TRIES) {
- return Promise.reject(new Error("Max tries exceeded"));
- }
-
- let url = `${URL}?r=${Math.random()}`;
+ let success = false;
+ for (let tries = 0; !success && tries < MAX_TRIES; tries++) {
+ let url = `${URL}?r=${Math.random()}`;
- let loadingPromise = new Promise(resolve => {
- browser.tabs.onUpdated.addListener(function listener(tabId, changed, tab_) {
- if (tabId == tab.id && changed.status == "loading" && tab_.url == url) {
- browser.tabs.onUpdated.removeListener(listener);
- resolve();
- }
+ let loadingPromise = new Promise(resolve => {
+ browser.tabs.onUpdated.addListener(function listener(tabId, changed, tab_) {
+ if (tabId == tab.id && changed.status == "loading" && tab_.url == url) {
+ browser.tabs.onUpdated.removeListener(listener);
+ resolve();
+ }
+ });
});
- });
- // TODO: Test allFrames and frameId.
+ // TODO: Test allFrames and frameId.
- return browser.tabs.update({url}).then(() => {
- return loadingPromise;
- }).then(() => {
- return Promise.all([
+ await browser.tabs.update({url});
+ await loadingPromise;
+
+ let states = await Promise.all([
// Send the executeScript requests in the reverse order that we expect
// them to execute in, to avoid them passing only because of timing
// races.
browser.tabs.executeScript({
code: "document.readyState",
runAt: "document_idle",
}),
browser.tabs.executeScript({
code: "document.readyState",
runAt: "document_end",
}),
browser.tabs.executeScript({
code: "document.readyState",
runAt: "document_start",
}),
].reverse());
- }).then(states => {
+
browser.test.log(`Got states: ${states}`);
// Make sure that none of our scripts executed earlier than expected,
// regardless of retries.
browser.test.assertTrue(states[1] == "interactive" || states[1] == "complete",
`document_end state is valid: ${states[1]}`);
browser.test.assertTrue(states[2] == "complete",
`document_idle state is valid: ${states[2]}`);
// If we have the earliest valid states for each script, we're done.
// Otherwise, try again.
- if (states[0] != "loading" || states[1] != "interactive" || states[2] != "complete") {
- return again();
- }
- });
- }
+ success = (states[0] == "loading" &&
+ states[1] == "interactive" &&
+ states[2] == "complete");
+ }
- browser.tabs.query({active: true, currentWindow: true}).then(tabs => {
- tab = tabs[0];
+ browser.test.assertTrue(success, "Got the earliest expected states at least once");
- return again();
- }).then(() => {
browser.test.notifyPass("executeScript-runAt");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`Error: ${e} :: ${e.stack}`);
browser.test.notifyFail("executeScript-runAt");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["http://mochi.test/", "tabs"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_insertCSS.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_insertCSS.js
@@ -5,18 +5,18 @@
add_task(function* testExecuteScript() {
let {MessageChannel} = Cu.import("resource://gre/modules/MessageChannel.jsm", {});
let messageManagersSize = MessageChannel.messageManagers.size;
let responseManagersSize = MessageChannel.responseManagers.size;
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/", true);
- function background() {
- let promises = [
+ async function background() {
+ let tasks = [
{
background: "transparent",
foreground: "rgb(0, 113, 4)",
promise: () => {
return browser.tabs.insertCSS({
file: "file2.css",
});
},
@@ -32,41 +32,35 @@ add_task(function* testExecuteScript() {
},
];
function checkCSS() {
let computedStyle = window.getComputedStyle(document.body);
return [computedStyle.backgroundColor, computedStyle.color];
}
- function next() {
- if (!promises.length) {
- return;
- }
+ try {
+ for (let {promise, background, foreground} of tasks) {
+ let result = await promise();
- let {promise, background, foreground} = promises.shift();
- return promise().then(result => {
browser.test.assertEq(undefined, result, "Expected callback result");
- return browser.tabs.executeScript({
+ [result] = await browser.tabs.executeScript({
code: `(${checkCSS})()`,
});
- }).then(([result]) => {
+
browser.test.assertEq(background, result[0], "Expected background color");
browser.test.assertEq(foreground, result[1], "Expected foreground color");
- return next();
- });
- }
+ }
- next().then(() => {
browser.test.notifyPass("insertCSS");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`Error: ${e} :: ${e.stack}`);
browser.test.notifyFailure("insertCSS");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["http://mochi.test/"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_move.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_move.js
@@ -8,116 +8,94 @@ add_task(function* () {
gBrowser.selectedTab = tab1;
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
- background: function() {
- browser.tabs.query({
- lastFocusedWindow: true,
- }, function(tabs) {
- let tab = tabs[0];
- browser.tabs.move(tab.id, {index: 0});
- browser.tabs.query(
- {lastFocusedWindow: true},
- tabs => {
- browser.test.assertEq(tabs[0].url, tab.url, "should be first tab");
- browser.test.notifyPass("tabs.move.single");
- });
- });
+ background: async function() {
+ let [tab] = await browser.tabs.query({lastFocusedWindow: true});
+
+ browser.tabs.move(tab.id, {index: 0});
+ let tabs = await browser.tabs.query({lastFocusedWindow: true});
+
+ browser.test.assertEq(tabs[0].url, tab.url, "should be first tab");
+ browser.test.notifyPass("tabs.move.single");
},
});
yield extension.startup();
yield extension.awaitFinish("tabs.move.single");
yield extension.unload();
extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
- background: function() {
- browser.tabs.query(
- {lastFocusedWindow: true},
- tabs => {
- tabs.sort(function(a, b) { return a.url > b.url; });
- browser.tabs.move(tabs.map(tab => tab.id), {index: 0});
- browser.tabs.query(
- {lastFocusedWindow: true},
- tabs => {
- browser.test.assertEq(tabs[0].url, "about:blank", "should be first tab");
- browser.test.assertEq(tabs[1].url, "about:config", "should be second tab");
- browser.test.assertEq(tabs[2].url, "about:robots", "should be third tab");
- browser.test.notifyPass("tabs.move.multiple");
- });
- });
+ background: async function() {
+ let tabs = await browser.tabs.query({lastFocusedWindow: true});
+
+ tabs.sort(function(a, b) { return a.url > b.url; });
+
+ browser.tabs.move(tabs.map(tab => tab.id), {index: 0});
+
+ tabs = await browser.tabs.query({lastFocusedWindow: true});
+
+ browser.test.assertEq(tabs[0].url, "about:blank", "should be first tab");
+ browser.test.assertEq(tabs[1].url, "about:config", "should be second tab");
+ browser.test.assertEq(tabs[2].url, "about:robots", "should be third tab");
+
+ browser.test.notifyPass("tabs.move.multiple");
},
});
yield extension.startup();
yield extension.awaitFinish("tabs.move.multiple");
yield extension.unload();
extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
- background: function() {
- browser.tabs.query(
- {lastFocusedWindow: true},
- tabs => {
- let tab = tabs[1];
- // Assuming that tab.id of 12345 does not exist.
- browser.tabs.move([tab.id, 12345], {index: 0})
- .then(
- tabs => { browser.test.fail("Promise should not resolve"); },
- e => {
- browser.test.assertTrue(/Invalid tab/.test(e),
- "Invalid tab should be in error");
- })
- .then(
- browser.tabs.query({lastFocusedWindow: true})
- .then(
- (tabs) => {
- browser.test.assertEq(tabs[1].url, tab.url, "should be second tab");
- browser.test.notifyPass("tabs.move.invalid");
- }
- )
- );
- });
+ async background() {
+ let [, tab] = await browser.tabs.query({lastFocusedWindow: true});
+
+ // Assuming that tab.id of 12345 does not exist.
+ await browser.test.assertRejects(
+ browser.tabs.move([tab.id, 12345], {index: 0}),
+ /Invalid tab/,
+ "Should receive invalid tab error");
+
+ let tabs = await browser.tabs.query({lastFocusedWindow: true});
+ browser.test.assertEq(tabs[1].url, tab.url, "should be second tab");
+ browser.test.notifyPass("tabs.move.invalid");
},
});
yield extension.startup();
yield extension.awaitFinish("tabs.move.invalid");
yield extension.unload();
extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
- background: function() {
- browser.tabs.query(
- {lastFocusedWindow: true},
- tabs => {
- let tab = tabs[0];
- browser.tabs.move(tab.id, {index: -1});
- browser.tabs.query(
- {lastFocusedWindow: true},
- tabs => {
- browser.test.assertEq(tabs[2].url, tab.url, "should be last tab");
- browser.test.notifyPass("tabs.move.last");
- });
- });
+ background: async function() {
+ let [tab] = await browser.tabs.query({lastFocusedWindow: true});
+ browser.tabs.move(tab.id, {index: -1});
+
+ let tabs = await browser.tabs.query({lastFocusedWindow: true});
+
+ browser.test.assertEq(tabs[2].url, tab.url, "should be last tab");
+ browser.test.notifyPass("tabs.move.last");
},
});
yield extension.startup();
yield extension.awaitFinish("tabs.move.last");
yield extension.unload();
yield BrowserTestUtils.removeTab(tab1);
--- a/browser/components/extensions/test/browser/browser_ext_tabs_move_window.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_move_window.js
@@ -7,42 +7,33 @@ add_task(function* () {
let window1 = yield BrowserTestUtils.openNewBrowserWindow();
yield BrowserTestUtils.openNewForegroundTab(window1.gBrowser, "http://example.com/");
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
- background: function() {
- browser.tabs.query({
- url: "<all_urls>",
- }, function(tabs) {
- let destination = tabs[0];
- let source = tabs[1]; // skip over about:blank in window1
- browser.tabs.move(source.id, {windowId: destination.windowId, index: 0});
+ async background() {
+ let tabs = await browser.tabs.query({url: "<all_urls>"});
+ let destination = tabs[0];
+ let source = tabs[1]; // skip over about:blank in window1
- browser.tabs.query(
- {url: "<all_urls>"},
- tabs => {
- browser.test.assertEq(tabs[0].url, "http://example.com/");
- browser.test.assertEq(tabs[0].windowId, destination.windowId);
- browser.test.notifyPass("tabs.move.window");
- });
+ // Assuming that this windowId does not exist.
+ await browser.test.assertRejects(
+ browser.tabs.move(source.id, {windowId: 123144576, index: 0}),
+ /Invalid window/,
+ "Should receive invalid window error");
- // Assuming that this windowId does not exist.
- browser.tabs.move(source.id, {windowId: 123144576, index: 0})
- .then(
- tabs => { browser.test.fail("Promise should not resolve"); },
- e => {
- browser.test.assertTrue(/Invalid window/.test(e),
- "Invalid window should be in error");
- }
- );
- });
+ browser.tabs.move(source.id, {windowId: destination.windowId, index: 0});
+
+ tabs = await browser.tabs.query({url: "<all_urls>"});
+ browser.test.assertEq(tabs[0].url, "http://example.com/");
+ browser.test.assertEq(tabs[0].windowId, destination.windowId);
+ browser.test.notifyPass("tabs.move.window");
},
});
yield extension.startup();
yield extension.awaitFinish("tabs.move.window");
yield extension.unload();
for (let tab of window.gBrowser.tabs) {
@@ -61,33 +52,33 @@ add_task(function* test_currentWindowAft
browser.test.sendMessage("id", win.id);
});
}
});
browser.test.sendMessage("ready");
},
};
- function background() {
+ async function background() {
let tabId;
+
const url = browser.extension.getURL("current.html");
- browser.tabs.create({url}).then(tab => {
- tabId = tab.id;
- });
- browser.test.onMessage.addListener(msg => {
+
+ browser.test.onMessage.addListener(async msg => {
if (msg === "move") {
- browser.windows.create({tabId}).then(() => {
- browser.test.sendMessage("moved");
- });
+ await browser.windows.create({tabId});
+ browser.test.sendMessage("moved");
} else if (msg === "close") {
- browser.tabs.remove(tabId).then(() => {
- browser.test.sendMessage("done");
- });
+ await browser.tabs.remove(tabId);
+ browser.test.sendMessage("done");
}
});
+
+ let tab = await browser.tabs.create({url});
+ tabId = tab.id;
}
const extension = ExtensionTestUtils.loadExtension({files, background});
yield extension.startup();
yield extension.awaitMessage("ready");
extension.sendMessage("current");
--- a/browser/components/extensions/test/browser/browser_ext_tabs_onHighlighted.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_onHighlighted.js
@@ -1,14 +1,14 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* testTabEvents() {
- function background() {
+ async function background() {
/** The list of active tab ID's */
let tabIds = [];
/**
* Stores the events that fire for each tab.
*
* events {
* tabId1: [event1, event2, ...],
@@ -34,89 +34,87 @@ add_task(function* testTabEvents() {
});
/**
* Asserts that the expected events are fired for the tab with id = tabId.
* The events associated to the specified tab are removed after this check is made.
*
* @param {number} tabId
* @param {Array<string>} expectedEvents
- * @returns {Promise}
*/
- function expectEvents(tabId, expectedEvents) {
+ async function expectEvents(tabId, expectedEvents) {
browser.test.log(`Expecting events: ${expectedEvents.join(", ")}`);
- return new Promise(resolve => {
- setTimeout(resolve, 0);
- }).then(() => {
- browser.test.assertEq(expectedEvents.length, events[tabId].length,
- `Got expected number of events for ${tabId}`);
- for (let [i, name] of expectedEvents.entries()) {
- browser.test.assertEq(name, i in events[tabId] && events[tabId][i],
- `Got expected ${name} event`);
- }
- delete events[tabId];
- });
+ await new Promise(resolve => setTimeout(resolve, 0));
+
+ browser.test.assertEq(expectedEvents.length, events[tabId].length,
+ `Got expected number of events for ${tabId}`);
+
+ for (let [i, name] of expectedEvents.entries()) {
+ browser.test.assertEq(name, i in events[tabId] && events[tabId][i],
+ `Got expected ${name} event`);
+ }
+ delete events[tabId];
}
/**
* Opens a new tab and asserts that the correct events are fired.
*
* @param {number} windowId
- * @returns {Promise}
*/
- function openTab(windowId) {
- return browser.tabs.create({windowId}).then(tab => {
- tabIds.push(tab.id);
- browser.test.log(`Opened tab ${tab.id}`);
- return expectEvents(tab.id, [
- "onActivated",
- "onHighlighted",
- ]);
- });
+ async function openTab(windowId) {
+ let tab = await browser.tabs.create({windowId});
+
+ tabIds.push(tab.id);
+ browser.test.log(`Opened tab ${tab.id}`);
+
+ await expectEvents(tab.id, [
+ "onActivated",
+ "onHighlighted",
+ ]);
}
/**
* Highlights an existing tab and asserts that the correct events are fired.
*
* @param {number} tabId
- * @returns {Promise}
*/
- function highlightTab(tabId) {
+ async function highlightTab(tabId) {
browser.test.log(`Highlighting tab ${tabId}`);
- return browser.tabs.update(tabId, {active: true}).then(tab => {
- browser.test.assertEq(tab.id, tabId, `Tab ${tab.id} highlighted`);
- return expectEvents(tab.id, [
- "onActivated",
- "onHighlighted",
- ]);
- });
+ let tab = await browser.tabs.update(tabId, {active: true});
+
+ browser.test.assertEq(tab.id, tabId, `Tab ${tab.id} highlighted`);
+
+ await expectEvents(tab.id, [
+ "onActivated",
+ "onHighlighted",
+ ]);
}
/**
* The main entry point to the tests.
*/
- browser.tabs.query({active: true, currentWindow: true}, tabs => {
- let activeWindow = tabs[0].windowId;
- Promise.all([
- openTab(activeWindow),
- openTab(activeWindow),
- openTab(activeWindow),
- ]).then(() => {
- return Promise.all([
- highlightTab(tabIds[0]),
- highlightTab(tabIds[1]),
- highlightTab(tabIds[2]),
- ]);
- }).then(() => {
- return Promise.all(tabIds.map(id => browser.tabs.remove(id)));
- }).then(() => {
- browser.test.notifyPass("tabs.highlight");
- });
- });
+ let tabs = await browser.tabs.query({active: true, currentWindow: true});
+
+ let activeWindow = tabs[0].windowId;
+ await Promise.all([
+ openTab(activeWindow),
+ openTab(activeWindow),
+ openTab(activeWindow),
+ ]);
+
+ await Promise.all([
+ highlightTab(tabIds[0]),
+ highlightTab(tabIds[1]),
+ highlightTab(tabIds[2]),
+ ]);
+
+ await Promise.all(tabIds.map(id => browser.tabs.remove(id)));
+
+ browser.test.notifyPass("tabs.highlight");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_query.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_query.js
@@ -134,21 +134,21 @@ add_task(function* () {
// test width and height
extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
background: function() {
- browser.test.onMessage.addListener((msg) => {
- browser.tabs.query({active: true}).then(tabs => {
- browser.test.assertEq(tabs.length, 1, "should have one tab");
- browser.test.sendMessage("dims", {width: tabs[0].width, height: tabs[0].height});
- });
+ browser.test.onMessage.addListener(async msg => {
+ let tabs = await browser.tabs.query({active: true});
+
+ browser.test.assertEq(tabs.length, 1, "should have one tab");
+ browser.test.sendMessage("dims", {width: tabs[0].width, height: tabs[0].height});
});
browser.test.sendMessage("ready");
},
});
const RESOLUTION_PREF = "layout.css.devPixelsPerPx";
registerCleanupFunction(() => {
SpecialPowers.clearUserPref(RESOLUTION_PREF);
@@ -177,47 +177,47 @@ add_task(function* () {
});
add_task(function* testQueryPermissions() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": [],
},
- background: function(x) {
- browser.tabs.query({currentWindow: true, active: true}).then((tabs) => {
+ async background() {
+ try {
+ let tabs = await browser.tabs.query({currentWindow: true, active: true});
browser.test.assertEq(tabs.length, 1, "Expect query to return tabs");
browser.test.notifyPass("queryPermissions");
- }).catch((e) => {
+ } catch (e) {
browser.test.notifyFail("queryPermissions");
- });
+ }
},
});
yield extension.startup();
yield extension.awaitFinish("queryPermissions");
yield extension.unload();
});
add_task(function* testQueryWithURLPermissions() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": [],
},
- background: function(x) {
- browser.tabs.query({"url": "http://www.bbc.com/"}).then(() => {
- browser.test.notifyFail("queryWithURLPermissions");
- }).catch((e) => {
- browser.test.assertEq('The "tabs" permission is required to use the query API with the "url" parameter',
- e.message, "Expected permissions error message");
- browser.test.notifyPass("queryWithURLPermissions");
- });
+ async background() {
+ await browser.test.assertRejects(
+ browser.tabs.query({"url": "http://www.bbc.com/"}),
+ 'The "tabs" permission is required to use the query API with the "url" parameter',
+ "Expected tabs.query with 'url' to fail with permissions error message");
+
+ browser.test.notifyPass("queryWithURLPermissions");
},
});
yield extension.startup();
yield extension.awaitFinish("queryWithURLPermissions");
yield extension.unload();
--- a/browser/components/extensions/test/browser/browser_ext_tabs_reload.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_reload.js
@@ -14,41 +14,41 @@ add_task(function* () {
},
"tab.html":
`<head>
<meta charset="utf-8">
<script src="tab.js"></script>
</head>`,
},
- background: function() {
+ async background() {
let tabLoadedCount = 0;
- browser.tabs.create({url: "tab.html", active: true}).then(tab => {
- browser.runtime.onMessage.addListener(msg => {
- if (msg == "tab-loaded") {
- tabLoadedCount++;
+ let tab = await browser.tabs.create({url: "tab.html", active: true});
- if (tabLoadedCount == 1) {
- // Reload the tab once passing no arguments.
- return browser.tabs.reload();
- }
+ browser.runtime.onMessage.addListener(msg => {
+ if (msg == "tab-loaded") {
+ tabLoadedCount++;
+
+ if (tabLoadedCount == 1) {
+ // Reload the tab once passing no arguments.
+ return browser.tabs.reload();
+ }
- if (tabLoadedCount == 2) {
- // Reload the tab again with explicit arguments.
- return browser.tabs.reload(tab.id, {
- bypassCache: false,
- });
- }
+ if (tabLoadedCount == 2) {
+ // Reload the tab again with explicit arguments.
+ return browser.tabs.reload(tab.id, {
+ bypassCache: false,
+ });
+ }
- if (tabLoadedCount == 3) {
- browser.test.notifyPass("tabs.reload");
- }
+ if (tabLoadedCount == 3) {
+ browser.test.notifyPass("tabs.reload");
}
- });
+ }
});
},
});
yield extension.startup();
yield extension.awaitFinish("tabs.reload");
yield extension.unload();
});
--- a/browser/components/extensions/test/browser/browser_ext_tabs_reload_bypass_cache.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_reload_bypass_cache.js
@@ -3,57 +3,56 @@
"use strict";
add_task(function* () {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs", "<all_urls>"],
},
- background: function() {
+ async background() {
const BASE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/";
const URL = BASE + "file_bypass_cache.sjs";
function awaitLoad(tabId) {
return new Promise(resolve => {
browser.tabs.onUpdated.addListener(function listener(tabId_, changed, tab) {
if (tabId == tabId_ && changed.status == "complete" && tab.url == URL) {
browser.tabs.onUpdated.removeListener(listener);
resolve();
}
});
});
}
- let tabId;
- browser.tabs.create({url: URL}).then((tab) => {
- tabId = tab.id;
- return awaitLoad(tabId);
- }).then(() => {
- return browser.tabs.reload(tabId, {bypassCache: false});
- }).then(() => {
- return awaitLoad(tabId);
- }).then(() => {
- return browser.tabs.executeScript(tabId, {code: "document.body.textContent"});
- }).then(([textContent]) => {
+ try {
+ let tab = await browser.tabs.create({url: URL});
+ await awaitLoad(tab.id);
+
+ await browser.tabs.reload(tab.id, {bypassCache: false});
+ await awaitLoad(tab.id);
+
+ let [textContent] = await browser.tabs.executeScript(tab.id, {code: "document.body.textContent"});
browser.test.assertEq("", textContent, "`textContent` should be empty when bypassCache=false");
- return browser.tabs.reload(tabId, {bypassCache: true});
- }).then(() => {
- return awaitLoad(tabId);
- }).then(() => {
- return browser.tabs.executeScript(tabId, {code: "document.body.textContent"});
- }).then(([textContent]) => {
+
+ await browser.tabs.reload(tab.id, {bypassCache: true});
+ await awaitLoad(tab.id);
+
+ [textContent] = await browser.tabs.executeScript(tab.id, {code: "document.body.textContent"});
+
let [pragma, cacheControl] = textContent.split(":");
browser.test.assertEq("no-cache", pragma, "`pragma` should be set to `no-cache` when bypassCache is true");
browser.test.assertEq("no-cache", cacheControl, "`cacheControl` should be set to `no-cache` when bypassCache is true");
- browser.tabs.remove(tabId);
+
+ await browser.tabs.remove(tab.id);
+
browser.test.notifyPass("tabs.reload_bypass_cache");
- }).catch(error => {
+ } catch (error) {
browser.test.fail(`${error} :: ${error.stack}`);
browser.test.notifyFail("tabs.reload_bypass_cache");
- });
+ }
},
});
yield extension.startup();
yield extension.awaitFinish("tabs.reload_bypass_cache");
yield extension.unload();
});
--- a/browser/components/extensions/test/browser/browser_ext_tabs_removeCSS.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_removeCSS.js
@@ -1,17 +1,17 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* testExecuteScript() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/", true);
- function background() {
- let promises = [
+ async function background() {
+ let tasks = [
// Insert CSS file.
{
background: "transparent",
foreground: "rgb(0, 113, 4)",
promise: () => {
return browser.tabs.insertCSS({
file: "file2.css",
});
@@ -49,41 +49,33 @@ add_task(function* testExecuteScript() {
},
];
function checkCSS() {
let computedStyle = window.getComputedStyle(document.body);
return [computedStyle.backgroundColor, computedStyle.color];
}
- function next() {
- if (!promises.length) {
- return;
- }
-
- let {promise, background, foreground} = promises.shift();
- return promise().then(result => {
+ try {
+ for (let {promise, background, foreground} of tasks) {
+ let result = await promise();
browser.test.assertEq(undefined, result, "Expected callback result");
- return browser.tabs.executeScript({
+ [result] = await browser.tabs.executeScript({
code: `(${checkCSS})()`,
});
- }).then(([result]) => {
browser.test.assertEq(background, result[0], "Expected background color");
browser.test.assertEq(foreground, result[1], "Expected foreground color");
- return next();
- });
- }
+ }
- next().then(() => {
browser.test.notifyPass("removeCSS");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`Error: ${e} :: ${e.stack}`);
browser.test.notifyFailure("removeCSS");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["http://mochi.test/"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_tabs_sendMessage.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_sendMessage.js
@@ -9,17 +9,17 @@ add_task(function* tabsSendMessageReply(
"content_scripts": [{
"matches": ["http://example.com/"],
"js": ["content-script.js"],
"run_at": "document_start",
}],
},
- background: function() {
+ background: async function() {
let firstTab;
let promiseResponse = new Promise(resolve => {
browser.runtime.onMessage.addListener((msg, sender, respond) => {
if (msg == "content-script-ready") {
let tabId = sender.tab.id;
Promise.all([
promiseResponse,
@@ -61,50 +61,50 @@ add_task(function* tabsSendMessageReply(
return Promise.resolve("expected-response");
} else if (msg[0] == "got-response") {
resolve(msg[1]);
}
});
});
- browser.tabs.query({currentWindow: true, active: true}).then(tabs => {
- firstTab = tabs[0].id;
- browser.tabs.create({url: "http://example.com/"});
- });
+ let tabs = await browser.tabs.query({currentWindow: true, active: true});
+ firstTab = tabs[0].id;
+ browser.tabs.create({url: "http://example.com/"});
},
files: {
- "content-script.js": function() {
+ "content-script.js": async function() {
browser.runtime.onMessage.addListener((msg, sender, respond) => {
if (msg == "respond-now") {
respond(msg);
} else if (msg == "respond-soon") {
setTimeout(() => { respond(msg); }, 0);
return true;
} else if (msg == "respond-promise") {
return Promise.resolve(msg);
} else if (msg == "respond-never") {
return;
} else if (msg == "respond-error") {
return Promise.reject(new Error(msg));
} else if (msg == "throw-error") {
throw new Error(msg);
}
});
+
browser.runtime.onMessage.addListener((msg, sender, respond) => {
if (msg == "respond-now") {
respond("hello");
} else if (msg == "respond-now-2") {
respond(msg);
}
});
- browser.runtime.sendMessage("content-script-ready").then(response => {
- browser.runtime.sendMessage(["got-response", response]);
- });
+
+ let response = await browser.runtime.sendMessage("content-script-ready");
+ browser.runtime.sendMessage(["got-response", response]);
},
},
});
yield extension.startup();
yield extension.awaitFinish("sendMessage");
@@ -119,62 +119,60 @@ add_task(function* tabsSendHidden() {
"content_scripts": [{
"matches": ["http://example.com/content*"],
"js": ["content-script.js"],
"run_at": "document_start",
}],
},
- background: function() {
+ background: async function() {
let resolveContent;
browser.runtime.onMessage.addListener((msg, sender) => {
if (msg[0] == "content-ready") {
resolveContent(msg[1]);
}
});
let awaitContent = url => {
return new Promise(resolve => {
resolveContent = resolve;
}).then(result => {
browser.test.assertEq(url, result, "Expected content script URL");
});
};
- const URL1 = "http://example.com/content1.html";
- const URL2 = "http://example.com/content2.html";
- browser.tabs.create({url: URL1}).then(tab => {
- return awaitContent(URL1).then(() => {
- return browser.tabs.sendMessage(tab.id, URL1);
- }).then(url => {
- browser.test.assertEq(URL1, url, "Should get response from expected content window");
+ try {
+ const URL1 = "http://example.com/content1.html";
+ const URL2 = "http://example.com/content2.html";
+
+ let tab = await browser.tabs.create({url: URL1});
+ await awaitContent(URL1);
+
+ let url = await browser.tabs.sendMessage(tab.id, URL1);
+ browser.test.assertEq(URL1, url, "Should get response from expected content window");
+
+ await browser.tabs.update(tab.id, {url: URL2});
+ await awaitContent(URL2);
- return browser.tabs.update(tab.id, {url: URL2});
- }).then(() => {
- return awaitContent(URL2);
- }).then(() => {
- return browser.tabs.sendMessage(tab.id, URL2);
- }).then(url => {
- browser.test.assertEq(URL2, url, "Should get response from expected content window");
+ url = await browser.tabs.sendMessage(tab.id, URL2);
+ browser.test.assertEq(URL2, url, "Should get response from expected content window");
- // Repeat once just to be sure the first message was processed by all
- // listeners before we exit the test.
- return browser.tabs.sendMessage(tab.id, URL2);
- }).then(url => {
- browser.test.assertEq(URL2, url, "Should get response from expected content window");
+ // Repeat once just to be sure the first message was processed by all
+ // listeners before we exit the test.
+ url = await browser.tabs.sendMessage(tab.id, URL2);
+ browser.test.assertEq(URL2, url, "Should get response from expected content window");
- return browser.tabs.remove(tab.id);
- });
- }).then(() => {
+ await browser.tabs.remove(tab.id);
+
browser.test.notifyPass("contentscript-bfcache-window");
- }).catch(error => {
+ } catch (error) {
browser.test.fail(`Error: ${error} :: ${error.stack}`);
browser.test.notifyFail("contentscript-bfcache-window");
- });
+ }
},
files: {
"content-script.js": function() {
// Store this in a local variable to make sure we don't touch any
// properties of the possibly-hidden content window.
let href = window.location.href;
@@ -198,32 +196,30 @@ add_task(function* tabsSendHidden() {
add_task(function* tabsSendMessageNoExceptionOnNonExistentTab() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
- background: function() {
+ async background() {
let url = "http://example.com/mochitest/browser/browser/components/extensions/test/browser/file_dummy.html";
- browser.tabs.create({url}, tab => {
- let exception;
- try {
- browser.tabs.sendMessage(tab.id, "message");
- browser.tabs.sendMessage(tab.id + 100, "message");
- } catch (e) {
- exception = e;
- }
+ let tab = await browser.tabs.create({url});
- browser.test.assertEq(undefined, exception, "no exception should be raised on tabs.sendMessage to nonexistent tabs");
- browser.tabs.remove(tab.id, function() {
- browser.test.notifyPass("tabs.sendMessage");
- });
- });
+ try {
+ browser.tabs.sendMessage(tab.id, "message");
+ browser.tabs.sendMessage(tab.id + 100, "message");
+ } catch (e) {
+ browser.test.fail("no exception should be raised on tabs.sendMessage to nonexistent tabs");
+ }
+
+ await browser.tabs.remove(tab.id);
+
+ browser.test.notifyPass("tabs.sendMessage");
},
});
yield Promise.all([
extension.startup(),
extension.awaitFinish("tabs.sendMessage"),
]);
--- a/browser/components/extensions/test/browser/browser_ext_tabs_update_url.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_update_url.js
@@ -19,41 +19,31 @@ function* testTabsUpdateURL(existentTabU
<h1>tab page</h1>
</body>
</html>
`.trim(),
},
background: function() {
browser.test.sendMessage("ready", browser.runtime.getURL("tab.html"));
- browser.test.onMessage.addListener((msg, tabsUpdateURL, isErrorExpected) => {
- let onTabsUpdated = (tab) => {
- if (isErrorExpected) {
- browser.test.fail(`tabs.update with URL ${tabsUpdateURL} should be rejected`);
- } else {
- browser.test.assertTrue(tab, "on success the tab should be defined");
- }
- };
+ browser.test.onMessage.addListener(async (msg, tabsUpdateURL, isErrorExpected) => {
+ let tabs = await browser.tabs.query({lastFocusedWindow: true});
+
+ try {
+ let tab = await browser.tabs.update(tabs[1].id, {url: tabsUpdateURL});
- let onTabsUpdateError = (error) => {
- if (!isErrorExpected) {
- browser.test.fails(`tabs.update with URL ${tabsUpdateURL} should not be rejected`);
- } else {
- browser.test.assertTrue(/^Illegal URL/.test(error.message),
- "tabs.update should be rejected with the expected error message");
- }
- };
+ browser.test.assertFalse(isErrorExpected, `tabs.update with URL ${tabsUpdateURL} should be rejected`);
+ browser.test.assertTrue(tab, "on success the tab should be defined");
+ } catch (error) {
+ browser.test.assertTrue(isErrorExpected, `tabs.update with URL ${tabsUpdateURL} should not be rejected`);
+ browser.test.assertTrue(/^Illegal URL/.test(error.message),
+ "tabs.update should be rejected with the expected error message");
+ }
- let onTabsUpdateDone = () => browser.test.sendMessage("done");
-
- browser.tabs.query({lastFocusedWindow: true}, (tabs) => {
- browser.tabs.update(tabs[1].id, {url: tabsUpdateURL})
- .then(onTabsUpdated, onTabsUpdateError)
- .then(onTabsUpdateDone);
- });
+ browser.test.sendMessage("done");
});
},
});
yield extension.startup();
let mozExtTabURL = yield extension.awaitMessage("ready");
--- a/browser/components/extensions/test/browser/browser_ext_tabs_zoom.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_zoom.js
@@ -5,17 +5,17 @@
const SITE_SPECIFIC_PREF = "browser.zoom.siteSpecific";
add_task(function* () {
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.net/");
gBrowser.selectedTab = tab1;
- function background() {
+ async function background() {
function promiseUpdated(tabId, attr) {
return new Promise(resolve => {
let onUpdated = (tabId_, changeInfo, tab) => {
if (tabId == tabId_ && attr in changeInfo) {
browser.tabs.onUpdated.removeListener(onUpdated);
resolve({changeInfo, tab});
}
@@ -45,156 +45,144 @@ add_task(function* () {
let eventPromises = [];
browser.tabs.onZoomChange.addListener(info => {
zoomEvents.push(info);
if (eventPromises.length) {
eventPromises.shift().resolve();
}
});
- let awaitZoom = (tabId, newValue) => {
+ let awaitZoom = async (tabId, newValue) => {
let listener;
- return new Promise(resolve => {
+ await new Promise(async resolve => {
listener = info => {
if (info.tabId == tabId && info.newZoomFactor == newValue) {
resolve();
}
};
browser.tabs.onZoomChange.addListener(listener);
- browser.tabs.getZoom(tabId).then(zoomFactor => {
- if (zoomFactor == newValue) {
- resolve();
- }
- });
- }).then(() => {
- browser.tabs.onZoomChange.removeListener(listener);
+ let zoomFactor = await browser.tabs.getZoom(tabId);
+ if (zoomFactor == newValue) {
+ resolve();
+ }
});
+
+ browser.tabs.onZoomChange.removeListener(listener);
};
- let checkZoom = (tabId, newValue, oldValue = null) => {
+ let checkZoom = async (tabId, newValue, oldValue = null) => {
let awaitEvent;
if (oldValue != null && !zoomEvents.length) {
awaitEvent = new Promise(resolve => {
eventPromises.push({resolve});
});
}
- return Promise.all([
+ let [apiZoom, realZoom] = await Promise.all([
browser.tabs.getZoom(tabId),
msg("get-zoom", tabId),
awaitEvent,
- ]).then(([apiZoom, realZoom]) => {
- browser.test.assertEq(newValue, apiZoom, `Got expected zoom value from API`);
- browser.test.assertEq(newValue, realZoom, `Got expected zoom value from parent`);
+ ]);
+
+ browser.test.assertEq(newValue, apiZoom, `Got expected zoom value from API`);
+ browser.test.assertEq(newValue, realZoom, `Got expected zoom value from parent`);
- if (oldValue != null) {
- let event = zoomEvents.shift();
- browser.test.assertEq(tabId, event.tabId, `Got expected zoom event tab ID`);
- browser.test.assertEq(newValue, event.newZoomFactor, `Got expected zoom event zoom factor`);
- browser.test.assertEq(oldValue, event.oldZoomFactor, `Got expected zoom event old zoom factor`);
+ if (oldValue != null) {
+ let event = zoomEvents.shift();
+ browser.test.assertEq(tabId, event.tabId, `Got expected zoom event tab ID`);
+ browser.test.assertEq(newValue, event.newZoomFactor, `Got expected zoom event zoom factor`);
+ browser.test.assertEq(oldValue, event.oldZoomFactor, `Got expected zoom event old zoom factor`);
- browser.test.assertEq(3, Object.keys(event.zoomSettings).length, `Zoom settings should have 3 keys`);
- browser.test.assertEq("automatic", event.zoomSettings.mode, `Mode should be "automatic"`);
- browser.test.assertEq("per-origin", event.zoomSettings.scope, `Scope should be "per-origin"`);
- browser.test.assertEq(1, event.zoomSettings.defaultZoomFactor, `Default zoom should be 1`);
- }
- });
+ browser.test.assertEq(3, Object.keys(event.zoomSettings).length, `Zoom settings should have 3 keys`);
+ browser.test.assertEq("automatic", event.zoomSettings.mode, `Mode should be "automatic"`);
+ browser.test.assertEq("per-origin", event.zoomSettings.scope, `Scope should be "per-origin"`);
+ browser.test.assertEq(1, event.zoomSettings.defaultZoomFactor, `Default zoom should be 1`);
+ }
};
- let tabIds;
-
- browser.tabs.query({lastFocusedWindow: true}).then(tabs => {
+ try {
+ let tabs = await browser.tabs.query({lastFocusedWindow: true});
browser.test.assertEq(tabs.length, 3, "We have three tabs");
- tabIds = [tabs[1].id, tabs[2].id];
+ let tabIds = [tabs[1].id, tabs[2].id];
+ await checkZoom(tabIds[0], 1);
- return checkZoom(tabIds[0], 1);
- }).then(() => {
- return browser.tabs.setZoom(tabIds[0], 2);
- }).then(() => {
- return checkZoom(tabIds[0], 2, 1);
- }).then(() => {
- return browser.tabs.getZoomSettings(tabIds[0]);
- }).then(zoomSettings => {
+ await browser.tabs.setZoom(tabIds[0], 2);
+ await checkZoom(tabIds[0], 2, 1);
+
+ let zoomSettings = await browser.tabs.getZoomSettings(tabIds[0]);
browser.test.assertEq(3, Object.keys(zoomSettings).length, `Zoom settings should have 3 keys`);
browser.test.assertEq("automatic", zoomSettings.mode, `Mode should be "automatic"`);
browser.test.assertEq("per-origin", zoomSettings.scope, `Scope should be "per-origin"`);
browser.test.assertEq(1, zoomSettings.defaultZoomFactor, `Default zoom should be 1`);
+
browser.test.log(`Switch to tab 2`);
- return browser.tabs.update(tabIds[1], {active: true});
- }).then(() => {
- return checkZoom(tabIds[1], 1);
- }).then(() => {
+ await browser.tabs.update(tabIds[1], {active: true});
+ await checkZoom(tabIds[1], 1);
+
+
browser.test.log(`Navigate tab 2 to origin of tab 1`);
browser.tabs.update(tabIds[1], {url: "http://example.com"});
+ await promiseUpdated(tabIds[1], "url");
+ await checkZoom(tabIds[1], 2, 1);
- return promiseUpdated(tabIds[1], "url");
- }).then(() => {
- return checkZoom(tabIds[1], 2, 1);
- }).then(() => {
+
browser.test.log(`Update zoom in tab 2, expect changes in both tabs`);
- return browser.tabs.setZoom(tabIds[1], 1.5);
- }).then(() => {
- return checkZoom(tabIds[1], 1.5, 2);
- }).then(() => {
+ await browser.tabs.setZoom(tabIds[1], 1.5);
+ await checkZoom(tabIds[1], 1.5, 2);
+
+
browser.test.log(`Switch to tab 1, expect asynchronous zoom change just after the switch`);
- return Promise.all([
+ await Promise.all([
awaitZoom(tabIds[0], 1.5),
browser.tabs.update(tabIds[0], {active: true}),
]);
- }).then(() => {
- return checkZoom(tabIds[0], 1.5, 2);
- }).then(() => {
+ await checkZoom(tabIds[0], 1.5, 2);
+
+
browser.test.log("Set zoom to 0, expect it set to 1");
- return browser.tabs.setZoom(tabIds[0], 0);
- }).then(() => {
- return checkZoom(tabIds[0], 1, 1.5);
- }).then(() => {
+ await browser.tabs.setZoom(tabIds[0], 0);
+ await checkZoom(tabIds[0], 1, 1.5);
+
+
browser.test.log("Change zoom externally, expect changes reflected");
- return msg("enlarge");
- }).then(() => {
- return checkZoom(tabIds[0], 1.1, 1);
- }).then(() => {
- return Promise.all([
+ await msg("enlarge");
+ await checkZoom(tabIds[0], 1.1, 1);
+
+ await Promise.all([
browser.tabs.setZoom(tabIds[0], 0),
browser.tabs.setZoom(tabIds[1], 0),
]);
- }).then(() => {
- return Promise.all([
+ await Promise.all([
checkZoom(tabIds[0], 1, 1.1),
checkZoom(tabIds[1], 1, 1.5),
]);
- }).then(() => {
+
+
browser.test.log("Check that invalid zoom values throw an error");
- return browser.tabs.setZoom(tabIds[0], 42).then(
- () => {
- browser.test.fail("Expected an error");
- },
- error => {
- browser.test.assertTrue(error.message.includes("Zoom value 42 out of range"),
- "Got expected error");
- });
- }).then(() => {
+ await browser.test.assertRejects(
+ browser.tabs.setZoom(tabIds[0], 42),
+ /Zoom value 42 out of range/,
+ "Expected an out of range error");
+
browser.test.log("Disable site-specific zoom, expect correct scope");
- return msg("site-specific", false);
- }).then(() => {
- return browser.tabs.getZoomSettings(tabIds[0]);
- }).then(zoomSettings => {
+ await msg("site-specific", false);
+ zoomSettings = await browser.tabs.getZoomSettings(tabIds[0]);
+
browser.test.assertEq("per-tab", zoomSettings.scope, `Scope should be "per-tab"`);
- }).then(() => {
- return msg("site-specific", null);
- }).then(() => {
+ await msg("site-specific", null);
+
browser.test.notifyPass("tab-zoom");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`Error: ${e} :: ${e.stack}`);
browser.test.notifyFail("tab-zoom");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_webNavigation_frameId0.js
+++ b/browser/components/extensions/test/browser/browser_ext_webNavigation_frameId0.js
@@ -15,25 +15,23 @@ add_task(function* webNavigation_getFram
// main process:
// Cu.import("resource://gre/modules/ExtensionManagement.jsm", {});
//
// Or simply run the test again.
const BASE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/";
const DUMMY_URL = BASE + "file_dummy.html";
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, DUMMY_URL, true);
- function background(DUMMY_URL) {
- browser.tabs.query({active: true, currentWindow: true}).then(tabs => {
- return browser.webNavigation.getAllFrames({tabId: tabs[0].id});
- }).then(frames => {
- browser.test.assertEq(1, frames.length, "The dummy page has one frame");
- browser.test.assertEq(0, frames[0].frameId, "Main frame's ID must be 0");
- browser.test.assertEq(DUMMY_URL, frames[0].url, "Main frame URL must match");
- browser.test.notifyPass("frameId checked");
- });
+ async function background(DUMMY_URL) {
+ let tabs = await browser.tabs.query({active: true, currentWindow: true});
+ let frames = await browser.webNavigation.getAllFrames({tabId: tabs[0].id});
+ browser.test.assertEq(1, frames.length, "The dummy page has one frame");
+ browser.test.assertEq(0, frames[0].frameId, "Main frame's ID must be 0");
+ browser.test.assertEq(DUMMY_URL, frames[0].url, "Main frame URL must match");
+ browser.test.notifyPass("frameId checked");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["webNavigation"],
},
background: `(${background})(${JSON.stringify(DUMMY_URL)});`,
--- a/browser/components/extensions/test/browser/browser_ext_webNavigation_getFrames.js
+++ b/browser/components/extensions/test/browser/browser_ext_webNavigation_getFrames.js
@@ -1,38 +1,31 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* testWebNavigationGetNonExistentTab() {
let extension = ExtensionTestUtils.loadExtension({
- background: "(" + function() {
- let results = [
- // There is no "tabId = 0" because the id assigned by TabManager (defined in ext-utils.js)
- // starts from 1.
- browser.webNavigation.getAllFrames({tabId: 0}).then(() => {
- browser.test.fail("getAllFrames Promise should be rejected on error");
- }, (error) => {
- browser.test.assertEq("Invalid tab ID: 0", error.message,
- "getAllFrames rejected Promise should pass the expected error");
- }),
- // There is no "tabId = 0" because the id assigned by TabManager (defined in ext-utils.js)
- // starts from 1, processId is currently marked as optional and it is ignored.
- browser.webNavigation.getFrame({tabId: 0, frameId: 15, processId: 20}).then(() => {
- browser.test.fail("getFrame Promise should be rejected on error");
- }, (error) => {
- browser.test.assertEq("Invalid tab ID: 0", error.message,
- "getFrame rejected Promise should pass the expected error");
- }),
- ];
+ background: async function() {
+ // There is no "tabId = 0" because the id assigned by TabManager (defined in ext-utils.js)
+ // starts from 1.
+ await browser.test.assertRejects(
+ browser.webNavigation.getAllFrames({tabId: 0}),
+ "Invalid tab ID: 0",
+ "getAllFrames rejected Promise should pass the expected error");
- Promise.all(results).then(() => {
- browser.test.sendMessage("getNonExistentTab.done");
- });
- } + ")();",
+ // There is no "tabId = 0" because the id assigned by TabManager (defined in ext-utils.js)
+ // starts from 1, processId is currently marked as optional and it is ignored.
+ await browser.test.assertRejects(
+ browser.webNavigation.getFrame({tabId: 0, frameId: 15, processId: 20}),
+ "Invalid tab ID: 0",
+ "getFrame rejected Promise should pass the expected error");
+
+ browser.test.sendMessage("getNonExistentTab.done");
+ },
manifest: {
permissions: ["webNavigation"],
},
});
info("load complete");
yield extension.startup();
info("startup complete");
@@ -40,68 +33,61 @@ add_task(function* testWebNavigationGetN
yield extension.awaitMessage("getNonExistentTab.done");
yield extension.unload();
info("extension unloaded");
});
add_task(function* testWebNavigationFrames() {
let extension = ExtensionTestUtils.loadExtension({
- background: "(" + function() {
+ background: async function() {
let tabId;
let collectedDetails = [];
- browser.webNavigation.onCompleted.addListener((details) => {
+ browser.webNavigation.onCompleted.addListener(async details => {
collectedDetails.push(details);
if (details.frameId !== 0) {
// wait for the top level iframe to be complete
return;
}
- browser.webNavigation.getAllFrames({tabId}).then((getAllFramesDetails) => {
- let getFramePromises = getAllFramesDetails.map((frameDetail) => {
- let {frameId} = frameDetail;
- // processId is currently marked as optional and it is ignored.
- return browser.webNavigation.getFrame({tabId, frameId, processId: 0});
- });
+ let getAllFramesDetails = await browser.webNavigation.getAllFrames({tabId});
- Promise.all(getFramePromises).then((getFrameResults) => {
- browser.test.sendMessage("webNavigationFrames.done", {
- collectedDetails, getAllFramesDetails, getFrameResults,
- });
- }, () => {
- browser.test.assertTrue(false, "None of the getFrame promises should have been rejected");
- });
+ let getFramePromises = getAllFramesDetails.map(({frameId}) => {
+ // processId is currently marked as optional and it is ignored.
+ return browser.webNavigation.getFrame({tabId, frameId, processId: 0});
+ });
+
+ let getFrameResults = await Promise.all(getFramePromises);
+ browser.test.sendMessage("webNavigationFrames.done", {
+ collectedDetails, getAllFramesDetails, getFrameResults,
+ });
- // Pick a random frameId.
- let nonExistentFrameId = Math.floor(Math.random() * 10000);
+ // Pick a random frameId.
+ let nonExistentFrameId = Math.floor(Math.random() * 10000);
- // Increment the picked random nonExistentFrameId until it doesn't exists.
- while (getAllFramesDetails.filter((details) => details.frameId == nonExistentFrameId).length > 0) {
- nonExistentFrameId += 1;
- }
+ // Increment the picked random nonExistentFrameId until it doesn't exists.
+ while (getAllFramesDetails.filter((details) => details.frameId == nonExistentFrameId).length > 0) {
+ nonExistentFrameId += 1;
+ }
- // Check that getFrame Promise is rejected with the expected error message on nonexistent frameId.
- browser.webNavigation.getFrame({tabId, frameId: nonExistentFrameId, processId: 20}).then(() => {
- browser.test.fail("getFrame promise should be rejected for an unexistent frameId");
- }, (error) => {
- browser.test.assertEq(`No frame found with frameId: ${nonExistentFrameId}`, error.message,
- "getFrame promise should be rejected with the expected error message on unexistent frameId");
- }).then(() => {
- browser.tabs.remove(tabId);
- browser.test.sendMessage("webNavigationFrames.done");
- });
- });
+ // Check that getFrame Promise is rejected with the expected error message on nonexistent frameId.
+ await browser.test.assertRejects(
+ browser.webNavigation.getFrame({tabId, frameId: nonExistentFrameId, processId: 20}),
+ `No frame found with frameId: ${nonExistentFrameId}`,
+ "getFrame promise should be rejected with the expected error message on unexistent frameId");
+
+ await browser.tabs.remove(tabId);
+ browser.test.sendMessage("webNavigationFrames.done");
});
- browser.tabs.create({url: "tab.html"}, (tab) => {
- tabId = tab.id;
- });
- } + ")();",
+ let tab = await browser.tabs.create({url: "tab.html"});
+ tabId = tab.id;
+ },
manifest: {
permissions: ["webNavigation", "tabs"],
},
files: {
"tab.html": `
<!DOCTYPE html>
<html>
<head>
--- a/browser/components/extensions/test/browser/browser_ext_windows_create.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create.js
@@ -1,15 +1,15 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* testWindowCreate() {
let extension = ExtensionTestUtils.loadExtension({
- background() {
+ async background() {
let _checkWindowPromise;
browser.test.onMessage.addListener(msg => {
if (msg == "checked-window") {
_checkWindowPromise.resolve();
_checkWindowPromise = null;
}
});
@@ -17,69 +17,71 @@ add_task(function* testWindowCreate() {
function checkWindow(expected) {
return new Promise(resolve => {
_checkWindowPromise = {resolve};
browser.test.sendMessage("check-window", expected);
});
}
- function createWindow(params, expected, keep = false) {
- return browser.windows.create(params).then(window => {
- for (let key of Object.keys(params)) {
- if (key == "state" && os == "mac" && params.state == "normal") {
- // OS-X doesn't have a hard distinction between "normal" and
- // "maximized" states.
- browser.test.assertTrue(window.state == "normal" || window.state == "maximized",
- `Expected window.state (currently ${window.state}) to be "normal" but will accept "maximized"`);
- } else {
- browser.test.assertEq(params[key], window[key], `Got expected value for window.${key}`);
- }
+ async function createWindow(params, expected, keep = false) {
+ let window = await browser.windows.create(params);
+
+ for (let key of Object.keys(params)) {
+ if (key == "state" && os == "mac" && params.state == "normal") {
+ // OS-X doesn't have a hard distinction between "normal" and
+ // "maximized" states.
+ browser.test.assertTrue(window.state == "normal" || window.state == "maximized",
+ `Expected window.state (currently ${window.state}) to be "normal" but will accept "maximized"`);
+ } else {
+ browser.test.assertEq(params[key], window[key], `Got expected value for window.${key}`);
}
+ }
- browser.test.assertEq(1, window.tabs.length, "tabs property got populated");
- return checkWindow(expected).then(() => {
- if (keep) {
- return window;
- }
- if (params.state == "fullscreen" && os == "win") {
- // FIXME: Closing a fullscreen window causes a window leak in
- // Windows tests.
- return browser.windows.update(window.id, {state: "normal"}).then(() => {
- return browser.windows.remove(window.id);
- });
- }
- return browser.windows.remove(window.id);
- });
- });
+ browser.test.assertEq(1, window.tabs.length, "tabs property got populated");
+
+ await checkWindow(expected);
+ if (keep) {
+ return window;
+ }
+
+ if (params.state == "fullscreen" && os == "win") {
+ // FIXME: Closing a fullscreen window causes a window leak in
+ // Windows tests.
+ await browser.windows.update(window.id, {state: "normal"});
+ }
+ await browser.windows.remove(window.id);
}
- browser.runtime.getPlatformInfo().then(info => { os = info.os; })
- .then(() => createWindow({state: "maximized"}, {state: "STATE_MAXIMIZED"}))
- .then(() => createWindow({state: "minimized"}, {state: "STATE_MINIMIZED"}))
- .then(() => createWindow({state: "normal"}, {state: "STATE_NORMAL", hiddenChrome: []}))
- .then(() => createWindow({state: "fullscreen"}, {state: "STATE_FULLSCREEN"}))
- .then(() => {
- return createWindow({type: "popup"},
- {hiddenChrome: ["menubar", "toolbar", "location", "directories", "status", "extrachrome"],
- chromeFlags: ["CHROME_OPENAS_DIALOG"]},
- true);
- }).then(window => {
- return browser.tabs.query({windowType: "popup", active: true}).then(tabs => {
- browser.test.assertEq(1, tabs.length, "Expected only one popup");
- browser.test.assertEq(window.id, tabs[0].windowId, "Expected new window to be returned in query");
+ try {
+ ({os} = await browser.runtime.getPlatformInfo());
+
+ await createWindow({state: "maximized"}, {state: "STATE_MAXIMIZED"});
+ await createWindow({state: "minimized"}, {state: "STATE_MINIMIZED"});
+ await createWindow({state: "normal"}, {state: "STATE_NORMAL", hiddenChrome: []});
+ await createWindow({state: "fullscreen"}, {state: "STATE_FULLSCREEN"});
- return browser.windows.remove(window.id);
- });
- }).then(() => {
+ let window = await createWindow(
+ {type: "popup"},
+ {hiddenChrome: ["menubar", "toolbar", "location", "directories", "status", "extrachrome"],
+ chromeFlags: ["CHROME_OPENAS_DIALOG"]},
+ true);
+
+ let tabs = await browser.tabs.query({windowType: "popup", active: true});
+
+ browser.test.assertEq(1, tabs.length, "Expected only one popup");
+ browser.test.assertEq(window.id, tabs[0].windowId, "Expected new window to be returned in query");
+
+ await browser.windows.remove(window.id);
+
browser.test.notifyPass("window-create");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("window-create");
- });
+ }
},
});
let latestWindow;
let windowListener = (window, topic) => {
if (topic == "domwindowopened") {
latestWindow = window;
}
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_params.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_params.js
@@ -1,40 +1,33 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
// Tests that incompatible parameters can't be used together.
add_task(function* testWindowCreateParams() {
let extension = ExtensionTestUtils.loadExtension({
- background() {
- function* getCalls() {
+ async background() {
+ try {
for (let state of ["minimized", "maximized", "fullscreen"]) {
for (let param of ["left", "top", "width", "height"]) {
let expected = `"state": "${state}" may not be combined with "left", "top", "width", or "height"`;
- yield browser.windows.create({state, [param]: 100}).then(
- val => {
- browser.test.fail(`Expected error but got "${val}" instead`);
- },
- error => {
- browser.test.assertTrue(
- error.message.includes(expected),
- `Got expected error (got: '${error.message}', expected: '${expected}'`);
- });
+ await browser.test.assertRejects(
+ browser.windows.create({state, [param]: 100}),
+ RegExp(expected),
+ `Got expected error from create(${param}=100)`);
}
}
- }
- Promise.all(getCalls()).then(() => {
browser.test.notifyPass("window-create-params");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("window-create-params");
- });
+ }
},
});
yield extension.startup();
yield extension.awaitFinish("window-create-params");
yield extension.unload();
});
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
@@ -1,14 +1,14 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* testWindowCreate() {
- function background() {
+ async function background() {
let promiseTabAttached = () => {
return new Promise(resolve => {
browser.tabs.onAttached.addListener(function listener() {
browser.tabs.onAttached.removeListener(listener);
resolve();
});
});
};
@@ -19,130 +19,113 @@ add_task(function* testWindowCreate() {
if (changeInfo.url === expected) {
browser.tabs.onUpdated.removeListener(listener);
resolve();
}
});
});
};
- let windowId, tabId;
- browser.windows.getCurrent().then(window => {
- windowId = window.id;
+ try {
+ let window = await browser.windows.getCurrent();
+ let windowId = window.id;
browser.test.log("Create additional tab in window 1");
- return browser.tabs.create({windowId, url: "about:blank"});
- }).then(tab => {
- tabId = tab.id;
+ let tab = await browser.tabs.create({windowId, url: "about:blank"});
+ let tabId = tab.id;
+
browser.test.log("Create a new window, adopting the new tab");
// Note that we want to check against actual boolean values for
// all of the `incognito` property tests.
browser.test.assertEq(false, tab.incognito, "Tab is not private");
- return Promise.all([
- promiseTabAttached(),
- browser.windows.create({tabId: tabId}),
- ]);
- }).then(([, window]) => {
- browser.test.assertEq(false, window.incognito, "New window is not private");
- browser.test.assertEq(tabId, window.tabs[0].id, "tabs property populated correctly");
+ {
+ let [, window] = await Promise.all([
+ promiseTabAttached(),
+ browser.windows.create({tabId: tabId}),
+ ]);
+ browser.test.assertEq(false, window.incognito, "New window is not private");
+ browser.test.assertEq(tabId, window.tabs[0].id, "tabs property populated correctly");
- browser.test.log("Close the new window");
- return browser.windows.remove(window.id);
- }).then(() => {
- browser.test.log("Create a new private window");
+ browser.test.log("Close the new window");
+ await browser.windows.remove(window.id);
+ }
- return browser.windows.create({incognito: true});
- }).then(privateWindow => {
- browser.test.assertEq(true, privateWindow.incognito, "Private window is private");
+ {
+ browser.test.log("Create a new private window");
+ let privateWindow = await browser.windows.create({incognito: true});
+ browser.test.assertEq(true, privateWindow.incognito, "Private window is private");
- browser.test.log("Create additional tab in private window");
- return browser.tabs.create({windowId: privateWindow.id}).then(privateTab => {
+ browser.test.log("Create additional tab in private window");
+ let privateTab = await browser.tabs.create({windowId: privateWindow.id});
browser.test.assertEq(true, privateTab.incognito, "Private tab is private");
browser.test.log("Create a new window, adopting the new private tab");
-
- return Promise.all([
+ let [, newWindow] = await Promise.all([
promiseTabAttached(),
browser.windows.create({tabId: privateTab.id}),
]);
- }).then(([, newWindow]) => {
browser.test.assertEq(true, newWindow.incognito, "New private window is private");
browser.test.log("Close the new private window");
- return browser.windows.remove(newWindow.id);
- }).then(() => {
+ await browser.windows.remove(newWindow.id);
+
browser.test.log("Close the private window");
- return browser.windows.remove(privateWindow.id);
- });
- }).then(() => {
- return browser.tabs.query({windowId, active: true});
- }).then(([tab]) => {
- browser.test.log("Try to create a window with both a tab and a URL");
+ await browser.windows.remove(privateWindow.id);
+ }
+
- return browser.windows.create({tabId: tab.id, url: "http://example.com/"}).then(
- window => {
- browser.test.fail("Create call should have failed");
- },
- error => {
- browser.test.assertTrue(/`tabId` may not be used in conjunction with `url`/.test(error.message),
- "Create call failed as expected");
- }).then(() => {
- browser.test.log("Try to create a window with both a tab and an invalid incognito setting");
+ browser.test.log("Try to create a window with both a tab and a URL");
+ [tab] = await browser.tabs.query({windowId, active: true});
+ await browser.test.assertRejects(
+ browser.windows.create({tabId: tab.id, url: "http://example.com/"}),
+ /`tabId` may not be used in conjunction with `url`/,
+ "Create call failed as expected");
- return browser.windows.create({tabId: tab.id, incognito: true});
- }).then(
- window => {
- browser.test.fail("Create call should have failed");
- },
- error => {
- browser.test.assertTrue(/`incognito` property must match the incognito state of tab/.test(error.message),
- "Create call failed as expected");
- });
- }).then(() => {
- browser.test.log("Try to create a window with an invalid tabId");
+ browser.test.log("Try to create a window with both a tab and an invalid incognito setting");
+ await browser.test.assertRejects(
+ browser.windows.create({tabId: tab.id, incognito: true}),
+ /`incognito` property must match the incognito state of tab/,
+ "Create call failed as expected");
+
- return browser.windows.create({tabId: 0}).then(
- window => {
- browser.test.fail("Create call should have failed");
- },
- error => {
- browser.test.assertTrue(/Invalid tab ID: 0/.test(error.message),
- "Create call failed as expected");
- }
- );
- }).then(() => {
+ browser.test.log("Try to create a window with an invalid tabId");
+ await browser.test.assertRejects(
+ browser.windows.create({tabId: 0}),
+ /Invalid tab ID: 0/,
+ "Create call failed as expected");
+
+
browser.test.log("Try to create a window with two URLs");
-
- return Promise.all([
+ [, , window] = await Promise.all([
// tabs.onUpdated can be invoked between the call of windows.create and
// the invocation of its callback/promise, so set up the listeners
// before creating the window.
promiseTabUpdated("http://example.com/"),
promiseTabUpdated("http://example.org/"),
browser.windows.create({url: ["http://example.com/", "http://example.org/"]}),
]);
- }).then(([, , window]) => {
browser.test.assertEq(2, window.tabs.length, "2 tabs were opened in new window");
browser.test.assertEq("about:blank", window.tabs[0].url, "about:blank, page not loaded yet");
browser.test.assertEq("about:blank", window.tabs[1].url, "about:blank, page not loaded yet");
- return browser.windows.get(window.id, {populate: true});
- }).then(window => {
+ window = await browser.windows.get(window.id, {populate: true});
+
browser.test.assertEq(2, window.tabs.length, "2 tabs were opened in new window");
browser.test.assertEq("http://example.com/", window.tabs[0].url, "Correct URL was loaded in tab 1");
browser.test.assertEq("http://example.org/", window.tabs[1].url, "Correct URL was loaded in tab 2");
- return browser.windows.remove(window.id);
- }).then(() => {
+
+ await browser.windows.remove(window.id);
+
browser.test.notifyPass("window-create");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("window-create");
- });
+ }
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
background,
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_url.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_url.js
@@ -3,17 +3,17 @@
"use strict";
add_task(function* testWindowCreate() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["tabs"],
},
- background() {
+ background: async function() {
const EXTENSION_URL = browser.runtime.getURL("test.html");
const REMOTE_URL = browser.runtime.getURL("test.html");
let windows = new class extends Map { // eslint-disable-line new-parens
get(id) {
if (!this.has(id)) {
let window = {
tabs: new Map(),
@@ -35,47 +35,47 @@ add_task(function* testWindowCreate() {
window.tabs.set(tab.index, tab);
if (window.tabs.size === window.expectedTabs) {
window.resolvePromise(window);
}
}
});
- function create(options) {
- return browser.windows.create(options).then(window => {
- let win = windows.get(window.id);
+ async function create(options) {
+ let window = await browser.windows.create(options);
+ let win = windows.get(window.id);
- win.expectedTabs = Array.isArray(options.url) ? options.url.length : 1;
+ win.expectedTabs = Array.isArray(options.url) ? options.url.length : 1;
- return win.promise;
- });
+ return win.promise;
}
- Promise.all([
- create({url: REMOTE_URL}),
- create({url: "test.html"}),
- create({url: EXTENSION_URL}),
- create({url: [REMOTE_URL, "test.html", EXTENSION_URL]}),
- ]).then(windows => {
+ try {
+ let windows = await Promise.all([
+ create({url: REMOTE_URL}),
+ create({url: "test.html"}),
+ create({url: EXTENSION_URL}),
+ create({url: [REMOTE_URL, "test.html", EXTENSION_URL]}),
+ ]);
browser.test.assertEq(REMOTE_URL, windows[0].tabs.get(0).url, "Single, absolute, remote URL");
browser.test.assertEq(REMOTE_URL, windows[1].tabs.get(0).url, "Single, relative URL");
browser.test.assertEq(REMOTE_URL, windows[2].tabs.get(0).url, "Single, absolute, extension URL");
browser.test.assertEq(REMOTE_URL, windows[3].tabs.get(0).url, "url[0]: Absolute, remote URL");
browser.test.assertEq(EXTENSION_URL, windows[3].tabs.get(1).url, "url[1]: Relative URL");
browser.test.assertEq(EXTENSION_URL, windows[3].tabs.get(2).url, "url[2]: Absolute, extension URL");
- }).then(() => {
+
browser.test.notifyPass("window-create-url");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("window-create-url");
- });
+ }
},
files: {
"test.html": `<DOCTYPE html><html><head><meta charset="utf-8"></head></html>`,
},
});
yield extension.startup();
--- a/browser/components/extensions/test/browser/browser_ext_windows_events.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_events.js
@@ -1,50 +1,50 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
SimpleTest.requestCompleteLog();
add_task(function* testWindowsEvents() {
function background() {
- browser.windows.onCreated.addListener(function listener(window) {
+ browser.windows.onCreated.addListener(window => {
browser.test.log(`onCreated: windowId=${window.id}`);
browser.test.assertTrue(Number.isInteger(window.id),
"Window object's id is an integer");
browser.test.assertEq("normal", window.type,
"Window object returned with the correct type");
browser.test.sendMessage("window-created", window.id);
});
let lastWindowId, os;
- browser.windows.onFocusChanged.addListener(function listener(windowId) {
+ browser.windows.onFocusChanged.addListener(async windowId => {
browser.test.log(`onFocusChange: windowId=${windowId} lastWindowId=${lastWindowId}`);
if (windowId === browser.windows.WINDOW_ID_NONE && os === "linux") {
browser.test.log("Ignoring a superfluous WINDOW_ID_NONE (blur) event on Linux");
return;
}
browser.test.assertTrue(lastWindowId !== windowId,
"onFocusChanged fired once for the given window");
lastWindowId = windowId;
browser.test.assertTrue(Number.isInteger(windowId),
"windowId is an integer");
- browser.windows.getLastFocused().then(window => {
- browser.test.assertEq(windowId, window.id,
- "Last focused window has the correct id");
- browser.test.sendMessage(`window-focus-changed`, window.id);
- });
+ let window = await browser.windows.getLastFocused();
+
+ browser.test.assertEq(windowId, window.id,
+ "Last focused window has the correct id");
+ browser.test.sendMessage(`window-focus-changed`, window.id);
});
- browser.windows.onRemoved.addListener(function listener(windowId) {
+ browser.windows.onRemoved.addListener(windowId => {
browser.test.log(`onRemoved: windowId=${windowId}`);
browser.test.assertTrue(Number.isInteger(windowId),
"windowId is an integer");
browser.test.sendMessage(`window-removed`, windowId);
browser.test.notifyPass("windows.events");
});
--- a/browser/components/extensions/test/browser/browser_ext_windows_size.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_size.js
@@ -1,15 +1,15 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* testWindowCreate() {
let extension = ExtensionTestUtils.loadExtension({
- background() {
+ async background() {
let _checkWindowPromise;
browser.test.onMessage.addListener((msg, arg) => {
if (msg == "checked-window") {
_checkWindowPromise.resolve(arg);
_checkWindowPromise = null;
}
});
@@ -23,83 +23,73 @@ add_task(function* testWindowCreate() {
const KEYS = ["left", "top", "width", "height"];
function checkGeom(expected, actual) {
for (let key of KEYS) {
browser.test.assertEq(expected[key], actual[key], `Expected '${key}' value`);
}
}
let windowId;
- function checkWindow(expected, retries = 5) {
- return getWindowSize().then(geom => {
- if (retries && KEYS.some(key => expected[key] != geom[key])) {
- browser.test.log(`Got mismatched size (${JSON.stringify(expected)} != ${JSON.stringify(geom)}). ` +
- `Retrying after a short delay.`);
+ async function checkWindow(expected, retries = 5) {
+ let geom = await getWindowSize();
+
+ if (retries && KEYS.some(key => expected[key] != geom[key])) {
+ browser.test.log(`Got mismatched size (${JSON.stringify(expected)} != ${JSON.stringify(geom)}). ` +
+ `Retrying after a short delay.`);
+
+ await new Promise(resolve => setTimeout(resolve, 200));
- return new Promise(resolve => {
- setTimeout(resolve, 200);
- }).then(() => {
- return checkWindow(expected, retries - 1);
- });
- }
+ return checkWindow(expected, retries - 1);
+ }
+
+ browser.test.log(`Check actual window size`);
+ checkGeom(expected, geom);
- browser.test.log(`Check actual window size`);
- checkGeom(expected, geom);
+ browser.test.log("Check API-reported window size");
- browser.test.log("Check API-reported window size");
- return browser.windows.get(windowId).then(geom => {
- checkGeom(expected, geom);
- });
- });
+ geom = await browser.windows.get(windowId);
+
+ checkGeom(expected, geom);
}
- let geom = {left: 100, top: 100, width: 500, height: 300};
+ try {
+ let geom = {left: 100, top: 100, width: 500, height: 300};
- return browser.windows.create(geom).then(window => {
+ let window = await browser.windows.create(geom);
windowId = window.id;
- return checkWindow(geom);
- }).then(() => {
+ await checkWindow(geom);
+
let update = {left: 150, width: 600};
Object.assign(geom, update);
-
- return browser.windows.update(windowId, update);
- }).then(() => {
- return checkWindow(geom);
- }).then(() => {
- let update = {top: 150, height: 400};
- Object.assign(geom, update);
+ await browser.windows.update(windowId, update);
+ await checkWindow(geom);
- return browser.windows.update(windowId, update);
- }).then(() => {
- return checkWindow(geom);
- }).then(() => {
- geom = {left: 200, top: 200, width: 800, height: 600};
+ update = {top: 150, height: 400};
+ Object.assign(geom, update);
+ await browser.windows.update(windowId, update);
+ await checkWindow(geom);
- return browser.windows.update(windowId, geom);
- }).then(() => {
- return checkWindow(geom);
- }).then(() => {
- return browser.runtime.getPlatformInfo();
- }).then((platformInfo) => {
+ geom = {left: 200, top: 200, width: 800, height: 600};
+ await browser.windows.update(windowId, geom);
+ await checkWindow(geom);
+
+ let platformInfo = await browser.runtime.getPlatformInfo();
if (platformInfo.os != "linux") {
geom = {left: -50, top: -50, width: 800, height: 600};
-
- return browser.windows.update(windowId, geom).then(() => {
- return checkWindow(geom);
- });
+ await browser.windows.update(windowId, geom);
+ await checkWindow(geom);
}
- }).then(() => {
- return browser.windows.remove(windowId);
- }).then(() => {
+
+ await browser.windows.remove(windowId);
browser.test.notifyPass("window-size");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("window-size");
- });
+ }
},
});
let latestWindow;
let windowListener = (window, topic) => {
if (topic == "domwindowopened") {
latestWindow = window;
}
--- a/browser/components/extensions/test/browser/browser_ext_windows_update.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_update.js
@@ -46,17 +46,17 @@ add_task(function* () {
yield extension.unload();
yield BrowserTestUtils.closeWindow(window2);
});
add_task(function* testWindowUpdate() {
let extension = ExtensionTestUtils.loadExtension({
- background() {
+ async background() {
let _checkWindowPromise;
browser.test.onMessage.addListener(msg => {
if (msg == "checked-window") {
_checkWindowPromise.resolve();
_checkWindowPromise = null;
}
});
@@ -64,49 +64,53 @@ add_task(function* testWindowUpdate() {
function checkWindow(expected) {
return new Promise(resolve => {
_checkWindowPromise = {resolve};
browser.test.sendMessage("check-window", expected);
});
}
let currentWindowId;
- function updateWindow(windowId, params, expected) {
- return browser.windows.update(windowId, params).then(window => {
- browser.test.assertEq(currentWindowId, window.id, "Expected WINDOW_ID_CURRENT to refer to the same window");
- for (let key of Object.keys(params)) {
- if (key == "state" && os == "mac" && params.state == "normal") {
- // OS-X doesn't have a hard distinction between "normal" and
- // "maximized" states.
- browser.test.assertTrue(window.state == "normal" || window.state == "maximized",
- `Expected window.state (currently ${window.state}) to be "normal" but will accept "maximized"`);
- } else {
- browser.test.assertEq(params[key], window[key], `Got expected value for window.${key}`);
- }
+ async function updateWindow(windowId, params, expected) {
+ let window = await browser.windows.update(windowId, params);
+
+ browser.test.assertEq(currentWindowId, window.id, "Expected WINDOW_ID_CURRENT to refer to the same window");
+ for (let key of Object.keys(params)) {
+ if (key == "state" && os == "mac" && params.state == "normal") {
+ // OS-X doesn't have a hard distinction between "normal" and
+ // "maximized" states.
+ browser.test.assertTrue(window.state == "normal" || window.state == "maximized",
+ `Expected window.state (currently ${window.state}) to be "normal" but will accept "maximized"`);
+ } else {
+ browser.test.assertEq(params[key], window[key], `Got expected value for window.${key}`);
}
+ }
- return checkWindow(expected);
- });
+ return checkWindow(expected);
}
- let windowId = browser.windows.WINDOW_ID_CURRENT;
+ try {
+ let windowId = browser.windows.WINDOW_ID_CURRENT;
+
+ ({os} = await browser.runtime.getPlatformInfo());
+
+ let window = await browser.windows.getCurrent();
+ currentWindowId = window.id;
- browser.runtime.getPlatformInfo().then(info => { os = info.os; })
- .then(() => browser.windows.getCurrent().then(window => { currentWindowId = window.id; }))
- .then(() => updateWindow(windowId, {state: "maximized"}, {state: "STATE_MAXIMIZED"}))
- .then(() => updateWindow(windowId, {state: "minimized"}, {state: "STATE_MINIMIZED"}))
- .then(() => updateWindow(windowId, {state: "normal"}, {state: "STATE_NORMAL"}))
- .then(() => updateWindow(windowId, {state: "fullscreen"}, {state: "STATE_FULLSCREEN"}))
- .then(() => updateWindow(windowId, {state: "normal"}, {state: "STATE_NORMAL"}))
- .then(() => {
+ await updateWindow(windowId, {state: "maximized"}, {state: "STATE_MAXIMIZED"});
+ await updateWindow(windowId, {state: "minimized"}, {state: "STATE_MINIMIZED"});
+ await updateWindow(windowId, {state: "normal"}, {state: "STATE_NORMAL"});
+ await updateWindow(windowId, {state: "fullscreen"}, {state: "STATE_FULLSCREEN"});
+ await updateWindow(windowId, {state: "normal"}, {state: "STATE_NORMAL"});
+
browser.test.notifyPass("window-update");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("window-update");
- });
+ }
},
});
extension.onMessage("check-window", expected => {
if (expected.state != null) {
let {windowState} = window;
if (window.fullScreen) {
windowState = window.STATE_FULLSCREEN;
@@ -152,41 +156,34 @@ add_task(function* () {
yield BrowserTestUtils.closeWindow(window2);
});
// Tests that incompatible parameters can't be used together.
add_task(function* testWindowUpdateParams() {
let extension = ExtensionTestUtils.loadExtension({
- background() {
- function* getCalls() {
+ async background() {
+ try {
for (let state of ["minimized", "maximized", "fullscreen"]) {
for (let param of ["left", "top", "width", "height"]) {
let expected = `"state": "${state}" may not be combined with "left", "top", "width", or "height"`;
let windowId = browser.windows.WINDOW_ID_CURRENT;
- yield browser.windows.update(windowId, {state, [param]: 100}).then(
- val => {
- browser.test.fail(`Expected error but got "${val}" instead`);
- },
- error => {
- browser.test.assertTrue(
- error.message.includes(expected),
- `Got expected error (got: '${error.message}', expected: '${expected}'`);
- });
+ await browser.test.assertRejects(
+ browser.windows.update(windowId, {state, [param]: 100}),
+ RegExp(expected),
+ `Got expected error for create(${param}=100`);
}
}
- }
- Promise.all(getCalls()).then(() => {
browser.test.notifyPass("window-update-params");
- }).catch(e => {
+ } catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("window-update-params");
- });
+ }
},
});
yield extension.startup();
yield extension.awaitFinish("window-update-params");
yield extension.unload();
});
--- a/browser/components/extensions/test/browser/head_pageAction.js
+++ b/browser/components/extensions/test/browser/head_pageAction.js
@@ -7,71 +7,66 @@
function* runTests(options) {
function background(getTests) {
let tabs;
let tests;
// Gets the current details of the page action, and returns a
// promise that resolves to an object containing them.
- function getDetails() {
- return new Promise(resolve => {
- return browser.tabs.query({active: true, currentWindow: true}, resolve);
- }).then(([tab]) => {
- let tabId = tab.id;
- browser.test.log(`Get details: tab={id: ${tabId}, url: ${JSON.stringify(tab.url)}}`);
- return Promise.all([
- browser.pageAction.getTitle({tabId}),
- browser.pageAction.getPopup({tabId})]);
- }).then(details => {
- return Promise.resolve({title: details[0],
- popup: details[1]});
- });
+ async function getDetails() {
+ let [tab] = await browser.tabs.query({active: true, currentWindow: true});
+ let tabId = tab.id;
+
+ browser.test.log(`Get details: tab={id: ${tabId}, url: ${JSON.stringify(tab.url)}}`);
+
+ return {
+ title: await browser.pageAction.getTitle({tabId}),
+ popup: await browser.pageAction.getPopup({tabId}),
+ };
}
// Runs the next test in the `tests` array, checks the results,
// and passes control back to the outer test scope.
function nextTest() {
let test = tests.shift();
- test(expecting => {
+ test(async expecting => {
function finish() {
// Check that the actual icon has the expected values, then
// run the next test.
browser.test.sendMessage("nextTest", expecting, tests.length);
}
if (expecting) {
// Check that the API returns the expected values, and then
// run the next test.
- getDetails().then(details => {
- browser.test.assertEq(expecting.title, details.title,
- "expected value from getTitle");
+ let details = await getDetails();
+
+ browser.test.assertEq(expecting.title, details.title,
+ "expected value from getTitle");
- browser.test.assertEq(expecting.popup, details.popup,
- "expected value from getPopup");
+ browser.test.assertEq(expecting.popup, details.popup,
+ "expected value from getPopup");
+ }
- finish();
- });
- } else {
- finish();
- }
+ finish();
});
}
- function runTests() {
+ async function runTests() {
tabs = [];
tests = getTests(tabs);
- browser.tabs.query({active: true, currentWindow: true}, resultTabs => {
- tabs[0] = resultTabs[0].id;
+ let resultTabs = await browser.tabs.query({active: true, currentWindow: true});
- nextTest();
- });
+ tabs[0] = resultTabs[0].id;
+
+ nextTest();
}
browser.test.onMessage.addListener((msg) => {
if (msg == "runTests") {
runTests();
} else if (msg == "runNextTest") {
nextTest();
} else {
--- a/browser/components/originattributes/moz.build
+++ b/browser/components/originattributes/moz.build
@@ -3,10 +3,14 @@
# 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/.
BROWSER_CHROME_MANIFESTS += [
'test/browser/browser.ini',
]
+MOCHITEST_MANIFESTS += [
+ 'test/mochitest/mochitest.ini'
+]
+
with Files('**'):
BUG_COMPONENT = ('Firefox', 'OriginAttributes')
--- a/browser/components/originattributes/test/browser/browser_cache.js
+++ b/browser/components/originattributes/test/browser/browser_cache.js
@@ -216,16 +216,24 @@ function* doTest(aBrowser) {
// The check function, which checks the number of cache entries.
function* doCheck(aShouldIsolate, aInputA, aInputB) {
let expectedEntryCount = 1;
let data = [];
data = data.concat(yield cacheDataForContext(LoadContextInfo.default));
data = data.concat(yield cacheDataForContext(LoadContextInfo.private));
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, {})));
+ data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(false, { userContextId: 1 })));
+ data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, { userContextId: 1 })));
+ data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(false, { userContextId: 2 })));
+ data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, { userContextId: 2 })));
+ data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(false, { firstPartyDomain: "example.com" })));
+ data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, { firstPartyDomain: "example.com" })));
+ data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(false, { firstPartyDomain: "example.org" })));
+ data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, { firstPartyDomain: "example.org" })));
if (aShouldIsolate) {
expectedEntryCount = 2;
}
for (let suffix of suffixes) {
let foundEntryCount = countMatchingCacheEntries(data, "example.net", suffix);
let result = (expectedEntryCount === foundEntryCount);
new file mode 100644
--- /dev/null
+++ b/browser/components/originattributes/test/mochitest/file_empty.html
@@ -0,0 +1,2 @@
+<h1>I'm just a support file</h1>
+<p>I get loaded to do permission testing.</p>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/originattributes/test/mochitest/mochitest.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+support-files =
+ file_empty.html
+
+[test_permissions_api.html]
new file mode 100644
--- /dev/null
+++ b/browser/components/originattributes/test/mochitest/test_permissions_api.html
@@ -0,0 +1,207 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+
+<head>
+ <meta charset="utf-8">
+ <title>Test for Permissions API</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+
+<body>
+ <pre id="test"></pre>
+ <script type="application/javascript;version=1.8">
+ /*globals SpecialPowers, SimpleTest, is, ok, */
+ 'use strict';
+
+ const {
+ UNKNOWN_ACTION,
+ PROMPT_ACTION,
+ ALLOW_ACTION,
+ DENY_ACTION
+ } = SpecialPowers.Ci.nsIPermissionManager;
+
+ SimpleTest.waitForExplicitFinish();
+
+ const PERMISSIONS = [{
+ name: 'geolocation',
+ type: 'geo'
+ }, {
+ name: 'notifications',
+ type: 'desktop-notification'
+ }, {
+ name: 'push',
+ type: 'desktop-notification'
+ }, ];
+
+ const UNSUPPORTED_PERMISSIONS = [
+ 'foobarbaz', // Not in spec, for testing only.
+ 'midi',
+ ];
+
+ // Create a closure, so that tests are run on the correct window object.
+ function createPermissionTester(aWindow) {
+ return {
+ setPermissions(allow) {
+ const permissions = PERMISSIONS.map(({ type }) => {
+ return {
+ type,
+ allow,
+ 'context': aWindow.document
+ };
+ });
+ return new Promise((resolve) => {
+ SpecialPowers.popPermissions(() => {
+ SpecialPowers.pushPermissions(permissions, resolve);
+ });
+ });
+ },
+ revokePermissions() {
+ const promisesToRevoke = PERMISSIONS.map(({ name }) => {
+ return aWindow.navigator.permissions
+ .revoke({ name })
+ .then(
+ ({ state }) => is(state, 'prompt', `correct state for '${name}'`),
+ () => ok(false, `revoke should not have rejected for '${name}'`)
+ );
+ });
+ return Promise.all(promisesToRevoke);
+ },
+ revokeUnsupportedPermissions() {
+ const promisesToRevoke = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
+ return aWindow.navigator.permissions
+ .revoke({ name })
+ .then(
+ () => ok(false, `revoke should not have resolved for '${name}'`),
+ error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`)
+ );
+ });
+ return Promise.all(promisesToRevoke);
+ },
+ checkPermissions(state) {
+ const promisesToQuery = PERMISSIONS.map(({ name }) => {
+ return aWindow.navigator.permissions
+ .query({ name })
+ .then(
+ () => is(state, state, `correct state for '${name}'`),
+ () => ok(false, `query should not have rejected for '${name}'`)
+ );
+ });
+ return Promise.all(promisesToQuery);
+ },
+ checkUnsupportedPermissions() {
+ const promisesToQuery = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
+ return aWindow.navigator.permissions
+ .query({ name })
+ .then(
+ () => ok(false, `query should not have resolved for '${name}'`),
+ error => {
+ is(error.name, 'TypeError',
+ `query should have thrown TypeError for '${name}'`);
+ }
+ );
+ });
+ return Promise.all(promisesToQuery);
+ },
+ promiseStateChanged(name, state) {
+ return aWindow.navigator.permissions
+ .query({ name })
+ .then(status => {
+ return new Promise( resolve => {
+ status.onchange = () => {
+ status.onchange = null;
+ is(status.state, state, `state changed for '${name}'`);
+ resolve();
+ };
+ });
+ },
+ () => ok(false, `query should not have rejected for '${name}'`));
+ },
+ testStatusOnChange() {
+ return new Promise((resolve) => {
+ SpecialPowers.popPermissions(() => {
+ const permission = 'geolocation';
+ const promiseGranted = this.promiseStateChanged(permission, 'granted');
+ this.setPermissions(ALLOW_ACTION);
+ promiseGranted.then(() => {
+ const promisePrompt = this.promiseStateChanged(permission, 'prompt');
+ SpecialPowers.popPermissions();
+ return promisePrompt;
+ }).then(resolve);
+ });
+ });
+ },
+ testInvalidQuery() {
+ return aWindow.navigator.permissions
+ .query({ name: 'invalid' })
+ .then(
+ () => ok(false, 'invalid query should not have resolved'),
+ () => ok(true, 'invalid query should have rejected')
+ );
+ },
+ testInvalidRevoke() {
+ return aWindow.navigator.permissions
+ .revoke({ name: 'invalid' })
+ .then(
+ () => ok(false, 'invalid revoke should not have resolved'),
+ () => ok(true, 'invalid revoke should have rejected')
+ );
+ },
+ };
+ }
+
+ function enablePrefs() {
+ const ops = {
+ 'set': [
+ ['dom.permissions.revoke.enable', true],
+ ['privacy.firstparty.isolate', true],
+ ],
+ };
+ return SpecialPowers.pushPrefEnv(ops);
+ }
+
+ function createIframe() {
+ return new Promise((resolve) => {
+ const iframe = document.createElement('iframe');
+ iframe.src = 'file_empty.html';
+ iframe.onload = () => resolve(iframe.contentWindow);
+ document.body.appendChild(iframe);
+ });
+ }
+ debugger;
+ window.onload = () => {
+ enablePrefs()
+ .then(createIframe)
+ .then(createPermissionTester)
+ .then((tester) => {
+ return tester
+ .checkUnsupportedPermissions()
+ .then(() => tester.setPermissions(UNKNOWN_ACTION))
+ .then(() => tester.checkPermissions('prompt'))
+ .then(() => tester.setPermissions(PROMPT_ACTION))
+ .then(() => tester.checkPermissions('prompt'))
+ .then(() => tester.setPermissions(ALLOW_ACTION))
+ .then(() => tester.checkPermissions('granted'))
+ .then(() => tester.setPermissions(DENY_ACTION))
+ .then(() => tester.checkPermissions('denied'))
+ .then(() => tester.testStatusOnChange())
+ .then(() => tester.testInvalidQuery())
+ .then(() => tester.revokeUnsupportedPermissions())
+ .then(() => tester.revokePermissions())
+ .then(() => tester.checkPermissions('prompt'))
+ .then(() => tester.testInvalidRevoke());
+ })
+ .then(SimpleTest.finish)
+ .catch((e) => {
+ ok(false, `Unexpected error ${e}`);
+ SimpleTest.finish();
+ });
+ };
+ </script>
+</body>
+
+</html>
--- a/browser/components/safebrowsing/content/test/head.js
+++ b/browser/components/safebrowsing/content/test/head.js
@@ -28,18 +28,16 @@ function promiseTabLoadEvent(tab, url, e
info(`Skipping spurious load event for ${loadedUrl}`);
return false;
}
info("Tab event received: load");
return true;
}
- // Create two promises: one resolved from the content process when the page
- // loads and one that is rejected if we take too long to load the url.
let loaded;
if (eventType === "load") {
loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
} else {
// No need to use handle.
loaded =
BrowserTestUtils.waitForContentEvent(tab.linkedBrowser, eventType,
true, undefined, true);
--- a/browser/components/search/test/head.js
+++ b/browser/components/search/test/head.js
@@ -107,18 +107,16 @@ function promiseTabLoadEvent(tab, url)
info(`Skipping spurious load event for ${loadedUrl}`);
return false;
}
info("Tab event received: load");
return true;
}
- // Create two promises: one resolved from the content process when the page
- // loads and one that is rejected if we take too long to load the url.
let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
if (url)
BrowserTestUtils.loadURI(tab.linkedBrowser, url);
return loaded;
}
--- a/browser/locales/en-US/chrome/browser/tabbrowser.properties
+++ b/browser/locales/en-US/chrome/browser/tabbrowser.properties
@@ -12,16 +12,17 @@
# tabs.downloading = Firefox is downloading a file for a helper application (PDF)
tabs.connecting=Connecting…
tabs.encryptingConnection=Securing connection…
tabs.searching=Searching…
tabs.loading=Loading…
tabs.waiting=Waiting…
tabs.downloading=Downloading…
+tabs.restoreLastTabs=Restore Tabs From Last Time
tabs.emptyTabTitle=New Tab
tabs.closeTab=Close Tab
tabs.close=Close
tabs.closeWarningTitle=Confirm close
# LOCALIZATION NOTE (tabs.closeWarningMultiple):
# Semicolon-separated list of plural forms. See:
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
# The singular form is not considered since this string is used only for
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -142,22 +142,16 @@
}
/** End titlebar **/
#main-window[chromehidden~="toolbar"][chromehidden~="location"][chromehidden~="directories"] {
border-top: 1px solid rgba(0,0,0,0.65);
}
-/* Because of -moz-box-align: center above, separators will be invisible unless
- we set their min-height. See bug 583510 for more information. */
-toolbarseparator {
- min-height: 22px;
-}
-
#navigator-toolbox > toolbar:not(#TabsToolbar):not(#nav-bar):not(:-moz-lwtheme) {
-moz-appearance: none;
background: url(chrome://browser/skin/Toolbar-background-noise.png) hsl(0,0%,83%);
}
/* remove noise texture on Yosemite */
@media (-moz-mac-yosemite-theme) {
#navigator-toolbox > toolbar:not(#TabsToolbar):not(#nav-bar):not(:-moz-lwtheme) {
--- a/build/gecko_templates.mozbuild
+++ b/build/gecko_templates.mozbuild
@@ -53,22 +53,24 @@ def GeckoBinary(linkage='dependent', msv
]
elif linkage != None:
error('`linkage` must be "dependent", "standalone" or None')
if mozglue:
LDFLAGS += CONFIG['MOZ_GLUE_WRAP_LDFLAGS']
if mozglue == 'program':
USE_LIBS += ['mozglue']
+ DEFINES['MOZ_HAS_MOZGLUE'] = True
if CONFIG['MOZ_GLUE_IN_PROGRAM']:
if CONFIG['GNU_CC']:
LDFLAGS += ['-rdynamic']
if CONFIG['MOZ_MEMORY']:
USE_LIBS += ['memory']
elif mozglue == 'library':
+ LIBRARY_DEFINES['MOZ_HAS_MOZGLUE'] = True
if not CONFIG['MOZ_GLUE_IN_PROGRAM']:
USE_LIBS += ['mozglue']
else:
error('`mozglue` must be "program" or "library"')
if not CONFIG['JS_STANDALONE']:
USE_LIBS += [
'fallible',
--- a/config/external/fdlibm/moz.build
+++ b/config/external/fdlibm/moz.build
@@ -1,14 +1,12 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
-Library('fdlibm')
-
with Files('**'):
BUG_COMPONENT = ('Core', 'JavaScript Engine')
DIRS += [
'../../../modules/fdlibm',
]
--- a/devtools/client/netmonitor/test/browser_net_content-type.js
+++ b/devtools/client/netmonitor/test/browser_net_content-type.js
@@ -19,17 +19,17 @@ function* content_type_test(isHTTPS) {
let { tab, monitor } = yield initNetMonitor(pageURL);
info("Starting test... ");
let { document, Editor, NetMonitorView } = monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
- let wait = waitForNetworkEvents(monitor, 8);
+ let wait = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.wrappedJSObject.performRequests();
});
yield wait;
let okStatus = isHTTPS ? "Connected" : "OK";
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
--- a/devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
@@ -11,17 +11,17 @@ add_task(function* () {
let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
info("Starting test... ");
let { NetMonitorView } = monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
- let wait = waitForNetworkEvents(monitor, 8);
+ let wait = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.wrappedJSObject.performRequests();
});
yield wait;
let requestItem = RequestsMenu.getItemAtIndex(5);
RequestsMenu.selectedItem = requestItem;
--- a/devtools/client/netmonitor/test/browser_net_copy_response.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_response.js
@@ -13,17 +13,17 @@ add_task(function* () {
const EXPECTED_RESULT = '{ "greeting": "Hello JSON!" }';
let { NetMonitorView } = monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
- let wait = waitForNetworkEvents(monitor, 8);
+ let wait = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.wrappedJSObject.performRequests();
});
yield wait;
let requestItem = RequestsMenu.getItemAtIndex(3);
RequestsMenu.selectedItem = requestItem;
--- a/devtools/client/netmonitor/test/browser_net_icon-preview.js
+++ b/devtools/client/netmonitor/test/browser_net_icon-preview.js
@@ -39,17 +39,17 @@ add_task(function* () {
info("Checking the image thumbnail after a reload.");
checkImageThumbnail();
yield teardown(monitor);
function waitForEvents() {
return promise.all([
- waitForNetworkEvents(monitor, 8),
+ waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS),
monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED)
]);
}
function performRequests() {
return ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.wrappedJSObject.performRequests();
});
--- a/devtools/client/netmonitor/test/browser_net_image-tooltip.js
+++ b/devtools/client/netmonitor/test/browser_net_image-tooltip.js
@@ -10,28 +10,28 @@ add_task(function* test() {
let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
info("Starting test... ");
let { $, EVENTS, ACTIVITY_TYPE, NetMonitorView, NetMonitorController } =
monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = true;
- let onEvents = waitForNetworkEvents(monitor, 8);
+ let onEvents = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
let onThumbnail = monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
yield performRequests();
yield onEvents;
yield onThumbnail;
info("Checking the image thumbnail after a few requests were made...");
yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.items[5]);
- // 7 XHRs as before + 1 extra document reload
- onEvents = waitForNetworkEvents(monitor, 8);
+ // +1 extra document reload
+ onEvents = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS + 1);
onThumbnail = monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
info("Reloading the debuggee and performing all requests again...");
yield NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
yield performRequests();
yield onEvents;
yield onThumbnail;
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -16,16 +16,17 @@ const EXAMPLE_URL = "http://example.com/
const HTTPS_EXAMPLE_URL = "https://example.com/browser/devtools/client/netmonitor/test/";
const API_CALLS_URL = EXAMPLE_URL + "html_api-calls-test-page.html";
const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
const CONTENT_TYPE_WITHOUT_CACHE_URL = EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
const HTTPS_CONTENT_TYPE_WITHOUT_CACHE_URL = HTTPS_EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
+const CONTENT_TYPE_WITHOUT_CACHE_REQUESTS = 8;
const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
const POST_JSON_URL = EXAMPLE_URL + "html_post-json-test-page.html";
const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
const POST_RAW_WITH_HEADERS_URL = EXAMPLE_URL + "html_post-raw-with-headers-test-page.html";
const PARAMS_URL = EXAMPLE_URL + "html_params-test-page.html";
const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
--- a/devtools/client/storage/test/storage-listings.html
+++ b/devtools/client/storage/test/storage-listings.html
@@ -14,17 +14,17 @@ Bug 970517 - Storage inspector front end
"use strict";
let partialHostname = location.hostname.match(/^[^.]+(\..*)$/)[1];
let cookieExpiresTime1 = 2000000000000;
let cookieExpiresTime2 = 2000000001000;
// Setting up some cookies to eat.
document.cookie = "c1=foobar; expires=" +
new Date(cookieExpiresTime1).toGMTString() + "; path=/browser";
document.cookie = "cs2=sessionCookie; path=/; domain=" + partialHostname;
-document.cookie = "c3=foobar-2; secure=true; expires=" +
+document.cookie = "c3=foobar-2; expires=" +
new Date(cookieExpiresTime2).toGMTString() + "; path=/";
// ... and some local storage items ..
localStorage.setItem("ls1", "foobar");
localStorage.setItem("ls2", "foobar-2");
// ... and finally some session storage items too
sessionStorage.setItem("ss1", "foobar-3");
dump("added cookies and storage from main page\n");
--- a/devtools/client/storage/test/storage-unsecured-iframe.html
+++ b/devtools/client/storage/test/storage-unsecured-iframe.html
@@ -4,16 +4,16 @@
Iframe for testing multiple host detetion in storage actor
-->
<head>
<meta charset="utf-8">
</head>
<body>
<script>
"use strict";
-document.cookie = "uc1=foobar; domain=.example.org; path=/; secure=true";
+document.cookie = "uc1=foobar; domain=.example.org; path=/";
localStorage.setItem("iframe-u-ls1", "foobar");
sessionStorage.setItem("iframe-u-ss1", "foobar1");
sessionStorage.setItem("iframe-u-ss2", "foobar2");
dump("added cookies and storage from unsecured iframe\n");
</script>
</body>
</html>
--- a/devtools/client/themes/computed.css
+++ b/devtools/client/themes/computed.css
@@ -31,22 +31,22 @@
align-items: center;
}
#browser-style-checkbox {
/* Bug 1200073 - extra space before the browser styles checkbox so
they aren't squished together in a small window. Put also
an extra space after. */
margin-inline-start: 5px;
- margin-inline-end: 5px;
-
+ margin-inline-end: 0;
}
#browser-style-checkbox-label {
- margin-right: 5px;
+ padding-inline-start: 5px;
+ margin-inline-end: 5px;
}
#propertyContainer {
-moz-user-select: text;
overflow-y: auto;
overflow-x: hidden;
flex: auto;
}
--- a/devtools/server/tests/browser/browser_storage_listings.js
+++ b/devtools/server/tests/browser/browser_storage_listings.js
@@ -30,17 +30,17 @@ const storeMap = {
},
{
name: "c3",
value: "foobar-2",
expires: 2000000001000,
path: "/",
host: "test1.example.org",
isDomain: false,
- isSecure: true,
+ isSecure: false,
},
{
name: "uc1",
value: "foobar",
host: ".example.org",
path: "/",
expires: 0,
isDomain: true,
@@ -339,17 +339,24 @@ function* testStores(data) {
function testCookies(cookiesActor) {
is(Object.keys(cookiesActor.hosts).length, 2, "Correct number of host entries for cookies");
return testCookiesObjects(0, cookiesActor.hosts, cookiesActor);
}
var testCookiesObjects = Task.async(function* (index, hosts, cookiesActor) {
let host = Object.keys(hosts)[index];
let matchItems = data => {
- is(data.total, storeMap.cookies[host].length,
+ let cookiesLength = 0;
+ for (let secureCookie of storeMap.cookies[host]) {
+ if (secureCookie.isSecure) {
+ ++cookiesLength;
+ }
+ }
+ // Any secure cookies did not get stored in the database.
+ is(data.total, storeMap.cookies[host].length - cookiesLength,
"Number of cookies in host " + host + " matches");
for (let item of data.data) {
let found = false;
for (let toMatch of storeMap.cookies[host]) {
if (item.name == toMatch.name) {
found = true;
ok(true, "Found cookie " + item.name + " in response");
is(item.value.str, toMatch.value, "The value matches.");
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -12263,16 +12263,17 @@ nsIDocument::InlineScriptAllowedByCSP()
{
nsCOMPtr<nsIContentSecurityPolicy> csp;
nsresult rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, true);
bool allowsInlineScript = true;
if (csp) {
nsresult rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
EmptyString(), // aNonce
+ false, // parserCreated
EmptyString(), // FIXME get script sample (bug 1314567)
0, // aLineNumber
&allowsInlineScript);
NS_ENSURE_SUCCESS(rv, true);
}
return allowsInlineScript;
}
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -1377,24 +1377,25 @@ CSPAllowsInlineScript(nsIScriptElement *
// no CSP --> allow
return true;
}
// query the nonce
nsCOMPtr<nsIContent> scriptContent = do_QueryInterface(aElement);
nsAutoString nonce;
scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
+ bool parserCreated = aElement->GetParserCreated() != mozilla::dom::NOT_FROM_PARSER;
// query the scripttext
nsAutoString scriptText;
aElement->GetScriptText(scriptText);
bool allowInlineScript = false;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
- nonce, scriptText,
+ nonce, parserCreated, scriptText,
aElement->GetScriptLineNumber(),
&allowInlineScript);
return allowInlineScript;
}
nsScriptLoadRequest*
nsScriptLoader::CreateLoadRequest(nsScriptKind aKind,
nsIScriptElement* aElement,
--- a/dom/cache/CacheOpParent.cpp
+++ b/dom/cache/CacheOpParent.cpp
@@ -49,30 +49,30 @@ CacheOpParent::~CacheOpParent()
void
CacheOpParent::Execute(ManagerId* aManagerId)
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
MOZ_ASSERT(!mManager);
MOZ_ASSERT(!mVerifier);
- RefPtr<Manager> manager;
- nsresult rv = Manager::GetOrCreate(aManagerId, getter_AddRefs(manager));
+ RefPtr<cache::Manager> manager;
+ nsresult rv = cache::Manager::GetOrCreate(aManagerId, getter_AddRefs(manager));
if (NS_WARN_IF(NS_FAILED(rv))) {
ErrorResult result(rv);
Unused << Send__delete__(this, result, void_t());
result.SuppressException();
return;
}
Execute(manager);
}
void
-CacheOpParent::Execute(Manager* aManager)
+CacheOpParent::Execute(cache::Manager* aManager)
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
MOZ_ASSERT(!mManager);
MOZ_ASSERT(!mVerifier);
mManager = aManager;
// Handle put op
--- a/dom/cache/CacheOpParent.h
+++ b/dom/cache/CacheOpParent.h
@@ -32,17 +32,17 @@ public:
CacheOpParent(mozilla::ipc::PBackgroundParent* aIpcManager,
Namespace aNamespace, const CacheOpArgs& aOpArgs);
~CacheOpParent();
void
Execute(ManagerId* aManagerId);
void
- Execute(Manager* aManager);
+ Execute(cache::Manager* aManager);
void
WaitForVerification(PrincipalVerifier* aVerifier);
private:
// PCacheOpParent methods
virtual void
ActorDestroy(ActorDestroyReason aReason) override;
@@ -62,17 +62,17 @@ private:
// utility methods
already_AddRefed<nsIInputStream>
DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid);
mozilla::ipc::PBackgroundParent* mIpcManager;
const CacheId mCacheId;
const Namespace mNamespace;
const CacheOpArgs mOpArgs;
- RefPtr<Manager> mManager;
+ RefPtr<cache::Manager> mManager;
RefPtr<PrincipalVerifier> mVerifier;
NS_DECL_OWNINGTHREAD
};
} // namespace cache
} // namespace dom
} // namespace mozilla
--- a/dom/cache/CacheTypes.ipdlh
+++ b/dom/cache/CacheTypes.ipdlh
@@ -45,22 +45,22 @@ union CacheReadStreamOrVoid
CacheReadStream;
};
struct HeadersEntry
{
nsCString name;
nsCString value;
};
-
struct CacheRequest
{
nsCString method;
nsCString urlWithoutQuery;
nsCString urlQuery;
+ nsCString urlFragment;
HeadersEntry[] headers;
HeadersGuardEnum headersGuard;
nsString referrer;
ReferrerPolicy referrerPolicy;
RequestMode mode;
RequestCredentials credentials;
CacheReadStreamOrVoid body;
uint32_t contentPolicyType;
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -27,30 +27,25 @@
#include "nsNetCID.h"
#include "nsPrintfCString.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
namespace cache {
namespace db {
-
const int32_t kFirstShippedSchemaVersion = 15;
-
namespace {
-
// Update this whenever the DB schema is changed.
-const int32_t kLatestSchemaVersion = 23;
-
+const int32_t kLatestSchemaVersion = 24;
// ---------
// The following constants define the SQL schema. These are defined in the
// same order the SQL should be executed in CreateOrMigrateSchema(). They are
// broken out as constants for convenient use in validation and migration.
// ---------
-
// The caches table is the single source of truth about what Cache
// objects exist for the origin. The contents of the Cache are stored
// in the entries table that references back to caches.
//
// The caches table is also referenced from storage. Rows in storage
// represent named Cache objects. There are cases, however, where
// a Cache can still exist, but not be in a named Storage. For example,
// when content is still using the Cache after CacheStorage::Delete()
@@ -98,24 +93,23 @@ const char* const kTableEntries =
"response_type INTEGER NOT NULL, "
"response_status INTEGER NOT NULL, "
"response_status_text TEXT NOT NULL, "
"response_headers_guard INTEGER NOT NULL, "
"response_body_id TEXT NULL, "
"response_security_info_id INTEGER NULL REFERENCES security_info(id), "
"response_principal_info TEXT NOT NULL, "
"cache_id INTEGER NOT NULL REFERENCES caches(id) ON DELETE CASCADE, "
-
"request_redirect INTEGER NOT NULL, "
"request_referrer_policy INTEGER NOT NULL, "
- "request_integrity TEXT NOT NULL"
+ "request_integrity TEXT NOT NULL, "
+ "request_url_fragment TEXT NOT NULL"
// New columns must be added at the end of table to migrate and
// validate properly.
")";
-
// Create an index to support the QueryCache() matching algorithm. This
// needs to quickly find entries in a given Cache that match the request
// URL. The url query is separated in order to support the ignoreSearch
// option. Finally, we index hashes of the URL values instead of the
// actual strings to avoid excessive disk bloat. The index will duplicate
// the contents of the columsn in the index. The hash index will prune
// the vast majority of values from the query result so that normal
// scanning only has to be done on a few values to find an exact URL match.
@@ -1650,16 +1644,17 @@ InsertEntry(mozIStorageConnection* aConn
nsCOMPtr<mozIStorageStatement> state;
rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO entries ("
"request_method, "
"request_url_no_query, "
"request_url_no_query_hash, "
"request_url_query, "
"request_url_query_hash, "
+ "request_url_fragment, "
"request_referrer, "
"request_referrer_policy, "
"request_headers_guard, "
"request_mode, "
"request_credentials, "
"request_contentpolicytype, "
"request_cache, "
"request_redirect, "
@@ -1674,16 +1669,17 @@ InsertEntry(mozIStorageConnection* aConn
"response_principal_info, "
"cache_id "
") VALUES ("
":request_method, "
":request_url_no_query, "
":request_url_no_query_hash, "
":request_url_query, "
":request_url_query_hash, "
+ ":request_url_fragment, "
":request_referrer, "
":request_referrer_policy, "
":request_headers_guard, "
":request_mode, "
":request_credentials, "
":request_contentpolicytype, "
":request_cache, "
":request_redirect, "
@@ -1719,29 +1715,29 @@ InsertEntry(mozIStorageConnection* aConn
rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("request_url_query"),
aRequest.urlQuery());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
nsAutoCString urlQueryHash;
rv = HashCString(crypto, aRequest.urlQuery(), urlQueryHash);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
rv = state->BindUTF8StringAsBlobByName(
NS_LITERAL_CSTRING("request_url_query_hash"), urlQueryHash);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+ rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("request_url_fragment"),
+ aRequest.urlFragment());
+ if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindStringByName(NS_LITERAL_CSTRING("request_referrer"),
aRequest.referrer());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("request_referrer_policy"),
static_cast<int32_t>(aRequest.referrerPolicy()));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("request_headers_guard"),
static_cast<int32_t>(aRequest.headersGuard()));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("request_mode"),
static_cast<int32_t>(aRequest.mode()));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -2038,23 +2034,23 @@ ReadResponse(mozIStorageConnection* aCon
nsresult
ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
SavedRequest* aSavedRequestOut)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aConn);
MOZ_ASSERT(aSavedRequestOut);
-
nsCOMPtr<mozIStorageStatement> state;
nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT "
"request_method, "
"request_url_no_query, "
"request_url_query, "
+ "request_url_fragment, "
"request_referrer, "
"request_referrer_policy, "
"request_headers_guard, "
"request_mode, "
"request_credentials, "
"request_contentpolicytype, "
"request_cache, "
"request_redirect, "
@@ -2069,80 +2065,69 @@ ReadRequest(mozIStorageConnection* aConn
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
bool hasMoreData = false;
rv = state->ExecuteStep(&hasMoreData);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->GetUTF8String(0, aSavedRequestOut->mValue.method());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
rv = state->GetUTF8String(1, aSavedRequestOut->mValue.urlWithoutQuery());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
rv = state->GetUTF8String(2, aSavedRequestOut->mValue.urlQuery());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
- rv = state->GetString(3, aSavedRequestOut->mValue.referrer());
+ rv = state->GetUTF8String(3, aSavedRequestOut->mValue.urlFragment());
+ if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+ rv = state->GetString(4, aSavedRequestOut->mValue.referrer());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
int32_t referrerPolicy;
- rv = state->GetInt32(4, &referrerPolicy);
+ rv = state->GetInt32(5, &referrerPolicy);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.referrerPolicy() =
static_cast<ReferrerPolicy>(referrerPolicy);
-
int32_t guard;
- rv = state->GetInt32(5, &guard);
+ rv = state->GetInt32(6, &guard);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.headersGuard() =
static_cast<HeadersGuardEnum>(guard);
-
int32_t mode;
- rv = state->GetInt32(6, &mode);
+ rv = state->GetInt32(7, &mode);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.mode() = static_cast<RequestMode>(mode);
-
int32_t credentials;
- rv = state->GetInt32(7, &credentials);
+ rv = state->GetInt32(8, &credentials);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.credentials() =
static_cast<RequestCredentials>(credentials);
-
int32_t requestContentPolicyType;
- rv = state->GetInt32(8, &requestContentPolicyType);
+ rv = state->GetInt32(9, &requestContentPolicyType);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.contentPolicyType() =
static_cast<nsContentPolicyType>(requestContentPolicyType);
-
int32_t requestCache;
- rv = state->GetInt32(9, &requestCache);
+ rv = state->GetInt32(10, &requestCache);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.requestCache() =
static_cast<RequestCache>(requestCache);
-
int32_t requestRedirect;
- rv = state->GetInt32(10, &requestRedirect);
+ rv = state->GetInt32(11, &requestRedirect);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.requestRedirect() =
static_cast<RequestRedirect>(requestRedirect);
-
- rv = state->GetString(11, aSavedRequestOut->mValue.integrity());
+ rv = state->GetString(12, aSavedRequestOut->mValue.integrity());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
bool nullBody = false;
- rv = state->GetIsNull(12, &nullBody);
+ rv = state->GetIsNull(13, &nullBody);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mHasBodyId = !nullBody;
-
if (aSavedRequestOut->mHasBodyId) {
- rv = ExtractId(state, 12, &aSavedRequestOut->mBodyId);
+ rv = ExtractId(state, 13, &aSavedRequestOut->mBodyId);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
}
-
rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT "
"name, "
"value "
"FROM request_headers "
"WHERE entry_id=:entry_id;"
), getter_AddRefs(state));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -2487,31 +2472,30 @@ struct Migration
nsresult MigrateFrom15To16(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom16To17(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom17To18(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom18To19(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom19To20(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom20To21(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom21To22(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom22To23(mozIStorageConnection* aConn, bool& aRewriteSchema);
-
+nsresult MigrateFrom23To24(mozIStorageConnection* aConn, bool& aRewriteSchema);
// Configure migration functions to run for the given starting version.
Migration sMigrationList[] = {
Migration(15, MigrateFrom15To16),
Migration(16, MigrateFrom16To17),
Migration(17, MigrateFrom17To18),
Migration(18, MigrateFrom18To19),
Migration(19, MigrateFrom19To20),
Migration(20, MigrateFrom20To21),
Migration(21, MigrateFrom21To22),
Migration(22, MigrateFrom22To23),
+ Migration(23, MigrateFrom23To24),
};
-
uint32_t sMigrationListLength = sizeof(sMigrationList) / sizeof(Migration);
-
nsresult
RewriteEntriesSchema(mozIStorageConnection* aConn)
{
nsresult rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"PRAGMA writable_schema = ON"
));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -2996,21 +2980,37 @@ nsresult MigrateFrom21To22(mozIStorageCo
nsresult MigrateFrom22To23(mozIStorageConnection* aConn, bool& aRewriteSchema)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aConn);
// The only change between 22 and 23 was a different snappy compression
// format, but it's backwards-compatible.
-
nsresult rv = aConn->SetSchemaVersion(23);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+ return rv;
+}
+nsresult MigrateFrom23To24(mozIStorageConnection* aConn, bool& aRewriteSchema)
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+ MOZ_ASSERT(aConn);
+
+ // Add the request_url_fragment column.
+ nsresult rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+ "ALTER TABLE entries "
+ "ADD COLUMN request_url_fragment TEXT NOT NULL DEFAULT ''"
+ ));
+ if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+ rv = aConn->SetSchemaVersion(24);
+ if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+ aRewriteSchema = true;
return rv;
}
} // anonymous namespace
-
} // namespace db
} // namespace cache
} // namespace dom
} // namespace mozilla
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -117,40 +117,35 @@ TypeUtils::ToInternalRequest(const Ownin
void
TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
BodyAction aBodyAction, SchemeAction aSchemeAction,
nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
ErrorResult& aRv)
{
MOZ_ASSERT(aIn);
-
aIn->GetMethod(aOut.method());
-
- nsAutoCString url;
- aIn->GetURL(url);
-
+ nsCString url(aIn->GetURLWithoutFragment());
bool schemeValid;
ProcessURL(url, &schemeValid, &aOut.urlWithoutQuery(), &aOut.urlQuery(), aRv);
if (aRv.Failed()) {
return;
}
-
if (!schemeValid) {
if (aSchemeAction == TypeErrorOnInvalidScheme) {
NS_ConvertUTF8toUTF16 urlUTF16(url);
aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(NS_LITERAL_STRING("Request"),
urlUTF16);
return;
}
}
+ aOut.urlFragment() = aIn->GetFragment();
aIn->GetReferrer(aOut.referrer());
aOut.referrerPolicy() = aIn->ReferrerPolicy_();
-
RefPtr<InternalHeaders> headers = aIn->Headers();
MOZ_ASSERT(headers);
ToHeadersEntryList(aOut.headers(), headers);
aOut.headersGuard() = headers->Guard();
aOut.mode() = aIn->Mode();
aOut.credentials() = aIn->GetCredentialsMode();
aOut.contentPolicyType() = aIn->ContentPolicyType();
aOut.requestCache() = aIn->GetCacheMode();
@@ -301,27 +296,24 @@ TypeUtils::ToResponse(const CacheRespons
default:
MOZ_CRASH("Unexpected ResponseType!");
}
MOZ_ASSERT(ir);
RefPtr<Response> ref = new Response(GetGlobalObject(), ir);
return ref.forget();
}
-
already_AddRefed<InternalRequest>
TypeUtils::ToInternalRequest(const CacheRequest& aIn)
{
nsAutoCString url(aIn.urlWithoutQuery());
url.Append(aIn.urlQuery());
-
- RefPtr<InternalRequest> internalRequest = new InternalRequest(url);
-
+ RefPtr<InternalRequest> internalRequest =
+ new InternalRequest(url, aIn.urlFragment());
internalRequest->SetMethod(aIn.method());
-
internalRequest->SetReferrer(aIn.referrer());
internalRequest->SetReferrerPolicy(aIn.referrerPolicy());
internalRequest->SetMode(aIn.mode());
internalRequest->SetCredentialsMode(aIn.credentials());
internalRequest->SetContentPolicyType(aIn.contentPolicyType());
internalRequest->SetCacheMode(aIn.requestCache());
internalRequest->SetRedirectMode(aIn.requestRedirect());
internalRequest->SetIntegrity(aIn.integrity());
--- a/dom/cache/test/mochitest/test_cache_keys.js
+++ b/dom/cache/test/mochitest/test_cache_keys.js
@@ -10,16 +10,21 @@ caches.open(name).then(function(cache) {
c = cache;
return c.addAll(tests);
}).then(function() {
// Add another cache entry using Cache.add
var another = "//mochi.test:8888/?yetanother" + context;
tests.push(another);
return c.add(another);
}).then(function() {
+ // Add another cache entry with URL fragment using Cache.add
+ var anotherWithFragment = "//mochi.test:8888/?fragment" + context + "#fragment";
+ tests.push(anotherWithFragment);
+ return c.add(anotherWithFragment);
+}).then(function() {
return c.keys();
}).then(function(keys) {
is(keys.length, tests.length, "Same number of elements");
// Verify both the insertion order of the requests and their validity.
keys.forEach(function(r, i) {
ok(r instanceof Request, "Valid request object");
ok(r.url.indexOf(tests[i]) >= 0, "Valid URL");
});
--- a/dom/cache/test/mochitest/test_cache_match_request.js
+++ b/dom/cache/test/mochitest/test_cache_match_request.js
@@ -20,31 +20,29 @@ function checkResponse(r, expectedBody)
"Both responses should have the same status text");
return r.text().then(function(text) {
// Avoid dumping out the large response text to the log if they're equal.
if (text !== expectedBody) {
is(text, responseText, "The response body should be correct");
}
});
}
-
fetch(new Request(request)).then(function(r) {
response = r;
return response.text();
}).then(function(text) {
responseText = text;
return testRequest(request, unknownRequest, requestWithAltQS,
request.url.replace("#fragment", "#other"));
}).then(function() {
return testRequest(request.url, unknownRequest.url, requestWithAltQS.url,
request.url.replace("#fragment", "#other"));
}).then(function() {
testDone();
});
-
// The request argument can either be a URL string, or a Request object.
function testRequest(request, unknownRequest, requestWithAlternateQueryString,
requestWithDifferentFragment) {
return caches.open(name).then(function(cache) {
c = cache;
return c.add(request);
}).then(function() {
return Promise.all(
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -867,16 +867,17 @@ EventListenerManager::SetEventHandler(ns
scriptSample.Assign(attr);
scriptSample.AppendLiteral(" attribute on ");
scriptSample.Append(tagName);
scriptSample.AppendLiteral(" element");
bool allowsInlineScript = true;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
EmptyString(), // aNonce
+ false, // aParserCreated
scriptSample,
0, // aLineNumber
&allowsInlineScript);
NS_ENSURE_SUCCESS(rv, rv);
// return early if CSP wants us to block inline scripts
if (!allowsInlineScript) {
return NS_OK;
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -370,29 +370,25 @@ FetchDriver::HttpFetch()
}
rv = chan->AsyncOpen2(this);
NS_ENSURE_SUCCESS(rv, rv);
// Step 4 onwards of "HTTP Fetch" is handled internally by Necko.
return NS_OK;
}
-
already_AddRefed<InternalResponse>
FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse,
bool aFoundOpaqueRedirect)
{
MOZ_ASSERT(aResponse);
-
AutoTArray<nsCString, 4> reqURLList;
- mRequest->GetURLList(reqURLList);
-
+ mRequest->GetURLListWithoutFragment(reqURLList);
MOZ_ASSERT(!reqURLList.IsEmpty());
aResponse->SetURLList(reqURLList);
-
RefPtr<InternalResponse> filteredResponse;
if (aFoundOpaqueRedirect) {
filteredResponse = aResponse->OpaqueRedirectResponse();
} else {
switch (mRequest->GetResponseTainting()) {
case LoadTainting::Basic:
filteredResponse = aResponse->BasicResponse();
break;
@@ -803,25 +799,28 @@ FetchDriver::AsyncOnChannelRedirect(nsIC
nsCOMPtr<nsIURI> uri;
MOZ_ALWAYS_SUCCEEDS(aNewChannel->GetURI(getter_AddRefs(uri)));
nsCOMPtr<nsIURI> uriClone;
nsresult rv = uri->CloneIgnoringRef(getter_AddRefs(uriClone));
if(NS_WARN_IF(NS_FAILED(rv))){
return rv;
}
-
nsCString spec;
rv = uriClone->GetSpec(spec);
if(NS_WARN_IF(NS_FAILED(rv))){
return rv;
}
+ nsCString fragment;
+ rv = uri->GetRef(fragment);
+ if(NS_WARN_IF(NS_FAILED(rv))){
+ return rv;
+ }
- mRequest->AddURL(spec);
-
+ mRequest->AddURL(spec, fragment);
NS_ConvertUTF8toUTF16 tRPHeaderValue(tRPHeaderCValue);
// updates request’s associated referrer policy according to the
// Referrer-Policy header (if any).
if (!tRPHeaderValue.IsEmpty()) {
net::ReferrerPolicy net_referrerPolicy =
nsContentUtils::GetReferrerPolicyFromHeader(tRPHeaderValue);
if (net_referrerPolicy != net::RP_Unset) {
ReferrerPolicy referrerPolicy = mRequest->ReferrerPolicy_();
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -14,28 +14,26 @@
#include "mozilla/dom/FetchTypes.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/workers/Workers.h"
#include "WorkerPrivate.h"
namespace mozilla {
namespace dom {
-
// The global is used to extract the principal.
already_AddRefed<InternalRequest>
InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const
{
MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(), "Internal Request's urlList should not be empty when copied from constructor.");
-
- RefPtr<InternalRequest> copy = new InternalRequest(mURLList.LastElement());
+ RefPtr<InternalRequest> copy = new InternalRequest(mURLList.LastElement(),
+ mFragment);
copy->SetMethod(mMethod);
copy->mHeaders = new InternalHeaders(*mHeaders);
copy->SetUnsafeRequest();
-
copy->mBodyStream = mBodyStream;
copy->mForceOriginHeader = true;
// The "client" is not stored in our implementation. Fetch API users should
// use the appropriate window/document/principal and other Gecko security
// mechanisms as appropriate.
copy->mSameOriginDataURL = true;
copy->mPreserveContentCodings = true;
copy->mReferrer = mReferrer;
@@ -70,21 +68,20 @@ InternalRequest::Clone()
nsresult rv = NS_CloneInputStream(mBodyStream, getter_AddRefs(clonedBody),
getter_AddRefs(replacementBody));
if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; }
clone->mBodyStream.swap(clonedBody);
if (replacementBody) {
mBodyStream.swap(replacementBody);
}
-
return clone.forget();
}
-
-InternalRequest::InternalRequest(const nsACString& aURL)
+InternalRequest::InternalRequest(const nsACString& aURL,
+ const nsACString& aFragment)
: mMethod("GET")
, mHeaders(new InternalHeaders(HeadersGuardEnum::None))
, mContentPolicyType(nsIContentPolicy::TYPE_FETCH)
, mReferrer(NS_LITERAL_STRING(kFETCH_CLIENT_REFERRER_STR))
, mReferrerPolicy(ReferrerPolicy::_empty)
, mEnvironmentReferrerPolicy(net::RP_Default)
, mMode(RequestMode::No_cors)
, mCredentialsMode(RequestCredentials::Omit)
@@ -100,20 +97,20 @@ InternalRequest::InternalRequest(const n
// specification does not handle this yet.
, mSameOriginDataURL(true)
, mSkipServiceWorker(false)
, mSynchronous(false)
, mUnsafeRequest(false)
, mUseURLCredentials(false)
{
MOZ_ASSERT(!aURL.IsEmpty());
- AddURL(aURL);
+ AddURL(aURL, aFragment);
}
-
InternalRequest::InternalRequest(const nsACString& aURL,
+ const nsACString& aFragment,
const nsACString& aMethod,
already_AddRefed<InternalHeaders> aHeaders,
RequestCache aCacheMode,
RequestMode aMode,
RequestRedirect aRequestRedirect,
RequestCredentials aRequestCredentials,
const nsAString& aReferrer,
ReferrerPolicy aReferrerPolicy,
@@ -137,33 +134,33 @@ InternalRequest::InternalRequest(const n
// FIXME See the above comment in the default constructor.
, mSameOriginDataURL(true)
, mSkipServiceWorker(false)
, mSynchronous(false)
, mUnsafeRequest(false)
, mUseURLCredentials(false)
{
MOZ_ASSERT(!aURL.IsEmpty());
- AddURL(aURL);
+ AddURL(aURL, aFragment);
}
-
InternalRequest::InternalRequest(const InternalRequest& aOther)
: mMethod(aOther.mMethod)
, mURLList(aOther.mURLList)
, mHeaders(new InternalHeaders(*aOther.mHeaders))
, mContentPolicyType(aOther.mContentPolicyType)
, mReferrer(aOther.mReferrer)
, mReferrerPolicy(aOther.mReferrerPolicy)
, mEnvironmentReferrerPolicy(aOther.mEnvironmentReferrerPolicy)
, mMode(aOther.mMode)
, mCredentialsMode(aOther.mCredentialsMode)
, mResponseTainting(aOther.mResponseTainting)
, mCacheMode(aOther.mCacheMode)
, mRedirectMode(aOther.mRedirectMode)
, mIntegrity(aOther.mIntegrity)
+ , mFragment(aOther.mFragment)
, mAuthenticationFlag(aOther.mAuthenticationFlag)
, mForceOriginHeader(aOther.mForceOriginHeader)
, mPreserveContentCodings(aOther.mPreserveContentCodings)
, mSameOriginDataURL(aOther.mSameOriginDataURL)
, mSkipServiceWorker(aOther.mSkipServiceWorker)
, mSynchronous(aOther.mSynchronous)
, mUnsafeRequest(aOther.mUnsafeRequest)
, mUseURLCredentials(aOther.mUseURLCredentials)
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -82,27 +82,24 @@ namespace dom {
* TODO: Add a content type for favicon
* TODO: Add a content type for download
*/
class Request;
class IPCInternalRequest;
#define kFETCH_CLIENT_REFERRER_STR "about:client"
-
class InternalRequest final
{
friend class Request;
-
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalRequest)
-
- explicit InternalRequest(const nsACString& aURL);
-
+ InternalRequest(const nsACString& aURL, const nsACString& aFragment);
InternalRequest(const nsACString& aURL,
+ const nsACString& aFragment,
const nsACString& aMethod,
already_AddRefed<InternalHeaders> aHeaders,
RequestCache aCacheMode,
RequestMode aMode,
RequestRedirect aRequestRedirect,
RequestCredentials aRequestCredentials,
const nsAString& aReferrer,
ReferrerPolicy aReferrerPolicy,
@@ -129,47 +126,59 @@ public:
bool
HasSimpleMethod() const
{
return mMethod.LowerCaseEqualsASCII("get") ||
mMethod.LowerCaseEqualsASCII("post") ||
mMethod.LowerCaseEqualsASCII("head");
}
-
- // GetURL should get the request's current url. A request has an associated
- // current url. It is a pointer to the last fetch URL in request's url list.
+ // GetURL should get the request's current url with fragment. A request has
+ // an associated current url. It is a pointer to the last fetch URL in
+ // request's url list.
void
GetURL(nsACString& aURL) const
{
- MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(), "Internal Request's urlList should not be empty.");
-
- aURL.Assign(mURLList.LastElement());
+ aURL.Assign(GetURLWithoutFragment());
+ if (GetFragment().IsEmpty()) {
+ return;
+ }
+ aURL.Append(NS_LITERAL_CSTRING("#"));
+ aURL.Append(GetFragment());
}
+ const nsCString&
+ GetURLWithoutFragment() const
+ {
+ MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(),
+ "Internal Request's urlList should not be empty.");
+
+ return mURLList.LastElement();
+ }
// AddURL should append the url into url list.
- // Normally we strip the fragment from the URL in Request::Constructor.
- // If internal code is directly constructing this object they must
- // strip the fragment first. Since these should be well formed URLs we
- // can use a simple check for a fragment here. The full parser is
- // difficult to use off the main thread.
+ // Normally we strip the fragment from the URL in Request::Constructor and
+ // pass the fragment as the second argument into it.
+ // If a fragment is present in the URL it must be stripped and passed in
+ // separately.
void
- AddURL(const nsACString& aURL)
+ AddURL(const nsACString& aURL, const nsACString& aFragment)
{
MOZ_ASSERT(!aURL.IsEmpty());
+ MOZ_ASSERT(!aURL.Contains('#'));
+
mURLList.AppendElement(aURL);
- MOZ_ASSERT(mURLList.LastElement().Find(NS_LITERAL_CSTRING("#")) == kNotFound);
+
+ mFragment.Assign(aFragment);
}
-
+ // Get the URL list without their fragments.
void
- GetURLList(nsTArray<nsCString>& aURLList)
+ GetURLListWithoutFragment(nsTArray<nsCString>& aURLList)
{
aURLList.Assign(mURLList);
}
-
void
GetReferrer(nsAString& aReferrer) const
{
aReferrer.Assign(mReferrer);
}
void
SetReferrer(const nsAString& aReferrer)
@@ -316,30 +325,33 @@ public:
mRedirectMode = aRedirectMode;
}
const nsString&
GetIntegrity() const
{
return mIntegrity;
}
-
void
SetIntegrity(const nsAString& aIntegrity)
{
MOZ_ASSERT(mIntegrity.IsEmpty());
mIntegrity.Assign(aIntegrity);
}
+ const nsCString&
+ GetFragment() const
+ {
+ return mFragment;
+ }
nsContentPolicyType
ContentPolicyType() const
{
return mContentPolicyType;
}
-
void
SetContentPolicyType(nsContentPolicyType aContentPolicyType);
void
OverrideContentPolicyType(nsContentPolicyType aContentPolicyType);
RequestContext
Context() const
@@ -486,25 +498,23 @@ private:
ReferrerPolicy mReferrerPolicy;
// This will be used for request created from Window or Worker contexts
// In case there's no Referrer Policy in Request, this will be passed to
// channel.
// The Environment Referrer Policy should be net::ReferrerPolicy so that it
// could be associated with nsIHttpChannel.
net::ReferrerPolicy mEnvironmentReferrerPolicy;
-
RequestMode mMode;
RequestCredentials mCredentialsMode;
MOZ_INIT_OUTSIDE_CTOR LoadTainting mResponseTainting;
RequestCache mCacheMode;
RequestRedirect mRedirectMode;
-
nsString mIntegrity;
-
+ nsCString mFragment;
MOZ_INIT_OUTSIDE_CTOR bool mAuthenticationFlag;
MOZ_INIT_OUTSIDE_CTOR bool mForceOriginHeader;
MOZ_INIT_OUTSIDE_CTOR bool mPreserveContentCodings;
MOZ_INIT_OUTSIDE_CTOR bool mSameOriginDataURL;
MOZ_INIT_OUTSIDE_CTOR bool mSkipServiceWorker;
MOZ_INIT_OUTSIDE_CTOR bool mSynchronous;
MOZ_INIT_OUTSIDE_CTOR bool mUnsafeRequest;
MOZ_INIT_OUTSIDE_CTOR bool mUseURLCredentials;
--- a/dom/fetch/InternalResponse.h
+++ b/dom/fetch/InternalResponse.h
@@ -80,47 +80,40 @@ public:
return mType;
}
bool
IsError() const
{
return Type() == ResponseType::Error;
}
-
// GetUrl should return last fetch URL in response's url list and null if
// response's url list is the empty list.
- void
- GetURL(nsCString& aURL) const
+ const nsCString&
+ GetURL() const
{
// Empty urlList when response is a synthetic response.
if (mURLList.IsEmpty()) {
- aURL.Truncate();
- return;
+ return EmptyCString();
}
-
- aURL.Assign(mURLList.LastElement());
+ return mURLList.LastElement();
}
-
void
GetURLList(nsTArray<nsCString>& aURLList) const
{
aURLList.Assign(mURLList);
}
-
- void
- GetUnfilteredURL(nsCString& aURL) const
+ const nsCString&
+ GetUnfilteredURL() const
{
if (mWrappedResponse) {
- return mWrappedResponse->GetURL(aURL);
+ return mWrappedResponse->GetURL();
}
-
- return GetURL(aURL);
+ return GetURL();
}
-
void
GetUnfilteredURLList(nsTArray<nsCString>& aURLList) const
{
if (mWrappedResponse) {
return mWrappedResponse->GetURLList(aURLList);
}
return GetURLList(aURLList);
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -84,147 +84,158 @@ ParseURLFromDocument(nsIDocument* aDocum
nsCOMPtr<nsIURI> baseURI = aDocument->GetBaseURI();
nsCOMPtr<nsIURI> resolvedURI;
aRv = NS_NewURI(getter_AddRefs(resolvedURI), aInput, nullptr, baseURI);
if (NS_WARN_IF(aRv.Failed())) {
aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
}
return resolvedURI.forget();
}
-
void
GetRequestURLFromDocument(nsIDocument* aDocument, const nsAString& aInput,
- nsAString& aRequestURL, ErrorResult& aRv)
+ nsAString& aRequestURL, nsACString& aURLfragment,
+ ErrorResult& aRv)
{
nsCOMPtr<nsIURI> resolvedURI = ParseURLFromDocument(aDocument, aInput, aRv);
if (aRv.Failed()) {
return;
}
-
// This fails with URIs with weird protocols, even when they are valid,
// so we ignore the failure
nsAutoCString credentials;
Unused << resolvedURI->GetUserPass(credentials);
if (!credentials.IsEmpty()) {
aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
return;
}
nsCOMPtr<nsIURI> resolvedURIClone;
// We use CloneIgnoringRef to strip away the fragment even if the original URI
// is immutable.
aRv = resolvedURI->CloneIgnoringRef(getter_AddRefs(resolvedURIClone));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
-
nsAutoCString spec;
aRv = resolvedURIClone->GetSpec(spec);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
+ CopyUTF8toUTF16(spec, aRequestURL);
- CopyUTF8toUTF16(spec, aRequestURL);
+ // Get the fragment from nsIURI.
+ aRv = resolvedURI->GetRef(aURLfragment);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
}
-
already_AddRefed<nsIURI>
ParseURLFromChrome(const nsAString& aInput, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
-
nsCOMPtr<nsIURI> uri;
aRv = NS_NewURI(getter_AddRefs(uri), aInput, nullptr, nullptr);
if (NS_WARN_IF(aRv.Failed())) {
aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
}
return uri.forget();
}
-
void
GetRequestURLFromChrome(const nsAString& aInput, nsAString& aRequestURL,
- ErrorResult& aRv)
+ nsACString& aURLfragment, ErrorResult& aRv)
{
nsCOMPtr<nsIURI> uri = ParseURLFromChrome(aInput, aRv);
if (aRv.Failed()) {
return;
}
-
// This fails with URIs with weird protocols, even when they are valid,
// so we ignore the failure
nsAutoCString credentials;
Unused << uri->GetUserPass(credentials);
if (!credentials.IsEmpty()) {
aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
return;
}
nsCOMPtr<nsIURI> uriClone;
// We use CloneIgnoringRef to strip away the fragment even if the original URI
// is immutable.
aRv = uri->CloneIgnoringRef(getter_AddRefs(uriClone));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
-
nsAutoCString spec;
aRv = uriClone->GetSpec(spec);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
+ CopyUTF8toUTF16(spec, aRequestURL);
- CopyUTF8toUTF16(spec, aRequestURL);
+ // Get the fragment from nsIURI.
+ aRv = uri->GetRef(aURLfragment);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
}
-
already_AddRefed<URL>
ParseURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
ErrorResult& aRv)
{
workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref);
RefPtr<URL> url = URL::WorkerConstructor(aGlobal, aInput, baseURL, aRv);
if (NS_WARN_IF(aRv.Failed())) {
aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
}
return url.forget();
}
-
void
GetRequestURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
- nsAString& aRequestURL, ErrorResult& aRv)
+ nsAString& aRequestURL, nsACString& aURLfragment,
+ ErrorResult& aRv)
{
RefPtr<URL> url = ParseURLFromWorker(aGlobal, aInput, aRv);
if (aRv.Failed()) {
return;
}
-
nsString username;
url->GetUsername(username, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
nsString password;
url->GetPassword(password, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
-
if (!username.IsEmpty() || !password.IsEmpty()) {
aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
return;
}
+ // Get the fragment from URL.
+ nsAutoString fragment;
+ url->GetHash(fragment, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+
+ // Note: URL::GetHash() includes the "#" and we want the fragment with out
+ // the hash symbol.
+ if (!fragment.IsEmpty()) {
+ CopyUTF16toUTF8(Substring(fragment, 1), aURLfragment);
+ }
url->SetHash(EmptyString(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
-
url->Stringify(aRequestURL, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
class ReferrerSameOriginChecker final : public workers::WorkerMainThreadRunnable
{
@@ -279,48 +290,43 @@ Request::Constructor(const GlobalObject&
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
return nullptr;
}
if (body) {
temporaryBody = body;
}
request = inputReq->GetInternalRequest();
-
} else {
// aInput is USVString.
// We need to get url before we create a InternalRequest.
nsAutoString input;
input.Assign(aInput.GetAsUSVString());
-
nsAutoString requestURL;
+ nsCString fragment;
if (NS_IsMainThread()) {
nsIDocument* doc = GetEntryDocument();
if (doc) {
- GetRequestURLFromDocument(doc, input, requestURL, aRv);
+ GetRequestURLFromDocument(doc, input, requestURL, fragment, aRv);
} else {
// If we don't have a document, we must assume that this is a full URL.
- GetRequestURLFromChrome(input, requestURL, aRv);
+ GetRequestURLFromChrome(input, requestURL, fragment, aRv);
}
} else {
- GetRequestURLFromWorker(aGlobal, input, requestURL, aRv);
+ GetRequestURLFromWorker(aGlobal, input, requestURL, fragment, aRv);
}
-
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
-
- request = new InternalRequest(NS_ConvertUTF16toUTF8(requestURL));
+ request = new InternalRequest(NS_ConvertUTF16toUTF8(requestURL), fragment);
}
-
request = request->GetRequestConstructorCopy(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
-
RequestMode fallbackMode = RequestMode::EndGuard_;
RequestCredentials fallbackCredentials = RequestCredentials::EndGuard_;
RequestCache fallbackCache = RequestCache::EndGuard_;
if (aInput.IsUSVString()) {
fallbackMode = RequestMode::Cors;
fallbackCredentials = RequestCredentials::Omit;
fallbackCache = RequestCache::Default;
}
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -43,31 +43,26 @@ public:
return ResponseBinding::Wrap(aCx, this, aGivenProto);
}
ResponseType
Type() const
{
return mInternalResponse->Type();
}
-
void
GetUrl(nsAString& aUrl) const
{
- nsCString url;
- mInternalResponse->GetURL(url);
- CopyUTF8toUTF16(url, aUrl);
+ CopyUTF8toUTF16(mInternalResponse->GetURL(), aUrl);
}
-
bool
Redirected() const
{
return mInternalResponse->IsRedirected();
}
-
uint16_t
Status() const
{
return mInternalResponse->GetStatus();
}
bool
Ok() const
--- a/dom/flyweb/HttpServer.cpp
+++ b/dom/flyweb/HttpServer.cpp
@@ -580,26 +580,23 @@ HttpServer::Connection::ConsumeLine(cons
MOZ_ASSERT(!mPendingReq);
// Process request line
nsCWhitespaceTokenizer tokens(Substring(aBuffer, aLength));
NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
nsDependentCSubstring method = tokens.nextToken();
NS_ENSURE_TRUE(NS_IsValidHTTPToken(method), NS_ERROR_UNEXPECTED);
-
NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
nsDependentCSubstring url = tokens.nextToken();
// Seems like it's also allowed to pass full urls with scheme+host+port.
// May need to support that.
NS_ENSURE_TRUE(url.First() == '/', NS_ERROR_UNEXPECTED);
-
- mPendingReq = new InternalRequest(url);
+ mPendingReq = new InternalRequest(url, /* aURLFragment */ EmptyCString());
mPendingReq->SetMethod(method);
-
NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
nsDependentCSubstring version = tokens.nextToken();
NS_ENSURE_TRUE(StringBeginsWith(version, NS_LITERAL_CSTRING("HTTP/1.")),
NS_ERROR_UNEXPECTED);
nsresult rv;
// This integer parsing is likely not strict enough.
nsCString reqVersion;
reqVersion = Substring(version, MOZ_ARRAY_LENGTH("HTTP/1.") - 1);
--- a/dom/interfaces/security/nsIContentSecurityPolicy.idl
+++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl
@@ -126,26 +126,28 @@ interface nsIContentSecurityPolicy : nsI
void appendPolicy(in AString policyString,
in boolean reportOnly,
in boolean deliveredViaMetaTag);
/*
* Whether this policy allows inline script or style.
* @param aContentPolicyType Either TYPE_SCRIPT or TYPE_STYLESHEET
* @param aNonce The nonce string to check against the policy
+ * @param aParserCreated If the script element was created by the HTML Parser
* @param aContent The content of the inline resource to hash
* (and compare to the hashes listed in the policy)
* @param aLineNumber The line number of the inline resource
* (used for reporting)
* @return
* Whether or not the effects of the inline style should be allowed
* (block the rules if false).
*/
boolean getAllowsInline(in nsContentPolicyType aContentPolicyType,
in AString aNonce,
+ in boolean aParserCreated,
in AString aContent,
in unsigned long aLineNumber);
/**
* whether this policy allows eval and eval-like functions
* such as setTimeout("code string", time).
* @param shouldReportViolations
* Whether or not the use of eval should be reported.
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -20,16 +20,17 @@
#include "mozilla/LookAndFeel.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProcessHangMonitorIPC.h"
#include "mozilla/Unused.h"
#include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
#include "mozilla/docshell/OfflineCacheUpdateChild.h"
#include "mozilla/dom/ContentBridgeChild.h"
#include "mozilla/dom/ContentBridgeParent.h"
+#include "mozilla/dom/VideoDecoderManagerChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/DOMStorageIPC.h"
#include "mozilla/dom/ExternalHelperAppChild.h"
#include "mozilla/dom/FlyWebPublishedServerIPC.h"
#include "mozilla/dom/GetFilesHelper.h"
#include "mozilla/dom/PCrashReporterChild.h"
#include "mozilla/dom/ProcessGlobal.h"
@@ -1176,34 +1177,37 @@ ContentChild::RecvGMPsChanged(nsTArray<G
{
GeckoMediaPluginServiceChild::UpdateGMPCapabilities(Move(capabilities));
return true;
}
bool
ContentChild::RecvInitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor,
Endpoint<PImageBridgeChild>&& aImageBridge,
- Endpoint<PVRManagerChild>&& aVRBridge)
+ Endpoint<PVRManagerChild>&& aVRBridge,
+ Endpoint<PVideoDecoderManagerChild>&& aVideoManager)
{
if (!CompositorBridgeChild::InitForContent(Move(aCompositor))) {
return false;
}
if (!ImageBridgeChild::InitForContent(Move(aImageBridge))) {
return false;
}
if (!gfx::VRManagerChild::InitForContent(Move(aVRBridge))) {
return false;
}
+ VideoDecoderManagerChild::InitForContent(Move(aVideoManager));
return true;
}
bool
ContentChild::RecvReinitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor,
Endpoint<PImageBridgeChild>&& aImageBridge,
- Endpoint<PVRManagerChild>&& aVRBridge)
+ Endpoint<PVRManagerChild>&& aVRBridge,
+ Endpoint<PVideoDecoderManagerChild>&& aVideoManager)
{
nsTArray<RefPtr<TabChild>> tabs = TabChild::GetAll();
// Zap all the old layer managers we have lying around.
for (const auto& tabChild : tabs) {
if (tabChild->LayersId()) {
tabChild->InvalidateLayers();
}
@@ -1221,16 +1225,18 @@ ContentChild::RecvReinitRendering(Endpoi
}
// Establish new PLayerTransactions.
for (const auto& tabChild : tabs) {
if (tabChild->LayersId()) {
tabChild->ReinitRendering();
}
}
+
+ VideoDecoderManagerChild::InitForContent(Move(aVideoManager));
return true;
}
PBackgroundChild*
ContentChild::AllocPBackgroundChild(Transport* aTransport,
ProcessId aOtherProcess)
{
return BackgroundChild::Alloc(aTransport, aOtherProcess);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -164,23 +164,25 @@ public:
bool
RecvGMPsChanged(nsTArray<GMPCapabilityData>&& capabilities) override;
bool
RecvInitRendering(
Endpoint<PCompositorBridgeChild>&& aCompositor,
Endpoint<PImageBridgeChild>&& aImageBridge,
- Endpoint<PVRManagerChild>&& aVRBridge) override;
+ Endpoint<PVRManagerChild>&& aVRBridge,
+ Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override;
bool
RecvReinitRendering(
Endpoint<PCompositorBridgeChild>&& aCompositor,
Endpoint<PImageBridgeChild>&& aImageBridge,
- Endpoint<PVRManagerChild>&& aVRBridge) override;
+ Endpoint<PVRManagerChild>&& aVRBridge,
+ Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override;
PProcessHangMonitorChild*
AllocPProcessHangMonitorChild(Transport* aTransport,
ProcessId aOtherProcess) override;
virtual bool RecvSetProcessSandbox(const MaybeFileDesc& aBroker) override;
PBackgroundChild*
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1022,23 +1022,16 @@ ContentParent::RecvFindPlugins(const uin
nsresult* aRv,
nsTArray<PluginTag>* aPlugins,
uint32_t* aNewPluginEpoch)
{
*aRv = mozilla::plugins::FindPluginsForContent(aPluginEpoch, aPlugins, aNewPluginEpoch);
return true;
}
-bool
-ContentParent::RecvInitVideoDecoderManager(Endpoint<PVideoDecoderManagerChild>* aEndpoint)
-{
- GPUProcessManager::Get()->CreateContentVideoDecoderManager(OtherPid(), aEndpoint);
- return true;
-}
-
/*static*/ TabParent*
ContentParent::CreateBrowserOrApp(const TabContext& aContext,
Element* aFrameElement,
ContentParent* aOpenerContentParent,
bool aFreshProcess)
{
PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
@@ -2222,28 +2215,31 @@ ContentParent::InitInternal(ProcessPrior
// on demand.)
bool useOffMainThreadCompositing = !!CompositorThreadHolder::Loop();
if (useOffMainThreadCompositing) {
GPUProcessManager* gpm = GPUProcessManager::Get();
Endpoint<PCompositorBridgeChild> compositor;
Endpoint<PImageBridgeChild> imageBridge;
Endpoint<PVRManagerChild> vrBridge;
+ Endpoint<PVideoDecoderManagerChild> videoManager;
DebugOnly<bool> opened = gpm->CreateContentBridges(
OtherPid(),
&compositor,
&imageBridge,
- &vrBridge);
+ &vrBridge,
+ &videoManager);
MOZ_ASSERT(opened);
Unused << SendInitRendering(
Move(compositor),
Move(imageBridge),
- Move(vrBridge));
+ Move(vrBridge),
+ Move(videoManager));
gpm->AddListener(this);
}
}
if (gAppData) {
// Sending all information to content process.
Unused << SendAppInit();
@@ -2378,28 +2374,31 @@ ContentParent::RecvGetGfxVars(Infallible
void
ContentParent::OnCompositorUnexpectedShutdown()
{
GPUProcessManager* gpm = GPUProcessManager::Get();
Endpoint<PCompositorBridgeChild> compositor;
Endpoint<PImageBridgeChild> imageBridge;
Endpoint<PVRManagerChild> vrBridge;
+ Endpoint<PVideoDecoderManagerChild> videoManager;
DebugOnly<bool> opened = gpm->CreateContentBridges(
OtherPid(),
&compositor,
&imageBridge,
- &vrBridge);
+ &vrBridge,
+ &videoManager);
MOZ_ASSERT(opened);
Unused << SendReinitRendering(
Move(compositor),
Move(imageBridge),
- Move(vrBridge));
+ Move(vrBridge),
+ Move(videoManager));
}
void
ContentParent::OnVarChanged(const GfxVarUpdate& aVar)
{
if (!mIPCOpen) {
return;
}
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -257,18 +257,16 @@ public:
virtual bool RecvGetBlocklistState(const uint32_t& aPluginId,
uint32_t* aIsBlocklisted) override;
virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
nsresult* aRv,
nsTArray<PluginTag>* aPlugins,
uint32_t* aNewPluginEpoch) override;
- virtual bool RecvInitVideoDecoderManager(Endpoint<PVideoDecoderManagerChild>* endpoint) override;
-
virtual bool RecvUngrabPointer(const uint32_t& aTime) override;
virtual bool RecvRemovePermission(const IPC::Principal& aPrincipal,
const nsCString& aPermissionType,
nsresult* aRv) override;
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
--- a/dom/ipc/CrashReporterParent.cpp
+++ b/dom/ipc/CrashReporterParent.cpp
@@ -42,44 +42,16 @@ CrashReporterParent::ActorDestroy(ActorD
bool
CrashReporterParent::RecvAppendAppNotes(const nsCString& data)
{
mAppNotes.Append(data);
return true;
}
-mozilla::ipc::IProtocol*
-CrashReporterParent::CloneProtocol(Channel* aChannel,
- mozilla::ipc::ProtocolCloneContext* aCtx)
-{
-#ifdef MOZ_CRASHREPORTER
- ContentParent* contentParent = aCtx->GetContentParent();
- CrashReporter::ThreadId childThreadId = contentParent->Pid();
- GeckoProcessType childProcessType =
- contentParent->Process()->GetProcessType();
-
- nsAutoPtr<PCrashReporterParent> actor(
- contentParent->AllocPCrashReporterParent(childThreadId,
- childProcessType)
- );
- if (!actor ||
- !contentParent->RecvPCrashReporterConstructor(actor,
- childThreadId,
- childThreadId)) {
- return nullptr;
- }
-
- return actor.forget();
-#else
- MOZ_CRASH("Not Implemented");
- return nullptr;
-#endif
-}
-
CrashReporterParent::CrashReporterParent()
:
#ifdef MOZ_CRASHREPORTER
mNotes(4),
#endif
mStartTime(::time(nullptr))
, mInitialized(false)
{
--- a/dom/ipc/CrashReporterParent.h
+++ b/dom/ipc/CrashReporterParent.h
@@ -155,20 +155,16 @@ public:
const nsCString& aData) override
{
AnnotateCrashReport(aKey, aData);
return true;
}
virtual bool RecvAppendAppNotes(const nsCString& aData) override;
- virtual mozilla::ipc::IProtocol*
- CloneProtocol(Channel* aChannel,
- mozilla::ipc::ProtocolCloneContext *aCtx) override;
-
#ifdef MOZ_CRASHREPORTER
void
NotifyCrashService();
#endif
#ifdef MOZ_CRASHREPORTER
AnnotationTable mNotes;
#endif
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -424,25 +424,27 @@ both:
async PWebBrowserPersistDocument(nullable PBrowser aBrowser,
uint64_t aOuterWindowID);
child:
// Give the content process its endpoints to the compositor.
async InitRendering(
Endpoint<PCompositorBridgeChild> compositor,
Endpoint<PImageBridgeChild> imageBridge,
- Endpoint<PVRManagerChild> vr);
+ Endpoint<PVRManagerChild> vr,
+ Endpoint<PVideoDecoderManagerChild> video);
// Re-create the rendering stack using the given endpoints. This is sent
// after the compositor process has crashed. The new endpoints may be to a
// newly launched GPU process, or the compositor thread of the UI process.
async ReinitRendering(
Endpoint<PCompositorBridgeChild> compositor,
Endpoint<PImageBridgeChild> bridge,
- Endpoint<PVRManagerChild> vr);
+ Endpoint<PVRManagerChild> vr,
+ Endpoint<PVideoDecoderManagerChild> video);
/**
* Enable system-level sandboxing features, if available. Can
* usually only be performed zero or one times. The child may
* abnormally exit if this fails; the details are OS-specific.
*/
async SetProcessSandbox(MaybeFileDesc aBroker);
@@ -737,18 +739,16 @@ parent:
async PJavaScript();
async PRemoteSpellcheckEngine();
async PDeviceStorageRequest(DeviceStorageParams params);
sync PCrashReporter(NativeThreadId tid, uint32_t processType);
- sync InitVideoDecoderManager() returns (Endpoint<PVideoDecoderManagerChild> endpoint);
-
/**
* Is this token compatible with the provided version?
*
* |version| The offered version to test
* Returns |True| if the offered version is compatible
*/
sync NSSU2FTokenIsCompatibleVersion(nsString version)
returns (bool result);
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -178,16 +178,17 @@ nsresult nsJSThunk::EvaluateScript(nsICh
// allowed.
nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = principal->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, rv);
if (csp) {
bool allowsInlineScript = true;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
EmptyString(), // aNonce
+ false, // aParserCreated
EmptyString(), // aContent
0, // aLineNumber
&allowsInlineScript);
//return early if inline scripts are not allowed
if (!allowsInlineScript) {
return NS_ERROR_DOM_RETVAL_UNDEFINED;
}
--- a/dom/locales/en-US/chrome/security/csp.properties
+++ b/dom/locales/en-US/chrome/security/csp.properties
@@ -34,16 +34,27 @@ ignoringUnknownOption = Ignoring unknown
ignoringDuplicateSrc = Ignoring duplicate source %1$S
# LOCALIZATION NOTE (ignoringSrcFromMetaCSP):
# %1$S defines the ignored src
ignoringSrcFromMetaCSP = Ignoring source ‘%1$S’ (Not supported when delivered via meta element).
# LOCALIZATION NOTE (ignoringSrcWithinScriptStyleSrc):
# %1$S is the ignored src
# script-src and style-src are directive names and should not be localized
ignoringSrcWithinScriptStyleSrc = Ignoring “%1$S” within script-src or style-src: nonce-source or hash-source specified
+# LOCALIZATION NOTE (ignoringSrcForStrictDynamic):
+# %1$S is the ignored src
+# script-src, as well as 'strict-dynamic' should not be localized
+ignoringSrcForStrictDynamic = Ignoring “%1$S” within script-src: ‘strict-dynamic’ specified
+# LOCALIZATION NOTE (ignoringStrictDynamic):
+# %1$S is the ignored src
+ignoringStrictDynamic = Ignoring source “%1$S” (Only supported within script-src).
+# LOCALIZATION NOTE (strictDynamicButNoHashOrNonce):
+# %1$S is the csp directive that contains 'strict-dynamic'
+# 'strict-dynamic' should not be localized
+strictDynamicButNoHashOrNonce = Keyword ‘strict-dynamic’ within “%1$S” with no valid nonce or hash might block all scripts from loading
# LOCALIZATION NOTE (reportURInotHttpsOrHttp2):
# %1$S is the ETLD of the report URI that is not HTTP or HTTPS
reportURInotHttpsOrHttp2 = The report URI (%1$S) should be an HTTP or HTTPS URI.
# LOCALIZATION NOTE (reportURInotInReportOnlyHeader):
# %1$S is the ETLD of the page with the policy
reportURInotInReportOnlyHeader = This site (%1$S) has a Report-Only policy without a report URI. CSP will not block and cannot report violations of this policy.
# LOCALIZATION NOTE (failedToParseUnrecognizedSource):
# %1$S is the CSP Source that could not be parsed
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1507,26 +1507,30 @@ MediaFormatReader::Update(TrackType aTra
if (decoder.mNeedDraining) {
DrainDecoder(aTrack);
return;
}
if (decoder.mError && !decoder.HasFatalError()) {
decoder.mDecodePending = false;
- if (++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
+ bool needsNewDecoder = decoder.mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER;
+ if (!needsNewDecoder && ++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
NotifyError(aTrack, decoder.mError.ref());
return;
}
decoder.mError.reset();
LOG("%s decoded error count %d", TrackTypeToStr(aTrack),
decoder.mNumOfConsecutiveError);
media::TimeUnit nextKeyframe;
if (aTrack == TrackType::kVideoTrack && !decoder.HasInternalSeekPending() &&
NS_SUCCEEDED(decoder.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe))) {
+ if (needsNewDecoder) {
+ decoder.ShutdownDecoder();
+ }
SkipVideoDemuxToNextKeyFrame(decoder.mLastSampleTime.refOr(TimeInterval()).Length());
return;
} else if (aTrack == TrackType::kAudioTrack) {
decoder.Flush();
}
}
bool needInput = NeedInput(decoder);
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -323,19 +323,31 @@ private:
}
uint32_t mNumOfConsecutiveError;
uint32_t mMaxConsecutiveError;
Maybe<MediaResult> mError;
bool HasFatalError() const
{
- return mError.isSome() &&
- (mError.ref() != NS_ERROR_DOM_MEDIA_DECODE_ERR ||
- mNumOfConsecutiveError > mMaxConsecutiveError);
+ if (!mError.isSome()) {
+ return false;
+ }
+ if (mError.ref() == NS_ERROR_DOM_MEDIA_DECODE_ERR) {
+ // Allow decode errors to be non-fatal, but give up
+ // if we have too many.
+ return mNumOfConsecutiveError > mMaxConsecutiveError;
+ } else if (mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER) {
+ // If the caller asked for a new decoder we shouldn't treat
+ // it as fatal.
+ return false;
+ } else {
+ // All other error types are fatal
+ return true;
+ }
}
// If set, all decoded samples prior mTimeThreshold will be dropped.
// Used for internal seeking when a change of stream is detected or when
// encountering data discontinuity.
Maybe<InternalSeekTarget> mTimeThreshold;
// Time of last sample returned.
Maybe<media::TimeInterval> mLastSampleTime;
deleted file mode 100644
--- a/dom/media/compiledtest/moz.build
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-GeckoCppUnitTests([
- 'TestAudioBuffers',
- 'TestAudioMixer',
- 'TestAudioPacketizer',
- 'TestAudioSegment'
-])
-
-LOCAL_INCLUDES += [
- '..',
-]
-
-USE_LIBS += [
- 'lgpllibs',
-]
rename from dom/media/compiledtest/TestAudioBuffers.cpp
rename to dom/media/gtest/TestAudioBuffers.cpp
--- a/dom/media/compiledtest/TestAudioBuffers.cpp
+++ b/dom/media/gtest/TestAudioBuffers.cpp
@@ -1,59 +1,57 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include <stdint.h>
#include "AudioBufferUtils.h"
-#include <mozilla/Assertions.h>
+#include "gtest/gtest.h"
const uint32_t FRAMES = 256;
const uint32_t CHANNELS = 2;
const uint32_t SAMPLES = CHANNELS * FRAMES;
-int main() {
+TEST(AudioBuffers, Test)
+{
mozilla::AudioCallbackBufferWrapper<float, CHANNELS> mBuffer;
mozilla::SpillBuffer<float, 128, CHANNELS> b;
float fromCallback[SAMPLES];
float other[SAMPLES];
for (uint32_t i = 0; i < SAMPLES; i++) {
other[i] = 1.0;
fromCallback[i] = 0.0;
}
// Set the buffer in the wrapper from the callback
mBuffer.SetBuffer(fromCallback, FRAMES);
// Fill the SpillBuffer with data.
- MOZ_RELEASE_ASSERT(b.Fill(other, 15) == 15);
- MOZ_RELEASE_ASSERT(b.Fill(other, 17) == 17);
+ ASSERT_TRUE(b.Fill(other, 15) == 15);
+ ASSERT_TRUE(b.Fill(other, 17) == 17);
for (uint32_t i = 0; i < 32 * CHANNELS; i++) {
other[i] = 0.0;
}
// Empty it in the AudioCallbackBufferWrapper
- MOZ_RELEASE_ASSERT(b.Empty(mBuffer) == 32);
+ ASSERT_TRUE(b.Empty(mBuffer) == 32);
// Check available return something reasonnable
- MOZ_RELEASE_ASSERT(mBuffer.Available() == FRAMES - 32);
+ ASSERT_TRUE(mBuffer.Available() == FRAMES - 32);
// Fill the buffer with the rest of the data
mBuffer.WriteFrames(other + 32 * CHANNELS, FRAMES - 32);
// Check the buffer is now full
- MOZ_RELEASE_ASSERT(mBuffer.Available() == 0);
+ ASSERT_TRUE(mBuffer.Available() == 0);
for (uint32_t i = 0 ; i < SAMPLES; i++) {
- if (fromCallback[i] != 1.0) {
- fprintf(stderr, "Difference at %d (%f != %f)\n", i, fromCallback[i], 1.0);
- MOZ_CRASH("Samples differ");
- }
+ ASSERT_TRUE(fromCallback[i] == 1.0) <<
+ "Difference at " << i << " (" << fromCallback[i] << " != " << 1.0 <<
+ ")\n";
}
- MOZ_RELEASE_ASSERT(b.Fill(other, FRAMES) == 128);
- MOZ_RELEASE_ASSERT(b.Fill(other, FRAMES) == 0);
- MOZ_RELEASE_ASSERT(b.Empty(mBuffer) == 0);
-
- return 0;
+ ASSERT_TRUE(b.Fill(other, FRAMES) == 128);
+ ASSERT_TRUE(b.Fill(other, FRAMES) == 0);
+ ASSERT_TRUE(b.Empty(mBuffer) == 0);
}
rename from dom/media/compiledtest/TestAudioMixer.cpp
rename to dom/media/gtest/TestAudioMixer.cpp
--- a/dom/media/compiledtest/TestAudioMixer.cpp
+++ b/dom/media/gtest/TestAudioMixer.cpp
@@ -1,18 +1,21 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "AudioMixer.h"
+#include "gtest/gtest.h"
using mozilla::AudioDataValue;
using mozilla::AudioSampleFormat;
+namespace audio_mixer {
+
struct MixerConsumer : public mozilla::MixerCallbackReceiver
{
/* In this test, the different audio stream and channels are always created to
* cancel each other. */
void MixerCallback(AudioDataValue* aData, AudioSampleFormat aFormat, uint32_t aChannels, uint32_t aFrames, uint32_t aSampleRate)
{
bool silent = true;
for (uint32_t i = 0; i < aChannels * aFrames; i++) {
@@ -20,19 +23,17 @@ struct MixerConsumer : public mozilla::M
if (aFormat == mozilla::AUDIO_FORMAT_S16) {
fprintf(stderr, "Sample at %d is not silent: %d\n", i, (short)aData[i]);
} else {
fprintf(stderr, "Sample at %d is not silent: %f\n", i, (float)aData[i]);
}
silent = false;
}
}
- if (!silent) {
- MOZ_CRASH();
- }
+ ASSERT_TRUE(silent);
}
};
/* Helper function to give us the maximum and minimum value that don't clip,
* for a given sample format (integer or floating-point). */
template<typename T>
T GetLowValue();
@@ -62,17 +63,18 @@ short GetHighValue<short>() {
void FillBuffer(AudioDataValue* aBuffer, uint32_t aLength, AudioDataValue aValue)
{
AudioDataValue* end = aBuffer + aLength;
while (aBuffer != end) {
*aBuffer++ = aValue;
}
}
-int main(int argc, char* argv[]) {
+TEST(AudioMixer, Test)
+{
const uint32_t CHANNEL_LENGTH = 256;
const uint32_t AUDIO_RATE = 44100;
MixerConsumer consumer;
AudioDataValue a[CHANNEL_LENGTH * 2];
AudioDataValue b[CHANNEL_LENGTH * 2];
FillBuffer(a, CHANNEL_LENGTH, GetLowValue<AudioDataValue>());
FillBuffer(a + CHANNEL_LENGTH, CHANNEL_LENGTH, GetHighValue<AudioDataValue>());
FillBuffer(b, CHANNEL_LENGTH, GetHighValue<AudioDataValue>());
@@ -153,11 +155,11 @@ int main(int argc, char* argv[]) {
mixer.Mix(b, 2, CHANNEL_LENGTH, AUDIO_RATE);
mixer.Mix(a, 2, CHANNEL_LENGTH, AUDIO_RATE);
mixer.Mix(b, 2, CHANNEL_LENGTH, AUDIO_RATE);
mixer.FinishMixing();
mixer.Mix(a, 2, CHANNEL_LENGTH, AUDIO_RATE);
mixer.Mix(b, 2, CHANNEL_LENGTH, AUDIO_RATE);
mixer.FinishMixing();
}
+}
- return 0;
-}
+} // namespace audio_mixer
rename from dom/media/compiledtest/TestAudioPacketizer.cpp
rename to dom/media/gtest/TestAudioPacketizer.cpp
--- a/dom/media/compiledtest/TestAudioPacketizer.cpp
+++ b/dom/media/gtest/TestAudioPacketizer.cpp
@@ -1,17 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include <stdint.h>
#include <math.h>
#include "../AudioPacketizer.h"
-#include <mozilla/Assertions.h>
+#include "gtest/gtest.h"
using namespace mozilla;
template<typename T>
class AutoBuffer
{
public:
explicit AutoBuffer(size_t aLength)
@@ -35,39 +35,36 @@ int16_t Sequence(int16_t* aBuffer, uint3
aBuffer[i] = aStart + i;
}
return aStart + i;
}
void IsSequence(int16_t* aBuffer, uint32_t aSize, uint32_t aStart = 0)
{
for (uint32_t i = 0; i < aSize; i++) {
- if (aBuffer[i] != static_cast<int64_t>(aStart + i)) {
- fprintf(stderr, "Buffer is not a sequence at offset %u\n", i);
- MOZ_CRASH("Buffer is not a sequence");
- }
+ ASSERT_TRUE(aBuffer[i] == static_cast<int64_t>(aStart + i)) <<
+ "Buffer is not a sequence at offset " << i << std::endl;
}
// Buffer is a sequence.
}
void Zero(int16_t* aBuffer, uint32_t aSize)
{
for (uint32_t i = 0; i < aSize; i++) {
- if (aBuffer[i] != 0) {
- fprintf(stderr, "Buffer is not null at offset %u\n", i);
- MOZ_CRASH("Buffer is not null");
- }
+ ASSERT_TRUE(aBuffer[i] == 0) <<
+ "Buffer is not null at offset " << i << std::endl;
}
}
double sine(uint32_t aPhase) {
- return sin(aPhase * 2 * M_PI * 440 / 44100);
+ return sin(aPhase * 2 * M_PI * 440 / 44100);
}
-int main() {
+TEST(AudioPacketizer, Test)
+{
for (int16_t channels = 1; channels < 2; channels++) {
// Test that the packetizer returns zero on underrun
{
AudioPacketizer<int16_t, int16_t> ap(441, channels);
for (int16_t i = 0; i < 10; i++) {
int16_t* out = ap.Output();
Zero(out, 441);
delete[] out;
@@ -152,22 +149,19 @@ int main() {
}
phase++;
}
ap.Input(b.Get(), 128);
while (ap.PacketsAvailable()) {
int16_t* packet = ap.Output();
for (uint32_t k = 0; k < ap.PacketSize(); k++) {
for (int32_t c = 0; c < channels; c++) {
- MOZ_RELEASE_ASSERT(packet[k * channels + c] ==
- static_cast<int16_t>(((2 << 14) * sine(outPhase))));
+ ASSERT_TRUE(packet[k * channels + c] ==
+ static_cast<int16_t>(((2 << 14) * sine(outPhase))));
}
outPhase++;
}
delete [] packet;
}
}
}
}
-
- printf("OK\n");
- return 0;
}
rename from dom/media/compiledtest/TestAudioSegment.cpp
rename to dom/media/gtest/TestAudioSegment.cpp
--- a/dom/media/compiledtest/TestAudioSegment.cpp
+++ b/dom/media/gtest/TestAudioSegment.cpp
@@ -1,26 +1,20 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "AudioSegment.h"
#include <iostream>
-#include <mozilla/Assertions.h>
+#include "gtest/gtest.h"
using namespace mozilla;
-namespace mozilla {
-uint32_t
-GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2)
-{
- return std::max(aChannels1, aChannels2);
-}
-}
+namespace audio_segment {
/* Helper function to give us the maximum and minimum value that don't clip,
* for a given sample format (integer or floating-point). */
template<typename T>
T GetLowValue();
template<typename T>
T GetHighValue();
@@ -137,18 +131,18 @@ void TestInterleaveAndConvert()
for (uint32_t channels = 1; channels < maxChannels; channels++) {
const SrcT* const* src = GetPlanarChannelArray<SrcT>(channels, arraySize);
DstT* dst = new DstT[channels * arraySize];
InterleaveAndConvertBuffer(src, arraySize, 1.0, channels, dst);
uint32_t channelIndex = 0;
for (size_t i = 0; i < arraySize * channels; i++) {
- MOZ_RELEASE_ASSERT(FuzzyEqual(dst[i],
- FloatToAudioSample<DstT>(1. / (channelIndex + 1))));
+ ASSERT_TRUE(FuzzyEqual(dst[i],
+ FloatToAudioSample<DstT>(1. / (channelIndex + 1))));
channelIndex++;
channelIndex %= channels;
}
DeletePlanarChannelsArray(src, channels);
delete [] dst;
}
}
@@ -161,18 +155,18 @@ void TestDeinterleaveAndConvert()
for (uint32_t channels = 1; channels < maxChannels; channels++) {
const SrcT* src = GetInterleavedChannelArray<SrcT>(channels, arraySize);
DstT** dst = GetPlanarArray<DstT>(channels, arraySize);
DeinterleaveAndConvertBuffer(src, arraySize, channels, dst);
for (size_t channel = 0; channel < channels; channel++) {
for (size_t i = 0; i < arraySize; i++) {
- MOZ_RELEASE_ASSERT(FuzzyEqual(dst[channel][i],
- FloatToAudioSample<DstT>(1. / (channel + 1))));
+ ASSERT_TRUE(FuzzyEqual(dst[channel][i],
+ FloatToAudioSample<DstT>(1. / (channel + 1))));
}
}
DeleteInterleavedChannelArray(src);
DeletePlanarArray(dst, channels);
}
}
@@ -196,21 +190,21 @@ void TestUpmixStereo()
channels[0] = new T[arraySize];
for (size_t i = 0; i < arraySize; i++) {
channels[0][i] = GetHighValue<T>();
}
channelsptr[0] = channels[0];
- AudioChannelsUpMix(&channelsptr, 2, ::SilentChannel<T>());
+ AudioChannelsUpMix(&channelsptr, 2, SilentChannel<T>());
for (size_t channel = 0; channel < 2; channel++) {
for (size_t i = 0; i < arraySize; i++) {
- MOZ_RELEASE_ASSERT(channelsptr[channel][i] == GetHighValue<T>());
+ ASSERT_TRUE(channelsptr[channel][i] == GetHighValue<T>());
}
}
delete channels[0];
}
template<typename T>
void TestDownmixStereo()
{
@@ -231,32 +225,33 @@ void TestDownmixStereo()
input[channel][i] = channel == 0 ? GetLowValue<T>() : GetHighValue<T>();
}
inputptr[channel] = input[channel];
}
AudioChannelsDownMix(inputptr, output, 1, arraySize);
for (size_t i = 0; i < arraySize; i++) {
- MOZ_RELEASE_ASSERT(output[0][i] == GetSilentValue<T>());
- MOZ_RELEASE_ASSERT(output[0][i] == GetSilentValue<T>());
+ ASSERT_TRUE(output[0][i] == GetSilentValue<T>());
+ ASSERT_TRUE(output[0][i] == GetSilentValue<T>());
}
delete output[0];
delete output;
}
-int main(int argc, char* argv[]) {
+TEST(AudioSegment, Test)
+{
TestInterleaveAndConvert<float, float>();
TestInterleaveAndConvert<float, int16_t>();
TestInterleaveAndConvert<int16_t, float>();
TestInterleaveAndConvert<int16_t, int16_t>();
TestDeinterleaveAndConvert<float, float>();
TestDeinterleaveAndConvert<float, int16_t>();
TestDeinterleaveAndConvert<int16_t, float>();
TestDeinterleaveAndConvert<int16_t, int16_t>();
TestUpmixStereo<float>();
TestUpmixStereo<int16_t>();
TestDownmixStereo<float>();
TestDownmixStereo<int16_t>();
+}
- return 0;
-}
+} // namespace audio_segment
--- a/dom/media/gtest/TestRust.cpp
+++ b/dom/media/gtest/TestRust.cpp
@@ -1,8 +1,9 @@
#include <stdint.h>
+#include "gtest/gtest.h"
extern "C" uint8_t* test_rust();
TEST(rust, CallFromCpp) {
auto greeting = test_rust();
EXPECT_STREQ(reinterpret_cast<char*>(greeting), "hello from rust.");
}
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -1,17 +1,21 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
UNIFIED_SOURCES += [
'MockMediaResource.cpp',
+ 'TestAudioBuffers.cpp',
'TestAudioCompactor.cpp',
+ 'TestAudioMixer.cpp',
+ 'TestAudioPacketizer.cpp',
+ 'TestAudioSegment.cpp',
'TestGMPCrossOrigin.cpp',
'TestGMPRemoveAndDelete.cpp',
'TestGMPUtils.cpp',
'TestIntervalSet.cpp',
'TestMediaDataDecoder.cpp',
'TestMediaEventSource.cpp',
'TestMediaFormatReader.cpp',
'TestMozPromise.cpp',
--- a/dom/media/ipc/RemoteVideoDecoder.cpp
+++ b/dom/media/ipc/RemoteVideoDecoder.cpp
@@ -4,16 +4,17 @@
* 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/. */
#include "RemoteVideoDecoder.h"
#include "VideoDecoderChild.h"
#include "VideoDecoderManagerChild.h"
#include "mozilla/layers/TextureClient.h"
#include "base/thread.h"
#include "MediaInfo.h"
+#include "MediaPrefs.h"
#include "ImageContainer.h"
namespace mozilla {
namespace dom {
using base::Thread;
using namespace ipc;
using namespace layers;
@@ -142,17 +143,18 @@ PlatformDecoderModule::ConversionRequire
RemoteDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
{
return mWrapped->DecoderNeedsConversion(aConfig);
}
already_AddRefed<MediaDataDecoder>
RemoteDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
{
- if (!aParams.mKnowsCompositor ||
+ if (!MediaPrefs::PDMUseGPUDecoder() ||
+ !aParams.mKnowsCompositor ||
aParams.mKnowsCompositor->GetTextureFactoryIdentifier().mParentProcessType != GeckoProcessType_GPU) {
return nullptr;
}
MediaDataDecoderCallback* callback = aParams.mCallback;
MOZ_ASSERT(callback->OnReaderTaskQueue());
RefPtr<RemoteVideoDecoder> object = new RemoteVideoDecoder(callback);
--- a/dom/media/ipc/VideoDecoderChild.cpp
+++ b/dom/media/ipc/VideoDecoderChild.cpp
@@ -98,34 +98,45 @@ VideoDecoderChild::RecvInitFailed(const
mInitPromise.Reject(aReason, __func__);
return true;
}
void
VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy)
{
if (aWhy == AbnormalShutdown) {
- if (mInitialized) {
- mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
- } else {
- mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
- }
+ // Defer reporting an error until we've recreated the manager so that
+ // it'll be safe for MediaFormatReader to recreate decoders
+ RefPtr<VideoDecoderChild> ref = this;
+ GetManager()->RunWhenRecreated(NS_NewRunnableFunction([=]() {
+ if (ref->mInitialized) {
+ ref->mCallback->Error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+ } else {
+ ref->mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__);
+ }
+ }));
}
mCanSend = false;
}
void
VideoDecoderChild::InitIPDL(MediaDataDecoderCallback* aCallback,
const VideoInfo& aVideoInfo,
layers::KnowsCompositor* aKnowsCompositor)
{
RefPtr<VideoDecoderManagerChild> manager = VideoDecoderManagerChild::GetSingleton();
- if (!manager) {
+ // If the manager isn't available, then don't initialize mIPDLSelfRef and leave
+ // us in an error state. We'll then immediately reject the promise when Init()
+ // is called and the caller can try again. Hopefully by then the new manager is
+ // ready, or we've notified the caller of it being no longer available.
+ // If not, then the cycle repeats until we're ready.
+ if (!manager || !manager->CanSend()) {
return;
}
+
mIPDLSelfRef = this;
mCallback = aCallback;
mVideoInfo = aVideoInfo;
mKnowsCompositor = aKnowsCompositor;
if (manager->SendPVideoDecoderConstructor(this)) {
mCanSend = true;
}
}
@@ -145,96 +156,99 @@ VideoDecoderChild::IPDLActorDestroyed()
}
// MediaDataDecoder methods
RefPtr<MediaDataDecoder::InitPromise>
VideoDecoderChild::Init()
{
AssertOnManagerThread();
- if (!mCanSend || !SendInit(mVideoInfo, mKnowsCompositor->GetTextureFactoryIdentifier())) {
+
+ if (!mIPDLSelfRef) {
return MediaDataDecoder::InitPromise::CreateAndReject(
- NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
+ NS_ERROR_DOM_MEDIA_DECODE_ERR, __func__);
+ }
+ // If we failed to send this, then we'll still resolve the Init promise
+ // as ActorDestroy handles it.
+ if (mCanSend) {
+ SendInit(mVideoInfo, mKnowsCompositor->GetTextureFactoryIdentifier());
}
return mInitPromise.Ensure(__func__);
}
void
VideoDecoderChild::Input(MediaRawData* aSample)
{
AssertOnManagerThread();
if (!mCanSend) {
- mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
return;
}
// TODO: It would be nice to add an allocator method to
// MediaDataDecoder so that the demuxer could write directly
// into shmem rather than requiring a copy here.
Shmem buffer;
if (!AllocShmem(aSample->Size(), Shmem::SharedMemory::TYPE_BASIC, &buffer)) {
- mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
+ mCallback->Error(NS_ERROR_DOM_MEDIA_DECODE_ERR);
return;
}
memcpy(buffer.get<uint8_t>(), aSample->Data(), aSample->Size());
MediaRawDataIPDL sample(MediaDataIPDL(aSample->mOffset,
aSample->mTime,
aSample->mTimecode,
aSample->mDuration,
aSample->mFrames,
aSample->mKeyframe),
buffer);
- if (!SendInput(sample)) {
- mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
- }
+ SendInput(sample);
}
void
VideoDecoderChild::Flush()
{
AssertOnManagerThread();
- if (!mCanSend || !SendFlush()) {
- mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
+ if (mCanSend) {
+ SendFlush();
}
}
void
VideoDecoderChild::Drain()
{
AssertOnManagerThread();
- if (!mCanSend || !SendDrain()) {
- mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
+ if (mCanSend) {
+ SendDrain();
}
}
void
VideoDecoderChild::Shutdown()
{
AssertOnManagerThread();
- if (!mCanSend || !SendShutdown()) {
- mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
+ if (mCanSend) {
+ SendShutdown();
}
mInitialized = false;
}
bool
VideoDecoderChild::IsHardwareAccelerated(nsACString& aFailureReason) const
{
aFailureReason = mHardwareAcceleratedReason;
return mIsHardwareAccelerated;
}
void
VideoDecoderChild::SetSeekThreshold(const media::TimeUnit& aTime)
{
AssertOnManagerThread();
- if (!mCanSend || !SendSetSeekThreshold(aTime.ToMicroseconds())) {
- mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
+ if (mCanSend) {
+ SendSetSeekThreshold(aTime.ToMicroseconds());
}
}
void
VideoDecoderChild::AssertOnManagerThread()
{
MOZ_ASSERT(NS_GetCurrentThread() == mThread);
}
--- a/dom/media/ipc/VideoDecoderManagerChild.cpp
+++ b/dom/media/ipc/VideoDecoderManagerChild.cpp
@@ -8,109 +8,98 @@
#include "mozilla/dom/ContentChild.h"
#include "MediaPrefs.h"
#include "nsThreadUtils.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/layers/SynchronousTask.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/layers/ISurfaceAllocator.h"
+#include "base/task.h"
namespace mozilla {
namespace dom {
using namespace ipc;
using namespace layers;
using namespace gfx;
// Only modified on the main-thread
StaticRefPtr<nsIThread> sVideoDecoderChildThread;
StaticRefPtr<AbstractThread> sVideoDecoderChildAbstractThread;
// Only accessed from sVideoDecoderChildThread
static StaticRefPtr<VideoDecoderManagerChild> sDecoderManager;
+static UniquePtr<nsTArray<RefPtr<Runnable>>> sRecreateTasks;
/* static */ void
-VideoDecoderManagerChild::Initialize()
+VideoDecoderManagerChild::InitializeThread()
{
MOZ_ASSERT(NS_IsMainThread());
- MediaPrefs::GetSingleton();
-
-#ifdef XP_WIN
- if (!MediaPrefs::PDMUseGPUDecoder()) {
- return;
- }
-
- // Can't run remote video decoding in the parent process.
- if (!ContentChild::GetSingleton()) {
- return;
- }
-
if (!sVideoDecoderChildThread) {
RefPtr<nsIThread> childThread;
nsresult rv = NS_NewNamedThread("VideoChild", getter_AddRefs(childThread));
NS_ENSURE_SUCCESS_VOID(rv);
sVideoDecoderChildThread = childThread;
sVideoDecoderChildAbstractThread =
AbstractThread::CreateXPCOMThreadWrapper(childThread, false);
+
+ sRecreateTasks = MakeUnique<nsTArray<RefPtr<Runnable>>>();
}
-#else
- return;
-#endif
+}
+/* static */ void
+VideoDecoderManagerChild::InitForContent(Endpoint<PVideoDecoderManagerChild>&& aVideoManager)
+{
+ InitializeThread();
+ sVideoDecoderChildThread->Dispatch(NewRunnableFunction(&Open, Move(aVideoManager)), NS_DISPATCH_NORMAL);
}
/* static */ void
VideoDecoderManagerChild::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
if (sVideoDecoderChildThread) {
sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([]() {
- if (sDecoderManager) {
+ if (sDecoderManager && sDecoderManager->CanSend()) {
sDecoderManager->Close();
sDecoderManager = nullptr;
}
}), NS_DISPATCH_NORMAL);
sVideoDecoderChildAbstractThread = nullptr;
sVideoDecoderChildThread->Shutdown();
sVideoDecoderChildThread = nullptr;
+
+ sRecreateTasks = nullptr;
}
}
+void
+VideoDecoderManagerChild::RunWhenRecreated(already_AddRefed<Runnable> aTask)
+{
+ MOZ_ASSERT(NS_GetCurrentThread() == GetManagerThread());
+
+ // If we've already been recreated, then run the task immediately.
+ if (sDecoderManager && sDecoderManager != this && sDecoderManager->CanSend()) {
+ RefPtr<Runnable> task = aTask;
+ task->Run();
+ } else {
+ sRecreateTasks->AppendElement(aTask);
+ }
+}
+
+
/* static */ VideoDecoderManagerChild*
VideoDecoderManagerChild::GetSingleton()
{
MOZ_ASSERT(NS_GetCurrentThread() == GetManagerThread());
-
- if (!sDecoderManager || !sDecoderManager->mCanSend) {
- RefPtr<VideoDecoderManagerChild> manager;
-
- NS_DispatchToMainThread(NS_NewRunnableFunction([&]() {
- Endpoint<PVideoDecoderManagerChild> endpoint;
- if (!ContentChild::GetSingleton()->SendInitVideoDecoderManager(&endpoint)) {
- return;
- }
-
- if (!endpoint.IsValid()) {
- return;
- }
-
- manager = new VideoDecoderManagerChild();
-
- RefPtr<Runnable> task = NewRunnableMethod<Endpoint<PVideoDecoderManagerChild>&&>(
- manager, &VideoDecoderManagerChild::Open, Move(endpoint));
- sVideoDecoderChildThread->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
- }), NS_DISPATCH_SYNC);
-
- sDecoderManager = manager;
- }
return sDecoderManager;
}
/* static */ nsIThread*
VideoDecoderManagerChild::GetManagerThread()
{
return sVideoDecoderChildThread;
}
@@ -133,43 +122,66 @@ VideoDecoderManagerChild::DeallocPVideoD
VideoDecoderChild* child = static_cast<VideoDecoderChild*>(actor);
child->IPDLActorDestroyed();
return true;
}
void
VideoDecoderManagerChild::Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint)
{
- if (!aEndpoint.Bind(this)) {
- return;
+ // Make sure we always dispatch everything in sRecreateTasks, even if we
+ // fail since this is as close to being recreated as we will ever be.
+ sDecoderManager = nullptr;
+ if (aEndpoint.IsValid()) {
+ RefPtr<VideoDecoderManagerChild> manager = new VideoDecoderManagerChild();
+ if (aEndpoint.Bind(manager)) {
+ sDecoderManager = manager;
+ manager->InitIPDL();
+ }
}
- AddRef();
+ for (Runnable* task : *sRecreateTasks) {
+ task->Run();
+ }
+ sRecreateTasks->Clear();
+}
+
+void
+VideoDecoderManagerChild::InitIPDL()
+{
mCanSend = true;
+ mIPDLSelfRef = this;
}
void
VideoDecoderManagerChild::ActorDestroy(ActorDestroyReason aWhy)
{
mCanSend = false;
}
void
VideoDecoderManagerChild::DeallocPVideoDecoderManagerChild()
{
- Release();
+ mIPDLSelfRef = nullptr;
+}
+
+bool
+VideoDecoderManagerChild::CanSend()
+{
+ MOZ_ASSERT(NS_GetCurrentThread() == GetManagerThread());
+ return mCanSend;
}
bool
VideoDecoderManagerChild::DeallocShmem(mozilla::ipc::Shmem& aShmem)
{
if (NS_GetCurrentThread() != sVideoDecoderChildThread) {
RefPtr<VideoDecoderManagerChild> self = this;
mozilla::ipc::Shmem shmem = aShmem;
sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([self, shmem]() {
- if (self->mCanSend) {
+ if (self->CanSend()) {
mozilla::ipc::Shmem shmemCopy = shmem;
self->DeallocShmem(shmemCopy);
}
}), NS_DISPATCH_NORMAL);
return true;
}
return PVideoDecoderManagerChild::DeallocShmem(aShmem);
}
@@ -202,17 +214,17 @@ VideoDecoderManagerChild::Readback(const
// loop while it waits. This function can be called from JS and we
// don't want that to happen.
SynchronousTask task("Readback sync");
RefPtr<VideoDecoderManagerChild> ref = this;
SurfaceDescriptor sd;
sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([&]() {
AutoCompleteTask complete(&task);
- if (ref->mCanSend) {
+ if (ref->CanSend()) {
ref->SendReadback(aSD, &sd);
}
}), NS_DISPATCH_NORMAL);
task.Wait();
if (!IsSurfaceDescriptorValid(sd)) {
return nullptr;
@@ -234,22 +246,22 @@ VideoDecoderManagerChild::Readback(const
}
void
VideoDecoderManagerChild::DeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD)
{
RefPtr<VideoDecoderManagerChild> ref = this;
SurfaceDescriptorGPUVideo sd = Move(aSD);
sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([ref, sd]() {
- if (ref->mCanSend) {
+ if (ref->CanSend()) {
ref->SendDeallocateSurfaceDescriptorGPUVideo(sd);
}
}), NS_DISPATCH_NORMAL);
}
void
-VideoDecoderManagerChild::FatalError(const char* const aName, const char* const aMsg) const
+VideoDecoderManagerChild::HandleFatalError(const char* aName, const char* aMsg) const
{
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
}
} // namespace dom
} // namespace mozilla
--- a/dom/media/ipc/VideoDecoderManagerChild.h
+++ b/dom/media/ipc/VideoDecoderManagerChild.h
@@ -46,35 +46,50 @@ public:
return PVideoDecoderManagerChild::AllocUnsafeShmem(aSize, aShmType, aShmem);
}
// Can be called from any thread, dispatches the request to the IPDL thread internally
// and will be ignored if the IPDL actor has been destroyed.
bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
// Main thread only
- static void Initialize();
+ static void InitForContent(Endpoint<PVideoDecoderManagerChild>&& aVideoManager);
static void Shutdown();
+ // Run aTask (on the manager thread) when we next attempt to create a new manager
+ // (even if creation fails). Intended to be called from ActorDestroy when we get
+ // notified that the old manager is being destroyed.
+ // Can only be called from the manager thread.
+ void RunWhenRecreated(already_AddRefed<Runnable> aTask);
+
+ bool CanSend();
+
protected:
+ void InitIPDL();
+
void ActorDestroy(ActorDestroyReason aWhy) override;
void DeallocPVideoDecoderManagerChild() override;
- void FatalError(const char* const aName, const char* const aMsg) const override;
+ void HandleFatalError(const char* aName, const char* aMsg) const override;
PVideoDecoderChild* AllocPVideoDecoderChild() override;
bool DeallocPVideoDecoderChild(PVideoDecoderChild* actor) override;
private:
+ // Main thread only
+ static void InitializeThread();
+
VideoDecoderManagerChild()
: mCanSend(false)
{}
~VideoDecoderManagerChild() {}
- void Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint);
+ static void Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint);
+
+ RefPtr<VideoDecoderManagerChild> mIPDLSelfRef;
// Should only ever be accessed on the manager thread.
bool mCanSend;
};
} // namespace dom
} // namespace mozilla
--- a/dom/media/ipc/VideoDecoderManagerParent.h
+++ b/dom/media/ipc/VideoDecoderManagerParent.h
@@ -28,17 +28,17 @@ public:
protected:
PVideoDecoderParent* AllocPVideoDecoderParent() override;
bool DeallocPVideoDecoderParent(PVideoDecoderParent* actor) override;
bool RecvReadback(const SurfaceDescriptorGPUVideo& aSD, SurfaceDescriptor* aResult) override;
bool RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) override;
- void ActorDestroy(mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason) override {}
+ void ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override {}
void DeallocPVideoDecoderManagerParent() override;
private:
VideoDecoderManagerParent();
~VideoDecoderManagerParent();
void Open(Endpoint<PVideoDecoderManagerParent>&& aEndpoint);
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -50,17 +50,16 @@ if CONFIG['MOZ_ANDROID_OMX']:
if CONFIG['MOZ_FMP4']:
DIRS += ['fmp4']
if CONFIG['MOZ_WEBRTC']:
DIRS += ['bridge']
TEST_DIRS += [
- 'compiledtest',
'gtest',
]
MOCHITEST_MANIFESTS += [
'test/mochitest.ini',
'tests/mochitest/identity/mochitest.ini',
]
--- a/dom/media/systemservices/MediaParent.h
+++ b/dom/media/systemservices/MediaParent.h
@@ -17,17 +17,17 @@ namespace media {
// media::Parent implements the chrome-process side of ipc for media::Child APIs
// A same-process version may also be created to service non-e10s calls.
class OriginKeyStore;
class NonE10s
{
- typedef mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason
+ typedef mozilla::ipc::IProtocol::ActorDestroyReason
ActorDestroyReason;
public:
virtual ~NonE10s() {}
protected:
virtual bool RecvGetOriginKey(const uint32_t& aRequestId,
const nsCString& aOrigin,
const bool& aPrivateBrowsing,
const bool& aPersist) = 0;
@@ -40,17 +40,17 @@ protected:
nsCString aKey);
};
// Super = PMediaParent or NonE10s
template<class Super>
class Parent : public Super
{
- typedef mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason
+ typedef mozilla::ipc::IProtocol::ActorDestroyReason
ActorDestroyReason;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Parent<Super>)
virtual bool RecvGetOriginKey(const uint32_t& aRequestId,
const nsCString& aOrigin,
const bool& aPrivateBrowsing,
const bool& aPersist) override;
--- a/dom/permission/PermissionObserver.cpp
+++ b/dom/permission/PermissionObserver.cpp
@@ -81,17 +81,17 @@ PermissionObserver::RemoveSink(Permissio
void
PermissionObserver::Notify(PermissionName aName, nsIPrincipal& aPrincipal)
{
for (auto* sink : mSinks) {
if (sink->mName != aName) {
continue;
}
- nsIPrincipal* sinkPrincipal = sink->GetPrincipal();
+ nsCOMPtr<nsIPrincipal> sinkPrincipal = sink->GetPrincipal();
if (NS_WARN_IF(!sinkPrincipal) || !aPrincipal.Equals(sinkPrincipal)) {
continue;
}
sink->PermissionChanged();
}
}
--- a/dom/permission/PermissionStatus.cpp
+++ b/dom/permission/PermissionStatus.cpp
@@ -88,30 +88,34 @@ PermissionStatus::UpdateState()
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mState = ActionToPermissionState(action);
return NS_OK;
}
-nsIPrincipal*
+already_AddRefed<nsIPrincipal>
PermissionStatus::GetPrincipal() const
{
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
if (NS_WARN_IF(!window)) {
return nullptr;
}
nsIDocument* doc = window->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return nullptr;
}
- return doc->NodePrincipal();
+ nsCOMPtr<nsIPrincipal> principal =
+ mozilla::BasePrincipal::Cast(doc->NodePrincipal())->CloneStrippingUserContextIdAndFirstPartyDomain();
+ NS_ENSURE_TRUE(principal, nullptr);
+
+ return principal.forget();
}
void
PermissionStatus::PermissionChanged()
{
auto oldState = mState;
UpdateState();
if (mState != oldState) {
--- a/dom/permission/PermissionStatus.h
+++ b/dom/permission/PermissionStatus.h
@@ -37,17 +37,17 @@ private:
~PermissionStatus();
PermissionStatus(nsPIDOMWindowInner* aWindow, PermissionName aName);
nsresult Init();
nsresult UpdateState();
- nsIPrincipal* GetPrincipal() const;
+ already_AddRefed<nsIPrincipal> GetPrincipal() const;
void PermissionChanged();
PermissionName mName;
PermissionState mState;
RefPtr<PermissionObserver> mObserver;
};
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -5,18 +5,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_PLUGINS_PLUGINMESSAGEUTILS_H
#define DOM_PLUGINS_PLUGINMESSAGEUTILS_H
#include "ipc/IPCMessageUtils.h"
#include "base/message_loop.h"
+#include "mozilla/ipc/CrossProcessMutex.h"
#include "mozilla/ipc/MessageChannel.h"
-#include "mozilla/ipc/CrossProcessMutex.h"
+#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/UniquePtr.h"
#include "gfxipc/ShadowLayerUtils.h"
#include "npapi.h"
#include "npruntime.h"
#include "npfunctions.h"
#include "nsString.h"
#include "nsTArray.h"
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -1031,18 +1031,17 @@ PluginModuleChromeParent::GetInvokingPro
*
* This function needs to be updated if the subprotocols are modified in
* PPluginInstance.ipdl.
*/
PluginInstanceParent*
PluginModuleChromeParent::GetManagingInstance(mozilla::ipc::IProtocol* aProtocol)
{
MOZ_ASSERT(aProtocol);
- mozilla::ipc::MessageListener* listener =
- static_cast<mozilla::ipc::MessageListener*>(aProtocol);
+ mozilla::ipc::IProtocol* listener = aProtocol;
switch (listener->GetProtocolTypeId()) {
case PPluginInstanceMsgStart:
// In this case, aProtocol is the instance itself. Just cast it.
return static_cast<PluginInstanceParent*>(aProtocol);
case PPluginBackgroundDestroyerMsgStart: {
PPluginBackgroundDestroyerParent* actor =
static_cast<PPluginBackgroundDestroyerParent*>(aProtocol);
return static_cast<PluginInstanceParent*>(actor->Manager());
--- a/dom/presentation/PresentationAvailability.cpp
+++ b/dom/presentation/PresentationAvailability.cpp
@@ -48,33 +48,36 @@ PresentationAvailability::Create(nsPIDOM
}
PresentationAvailability::PresentationAvailability(nsPIDOMWindowInner* aWindow,
const nsTArray<nsString>& aUrls)
: DOMEventTargetHelper(aWindow)
, mIsAvailable(false)
, mUrls(aUrls)
{
+ for (uint32_t i = 0; i < mUrls.Length(); ++i) {
+ mAvailabilityOfUrl.AppendElement(false);
+ }
}
PresentationAvailability::~PresentationAvailability()
{
Shutdown();
}
bool
PresentationAvailability::Init(RefPtr<Promise>& aPromise)
{
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if (NS_WARN_IF(!service)) {
return false;
}
- nsresult rv = service->RegisterAvailabilityListener(this);
+ nsresult rv = service->RegisterAvailabilityListener(mUrls, this);
if (NS_WARN_IF(NS_FAILED(rv))) {
// If the user agent is unable to monitor available device,
// Resolve promise with |value| set to false.
mIsAvailable = false;
aPromise->MaybeResolve(this);
return true;
}
@@ -97,17 +100,18 @@ void PresentationAvailability::Shutdown(
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if (NS_WARN_IF(!service)) {
return;
}
Unused <<
- NS_WARN_IF(NS_FAILED(service->UnregisterAvailabilityListener(this)));
+ NS_WARN_IF(NS_FAILED(service->UnregisterAvailabilityListener(mUrls,
+ this)));
}
/* virtual */ void
PresentationAvailability::DisconnectFromOwner()
{
Shutdown();
DOMEventTargetHelper::DisconnectFromOwner();
}
@@ -152,22 +156,31 @@ PresentationAvailability::EnqueuePromise
bool
PresentationAvailability::Value() const
{
return mIsAvailable;
}
NS_IMETHODIMP
-PresentationAvailability::NotifyAvailableChange(bool aIsAvailable)
+PresentationAvailability::NotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls,
+ bool aIsAvailable)
{
+ bool available = false;
+ for (uint32_t i = 0; i < mUrls.Length(); ++i) {
+ if (aAvailabilityUrls.Contains(mUrls[i])) {
+ mAvailabilityOfUrl[i] = aIsAvailable;
+ }
+ available |= mAvailabilityOfUrl[i];
+ }
+
return NS_DispatchToCurrentThread(NewRunnableMethod
<bool>(this,
&PresentationAvailability::UpdateAvailabilityAndDispatchEvent,
- aIsAvailable));
+ available));
}
void
PresentationAvailability::UpdateAvailabilityAndDispatchEvent(bool aIsAvailable)
{
PRES_DEBUG("%s\n", __func__);
bool isChanged = (aIsAvailable != mIsAvailable);
--- a/dom/presentation/PresentationAvailability.h
+++ b/dom/presentation/PresentationAvailability.h
@@ -60,14 +60,15 @@ private:
void UpdateAvailabilityAndDispatchEvent(bool aIsAvailable);
bool mIsAvailable;
nsTArray<RefPtr<Promise>> mPromises;
nsTArray<nsString> mUrls;
+ nsTArray<bool> mAvailabilityOfUrl;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PresentationAvailability_h
--- a/dom/presentation/PresentationService.cpp
+++ b/dom/presentation/PresentationService.cpp
@@ -21,19 +21,16 @@
#include "nsISupportsPrimitives.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCID.h"
#include "nsXULAppAPI.h"
#include "PresentationLog.h"
-using namespace mozilla;
-using namespace mozilla::dom;
-
namespace mozilla {
namespace dom {
static bool
IsSameDevice(nsIPresentationDevice* aDevice, nsIPresentationDevice* aDeviceAnother) {
if (!aDevice || !aDeviceAnother) {
return false;
}
@@ -127,19 +124,16 @@ private:
nsWeakPtr mChromeEventHandler;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIPresentationServiceCallback> mCallback;
nsCOMPtr<nsIPresentationTransportBuilderConstructor> mBuilderConstructor;
};
LazyLogModule gPresentationLog("Presentation");
-} // namespace dom
-} // namespace mozilla
-
NS_IMPL_ISUPPORTS(PresentationDeviceRequest, nsIPresentationDeviceRequest)
PresentationDeviceRequest::PresentationDeviceRequest(
const nsTArray<nsString>& aUrls,
const nsAString& aId,
const nsAString& aOrigin,
uint64_t aWindowId,
nsIDOMEventTarget* aEventTarget,
@@ -271,17 +265,16 @@ PresentationDeviceRequest::Cancel(nsresu
* Implementation of PresentationService
*/
NS_IMPL_ISUPPORTS(PresentationService,
nsIPresentationService,
nsIObserver)
PresentationService::PresentationService()
- : mIsAvailable(false)
{
}
PresentationService::~PresentationService()
{
HandleShutdown();
}
@@ -311,36 +304,42 @@ PresentationService::Init()
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
rv = obs->AddObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
- nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
- do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
- if (NS_WARN_IF(!deviceManager)) {
- return false;
- }
-
- rv = deviceManager->GetDeviceAvailable(&mIsAvailable);
return !NS_WARN_IF(NS_FAILED(rv));
}
NS_IMETHODIMP
PresentationService::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
HandleShutdown();
return NS_OK;
} else if (!strcmp(aTopic, PRESENTATION_DEVICE_CHANGE_TOPIC)) {
- return HandleDeviceChange();
+ // Ignore the "update" case here, since we only care about the arrival and
+ // removal of the device.
+ if (!NS_strcmp(aData, u"add")) {
+ nsCOMPtr<nsIPresentationDevice> device = do_QueryInterface(aSubject);
+ if (NS_WARN_IF(!device)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return HandleDeviceAdded(device);
+ } else if(!NS_strcmp(aData, u"remove")) {
+ return HandleDeviceRemoved();
+ }
+
+ return NS_OK;
} else if (!strcmp(aTopic, PRESENTATION_SESSION_REQUEST_TOPIC)) {
nsCOMPtr<nsIPresentationSessionRequest> request(do_QueryInterface(aSubject));
if (NS_WARN_IF(!request)) {
return NS_ERROR_FAILURE;
}
return HandleSessionRequest(request);
} else if (!strcmp(aTopic, PRESENTATION_TERMINATE_REQUEST_TOPIC)) {
@@ -369,53 +368,114 @@ PresentationService::Observe(nsISupports
void
PresentationService::HandleShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
Shutdown();
- mAvailabilityListeners.Clear();
+ mAvailabilityManager.Clear();
mSessionInfoAtController.Clear();
mSessionInfoAtReceiver.Clear();
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
obs->RemoveObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC);
obs->RemoveObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC);
obs->RemoveObserver(this, PRESENTATION_TERMINATE_REQUEST_TOPIC);
obs->RemoveObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC);
}
}
nsresult
-PresentationService::HandleDeviceChange()
+PresentationService::HandleDeviceAdded(nsIPresentationDevice* aDevice)
+{
+ PRES_DEBUG("%s\n", __func__);
+ if (!aDevice) {
+ MOZ_ASSERT(false, "aDevice shoud no be null.");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // Query for only unavailable URLs while device added.
+ nsTArray<nsString> unavailableUrls;
+ mAvailabilityManager.GetAvailbilityUrlByAvailability(unavailableUrls, false);
+
+ nsTArray<nsString> supportedAvailabilityUrl;
+ for (const auto& url : unavailableUrls) {
+ bool isSupported;
+ if (NS_SUCCEEDED(aDevice->IsRequestedUrlSupported(url, &isSupported)) &&
+ isSupported) {
+ supportedAvailabilityUrl.AppendElement(url);
+ }
+ }
+
+ if (!supportedAvailabilityUrl.IsEmpty()) {
+ return mAvailabilityManager.DoNotifyAvailableChange(supportedAvailabilityUrl,
+ true);
+ }
+
+ return NS_OK;
+}
+
+nsresult
+PresentationService::HandleDeviceRemoved()
{
PRES_DEBUG("%s\n", __func__);
+ // Query for only available URLs while device removed.
+ nsTArray<nsString> availabilityUrls;
+ mAvailabilityManager.GetAvailbilityUrlByAvailability(availabilityUrls, true);
+
+ return UpdateAvailabilityUrlChange(availabilityUrls);
+}
+
+nsresult
+PresentationService::UpdateAvailabilityUrlChange(
+ const nsTArray<nsString>& aAvailabilityUrls)
+{
nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
if (NS_WARN_IF(!deviceManager)) {
return NS_ERROR_NOT_AVAILABLE;
}
- bool isAvailable;
- nsresult rv = deviceManager->GetDeviceAvailable(&isAvailable);
+ nsCOMPtr<nsIArray> devices;
+ nsresult rv = deviceManager->GetAvailableDevices(nullptr,
+ getter_AddRefs(devices));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- if (isAvailable != mIsAvailable) {
- mIsAvailable = isAvailable;
- NotifyAvailableChange(mIsAvailable);
+ uint32_t numOfDevices;
+ devices->GetLength(&numOfDevices);
+
+ nsTArray<nsString> supportedAvailabilityUrl;
+ for (const auto& url : aAvailabilityUrls) {
+ for (uint32_t i = 0; i < numOfDevices; ++i) {
+ nsCOMPtr<nsIPresentationDevice> device = do_QueryElementAt(devices, i);
+ if (device) {
+ bool isSupported;
+ if (NS_SUCCEEDED(device->IsRequestedUrlSupported(url, &isSupported)) &&
+ isSupported) {
+ supportedAvailabilityUrl.AppendElement(url);
+ break;
+ }
+ }
+ }
}
- return NS_OK;
+ if (supportedAvailabilityUrl.IsEmpty()) {
+ return mAvailabilityManager.DoNotifyAvailableChange(aAvailabilityUrls,
+ false);
+ }
+
+ return mAvailabilityManager.DoNotifyAvailableChange(supportedAvailabilityUrl,
+ true);
}
nsresult
PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aRequest)
{
nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
@@ -592,27 +652,16 @@ PresentationService::HandleReconnectRequ
if (NS_WARN_IF(!info->GetUrl().Equals(url))) {
ctrlChannel->Disconnect(rv);
return rv;
}
return HandleSessionRequest(aRequest);
}
-void
-PresentationService::NotifyAvailableChange(bool aIsAvailable)
-{
- nsTObserverArray<nsCOMPtr<nsIPresentationAvailabilityListener>>::ForwardIterator iter(mAvailabilityListeners);
- while (iter.HasMore()) {
- nsCOMPtr<nsIPresentationAvailabilityListener> listener = iter.GetNext();
- Unused <<
- NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aIsAvailable)));
- }
-}
-
NS_IMETHODIMP
PresentationService::StartSession(
const nsTArray<nsString>& aUrls,
const nsAString& aSessionId,
const nsAString& aOrigin,
const nsAString& aDeviceId,
uint64_t aWindowId,
nsIDOMEventTarget* aEventTarget,
@@ -873,38 +922,36 @@ PresentationService::BuildTransport(cons
if (NS_WARN_IF(!info)) {
return NS_ERROR_NOT_AVAILABLE;
}
return static_cast<PresentationControllingInfo*>(info.get())->BuildTransport();
}
NS_IMETHODIMP
-PresentationService::RegisterAvailabilityListener(nsIPresentationAvailabilityListener* aListener)
+PresentationService::RegisterAvailabilityListener(
+ const nsTArray<nsString>& aAvailabilityUrls,
+ nsIPresentationAvailabilityListener* aListener)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!aAvailabilityUrls.IsEmpty());
+ MOZ_ASSERT(aListener);
+
+ mAvailabilityManager.AddAvailabilityListener(aAvailabilityUrls, aListener);
+ return UpdateAvailabilityUrlChange(aAvailabilityUrls);
+}
+
+NS_IMETHODIMP
+PresentationService::UnregisterAvailabilityListener(
+ const nsTArray<nsString>& aAvailabilityUrls,
+ nsIPresentationAvailabilityListener* aListener)
{
MOZ_ASSERT(NS_IsMainThread());
- if (!mAvailabilityListeners.Contains(aListener)) {
- mAvailabilityListeners.AppendElement(aListener);
- }
-
- // Leverage availablility change notification to assign
- // the initial value of availability object.
- Unused <<
- NS_WARN_IF(NS_FAILED(aListener->NotifyAvailableChange(mIsAvailable)));
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationService::UnregisterAvailabilityListener(nsIPresentationAvailabilityListener* aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- mAvailabilityListeners.RemoveElement(aListener);
+ mAvailabilityManager.RemoveAvailabilityListener(aAvailabilityUrls, aListener);
return NS_OK;
}
NS_IMETHODIMP
PresentationService::RegisterSessionListener(const nsAString& aSessionId,
uint8_t aRole,
nsIPresentationSessionListener* aListener)
{
@@ -1114,16 +1161,19 @@ PresentationService::IsSessionAccessible
aRole == nsIPresentationService::ROLE_RECEIVER);
RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
if (NS_WARN_IF(!info)) {
return false;
}
return info->IsAccessible(aProcessId);
}
+} // namespace dom
+} // namespace mozilla
+
already_AddRefed<nsIPresentationService>
NS_CreatePresentationService()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIPresentationService> service;
if (XRE_GetProcessType() == GeckoProcessType_Content) {
service = new mozilla::dom::PresentationIPCService();
--- a/dom/presentation/PresentationService.h
+++ b/dom/presentation/PresentationService.h
@@ -4,17 +4,16 @@
* 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/. */
#ifndef mozilla_dom_PresentationService_h
#define mozilla_dom_PresentationService_h
#include "nsCOMPtr.h"
#include "nsIObserver.h"
-#include "nsTObserverArray.h"
#include "PresentationServiceBase.h"
#include "PresentationSessionInfo.h"
class nsIPresentationSessionRequest;
class nsIPresentationTerminateRequest;
class nsIURI;
class nsIPresentationSessionTransportBuilder;
@@ -41,28 +40,29 @@ public:
const uint8_t aRole,
base::ProcessId aProcessId);
private:
friend class PresentationDeviceRequest;
virtual ~PresentationService();
void HandleShutdown();
- nsresult HandleDeviceChange();
+ nsresult HandleDeviceAdded(nsIPresentationDevice* aDevice);
+ nsresult HandleDeviceRemoved();
nsresult HandleSessionRequest(nsIPresentationSessionRequest* aRequest);
nsresult HandleTerminateRequest(nsIPresentationTerminateRequest* aRequest);
nsresult HandleReconnectRequest(nsIPresentationSessionRequest* aRequest);
- void NotifyAvailableChange(bool aIsAvailable);
// This is meant to be called by PresentationDeviceRequest.
already_AddRefed<PresentationSessionInfo>
CreateControllingSessionInfo(const nsAString& aUrl,
const nsAString& aSessionId,
uint64_t aWindowId);
- bool mIsAvailable;
- nsTObserverArray<nsCOMPtr<nsIPresentationAvailabilityListener>> mAvailabilityListeners;
+ // Emumerate all devices to get the availability of each input Urls.
+ nsresult UpdateAvailabilityUrlChange(
+ const nsTArray<nsString>& aAvailabilityUrls);
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PresentationService_h
--- a/dom/presentation/PresentationServiceBase.h
+++ b/dom/presentation/PresentationServiceBase.h
@@ -2,24 +2,25 @@
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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/. */
#ifndef mozilla_dom_PresentationServiceBase_h
#define mozilla_dom_PresentationServiceBase_h
+#include "mozilla/Unused.h"
#include "nsClassHashtable.h"
+#include "nsCOMArray.h"
+#include "nsIPresentationListener.h"
#include "nsIPresentationService.h"
#include "nsRefPtrHashtable.h"
#include "nsString.h"
#include "nsTArray.h"
-class nsIPresentationRespondingListener;
-
namespace mozilla {
namespace dom {
template<class T>
class PresentationServiceBase
{
public:
PresentationServiceBase() = default;
@@ -127,16 +128,191 @@ protected:
mRespondingWindowIds.Clear();
}
private:
nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mRespondingSessionIds;
nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
};
+ class AvailabilityManager final
+ {
+ public:
+ explicit AvailabilityManager()
+ {
+ MOZ_COUNT_CTOR(AvailabilityManager);
+ }
+
+ ~AvailabilityManager()
+ {
+ MOZ_COUNT_DTOR(AvailabilityManager);
+ }
+
+ void AddAvailabilityListener(
+ const nsTArray<nsString>& aAvailabilityUrls,
+ nsIPresentationAvailabilityListener* aListener)
+ {
+ nsTArray<nsString> dummy;
+ AddAvailabilityListener(aAvailabilityUrls, aListener, dummy);
+ }
+
+ void AddAvailabilityListener(
+ const nsTArray<nsString>& aAvailabilityUrls,
+ nsIPresentationAvailabilityListener* aListener,
+ nsTArray<nsString>& aAddedUrls)
+ {
+ if (!aListener) {
+ MOZ_ASSERT(false, "aListener should not be null.");
+ return;
+ }
+
+ if (aAvailabilityUrls.IsEmpty()) {
+ MOZ_ASSERT(false, "aAvailabilityUrls should not be empty.");
+ return;
+ }
+
+ aAddedUrls.Clear();
+ nsTArray<nsString> knownAvailableUrls;
+ for (const auto& url : aAvailabilityUrls) {
+ AvailabilityEntry* entry;
+ if (!mAvailabilityUrlTable.Get(url, &entry)) {
+ entry = new AvailabilityEntry();
+ mAvailabilityUrlTable.Put(url, entry);
+ aAddedUrls.AppendElement(url);
+ }
+ if (!entry->mListeners.Contains(aListener)) {
+ entry->mListeners.AppendElement(aListener);
+ }
+ if (entry->mAvailable) {
+ knownAvailableUrls.AppendElement(url);
+ }
+ }
+
+ if (!knownAvailableUrls.IsEmpty()) {
+ Unused <<
+ NS_WARN_IF(
+ NS_FAILED(aListener->NotifyAvailableChange(knownAvailableUrls,
+ true)));
+ } else {
+ // If we can't find any known available url and there is no newly
+ // added url, we still need to notify the listener of the result.
+ // So, the promise returned by |getAvailability| can be resolved.
+ if (aAddedUrls.IsEmpty()) {
+ Unused <<
+ NS_WARN_IF(
+ NS_FAILED(aListener->NotifyAvailableChange(aAvailabilityUrls,
+ false)));
+ }
+ }
+ }
+
+ void RemoveAvailabilityListener(
+ const nsTArray<nsString>& aAvailabilityUrls,
+ nsIPresentationAvailabilityListener* aListener)
+ {
+ nsTArray<nsString> dummy;
+ RemoveAvailabilityListener(aAvailabilityUrls, aListener, dummy);
+ }
+
+ void RemoveAvailabilityListener(
+ const nsTArray<nsString>& aAvailabilityUrls,
+ nsIPresentationAvailabilityListener* aListener,
+ nsTArray<nsString>& aRemovedUrls)
+ {
+ if (!aListener) {
+ MOZ_ASSERT(false, "aListener should not be null.");
+ return;
+ }
+
+ if (aAvailabilityUrls.IsEmpty()) {
+ MOZ_ASSERT(false, "aAvailabilityUrls should not be empty.");
+ return;
+ }
+
+ aRemovedUrls.Clear();
+ for (const auto& url : aAvailabilityUrls) {
+ AvailabilityEntry* entry;
+ if (mAvailabilityUrlTable.Get(url, &entry)) {
+ entry->mListeners.RemoveElement(aListener);
+ if (entry->mListeners.IsEmpty()) {
+ mAvailabilityUrlTable.Remove(url);
+ aRemovedUrls.AppendElement(url);
+ }
+ }
+ }
+ }
+
+ nsresult DoNotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls,
+ bool aAvailable)
+ {
+ typedef nsClassHashtable<nsISupportsHashKey,
+ nsTArray<nsString>> ListenerToUrlsMap;
+ ListenerToUrlsMap availabilityListenerTable;
+ // Create a mapping from nsIPresentationAvailabilityListener to
+ // availabilityUrls.
+ for (auto it = mAvailabilityUrlTable.ConstIter(); !it.Done(); it.Next()) {
+ if (aAvailabilityUrls.Contains(it.Key())) {
+ AvailabilityEntry* entry = it.UserData();
+ entry->mAvailable = aAvailable;
+
+ for (uint32_t i = 0; i < entry->mListeners.Length(); ++i) {
+ nsIPresentationAvailabilityListener* listener =
+ entry->mListeners.ObjectAt(i);
+ nsTArray<nsString>* urlArray;
+ if (!availabilityListenerTable.Get(listener, &urlArray)) {
+ urlArray = new nsTArray<nsString>();
+ availabilityListenerTable.Put(listener, urlArray);
+ }
+ urlArray->AppendElement(it.Key());
+ }
+ }
+ }
+
+ for (auto it = availabilityListenerTable.Iter(); !it.Done(); it.Next()) {
+ auto listener =
+ static_cast<nsIPresentationAvailabilityListener*>(it.Key());
+
+ Unused <<
+ NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(*it.UserData(),
+ aAvailable)));
+ }
+ return NS_OK;
+ }
+
+ void GetAvailbilityUrlByAvailability(nsTArray<nsString>& aOutArray,
+ bool aAvailable)
+ {
+ aOutArray.Clear();
+
+ for (auto it = mAvailabilityUrlTable.ConstIter(); !it.Done(); it.Next()) {
+ if (it.UserData()->mAvailable == aAvailable) {
+ aOutArray.AppendElement(it.Key());
+ }
+ }
+ }
+
+ void Clear()
+ {
+ mAvailabilityUrlTable.Clear();
+ }
+
+ private:
+ struct AvailabilityEntry
+ {
+ explicit AvailabilityEntry()
+ : mAvailable(false)
+ {}
+
+ bool mAvailable;
+ nsCOMArray<nsIPresentationAvailabilityListener> mListeners;
+ };
+
+ nsClassHashtable<nsStringHashKey, AvailabilityEntry> mAvailabilityUrlTable;
+ };
+
virtual ~PresentationServiceBase() = default;
void Shutdown()
{
mRespondingListeners.Clear();
mControllerSessionIdManager.Clear();
mReceiverSessionIdManager.Clear();
}
@@ -210,14 +386,16 @@ protected:
// to retrieve the correspondent session ID. Besides, also keep the mapping
// between the responding session ID and the window ID to help look up the
// window ID.
SessionIdManager mControllerSessionIdManager;
SessionIdManager mReceiverSessionIdManager;
nsRefPtrHashtable<nsStringHashKey, T> mSessionInfoAtController;
nsRefPtrHashtable<nsStringHashKey, T> mSessionInfoAtReceiver;
+
+ AvailabilityManager mAvailabilityManager;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PresentationServiceBase_h
--- a/dom/presentation/interfaces/nsIPresentationListener.idl
+++ b/dom/presentation/interfaces/nsIPresentationListener.idl
@@ -1,21 +1,24 @@
/* 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/. */
#include "nsISupports.idl"
-[scriptable, uuid(0105f837-4279-4715-9d5b-2dc3f8b65353)]
+[ref] native URLArrayRef(const nsTArray<nsString>);
+
+[uuid(0105f837-4279-4715-9d5b-2dc3f8b65353)]
interface nsIPresentationAvailabilityListener : nsISupports
{
/*
* Called when device availability changes.
*/
- void notifyAvailableChange(in bool available);
+ [noscript] void notifyAvailableChange(in URLArrayRef urls,
+ in bool available);
};
[scriptable, uuid(7dd48df8-8f8c-48c7-ac37-7b9fd1acf2f8)]
interface nsIPresentationSessionListener : nsISupports
{
const unsigned short STATE_CONNECTING = 0;
const unsigned short STATE_CONNECTED = 1;
const unsigned short STATE_CLOSED = 2;
--- a/dom/presentation/interfaces/nsIPresentationService.idl
+++ b/dom/presentation/interfaces/nsIPresentationService.idl
@@ -153,25 +153,32 @@ interface nsIPresentationService : nsISu
[noscript] void reconnectSession(in URLArrayRef urls,
in DOMString sessionId,
in uint8_t role,
in nsIPresentationServiceCallback callback);
/*
* Register an availability listener. Must be called from the main thread.
*
+ * @param availabilityUrls: The Urls that this listener is interested in.
* @param listener: The listener to register.
*/
- void registerAvailabilityListener(in nsIPresentationAvailabilityListener listener);
+ [noscript] void registerAvailabilityListener(
+ in URLArrayRef availabilityUrls,
+ in nsIPresentationAvailabilityListener listener);
/*
* Unregister an availability listener. Must be called from the main thread.
+ *
+ * @param availabilityUrls: The Urls that are registered before.
* @param listener: The listener to unregister.
*/
- void unregisterAvailabilityListener(in nsIPresentationAvailabilityListener listener);
+ [noscript] void unregisterAvailabilityListener(
+ in URLArrayRef availabilityUrls,
+ in nsIPresentationAvailabilityListener listener);
/*
* Register a session listener. Must be called from the main thread.
*
* @param sessionId: An ID to identify presentation session.
* @param role: Identify the function called by controller or receiver.
* @param listener: The listener to register.
*/
--- a/dom/presentation/ipc/PPresentation.ipdl
+++ b/dom/presentation/ipc/PPresentation.ipdl
@@ -72,33 +72,34 @@ union PresentationIPCRequest
sync protocol PPresentation
{
manager PContent;
manages PPresentationBuilder;
manages PPresentationRequest;
child:
- async NotifyAvailableChange(bool aAvailable);
+ async NotifyAvailableChange(nsString[] aAvailabilityUrls,
+ bool aAvailable);
async NotifySessionStateChange(nsString aSessionId,
uint16_t aState,
nsresult aReason);
async NotifyMessage(nsString aSessionId, nsCString aData, bool aIsBinary);
async NotifySessionConnect(uint64_t aWindowId, nsString aSessionId);
async NotifyCloseSessionTransport(nsString aSessionId,
uint8_t aRole,
nsresult aReason);
async PPresentationBuilder(nsString aSessionId, uint8_t aRole);
parent:
async __delete__();
- async RegisterAvailabilityHandler();
- async UnregisterAvailabilityHandler();
+ async RegisterAvailabilityHandler(nsString[] aAvailabilityUrls);
+ async UnregisterAvailabilityHandler(nsString[] aAvailabilityUrls);
async RegisterSessionHandler(nsString aSessionId, uint8_t aRole);
async UnregisterSessionHandler(nsString aSessionId, uint8_t aRole);
async RegisterRespondingHandler(uint64_t aWindowId);
async UnregisterRespondingHandler(uint64_t aWindowId);
async PPresentationRequest(PresentationIPCRequest aRequest);
--- a/dom/presentation/ipc/PresentationChild.cpp
+++ b/dom/presentation/ipc/PresentationChild.cpp
@@ -84,20 +84,24 @@ PresentationChild::DeallocPPresentationB
{
RefPtr<PresentationBuilderChild> actor =
dont_AddRef(static_cast<PresentationBuilderChild*>(aActor));
return true;
}
bool
-PresentationChild::RecvNotifyAvailableChange(const bool& aAvailable)
+PresentationChild::RecvNotifyAvailableChange(
+ nsTArray<nsString>&& aAvailabilityUrls,
+ const bool& aAvailable)
{
if (mService) {
- Unused << NS_WARN_IF(NS_FAILED(mService->NotifyAvailableChange(aAvailable)));
+ Unused <<
+ NS_WARN_IF(NS_FAILED(mService->NotifyAvailableChange(aAvailabilityUrls,
+ aAvailable)));
}
return true;
}
bool
PresentationChild::RecvNotifySessionStateChange(const nsString& aSessionId,
const uint16_t& aState,
const nsresult& aReason)
--- a/dom/presentation/ipc/PresentationChild.h
+++ b/dom/presentation/ipc/PresentationChild.h
@@ -38,17 +38,18 @@ public:
virtual PPresentationBuilderChild*
AllocPPresentationBuilderChild(const nsString& aSessionId, const uint8_t& aRole) override;
virtual bool
DeallocPPresentationBuilderChild(PPresentationBuilderChild* aActor) override;
virtual bool
- RecvNotifyAvailableChange(const bool& aAvailable) override;
+ RecvNotifyAvailableChange(nsTArray<nsString>&& aAvailabilityUrls,
+ const bool& aAvailable) override;
virtual bool
RecvNotifySessionStateChange(const nsString& aSessionId,
const uint16_t& aState,
const nsresult& aReason) override;
virtual bool
RecvNotifyMessage(const nsString& aSessionId,
--- a/dom/presentation/ipc/PresentationIPCService.cpp
+++ b/dom/presentation/ipc/PresentationIPCService.cpp
@@ -23,17 +23,19 @@ using namespace mozilla::dom;
using namespace mozilla::ipc;
namespace {
PresentationChild* sPresentationChild;
} // anonymous
-NS_IMPL_ISUPPORTS(PresentationIPCService, nsIPresentationService)
+NS_IMPL_ISUPPORTS(PresentationIPCService,
+ nsIPresentationService,
+ nsIPresentationAvailabilityListener)
PresentationIPCService::PresentationIPCService()
{
ContentChild* contentChild = ContentChild::GetSingleton();
if (NS_WARN_IF(!contentChild)) {
return;
}
sPresentationChild = new PresentationChild(this);
@@ -41,17 +43,16 @@ PresentationIPCService::PresentationIPCS
NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild));
}
/* virtual */
PresentationIPCService::~PresentationIPCService()
{
Shutdown();
- mAvailabilityListeners.Clear();
mSessionListeners.Clear();
mSessionInfoAtController.Clear();
mSessionInfoAtReceiver.Clear();
sPresentationChild = nullptr;
}
NS_IMETHODIMP
PresentationIPCService::StartSession(
@@ -229,39 +230,53 @@ PresentationIPCService::SendRequest(nsIP
if (sPresentationChild) {
PresentationRequestChild* actor = new PresentationRequestChild(aCallback);
Unused << NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest));
}
return NS_OK;
}
NS_IMETHODIMP
-PresentationIPCService::RegisterAvailabilityListener(nsIPresentationAvailabilityListener* aListener)
+PresentationIPCService::RegisterAvailabilityListener(
+ const nsTArray<nsString>& aAvailabilityUrls,
+ nsIPresentationAvailabilityListener* aListener)
{
MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!aAvailabilityUrls.IsEmpty());
MOZ_ASSERT(aListener);
- mAvailabilityListeners.AppendElement(aListener);
- if (sPresentationChild) {
+ nsTArray<nsString> addedUrls;
+ mAvailabilityManager.AddAvailabilityListener(aAvailabilityUrls,
+ aListener,
+ addedUrls);
+
+ if (sPresentationChild && !addedUrls.IsEmpty()) {
Unused <<
- NS_WARN_IF(!sPresentationChild->SendRegisterAvailabilityHandler());
+ NS_WARN_IF(
+ !sPresentationChild->SendRegisterAvailabilityHandler(addedUrls));
}
return NS_OK;
}
NS_IMETHODIMP
-PresentationIPCService::UnregisterAvailabilityListener(nsIPresentationAvailabilityListener* aListener)
+PresentationIPCService::UnregisterAvailabilityListener(
+ const nsTArray<nsString>& aAvailabilityUrls,
+ nsIPresentationAvailabilityListener* aListener)
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aListener);
- mAvailabilityListeners.RemoveElement(aListener);
- if (mAvailabilityListeners.IsEmpty() && sPresentationChild) {
+ nsTArray<nsString> removedUrls;
+ mAvailabilityManager.RemoveAvailabilityListener(aAvailabilityUrls,
+ aListener,
+ removedUrls);
+
+ if (sPresentationChild && !removedUrls.IsEmpty()) {
Unused <<
- NS_WARN_IF(!sPresentationChild->SendUnregisterAvailabilityHandler());
+ NS_WARN_IF(
+ !sPresentationChild->SendUnregisterAvailabilityHandler(removedUrls));
}
return NS_OK;
}
NS_IMETHODIMP
PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
uint8_t aRole,
nsIPresentationSessionListener* aListener)
@@ -414,26 +429,23 @@ PresentationIPCService::NotifySessionCon
nsCOMPtr<nsIPresentationRespondingListener> listener;
if (NS_WARN_IF(!mRespondingListeners.Get(aWindowId, getter_AddRefs(listener)))) {
return NS_OK;
}
return listener->NotifySessionConnect(aWindowId, aSessionId);