Bug 1923899 - [bidi] Wait for currentWindowGlobal when sending commands to window global message handlers r=webdriver-reviewers,Sasha

When attempting to send commands on a very early browsing context, the command might fail
due to a missing currentWindowGlobal.
This patch adds a helper to wait for the currentWindowGlobal property to be set and uses it from
RootTransport in order to avoid this issue.
A browser mochitest is added to cover this scenario.

Differential Revision: https://phabricator.services.mozilla.com/D225281
This commit is contained in:
Julian Descottes 2024-10-15 14:33:29 +00:00
parent 8e48f8f2fd
commit 8f75db2421
3 changed files with 86 additions and 0 deletions

View File

@ -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.

View File

@ -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,
}
);
}

View File

@ -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);