summaryrefslogtreecommitdiff
path: root/accessible/tests/mochitest/jsat/dom_helper.js
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/tests/mochitest/jsat/dom_helper.js')
-rw-r--r--accessible/tests/mochitest/jsat/dom_helper.js209
1 files changed, 209 insertions, 0 deletions
diff --git a/accessible/tests/mochitest/jsat/dom_helper.js b/accessible/tests/mochitest/jsat/dom_helper.js
new file mode 100644
index 0000000000..c95d19dc11
--- /dev/null
+++ b/accessible/tests/mochitest/jsat/dom_helper.js
@@ -0,0 +1,209 @@
+'use strict';
+
+/* global getMainChromeWindow, AccessFuTest, GestureSettings, GestureTracker,
+ SimpleTest, getBoundsForDOMElm, Point, Utils */
+/* exported loadJSON, eventMap */
+
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+Cu.import('resource://gre/modules/Geometry.jsm');
+
+var win = getMainChromeWindow(window);
+
+/**
+ * Convert inch based point coordinates into pixels.
+ * @param {Array} aPoints Array of coordinates in inches.
+ * @return {Array} Array of coordinates in pixels.
+ */
+function convertPointCoordinates(aPoints) {
+ var dpi = Utils.dpi;
+ return aPoints.map(function convert(aPoint) {
+ return {
+ x: aPoint.x * dpi,
+ y: aPoint.y * dpi,
+ identifier: aPoint.identifier
+ };
+ });
+}
+
+/**
+ * For a given list of points calculate their coordinates in relation to the
+ * document body.
+ * @param {Array} aTouchPoints An array of objects of the following format: {
+ * base: {String}, // Id of an element to server as a base for the touch.
+ * x: {Number}, // An optional x offset from the base element's geometric
+ * // centre.
+ * y: {Number} // An optional y offset from the base element's geometric
+ * // centre.
+ * }
+ * @return {JSON} An array of {x, y} coordinations.
+ */
+function calculateTouchListCoordinates(aTouchPoints) {
+ var coords = [];
+ for (var i = 0, target = aTouchPoints[i]; i < aTouchPoints.length; ++i) {
+ var bounds = getBoundsForDOMElm(target.base);
+ var parentBounds = getBoundsForDOMElm('root');
+ var point = new Point(target.x || 0, target.y || 0);
+ point.scale(Utils.dpi);
+ point.add(bounds[0], bounds[1]);
+ point.add(bounds[2] / 2, bounds[3] / 2);
+ point.subtract(parentBounds[0], parentBounds[0]);
+ coords.push({
+ x: point.x,
+ y: point.y
+ });
+ }
+ return coords;
+}
+
+/**
+ * Send a touch event with specified touchPoints.
+ * @param {Array} aTouchPoints An array of points to be associated with
+ * touches.
+ * @param {String} aName A name of the touch event.
+ */
+function sendTouchEvent(aTouchPoints, aName) {
+ var touchList = sendTouchEvent.touchList;
+ if (aName === 'touchend') {
+ sendTouchEvent.touchList = null;
+ } else {
+ var coords = calculateTouchListCoordinates(aTouchPoints);
+ var touches = [];
+ for (var i = 0; i < coords.length; ++i) {
+ var {x, y} = coords[i];
+ var node = document.elementFromPoint(x, y);
+ var touch = document.createTouch(window, node, aName === 'touchstart' ?
+ 1 : touchList.item(i).identifier, x, y, x, y);
+ touches.push(touch);
+ }
+ touchList = document.createTouchList(touches);
+ sendTouchEvent.touchList = touchList;
+ }
+ var evt = document.createEvent('TouchEvent');
+ evt.initTouchEvent(aName, true, true, window, 0, false, false, false, false,
+ touchList, touchList, touchList);
+ document.dispatchEvent(evt);
+}
+
+sendTouchEvent.touchList = null;
+
+/**
+ * A map of event names to the functions that actually send them.
+ * @type {Object}
+ */
+var eventMap = {
+ touchstart: sendTouchEvent,
+ touchend: sendTouchEvent,
+ touchmove: sendTouchEvent
+};
+
+/**
+ * Attach a listener for the mozAccessFuGesture event that tests its
+ * type.
+ * @param {Array} aExpectedGestures A stack of expected event types.
+ * @param {String} aTitle Title of this sequence, if any.
+ * Note: the listener is removed once the stack reaches 0.
+ */
+function testMozAccessFuGesture(aExpectedGestures, aTitle) {
+ var types = aExpectedGestures;
+ function handleGesture(aEvent) {
+ if (aEvent.detail.type !== types[0].type) {
+ info('Got ' + aEvent.detail.type + ' waiting for ' + types[0].type);
+ // The is not the event of interest.
+ return;
+ }
+ is(!!aEvent.detail.edge, !!types[0].edge);
+ is(aEvent.detail.touches.length, types[0].fingers || 1,
+ 'failed to count fingers: ' + types[0].type);
+ ok(true, 'Received correct mozAccessFuGesture: ' +
+ JSON.stringify(types.shift()) + '. (' + aTitle + ')');
+ if (types.length === 0) {
+ win.removeEventListener('mozAccessFuGesture', handleGesture);
+ if (AccessFuTest.sequenceCleanup) {
+ AccessFuTest.sequenceCleanup();
+ }
+ AccessFuTest.nextTest();
+ }
+ }
+ win.addEventListener('mozAccessFuGesture', handleGesture);
+}
+
+/**
+ * Reset the thresholds and max delays that affect gesture rejection.
+ * @param {Number} aTimeStamp Gesture time stamp.
+ * @param {Boolean} aRemoveDwellThreshold An optional flag to reset dwell
+ * threshold.
+ * @param {Boolean} aRemoveSwipeMaxDuration An optional flag to reset swipe max
+ * duration.
+ */
+function setTimers(aTimeStamp, aRemoveDwellThreshold, aRemoveSwipeMaxDuration) {
+ if (!aRemoveDwellThreshold && !aRemoveSwipeMaxDuration) {
+ return;
+ }
+ if (aRemoveDwellThreshold) {
+ GestureSettings.dwellThreshold = 0;
+ }
+ if (aRemoveSwipeMaxDuration) {
+ GestureSettings.swipeMaxDuration = 0;
+ }
+ GestureTracker.current.clearTimer();
+ GestureTracker.current.startTimer(aTimeStamp);
+}
+
+function resetTimers(aRemoveGestureResolveDelay) {
+ GestureSettings.dwellThreshold = AccessFuTest.dwellThreshold;
+ GestureSettings.swipeMaxDuration = AccessFuTest.swipeMaxDuration;
+ GestureSettings.maxGestureResolveTimeout = aRemoveGestureResolveDelay ?
+ 0 : AccessFuTest.maxGestureResolveTimeout;
+}
+
+/**
+ * An extention to AccessFuTest that adds an ability to test a sequence of
+ * pointer events and their expected mozAccessFuGesture events.
+ * @param {Object} aSequence An object that has a list of pointer events to be
+ * generated and the expected mozAccessFuGesture events.
+ */
+AccessFuTest.addSequence = function AccessFuTest_addSequence(aSequence) {
+ AccessFuTest.addFunc(function testSequence() {
+ testMozAccessFuGesture(aSequence.expectedGestures, aSequence.title);
+ var events = aSequence.events;
+ function fireEvent(aEvent) {
+ var event = {
+ points: convertPointCoordinates(aEvent.points),
+ type: aEvent.type
+ };
+ var timeStamp = Date.now();
+ resetTimers(aEvent.removeGestureResolveDelay);
+ GestureTracker.handle(event, timeStamp);
+ setTimers(timeStamp, aEvent.removeDwellThreshold,
+ aEvent.removeSwipeMaxDuration);
+ processEvents();
+ }
+ function processEvents() {
+ if (events.length === 0) {
+ return;
+ }
+ var event = events.shift();
+ SimpleTest.executeSoon(function() {
+ fireEvent(event);
+ });
+ }
+ processEvents();
+ });
+};
+
+/**
+ * A helper function that loads JSON files.
+ * @param {String} aPath A path to a JSON file.
+ * @param {Function} aCallback A callback to be called on success.
+ */
+function loadJSON(aPath, aCallback) {
+ var request = new XMLHttpRequest();
+ request.open('GET', aPath, true);
+ request.responseType = 'json';
+ request.onload = function onload() {
+ aCallback(request.response);
+ };
+ request.send();
+}