fune/remote/shared/messagehandler/test/browser/browser_events_dispatcher.js
Julian Descottes 987247c956 Bug 1806820 - [remote] Refactor session data broadcast test r=webdriver-reviewers,Sasha,whimboo
The current test had complicated logic in the test module "command.sys.mjs" which means we were asserting the test module more than the actual behavior of MessageHandler/SessionData.

Instead, we use a simpler test module, and precisely assert all the updates we receive for session data updates. Also taking the opportunity to add some tests when updating session data items from several categories.

Differential Revision: https://phabricator.services.mozilla.com/D166969
2023-01-20 11:09:08 +00:00

449 lines
13 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Check the basic behavior of on/off.
*/
add_task(async function test_add_remove_event_listener() {
const tab = await addTab("https://example.com/document-builder.sjs?html=tab");
const browsingContext = tab.linkedBrowser.browsingContext;
const contextDescriptor = {
type: ContextDescriptorType.TopBrowsingContext,
id: browsingContext.browserId,
};
const root = createRootMessageHandler("session-id-event");
const monitoringEvents = await setupEventMonitoring(root);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(await isSubscribed(root, browsingContext), false);
info("Add an listener for eventemitter.testEvent");
const events = [];
const onEvent = (event, data) => events.push(data.text);
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
is(await isSubscribed(root, browsingContext), true);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 1);
info(
"Remove a listener for a callback not added before and check that the first one is still registered"
);
const anotherCallback = () => {};
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor,
anotherCallback
);
is(await isSubscribed(root, browsingContext), true);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 2);
info("Remove the listener for eventemitter.testEvent");
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
is(await isSubscribed(root, browsingContext), false);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 2);
info("Add the listener for eventemitter.testEvent again");
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
is(await isSubscribed(root, browsingContext), true);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 3);
info("Remove the listener for eventemitter.testEvent");
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
is(await isSubscribed(root, browsingContext), false);
info("Remove the listener again to check the API will not throw");
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
root.destroy();
gBrowser.removeTab(tab);
});
/**
* Check that two callbacks can subscribe to the same event in the same context
* in parallel.
*/
add_task(async function test_two_callbacks() {
const tab = await addTab("https://example.com/document-builder.sjs?html=tab");
const browsingContext = tab.linkedBrowser.browsingContext;
const contextDescriptor = {
type: ContextDescriptorType.TopBrowsingContext,
id: browsingContext.browserId,
};
const root = createRootMessageHandler("session-id-event");
const monitoringEvents = await setupEventMonitoring(root);
info("Add an listener for eventemitter.testEvent");
const events = [];
const onEvent = (event, data) => events.push(data.text);
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 1);
info("Add another listener for eventemitter.testEvent");
const otherevents = [];
const otherCallback = (event, data) => otherevents.push(data.text);
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptor,
otherCallback
);
is(await isSubscribed(root, browsingContext), true);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 2);
is(otherevents.length, 1);
info("Remove the other listener for eventemitter.testEvent");
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor,
otherCallback
);
is(await isSubscribed(root, browsingContext), true);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 3);
is(otherevents.length, 1);
info("Remove the first listener for eventemitter.testEvent");
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
is(await isSubscribed(root, browsingContext), false);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 3);
is(otherevents.length, 1);
root.destroy();
gBrowser.removeTab(tab);
});
/**
* Check that two callbacks can subscribe to the same event in the two contexts.
*/
add_task(async function test_two_contexts() {
const tab1 = await addTab("https://example.com/document-builder.sjs?html=1");
const browsingContext1 = tab1.linkedBrowser.browsingContext;
const tab2 = await addTab("https://example.com/document-builder.sjs?html=2");
const browsingContext2 = tab2.linkedBrowser.browsingContext;
const contextDescriptor1 = {
type: ContextDescriptorType.TopBrowsingContext,
id: browsingContext1.browserId,
};
const contextDescriptor2 = {
type: ContextDescriptorType.TopBrowsingContext,
id: browsingContext2.browserId,
};
const root = createRootMessageHandler("session-id-event");
const monitoringEvents = await setupEventMonitoring(root);
const events1 = [];
const onEvent1 = (event, data) => events1.push(data.text);
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptor1,
onEvent1
);
is(await isSubscribed(root, browsingContext1), true);
is(await isSubscribed(root, browsingContext2), false);
const events2 = [];
const onEvent2 = (event, data) => events2.push(data.text);
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptor2,
onEvent2
);
is(await isSubscribed(root, browsingContext1), true);
is(await isSubscribed(root, browsingContext2), true);
await emitTestEvent(root, browsingContext1, monitoringEvents);
is(events1.length, 1);
is(events2.length, 0);
await emitTestEvent(root, browsingContext2, monitoringEvents);
is(events1.length, 1);
is(events2.length, 1);
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor1,
onEvent1
);
is(await isSubscribed(root, browsingContext1), false);
is(await isSubscribed(root, browsingContext2), true);
// No event expected here since the module for browsingContext1 is no longer
// subscribed
await emitTestEvent(root, browsingContext1, monitoringEvents);
is(events1.length, 1);
is(events2.length, 1);
// Whereas the module for browsingContext2 is still subscribed
await emitTestEvent(root, browsingContext2, monitoringEvents);
is(events1.length, 1);
is(events2.length, 2);
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor2,
onEvent2
);
is(await isSubscribed(root, browsingContext1), false);
is(await isSubscribed(root, browsingContext2), false);
await emitTestEvent(root, browsingContext1, monitoringEvents);
await emitTestEvent(root, browsingContext2, monitoringEvents);
is(events1.length, 1);
is(events2.length, 2);
root.destroy();
gBrowser.removeTab(tab2);
gBrowser.removeTab(tab1);
});
/**
* Check that adding and removing first listener for the specific context and then
* for the global context works as expected.
*/
add_task(
async function test_remove_context_event_listener_and_then_global_event_listener() {
const tab = await addTab(
"https://example.com/document-builder.sjs?html=tab"
);
const browsingContext = tab.linkedBrowser.browsingContext;
const contextDescriptor = {
type: ContextDescriptorType.TopBrowsingContext,
id: browsingContext.browserId,
};
const contextDescriptorAll = {
type: ContextDescriptorType.All,
};
const root = createRootMessageHandler("session-id-event");
const monitoringEvents = await setupEventMonitoring(root);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(await isSubscribed(root, browsingContext), false);
info("Add an listener for eventemitter.testEvent");
const events = [];
const onEvent = (event, data) => events.push(data.text);
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
is(await isSubscribed(root, browsingContext), true);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 1);
info(
"Add another listener for eventemitter.testEvent, using global context"
);
const eventsAll = [];
const onEventAll = (event, data) => eventsAll.push(data.text);
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptorAll,
onEventAll
);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(eventsAll.length, 1);
is(events.length, 2);
info("Remove the first listener for eventemitter.testEvent");
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
info("Check that we are still subscribed to eventemitter.testEvent");
is(await isSubscribed(root, browsingContext), true);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(eventsAll.length, 2);
is(events.length, 2);
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptorAll,
onEventAll
);
is(await isSubscribed(root, browsingContext), false);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(eventsAll.length, 2);
is(events.length, 2);
root.destroy();
gBrowser.removeTab(tab);
}
);
/**
* Check that adding and removing first listener for the global context and then
* for the specific context works as expected.
*/
add_task(
async function test_global_event_listener_and_then_remove_context_event_listener() {
const tab = await addTab(
"https://example.com/document-builder.sjs?html=tab"
);
const browsingContext = tab.linkedBrowser.browsingContext;
const contextDescriptor = {
type: ContextDescriptorType.TopBrowsingContext,
id: browsingContext.browserId,
};
const contextDescriptorAll = {
type: ContextDescriptorType.All,
};
const root = createRootMessageHandler("session-id-event");
const monitoringEvents = await setupEventMonitoring(root);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(await isSubscribed(root, browsingContext), false);
info("Add an listener for eventemitter.testEvent");
const events = [];
const onEvent = (event, data) => events.push(data.text);
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
is(await isSubscribed(root, browsingContext), true);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(events.length, 1);
info(
"Add another listener for eventemitter.testEvent, using global context"
);
const eventsAll = [];
const onEventAll = (event, data) => eventsAll.push(data.text);
await root.eventsDispatcher.on(
"eventemitter.testEvent",
contextDescriptorAll,
onEventAll
);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(eventsAll.length, 1);
is(events.length, 2);
info("Remove the global listener for eventemitter.testEvent");
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptorAll,
onEventAll
);
info(
"Check that we are still subscribed to eventemitter.testEvent for the specific context"
);
is(await isSubscribed(root, browsingContext), true);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(eventsAll.length, 1);
is(events.length, 3);
await root.eventsDispatcher.off(
"eventemitter.testEvent",
contextDescriptor,
onEvent
);
is(await isSubscribed(root, browsingContext), false);
await emitTestEvent(root, browsingContext, monitoringEvents);
is(eventsAll.length, 1);
is(events.length, 3);
root.destroy();
gBrowser.removeTab(tab);
}
);
async function setupEventMonitoring(root) {
const monitoringEvents = [];
const onMonitoringEvent = (event, data) => monitoringEvents.push(data.text);
root.on("eventemitter.monitoringEvent", onMonitoringEvent);
registerCleanupFunction(() =>
root.off("eventemitter.monitoringEvent", onMonitoringEvent)
);
return monitoringEvents;
}
async function emitTestEvent(root, browsingContext, monitoringEvents) {
const count = monitoringEvents.length;
info("Call eventemitter.emitTestEvent");
await root.handleCommand({
moduleName: "eventemitter",
commandName: "emitTestEvent",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContext.id,
},
});
// The monitoring event is always emitted, regardless of the status of the
// module. Wait for catching this event before resuming the assertions.
info("Wait for the monitoring event");
await BrowserTestUtils.waitForCondition(
() => monitoringEvents.length >= count + 1
);
is(monitoringEvents.length, count + 1);
}
function isSubscribed(root, browsingContext) {
info("Call eventemitter.isSubscribed");
return root.handleCommand({
moduleName: "eventemitter",
commandName: "isSubscribed",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContext.id,
},
});
}