diff --git a/remote/shared/messagehandler/test/browser/browser_handle_simple_command.js b/remote/shared/messagehandler/test/browser/browser_handle_simple_command.js index 0a086d6f09c6..be8ef76b87a5 100644 --- a/remote/shared/messagehandler/test/browser/browser_handle_simple_command.js +++ b/remote/shared/messagehandler/test/browser/browser_handle_simple_command.js @@ -79,6 +79,53 @@ add_task(async function test_windowglobalModule_command() { rootMessageHandler.destroy(); }); +// Test calling a windowglobal module as soon as possible. +add_task(async function test_windowglobalModule_early_command() { + const rootMessageHandler = createRootMessageHandler( + "session-id-windowglobalModule-early" + ); + + info("Setup an observer to send a command as soon as the context is created"); + const onContext = new Promise((resolve, reject) => { + const onContextAttached = async browsingContext => { + try { + const result = await rootMessageHandler.handleCommand({ + moduleName: "command", + commandName: "testWindowGlobalModule", + destination: { + type: WindowGlobalMessageHandler.type, + id: browsingContext.id, + }, + }); + info("Early command succeeded, resolve the retrieved value"); + resolve(result); + } catch (e) { + info("Early command failed, reject"); + reject(e); + } finally { + Services.obs.removeObserver( + onContextAttached, + "browsing-context-attached" + ); + } + }; + Services.obs.addObserver(onContextAttached, "browsing-context-attached"); + }); + + const tab = await addTab("https://example.com/document-builder.sjs?html=tab"); + + const windowGlobalValue = await onContext; + is( + windowGlobalValue, + "windowglobal-value", + "Retrieved the expected value from testWindowGlobalModule" + ); + + rootMessageHandler.destroy(); + + gBrowser.removeTab(tab); +}); + // Test calling a method on a module which is only available in the "windowglobal" // folder. This will check that the MessageHandler/ModuleCache correctly moves // on to the next layer when no implementation can be found in the root layer. diff --git a/remote/shared/messagehandler/transports/BrowsingContextUtils.sys.mjs b/remote/shared/messagehandler/transports/BrowsingContextUtils.sys.mjs index e3ccf3bc8dfd..38e8359e151b 100644 --- a/remote/shared/messagehandler/transports/BrowsingContextUtils.sys.mjs +++ b/remote/shared/messagehandler/transports/BrowsingContextUtils.sys.mjs @@ -2,6 +2,12 @@ * 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/. */ +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + PollPromise: "chrome://remote/content/shared/Sync.sys.mjs", +}); + function isExtensionContext(browsingContext) { let principal; try { @@ -93,3 +99,31 @@ export function isBrowsingContextCompatible(browsingContext, options = {}) { !isExtensionContext(browsingContext) && !isParentProcess(browsingContext) ); } + +/** + * Wait until `currentWindowGlobal` is available on a browsing context. When a + * browsing context has just been created, the `currentWindowGlobal` might not + * be attached yet. + * + * @param {CanonicalBrowsingContext} browsingContext + * The browsing context to wait for. + * + * @returns {Promise} + * Promise which resolves when `currentWindowGlobal` is set on the browsing + * context or throws after 100ms. + */ +export async function waitForCurrentWindowGlobal(browsingContext) { + await lazy.PollPromise( + (resolve, reject) => { + if (browsingContext.currentWindowGlobal) { + resolve(); + } else { + reject(); + } + }, + { + errorMessage: `currentWindowGlobal was not available for Browsing Context with id: ${browsingContext.id}`, + timeout: 100, + } + ); +} diff --git a/remote/shared/messagehandler/transports/RootTransport.sys.mjs b/remote/shared/messagehandler/transports/RootTransport.sys.mjs index 516ba186daf2..14e7b8c9bf89 100644 --- a/remote/shared/messagehandler/transports/RootTransport.sys.mjs +++ b/remote/shared/messagehandler/transports/RootTransport.sys.mjs @@ -15,6 +15,8 @@ ChromeUtils.defineESModuleGetters(lazy, { MessageHandlerFrameActor: "chrome://remote/content/shared/messagehandler/transports/js-window-actors/MessageHandlerFrameActor.sys.mjs", TabManager: "chrome://remote/content/shared/TabManager.sys.mjs", + waitForCurrentWindowGlobal: + "chrome://remote/content/shared/messagehandler/transports/BrowsingContextUtils.sys.mjs", }); ChromeUtils.defineLazyGetter(lazy, "logger", () => lazy.Log.get()); @@ -124,6 +126,9 @@ export class RootTransport { let attempts = 0; while (true) { try { + if (!webProgress.browsingContext.currentWindowGlobal) { + await lazy.waitForCurrentWindowGlobal(webProgress.browsingContext); + } return await webProgress.browsingContext.currentWindowGlobal .getActor("MessageHandlerFrame") .sendCommand(command, this._messageHandler.sessionId);