summaryrefslogtreecommitdiffstats
path: root/testing/mochitest/tests/SimpleTest/EventUtils.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/mochitest/tests/SimpleTest/EventUtils.js')
-rw-r--r--testing/mochitest/tests/SimpleTest/EventUtils.js360
1 files changed, 257 insertions, 103 deletions
diff --git a/testing/mochitest/tests/SimpleTest/EventUtils.js b/testing/mochitest/tests/SimpleTest/EventUtils.js
index 739c7052ea..8833b8bc59 100644
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -1,3 +1,4 @@
+/* eslint-disable no-nested-ternary */
/**
* EventUtils provides some utility methods for creating and sending DOM events.
*
@@ -569,14 +570,86 @@ function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow) {
aWindow
);
}
-function synthesizeTouch(aTarget, aOffsetX, aOffsetY, aEvent, aWindow) {
- var rect = aTarget.getBoundingClientRect();
- return synthesizeTouchAtPoint(
- rect.left + aOffsetX,
- rect.top + aOffsetY,
- aEvent,
- aWindow
- );
+
+/**
+ * Synthesize one or more touches on aTarget. aTarget can be either Element
+ * or Array of Elements. aOffsetX, aOffsetY, aEvent.id, aEvent.rx, aEvent.ry,
+ * aEvent.angle, aEvent.force, aEvent.tiltX, aEvent.tiltY and aEvent.twist can
+ * be either Number or Array of Numbers (can be mixed). If you specify array
+ * to synthesize a multi-touch, you need to specify same length arrays. If
+ * you don't specify array to them, same values (or computed default values for
+ * aEvent.id) are used for all touches.
+ *
+ * @param {Element | Element[]} aTarget The target element which you specify
+ * relative offset from its top-left.
+ * @param {Number | Number[]} aOffsetX The relative offset from left of aTarget.
+ * @param {Number | Number[]} aOffsetY The relative offset from top of aTarget.
+ * @param {Object} aEvent
+ * type: The touch event type. If undefined, "touchstart" and "touchend" will
+ * be synthesized at same point.
+ *
+ * id: The touch id. If you don't specify this, default touch id will be used
+ * for first touch and further touch ids are the values incremented from the
+ * first id.
+ *
+ * rx, ry: The radii of the touch.
+ *
+ * angle: The angle in degree.
+ *
+ * force: The force of the touch. If the type is "touchend", this should be 0.
+ * If unspecified, this is default to 0 for "touchend" or 1 for the others.
+ *
+ * tiltX, tiltY: The tilt of the touch.
+ *
+ * twist: The twist of the touch.
+ * @param {Window} aWindow Default to `window`.
+ * @returns true if and only if aEvent.type is specified and default of the
+ * event is prevented.
+ */
+function synthesizeTouch(
+ aTarget,
+ aOffsetX,
+ aOffsetY,
+ aEvent = {},
+ aWindow = window
+) {
+ let rectX, rectY;
+ if (Array.isArray(aTarget)) {
+ let lastTarget, lastTargetRect;
+ aTarget.forEach(target => {
+ const rect =
+ target == lastTarget ? lastTargetRect : target.getBoundingClientRect();
+ rectX.push(rect.left);
+ rectY.push(rect.top);
+ lastTarget = target;
+ lastTargetRect = rect;
+ });
+ } else {
+ const rect = aTarget.getBoundingClientRect();
+ rectX = [rect.left];
+ rectY = [rect.top];
+ }
+ const offsetX = (() => {
+ if (Array.isArray(aOffsetX)) {
+ let ret = [];
+ aOffsetX.forEach((value, index) => {
+ ret.push(value + rectX[Math.min(index, rectX.length - 1)]);
+ });
+ return ret;
+ }
+ return aOffsetX + rectX[0];
+ })();
+ const offsetY = (() => {
+ if (Array.isArray(aOffsetY)) {
+ let ret = [];
+ aOffsetY.forEach((value, index) => {
+ ret.push(value + rectY[Math.min(index, rectY.length - 1)]);
+ });
+ return ret;
+ }
+ return aOffsetY + rectY[0];
+ })();
+ return synthesizeTouchAtPoint(offsetX, offsetY, aEvent, aWindow);
}
/**
@@ -776,68 +849,160 @@ function synthesizeMouseAtPoint(left, top, aEvent, aWindow = window) {
return defaultPrevented;
}
-function synthesizeTouchAtPoint(left, top, aEvent, aWindow = window) {
- var utils = _getDOMWindowUtils(aWindow);
- let defaultPrevented = false;
+/**
+ * Synthesize one or more touches at the points. aLeft, aTop, aEvent.id,
+ * aEvent.rx, aEvent.ry, aEvent.angle, aEvent.force, aEvent.tiltX, aEvent.tiltY
+ * and aEvent.twist can be either Number or Array of Numbers (can be mixed).
+ * If you specify array to synthesize a multi-touch, you need to specify same
+ * length arrays. If you don't specify array to them, same values are used for
+ * all touches.
+ *
+ * @param {Element | Element[]} aTarget The target element which you specify
+ * relative offset from its top-left.
+ * @param {Number | Number[]} aOffsetX The relative offset from left of aTarget.
+ * @param {Number | Number[]} aOffsetY The relative offset from top of aTarget.
+ * @param {Object} aEvent
+ * type: The touch event type. If undefined, "touchstart" and "touchend" will
+ * be synthesized at same point.
+ *
+ * id: The touch id. If you don't specify this, default touch id will be used
+ * for first touch and further touch ids are the values incremented from the
+ * first id.
+ *
+ * rx, ry: The radii of the touch.
+ *
+ * angle: The angle in degree.
+ *
+ * force: The force of the touch. If the type is "touchend", this should be 0.
+ * If unspecified, this is default to 0 for "touchend" or 1 for the others.
+ *
+ * tiltX, tiltY: The tilt of the touch.
+ *
+ * twist: The twist of the touch.
+ * @param {Window} aWindow Default to `window`.
+ * @returns true if and only if aEvent.type is specified and default of the
+ * event is prevented.
+ */
+function synthesizeTouchAtPoint(aLeft, aTop, aEvent = {}, aWindow = window) {
+ let utils = _getDOMWindowUtils(aWindow);
+ if (!utils) {
+ return false;
+ }
- if (utils) {
- var id = aEvent.id || utils.DEFAULT_TOUCH_POINTER_ID;
- var rx = aEvent.rx || 1;
- var ry = aEvent.ry || 1;
- var angle = aEvent.angle || 0;
- var force = aEvent.force || (aEvent.type === "touchend" ? 0 : 1);
- var tiltX = aEvent.tiltX || 0;
- var tiltY = aEvent.tiltY || 0;
- var twist = aEvent.twist || 0;
- var modifiers = _parseModifiers(aEvent, aWindow);
+ if (
+ Array.isArray(aLeft) &&
+ Array.isArray(aTop) &&
+ aLeft.length != aTop.length
+ ) {
+ throw new Error(`aLeft and aTop should be same length array`);
+ }
- if ("type" in aEvent && aEvent.type) {
- defaultPrevented = utils.sendTouchEvent(
- aEvent.type,
- [id],
- [left],
- [top],
- [rx],
- [ry],
- [angle],
- [force],
- [tiltX],
- [tiltY],
- [twist],
- modifiers
- );
- } else {
- utils.sendTouchEvent(
- "touchstart",
- [id],
- [left],
- [top],
- [rx],
- [ry],
- [angle],
- [force],
- [tiltX],
- [tiltY],
- [twist],
- modifiers
- );
- utils.sendTouchEvent(
- "touchend",
- [id],
- [left],
- [top],
- [rx],
- [ry],
- [angle],
- [force],
- [tiltX],
- [tiltY],
- [twist],
- modifiers
+ const arrayLength = Array.isArray(aLeft)
+ ? aLeft.length
+ : Array.isArray(aTop)
+ ? aTop.length
+ : 1;
+
+ function throwExceptionIfDifferentLengthArray(aArray, aName) {
+ if (Array.isArray(aArray) && arrayLength !== aArray.length) {
+ throw new Error(`${aName} is different length array`);
+ }
+ }
+ const leftArray = (() => {
+ if (Array.isArray(aLeft)) {
+ return aLeft;
+ }
+ return new Array(arrayLength).fill(aLeft);
+ })();
+ const topArray = (() => {
+ if (Array.isArray(aTop)) {
+ throwExceptionIfDifferentLengthArray(aTop, "aTop");
+ return aTop;
+ }
+ return new Array(arrayLength).fill(aTop);
+ })();
+ const idArray = (() => {
+ if ("id" in aEvent && Array.isArray(aEvent.id)) {
+ throwExceptionIfDifferentLengthArray(aEvent.id, "aEvent.id");
+ return aEvent.id;
+ }
+ let id = aEvent.id || utils.DEFAULT_TOUCH_POINTER_ID;
+ let ret = [];
+ for (let i = 0; i < arrayLength; i++) {
+ ret.push(id++);
+ }
+ return ret;
+ })();
+ function getSameLengthArrayOfEventProperty(aProperty, aDefaultValue) {
+ if (aProperty in aEvent && Array.isArray(aEvent[aProperty])) {
+ throwExceptionIfDifferentLengthArray(
+ aEvent.rx,
+ arrayLength,
+ `aEvent.${aProperty}`
);
+ return aEvent[aProperty];
}
+ return new Array(arrayLength).fill(aEvent[aProperty] || aDefaultValue);
}
- return defaultPrevented;
+ const rxArray = getSameLengthArrayOfEventProperty("rx", 1);
+ const ryArray = getSameLengthArrayOfEventProperty("ry", 1);
+ const angleArray = getSameLengthArrayOfEventProperty("angle", 0);
+ const forceArray = getSameLengthArrayOfEventProperty(
+ "force",
+ aEvent.type === "touchend" ? 0 : 1
+ );
+ const tiltXArray = getSameLengthArrayOfEventProperty("tiltX", 0);
+ const tiltYArray = getSameLengthArrayOfEventProperty("tiltY", 0);
+ const twistArray = getSameLengthArrayOfEventProperty("twist", 0);
+
+ const modifiers = _parseModifiers(aEvent, aWindow);
+
+ if ("type" in aEvent && aEvent.type) {
+ return utils.sendTouchEvent(
+ aEvent.type,
+ idArray,
+ leftArray,
+ topArray,
+ rxArray,
+ ryArray,
+ angleArray,
+ forceArray,
+ tiltXArray,
+ tiltYArray,
+ twistArray,
+ modifiers
+ );
+ }
+
+ utils.sendTouchEvent(
+ "touchstart",
+ idArray,
+ leftArray,
+ topArray,
+ rxArray,
+ ryArray,
+ angleArray,
+ forceArray,
+ tiltXArray,
+ tiltYArray,
+ twistArray,
+ modifiers
+ );
+ utils.sendTouchEvent(
+ "touchend",
+ idArray,
+ leftArray,
+ topArray,
+ rxArray,
+ ryArray,
+ angleArray,
+ forceArray,
+ tiltXArray,
+ tiltYArray,
+ twistArray,
+ modifiers
+ );
+ return false;
}
// Call synthesizeMouse with coordinates at the center of aTarget.
@@ -851,7 +1016,7 @@ function synthesizeMouseAtCenter(aTarget, aEvent, aWindow) {
aWindow
);
}
-function synthesizeTouchAtCenter(aTarget, aEvent, aWindow) {
+function synthesizeTouchAtCenter(aTarget, aEvent = {}, aWindow = window) {
var rect = aTarget.getBoundingClientRect();
synthesizeTouchAtPoint(
rect.left + rect.width / 2,
@@ -1020,7 +1185,9 @@ function _sendWheelAndPaint(
}
var onwheel = function () {
- SpecialPowers.removeSystemEventListener(window, "wheel", onwheel);
+ SpecialPowers.wrap(window).removeEventListener("wheel", onwheel, {
+ mozSystemGroup: true,
+ });
// Wait one frame since the wheel event has not caused a refresh observer
// to be added yet.
@@ -1055,7 +1222,9 @@ function _sendWheelAndPaint(
// Listen for the system wheel event, because it happens after all of
// the other wheel events, including legacy events.
- SpecialPowers.addSystemEventListener(aWindow, "wheel", onwheel);
+ SpecialPowers.wrap(aWindow).addEventListener("wheel", onwheel, {
+ mozSystemGroup: true,
+ });
if (aFlushMode === _FlushModes.FLUSH) {
synthesizeWheel(aTarget, aOffsetX, aOffsetY, aEvent, aWindow);
} else {
@@ -1405,13 +1574,10 @@ function synthesizeAndWaitNativeMouseMove(
);
let eventRegisteredPromise = new Promise(resolve => {
- mm.addMessageListener(
- "Test:MouseMoveRegistered",
- function processed(message) {
- mm.removeMessageListener("Test:MouseMoveRegistered", processed);
- resolve();
- }
- );
+ mm.addMessageListener("Test:MouseMoveRegistered", function processed() {
+ mm.removeMessageListener("Test:MouseMoveRegistered", processed);
+ resolve();
+ });
});
let eventReceivedPromise = ContentTask.spawn(
browser,
@@ -1579,7 +1745,7 @@ function synthesizeAndWaitKey(
);
let keyRegisteredPromise = new Promise(resolve => {
- mm.addMessageListener("Test:KeyRegistered", function processed(message) {
+ mm.addMessageListener("Test:KeyRegistered", function processed() {
mm.removeMessageListener("Test:KeyRegistered", processed);
resolve();
});
@@ -3853,21 +4019,19 @@ async function synthesizePlainDragAndCancel(
aExpectedDataTransferItems
);
}
- SpecialPowers.addSystemEventListener(
- srcElement.ownerDocument,
+ SpecialPowers.wrap(srcElement.ownerDocument).addEventListener(
"dragstart",
onDragStart,
- { capture: true }
+ { capture: true, mozSystemGroup: true }
);
try {
aParams.expectCancelDragStart = true;
await synthesizePlainDragAndDrop(aParams);
} finally {
- SpecialPowers.removeSystemEventListener(
- srcElement.ownerDocument,
+ SpecialPowers.wrap(srcElement.ownerDocument).removeEventListener(
"dragstart",
onDragStart,
- { capture: true }
+ { capture: true, mozSystemGroup: true }
);
}
return result;
@@ -3884,33 +4048,23 @@ class EventCounter {
// SpecialPowers is picky and needs to be passed an explicit reference to
// the function to be called. To avoid having to bind "this", we therefore
// define the method this way, via a property.
- this.handleEvent = aEvent => {
+ this.handleEvent = () => {
this.eventCount++;
};
- if (aOptions.mozSystemGroup) {
- SpecialPowers.addSystemEventListener(
- aTarget,
- aType,
- this.handleEvent,
- aOptions.capture
- );
- } else {
- aTarget.addEventListener(aType, this, aOptions);
- }
+ SpecialPowers.wrap(aTarget).addEventListener(
+ aType,
+ this.handleEvent,
+ aOptions
+ );
}
unregister() {
- if (this.options.mozSystemGroup) {
- SpecialPowers.removeSystemEventListener(
- this.target,
- this.type,
- this.handleEvent,
- this.options.capture
- );
- } else {
- this.target.removeEventListener(this.type, this, this.options);
- }
+ SpecialPowers.wrap(this.target).removeEventListener(
+ this.type,
+ this.handleEvent,
+ this.options
+ );
}
get count() {