Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
/* Any copyright is dedicated to the Public Domain.
"use strict";
const { RootMessageHandlerRegistry } = ChromeUtils.importESModule(
"chrome://remote/content/shared/messagehandler/RootMessageHandlerRegistry.sys.mjs"
);
const { RootMessageHandler } = ChromeUtils.importESModule(
"chrome://remote/content/shared/messagehandler/RootMessageHandler.sys.mjs"
);
/**
* Emit an event from a WindowGlobal module triggered by a specific command.
* Check that the event is emitted on the RootMessageHandler as well as on
* the parent process MessageHandlerRegistry.
*/
add_task(async function test_event() {
const tab = BrowserTestUtils.addTab(
gBrowser,
);
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
const browsingContext = tab.linkedBrowser.browsingContext;
const rootMessageHandler = createRootMessageHandler("session-id-event");
let messageHandlerEvent;
let registryEvent;
// Events are emitted both as generic message-handler-event events as well
// as under their own name. We expect to receive the event for both.
const _onMessageHandlerEvent = (eventName, eventData) => {
if (eventData.name === "event-from-window-global") {
messageHandlerEvent = eventData;
}
};
rootMessageHandler.on("message-handler-event", _onMessageHandlerEvent);
const onNamedEvent = rootMessageHandler.once("event-from-window-global");
// MessageHandlerRegistry should forward all the message-handler-events.
const _onMessageHandlerRegistryEvent = (eventName, eventData) => {
if (eventData.name === "event-from-window-global") {
registryEvent = eventData;
}
};
RootMessageHandlerRegistry.on(
"message-handler-registry-event",
_onMessageHandlerRegistryEvent
);
callTestEmitEvent(rootMessageHandler, browsingContext.id);
const namedEvent = await onNamedEvent;
is(
namedEvent.text,
`event from ${browsingContext.id}`,
"Received the expected payload"
);
is(
messageHandlerEvent.name,
"event-from-window-global",
"Received event on the ROOT MessageHandler"
);
is(
messageHandlerEvent.data.text,
`event from ${browsingContext.id}`,
"Received the expected payload"
);
is(
registryEvent,
messageHandlerEvent,
"The event forwarded by the MessageHandlerRegistry is identical to the MessageHandler event"
);
rootMessageHandler.off("message-handler-event", _onMessageHandlerEvent);
RootMessageHandlerRegistry.off(
"message-handler-registry-event",
_onMessageHandlerRegistryEvent
);
rootMessageHandler.destroy();
gBrowser.removeTab(tab);
});
/**
* Emit an event from a Root module triggered by a specific command.
* Check that the event is emitted on the RootMessageHandler.
*/
add_task(async function test_root_event() {
const rootMessageHandler = createRootMessageHandler("session-id-root_event");
// events are emitted both as generic message-handler-event events as
// well as under their own name. We expect to receive the event for both.
const onHandlerEvent = rootMessageHandler.once("message-handler-event");
const onNamedEvent = rootMessageHandler.once("event-from-root");
rootMessageHandler.handleCommand({
moduleName: "event",
commandName: "testEmitRootEvent",
destination: {
type: RootMessageHandler.type,
},
});
const { name, data } = await onHandlerEvent;
is(name, "event-from-root", "Received event on the ROOT MessageHandler");
is(data.text, "event from root", "Received the expected payload");
const namedEvent = await onNamedEvent;
is(namedEvent.text, "event from root", "Received the expected payload");
rootMessageHandler.destroy();
});
/**
* Emit an event from a windowglobal-in-root module triggered by a specific command.
* Check that the event is emitted on the RootMessageHandler.
*/
add_task(async function test_windowglobal_in_root_event() {
const tab = BrowserTestUtils.addTab(
gBrowser,
);
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
const browsingContext = tab.linkedBrowser.browsingContext;
const rootMessageHandler = createRootMessageHandler(
"session-id-windowglobal_in_root_event"
);
// events are emitted both as generic message-handler-event events as
// well as under their own name. We expect to receive the event for both.
const onHandlerEvent = rootMessageHandler.once("message-handler-event");
const onNamedEvent = rootMessageHandler.once(
"event-from-window-global-in-root"
);
rootMessageHandler.handleCommand({
moduleName: "event",
commandName: "testEmitWindowGlobalInRootEvent",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContext.id,
},
});
const { name, data } = await onHandlerEvent;
is(
name,
"event-from-window-global-in-root",
"Received event on the ROOT MessageHandler"
);
is(
data.text,
`windowglobal-in-root event for ${browsingContext.id}`,
"Received the expected payload"
);
const namedEvent = await onNamedEvent;
is(
namedEvent.text,
`windowglobal-in-root event for ${browsingContext.id}`,
"Received the expected payload"
);
rootMessageHandler.destroy();
gBrowser.removeTab(tab);
});
/**
* Emit an event from a windowglobal module, but from 2 different sessions.
* Check that the event is emitted by the corresponding RootMessageHandler as
* well as by the parent process MessageHandlerRegistry.
*/
add_task(async function test_event_multisession() {
const tab = BrowserTestUtils.addTab(
gBrowser,
);
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
const browsingContextId = tab.linkedBrowser.browsingContext.id;
const root1 = createRootMessageHandler("session-id-event_multisession-1");
let root1Events = 0;
const onRoot1Event = function (evtName, wrappedEvt) {
if (wrappedEvt.name === "event-from-window-global") {
root1Events++;
}
};
root1.on("message-handler-event", onRoot1Event);
const root2 = createRootMessageHandler("session-id-event_multisession-2");
let root2Events = 0;
const onRoot2Event = function (evtName, wrappedEvt) {
if (wrappedEvt.name === "event-from-window-global") {
root2Events++;
}
};
root2.on("message-handler-event", onRoot2Event);
let registryEvents = 0;
const onRegistryEvent = function (evtName, wrappedEvt) {
if (wrappedEvt.name === "event-from-window-global") {
registryEvents++;
}
};
RootMessageHandlerRegistry.on(
"message-handler-registry-event",
onRegistryEvent
);
callTestEmitEvent(root1, browsingContextId);
callTestEmitEvent(root2, browsingContextId);
info("Wait for root1 event to be received");
await TestUtils.waitForCondition(() => root1Events === 1);
info("Wait for root2 event to be received");
await TestUtils.waitForCondition(() => root2Events === 1);
await TestUtils.waitForTick();
is(root1Events, 1, "Session 1 only received 1 event");
is(root2Events, 1, "Session 2 only received 1 event");
is(
registryEvents,
2,
"MessageHandlerRegistry forwarded events from both sessions"
);
root1.off("message-handler-event", onRoot1Event);
root2.off("message-handler-event", onRoot2Event);
RootMessageHandlerRegistry.off(
"message-handler-registry-event",
onRegistryEvent
);
root1.destroy();
root2.destroy();
gBrowser.removeTab(tab);
});
/**
* Test that events can be emitted from individual frame contexts and that
* events going through a shared content process MessageHandlerRegistry are not
* duplicated.
*/
add_task(async function test_event_with_frames() {
info("Navigate the initial tab to the test URL");
const tab = gBrowser.selectedTab;
await loadURL(tab.linkedBrowser, createTestMarkupWithFrames());
const contexts =
tab.linkedBrowser.browsingContext.getAllBrowsingContextsInSubtree();
is(contexts.length, 4, "Test tab has 3 children contexts (4 in total)");
const rootMessageHandler = createRootMessageHandler(
"session-id-event_with_frames"
);
const rootEvents = [];
const onRootEvent = function (evtName, wrappedEvt) {
if (wrappedEvt.name === "event-from-window-global") {
rootEvents.push(wrappedEvt.data.text);
}
};
rootMessageHandler.on("message-handler-event", onRootEvent);
const namedEvents = [];
const onNamedEvent = (name, event) => namedEvents.push(event.text);
rootMessageHandler.on("event-from-window-global", onNamedEvent);
for (const context of contexts) {
callTestEmitEvent(rootMessageHandler, context.id);
info("Wait for root event to be received in both event arrays");
await TestUtils.waitForCondition(() =>
[namedEvents, rootEvents].every(events =>
events.includes(`event from ${context.id}`)
)
);
}
info("Wait for a bit and check that we did not receive duplicated events");
await TestUtils.waitForTick();
is(rootEvents.length, 4, "Only received 4 events");
rootMessageHandler.off("message-handler-event", onRootEvent);
rootMessageHandler.off("event-from-window-global", onNamedEvent);
rootMessageHandler.destroy();
});
function callTestEmitEvent(rootMessageHandler, browsingContextId) {
rootMessageHandler.handleCommand({
moduleName: "event",
commandName: "testEmitEvent",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContextId,
},
});
}