mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 04:38:02 +00:00
Bug 1691683 - [marionette] Remove unused WebElementEventTarget class. r=webdriver-reviewers,jdescottes
Differential Revision: https://phabricator.services.mozilla.com/D167688
This commit is contained in:
parent
c4409979ae
commit
f8b3f248f1
@ -11,7 +11,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
MessageManagerDestroyedPromise:
|
||||
"chrome://remote/content/marionette/sync.sys.mjs",
|
||||
TabManager: "chrome://remote/content/shared/TabManager.sys.mjs",
|
||||
WebElementEventTarget: "chrome://remote/content/marionette/dom.sys.mjs",
|
||||
windowManager: "chrome://remote/content/shared/WindowManager.sys.mjs",
|
||||
});
|
||||
|
||||
@ -312,9 +311,11 @@ browser.Context = class {
|
||||
await lazy.TabManager.selectTab(this.tab);
|
||||
}
|
||||
|
||||
// TODO(ato): Currently tied to curBrowser, but should be moved to
|
||||
// WebReference when introduced by https://bugzil.la/1400256.
|
||||
this.eventObserver = new lazy.WebElementEventTarget(this.messageManager);
|
||||
// By accessing the content browser's message manager a new browsing
|
||||
// context is created for browserless tabs, which is needed to successfully
|
||||
// run the WebDriver's is browsing context open step. This is temporary
|
||||
// until we find a better solution on bug 1812258.
|
||||
this.messageManager;
|
||||
|
||||
return this.tab;
|
||||
}
|
||||
|
@ -1,208 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||
|
||||
const lazy = {};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
Log: "chrome://remote/content/shared/Log.sys.mjs",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(lazy, "logger", () =>
|
||||
lazy.Log.get(lazy.Log.TYPES.MARIONETTE)
|
||||
);
|
||||
|
||||
/**
|
||||
* The ``EventTarget`` for web elements can be used to observe DOM
|
||||
* events in the content document.
|
||||
*
|
||||
* A caveat of the current implementation is that it is only possible
|
||||
* to listen for top-level ``window`` global events.
|
||||
*
|
||||
* It needs to be backed by a :js:class:`ContentEventObserverService`
|
||||
* in a content frame script.
|
||||
*
|
||||
* Usage::
|
||||
*
|
||||
* let observer = new WebElementEventTarget(messageManager);
|
||||
* await new Promise(resolve => {
|
||||
* observer.addEventListener("visibilitychange", resolve, {once: true});
|
||||
* chromeWindow.minimize();
|
||||
* });
|
||||
*/
|
||||
export class WebElementEventTarget {
|
||||
/**
|
||||
* @param {function(): nsIMessageListenerManager} messageManagerFn
|
||||
* Message manager to the current browser.
|
||||
*/
|
||||
constructor(messageManager) {
|
||||
this.mm = messageManager;
|
||||
this.listeners = {};
|
||||
this.mm.addMessageListener("Marionette:DOM:OnEvent", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an event handler of a specific event type from the content
|
||||
* frame.
|
||||
*
|
||||
* @param {string} type
|
||||
* Event type to listen for.
|
||||
* @param {EventListener} listener
|
||||
* Object which receives a notification (a ``BareEvent``)
|
||||
* when an event of the specified type occurs. This must be
|
||||
* an object implementing the ``EventListener`` interface,
|
||||
* or a JavaScript function.
|
||||
* @param {boolean=} once
|
||||
* Indicates that the ``listener`` should be invoked at
|
||||
* most once after being added. If true, the ``listener``
|
||||
* would automatically be removed when invoked.
|
||||
*/
|
||||
addEventListener(type, listener, { once = false } = {}) {
|
||||
if (!(type in this.listeners)) {
|
||||
this.listeners[type] = [];
|
||||
}
|
||||
|
||||
if (!this.listeners[type].includes(listener)) {
|
||||
listener.once = once;
|
||||
this.listeners[type].push(listener);
|
||||
}
|
||||
|
||||
this.mm.sendAsyncMessage("Marionette:DOM:AddEventListener", { type });
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an event listener.
|
||||
*
|
||||
* @param {string} type
|
||||
* Type of event to cease listening for.
|
||||
* @param {EventListener} listener
|
||||
* Event handler to remove from the event target.
|
||||
*/
|
||||
removeEventListener(type, listener) {
|
||||
if (!(type in this.listeners)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let stack = this.listeners[type];
|
||||
for (let i = stack.length - 1; i >= 0; --i) {
|
||||
if (stack[i] === listener) {
|
||||
stack.splice(i, 1);
|
||||
if (!stack.length) {
|
||||
this.mm.sendAsyncMessage("Marionette:DOM:RemoveEventListener", {
|
||||
type,
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatchEvent(event) {
|
||||
if (!(event.type in this.listeners)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.target = this;
|
||||
|
||||
let stack = this.listeners[event.type].slice(0);
|
||||
stack.forEach(listener => {
|
||||
if (typeof listener.handleEvent == "function") {
|
||||
listener.handleEvent(event);
|
||||
} else {
|
||||
listener(event);
|
||||
}
|
||||
|
||||
if (listener.once) {
|
||||
this.removeEventListener(event.type, listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
receiveMessage({ name, data }) {
|
||||
if (name != "Marionette:DOM:OnEvent") {
|
||||
return;
|
||||
}
|
||||
|
||||
let ev = {
|
||||
type: data.type,
|
||||
};
|
||||
this.dispatchEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the frame script backend for the
|
||||
* :js:class:`WebElementEventTarget`.
|
||||
*
|
||||
* This service receives requests for new DOM events to listen for and
|
||||
* to cease listening for, and despatches IPC messages to the browser
|
||||
* when they fire.
|
||||
*/
|
||||
export class ContentEventObserverService {
|
||||
/**
|
||||
* @param {WindowProxy} windowGlobal
|
||||
* Window.
|
||||
* @param {nsIMessageSender.sendAsyncMessage} sendAsyncMessage
|
||||
* Function for sending an async message to the parent browser.
|
||||
*/
|
||||
constructor(windowGlobal, sendAsyncMessage) {
|
||||
this.window = windowGlobal;
|
||||
this.sendAsyncMessage = sendAsyncMessage;
|
||||
this.events = new Set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Observe a new DOM event.
|
||||
*
|
||||
* When the DOM event of ``type`` fires, a message is passed to
|
||||
* the parent browser's event observer.
|
||||
*
|
||||
* If event type is already being observed, only a single message
|
||||
* is sent. E.g. multiple registration for events will only ever emit
|
||||
* a maximum of one message.
|
||||
*
|
||||
* @param {string} type
|
||||
* DOM event to listen for.
|
||||
*/
|
||||
add(type) {
|
||||
if (this.events.has(type)) {
|
||||
return;
|
||||
}
|
||||
this.window.addEventListener(type, this);
|
||||
this.events.add(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ceases observing a DOM event.
|
||||
*
|
||||
* @param {string} type
|
||||
* DOM event to stop listening for.
|
||||
*/
|
||||
remove(type) {
|
||||
if (!this.events.has(type)) {
|
||||
return;
|
||||
}
|
||||
this.window.removeEventListener(type, this);
|
||||
this.events.delete(type);
|
||||
}
|
||||
|
||||
/** Ceases observing all previously registered DOM events. */
|
||||
clear() {
|
||||
for (let ev of this) {
|
||||
this.remove(ev);
|
||||
}
|
||||
}
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
for (let ev of this.events) {
|
||||
yield ev;
|
||||
}
|
||||
}
|
||||
|
||||
handleEvent({ type, target }) {
|
||||
lazy.logger.trace(`Received DOM event ${type}`);
|
||||
this.sendAsyncMessage("Marionette:DOM:OnEvent", { type });
|
||||
}
|
||||
}
|
@ -17,7 +17,6 @@ remote.jar:
|
||||
content/marionette/browser.sys.mjs (browser.sys.mjs)
|
||||
content/marionette/cert.sys.mjs (cert.sys.mjs)
|
||||
content/marionette/cookie.sys.mjs (cookie.sys.mjs)
|
||||
content/marionette/dom.sys.mjs (dom.sys.mjs)
|
||||
content/marionette/driver.sys.mjs (driver.sys.mjs)
|
||||
content/marionette/element.sys.mjs (element.sys.mjs)
|
||||
content/marionette/evaluate.sys.mjs (evaluate.sys.mjs)
|
||||
|
@ -1,277 +0,0 @@
|
||||
const {
|
||||
ContentEventObserverService,
|
||||
WebElementEventTarget,
|
||||
} = ChromeUtils.importESModule(
|
||||
"chrome://remote/content/marionette/dom.sys.mjs"
|
||||
);
|
||||
|
||||
class MessageSender {
|
||||
constructor() {
|
||||
this.listeners = {};
|
||||
this.sent = [];
|
||||
}
|
||||
|
||||
addMessageListener(name, listener) {
|
||||
this.listeners[name] = listener;
|
||||
}
|
||||
|
||||
sendAsyncMessage(name, data) {
|
||||
this.sent.push({ name, data });
|
||||
}
|
||||
}
|
||||
|
||||
class Window {
|
||||
constructor() {
|
||||
this.events = [];
|
||||
}
|
||||
|
||||
addEventListener(type) {
|
||||
this.events.push(type);
|
||||
}
|
||||
|
||||
removeEventListener(type) {
|
||||
for (let i = 0; i < this.events.length; ++i) {
|
||||
if (this.events[i] === type) {
|
||||
this.events.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_test(function test_WebElementEventTarget_addEventListener_init() {
|
||||
let ipc = new MessageSender();
|
||||
let eventTarget = new WebElementEventTarget(ipc);
|
||||
equal(Object.keys(eventTarget.listeners).length, 0);
|
||||
equal(Object.keys(ipc.listeners).length, 1);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_addEventListener() {
|
||||
let ipc = new MessageSender();
|
||||
let eventTarget = new WebElementEventTarget(ipc);
|
||||
|
||||
let listener = () => {};
|
||||
eventTarget.addEventListener("click", listener);
|
||||
|
||||
// click listener was appended
|
||||
equal(Object.keys(eventTarget.listeners).length, 1);
|
||||
ok("click" in eventTarget.listeners);
|
||||
equal(eventTarget.listeners.click.length, 1);
|
||||
equal(eventTarget.listeners.click[0], listener);
|
||||
|
||||
// should have sent a registration message
|
||||
deepEqual(ipc.sent[0], {
|
||||
name: "Marionette:DOM:AddEventListener",
|
||||
data: { type: "click" },
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_addEventListener_sameReference() {
|
||||
let ipc = new MessageSender();
|
||||
let eventTarget = new WebElementEventTarget(ipc);
|
||||
|
||||
let listener = () => {};
|
||||
eventTarget.addEventListener("click", listener);
|
||||
eventTarget.addEventListener("click", listener);
|
||||
equal(eventTarget.listeners.click.length, 1);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_WebElementEventTarget_addEventListener_once() {
|
||||
let ipc = new MessageSender();
|
||||
let eventTarget = new WebElementEventTarget(ipc);
|
||||
|
||||
eventTarget.addEventListener("click", () => {}, { once: true });
|
||||
equal(eventTarget.listeners.click[0].once, true);
|
||||
|
||||
eventTarget.dispatchEvent({ type: "click" });
|
||||
equal(eventTarget.listeners.click.length, 0);
|
||||
deepEqual(ipc.sent[1], {
|
||||
name: "Marionette:DOM:RemoveEventListener",
|
||||
data: { type: "click" },
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_WebElementEventTarget_removeEventListener() {
|
||||
let ipc = new MessageSender();
|
||||
let eventTarget = new WebElementEventTarget(ipc);
|
||||
|
||||
equal(Object.keys(eventTarget.listeners).length, 0);
|
||||
eventTarget.removeEventListener("click", () => {});
|
||||
equal(Object.keys(eventTarget.listeners).length, 0);
|
||||
|
||||
let firstListener = () => {};
|
||||
eventTarget.addEventListener("click", firstListener);
|
||||
equal(eventTarget.listeners.click.length, 1);
|
||||
ok(eventTarget.listeners.click[0] === firstListener);
|
||||
|
||||
let secondListener = () => {};
|
||||
eventTarget.addEventListener("click", secondListener);
|
||||
equal(eventTarget.listeners.click.length, 2);
|
||||
ok(eventTarget.listeners.click[1] === secondListener);
|
||||
|
||||
ok(eventTarget.listeners.click[0] !== eventTarget.listeners.click[1]);
|
||||
|
||||
eventTarget.removeEventListener("click", secondListener);
|
||||
equal(eventTarget.listeners.click.length, 1);
|
||||
ok(eventTarget.listeners.click[0] === firstListener);
|
||||
|
||||
// event should not have been unregistered
|
||||
// because there still exists another click event
|
||||
equal(ipc.sent[ipc.sent.length - 1].name, "Marionette:DOM:AddEventListener");
|
||||
|
||||
eventTarget.removeEventListener("click", firstListener);
|
||||
equal(eventTarget.listeners.click.length, 0);
|
||||
deepEqual(ipc.sent[ipc.sent.length - 1], {
|
||||
name: "Marionette:DOM:RemoveEventListener",
|
||||
data: { type: "click" },
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_WebElementEventTarget_dispatchEvent() {
|
||||
let ipc = new MessageSender();
|
||||
let eventTarget = new WebElementEventTarget(ipc);
|
||||
|
||||
let listenerCalled = false;
|
||||
let listener = () => (listenerCalled = true);
|
||||
eventTarget.addEventListener("click", listener);
|
||||
eventTarget.dispatchEvent({ type: "click" });
|
||||
ok(listenerCalled);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_WebElementEventTarget_dispatchEvent_multipleListeners() {
|
||||
let ipc = new MessageSender();
|
||||
let eventTarget = new WebElementEventTarget(ipc);
|
||||
|
||||
let clicksA = 0;
|
||||
let clicksB = 0;
|
||||
let listenerA = () => ++clicksA;
|
||||
let listenerB = () => ++clicksB;
|
||||
|
||||
// the same listener should only be added, and consequently fire, once
|
||||
eventTarget.addEventListener("click", listenerA);
|
||||
eventTarget.addEventListener("click", listenerA);
|
||||
eventTarget.addEventListener("click", listenerB);
|
||||
eventTarget.dispatchEvent({ type: "click" });
|
||||
equal(clicksA, 1);
|
||||
equal(clicksB, 1);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_ContentEventObserverService_add() {
|
||||
let ipc = new MessageSender();
|
||||
let win = new Window();
|
||||
let obs = new ContentEventObserverService(
|
||||
win,
|
||||
ipc.sendAsyncMessage.bind(ipc)
|
||||
);
|
||||
|
||||
equal(obs.events.size, 0);
|
||||
equal(win.events.length, 0);
|
||||
|
||||
obs.add("foo");
|
||||
equal(obs.events.size, 1);
|
||||
equal(win.events.length, 1);
|
||||
equal(obs.events.values().next().value, "foo");
|
||||
equal(win.events[0], "foo");
|
||||
|
||||
obs.add("foo");
|
||||
equal(obs.events.size, 1);
|
||||
equal(win.events.length, 1);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_ContentEventObserverService_remove() {
|
||||
let ipc = new MessageSender();
|
||||
let win = new Window();
|
||||
let obs = new ContentEventObserverService(
|
||||
win,
|
||||
ipc.sendAsyncMessage.bind(ipc)
|
||||
);
|
||||
|
||||
obs.remove("foo");
|
||||
equal(obs.events.size, 0);
|
||||
equal(win.events.length, 0);
|
||||
|
||||
obs.add("bar");
|
||||
equal(obs.events.size, 1);
|
||||
equal(win.events.length, 1);
|
||||
|
||||
obs.remove("bar");
|
||||
equal(obs.events.size, 0);
|
||||
equal(win.events.length, 0);
|
||||
|
||||
obs.add("baz");
|
||||
obs.add("baz");
|
||||
equal(obs.events.size, 1);
|
||||
equal(win.events.length, 1);
|
||||
|
||||
obs.add("bah");
|
||||
equal(obs.events.size, 2);
|
||||
equal(win.events.length, 2);
|
||||
|
||||
obs.remove("baz");
|
||||
equal(obs.events.size, 1);
|
||||
equal(win.events.length, 1);
|
||||
|
||||
obs.remove("bah");
|
||||
equal(obs.events.size, 0);
|
||||
equal(win.events.length, 0);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_ContentEventObserverService_clear() {
|
||||
let ipc = new MessageSender();
|
||||
let win = new Window();
|
||||
let obs = new ContentEventObserverService(
|
||||
win,
|
||||
ipc.sendAsyncMessage.bind(ipc)
|
||||
);
|
||||
|
||||
obs.clear();
|
||||
equal(obs.events.size, 0);
|
||||
equal(win.events.length, 0);
|
||||
|
||||
obs.add("foo");
|
||||
obs.add("foo");
|
||||
obs.add("bar");
|
||||
equal(obs.events.size, 2);
|
||||
equal(win.events.length, 2);
|
||||
|
||||
obs.clear();
|
||||
equal(obs.events.size, 0);
|
||||
equal(win.events.length, 0);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_ContentEventObserverService_handleEvent() {
|
||||
let ipc = new MessageSender();
|
||||
let win = new Window();
|
||||
let obs = new ContentEventObserverService(
|
||||
win,
|
||||
ipc.sendAsyncMessage.bind(ipc)
|
||||
);
|
||||
|
||||
obs.handleEvent({ type: "click", target: win });
|
||||
deepEqual(ipc.sent[0], {
|
||||
name: "Marionette:DOM:OnEvent",
|
||||
data: { type: "click" },
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
@ -10,7 +10,6 @@ skip-if = appname == "thunderbird"
|
||||
[test_actors.js]
|
||||
[test_browser.js]
|
||||
[test_cookie.js]
|
||||
[test_dom.js]
|
||||
[test_element.js]
|
||||
[test_json.js]
|
||||
[test_message.js]
|
||||
|
Loading…
x
Reference in New Issue
Block a user