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
251 lines
7.2 KiB
JavaScript
251 lines
7.2 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const { RootMessageHandler } = ChromeUtils.importESModule(
|
|
"chrome://remote/content/shared/messagehandler/RootMessageHandler.sys.mjs"
|
|
);
|
|
|
|
// Test calling methods only implemented in the root version of a module.
|
|
add_task(async function test_rootModule_command() {
|
|
const rootMessageHandler = createRootMessageHandler("session-id-rootModule");
|
|
const rootValue = await rootMessageHandler.handleCommand({
|
|
moduleName: "command",
|
|
commandName: "testRootModule",
|
|
destination: {
|
|
type: RootMessageHandler.type,
|
|
},
|
|
});
|
|
|
|
is(
|
|
rootValue,
|
|
"root-value",
|
|
"Retrieved the expected value from testRootModule"
|
|
);
|
|
|
|
rootMessageHandler.destroy();
|
|
});
|
|
|
|
// Test calling methods only implemented in the windowglobal-in-root version of
|
|
// a module.
|
|
add_task(async function test_windowglobalInRootModule_command() {
|
|
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
|
|
|
|
const rootMessageHandler = createRootMessageHandler(
|
|
"session-id-windowglobalInRootModule"
|
|
);
|
|
const interceptedValue = await rootMessageHandler.handleCommand({
|
|
moduleName: "command",
|
|
commandName: "testInterceptModule",
|
|
destination: {
|
|
type: WindowGlobalMessageHandler.type,
|
|
id: browsingContextId,
|
|
},
|
|
});
|
|
|
|
is(
|
|
interceptedValue,
|
|
"intercepted-value",
|
|
"Retrieved the expected value from testInterceptModule"
|
|
);
|
|
|
|
rootMessageHandler.destroy();
|
|
});
|
|
|
|
// Test calling methods only implemented in the windowglobal version of a
|
|
// module.
|
|
add_task(async function test_windowglobalModule_command() {
|
|
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
|
|
|
|
const rootMessageHandler = createRootMessageHandler(
|
|
"session-id-windowglobalModule"
|
|
);
|
|
const windowGlobalValue = await rootMessageHandler.handleCommand({
|
|
moduleName: "command",
|
|
commandName: "testWindowGlobalModule",
|
|
destination: {
|
|
type: WindowGlobalMessageHandler.type,
|
|
id: browsingContextId,
|
|
},
|
|
});
|
|
|
|
is(
|
|
windowGlobalValue,
|
|
"windowglobal-value",
|
|
"Retrieved the expected value from testWindowGlobalModule"
|
|
);
|
|
|
|
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.
|
|
add_task(async function test_windowglobalOnlyModule_command() {
|
|
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
|
|
|
|
const rootMessageHandler = createRootMessageHandler(
|
|
"session-id-windowglobalOnlyModule"
|
|
);
|
|
const windowGlobalOnlyValue = await rootMessageHandler.handleCommand({
|
|
moduleName: "commandwindowglobalonly",
|
|
commandName: "testOnlyInWindowGlobal",
|
|
destination: {
|
|
type: WindowGlobalMessageHandler.type,
|
|
id: browsingContextId,
|
|
},
|
|
});
|
|
|
|
is(
|
|
windowGlobalOnlyValue,
|
|
"only-in-windowglobal",
|
|
"Retrieved the expected value from testOnlyInWindowGlobal"
|
|
);
|
|
|
|
rootMessageHandler.destroy();
|
|
});
|
|
|
|
// Try to create 2 sessions which will both set values in individual modules
|
|
// via a command `testSetValue`, and then retrieve the values via another
|
|
// command `testGetValue`.
|
|
// This will ensure that different sessions use different module instances.
|
|
add_task(async function test_multisession() {
|
|
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
|
|
|
|
const rootMessageHandler1 = createRootMessageHandler(
|
|
"session-id-multisession-1"
|
|
);
|
|
const rootMessageHandler2 = createRootMessageHandler(
|
|
"session-id-multisession-2"
|
|
);
|
|
|
|
info("Set value for session 1");
|
|
await rootMessageHandler1.handleCommand({
|
|
moduleName: "command",
|
|
commandName: "testSetValue",
|
|
params: { value: "session1-value" },
|
|
destination: {
|
|
type: WindowGlobalMessageHandler.type,
|
|
id: browsingContextId,
|
|
},
|
|
});
|
|
|
|
info("Set value for session 2");
|
|
await rootMessageHandler2.handleCommand({
|
|
moduleName: "command",
|
|
commandName: "testSetValue",
|
|
params: { value: "session2-value" },
|
|
destination: {
|
|
type: WindowGlobalMessageHandler.type,
|
|
id: browsingContextId,
|
|
},
|
|
});
|
|
|
|
const session1Value = await rootMessageHandler1.handleCommand({
|
|
moduleName: "command",
|
|
commandName: "testGetValue",
|
|
destination: {
|
|
type: WindowGlobalMessageHandler.type,
|
|
id: browsingContextId,
|
|
},
|
|
});
|
|
|
|
is(
|
|
session1Value,
|
|
"session1-value",
|
|
"Retrieved the expected value for session 1"
|
|
);
|
|
|
|
const session2Value = await rootMessageHandler2.handleCommand({
|
|
moduleName: "command",
|
|
commandName: "testGetValue",
|
|
destination: {
|
|
type: WindowGlobalMessageHandler.type,
|
|
id: browsingContextId,
|
|
},
|
|
});
|
|
|
|
is(
|
|
session2Value,
|
|
"session2-value",
|
|
"Retrieved the expected value for session 2"
|
|
);
|
|
|
|
rootMessageHandler1.destroy();
|
|
rootMessageHandler2.destroy();
|
|
});
|
|
|
|
// Test calling a method from the windowglobal-in-root module which will
|
|
// internally forward to the windowglobal module and will return a composite
|
|
// result built both in parent and content process.
|
|
add_task(async function test_forwarding_command() {
|
|
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
|
|
|
|
const rootMessageHandler = createRootMessageHandler("session-id-forwarding");
|
|
const interceptAndForwardValue = await rootMessageHandler.handleCommand({
|
|
moduleName: "command",
|
|
commandName: "testInterceptAndForwardModule",
|
|
params: { id: "value" },
|
|
destination: {
|
|
type: WindowGlobalMessageHandler.type,
|
|
id: browsingContextId,
|
|
},
|
|
});
|
|
|
|
is(
|
|
interceptAndForwardValue,
|
|
"intercepted-and-forward+forward-to-windowglobal-value",
|
|
"Retrieved the expected value from testInterceptAndForwardModule"
|
|
);
|
|
|
|
rootMessageHandler.destroy();
|
|
});
|