296 lines
9.4 KiB
JavaScript
296 lines
9.4 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"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,
|
|
"https://example.com/document-builder.sjs?html=tab"
|
|
);
|
|
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,
|
|
"https://example.com/document-builder.sjs?html=tab"
|
|
);
|
|
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,
|
|
"https://example.com/document-builder.sjs?html=tab"
|
|
);
|
|
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,
|
|
},
|
|
});
|
|
}
|