diff --git a/toolkit/components/extensions/ExtensionCommon.jsm b/toolkit/components/extensions/ExtensionCommon.jsm index 76a1457f50c4..1dffb69c1b6c 100644 --- a/toolkit/components/extensions/ExtensionCommon.jsm +++ b/toolkit/components/extensions/ExtensionCommon.jsm @@ -1804,10 +1804,11 @@ class EventManager { let primed = {pendingEvents: []}; listener.primed = primed; - let wakeup = () => new Promise(resolve => { - extension.once("startup", resolve); + let bgStartupPromise = new Promise(r => extension.once("startup", r)); + let wakeup = () => { extension.emit("background-page-event"); - }); + return bgStartupPromise; + }; let fireEvent = (...args) => new Promise((resolve, reject) => { primed.pendingEvents.push({args, resolve, reject}); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_messaging_startup.js b/toolkit/components/extensions/test/xpcshell/test_ext_messaging_startup.js index 2b9e9742a460..19fcd9d7617a 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_messaging_startup.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_messaging_startup.js @@ -17,6 +17,8 @@ let { Services.prefs.setBoolPref("extensions.webextensions.background-delayed-startup", true); +const PAGE_HTML = ``; + function trackEvents(wrapper) { let events = new Map(); for (let event of ["background-page-event", "start-background-page"]) { @@ -42,7 +44,7 @@ async function test(what, background, script) { }, files: { - "page.html": ``, + "page.html": PAGE_HTML, "script.js": script, }, @@ -121,8 +123,8 @@ async function test(what, background, script) { await page.close(); await extension.unload(); - ExtensionParent._resetStartupPromises(); await promiseShutdownManager(); + ExtensionParent._resetStartupPromises(); } add_task(function test_onMessage() { @@ -174,3 +176,55 @@ add_task(function test_onConnect() { return test("onConnect", background, script); }); + +// Test that messaging works if the background page is started before +// any messages are exchanged. (See bug 1467136 for an example of how +// this broke at one point). +add_task(async function test_other_startup() { + await promiseStartupManager(); + + let extension = ExtensionTestUtils.loadExtension({ + useAddonManager: "permanent", + + async background() { + browser.runtime.onMessage.addListener(msg => { + browser.test.notifyPass("startup"); + }); + + // addListener() returns right away but make a round trip to the + // main process to ensure the persistent onMessage listener is recorded. + await browser.runtime.getBrowserInfo(); + browser.test.sendMessage("bg-ran"); + }, + + files: { + "page.html": PAGE_HTML, + "script.js"() { + browser.runtime.sendMessage("ping"); + }, + }, + }); + + await extension.startup(); + await extension.awaitMessage("bg-ran"); + + await promiseRestartManager(); + await extension.awaitStartup(); + + // Start the background page. No message have been sent at this point. + Services.obs.notifyObservers(null, "sessionstore-windows-restored"); + await extension.awaitMessage("bg-ran"); + + // Now that the background page is fully started, load a new page that + // sends a message to the background page. + let url = extension.extension.baseURI.resolve("page.html"); + let page = await ExtensionTestUtils.loadContentPage(url, {extension}); + + await extension.awaitFinish("startup"); + + await page.close(); + await extension.unload(); + + await promiseShutdownManager(); + ExtensionParent._resetStartupPromises(); +});