Bug 976082 - added tests for Touch Adapter. r=eeejay

---
 accessible/tests/mochitest/jsat/a11y.ini           |   3 +
 accessible/tests/mochitest/jsat/dom_helper.js      | 157 +++++++++++++++++++++
 accessible/tests/mochitest/jsat/gestures.json      | 132 +++++++++++++++++
 accessible/tests/mochitest/jsat/jsatcommon.js      |  15 +-
 .../tests/mochitest/jsat/test_touch_adapter.html   |  54 +++++++
 5 files changed, 356 insertions(+), 5 deletions(-)
 create mode 100644 accessible/tests/mochitest/jsat/dom_helper.js
 create mode 100644 accessible/tests/mochitest/jsat/gestures.json
 create mode 100644 accessible/tests/mochitest/jsat/test_touch_adapter.html
This commit is contained in:
Yura Zenevich 2014-03-05 16:45:29 -05:00
parent 2b77c42b66
commit 9c303859ec
5 changed files with 356 additions and 5 deletions

View File

@ -1,5 +1,7 @@
[DEFAULT]
support-files =
dom_helper.js
gestures.json
jsatcommon.js
output.js
doc_traversal.html
@ -12,4 +14,5 @@ support-files =
[test_live_regions.html]
[test_output.html]
[test_tables.html]
[test_touch_adapter.html]
[test_traversal.html]

View File

@ -0,0 +1,157 @@
'use strict';
/*global getMainChromeWindow, getBoundsForDOMElm, AccessFuTest, Point*/
/* exported loadJSON*/
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
Cu.import('resource://gre/modules/Geometry.jsm');
var win = getMainChromeWindow(window);
var winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(
Ci.nsIDOMWindowUtils);
/**
* 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 = [];
var dpi = winUtils.displayDPI;
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(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.
* Note: the listener is removed once the stack reaches 0.
*/
function testMozAccessFuGesture(aExpectedGestures) {
var types = typeof aExpectedGestures === "string" ?
[aExpectedGestures] : aExpectedGestures;
function handleGesture(aEvent) {
is(aEvent.detail.type, types.shift(),
'Received correct mozAccessFuGesture: ' + aExpectedGestures + '.');
if (types.length === 0) {
win.removeEventListener('mozAccessFuGesture', handleGesture);
AccessFuTest.nextTest();
}
}
win.addEventListener('mozAccessFuGesture', handleGesture);
}
/**
* An extention to AccessFuTest that adds an ability to test a sequence of
* touch/mouse/etc events and their expected mozAccessFuGesture events.
* @param {Array} aSequence An array of touch/mouse/etc events to be generated
* and the expected mozAccessFuGesture events.
*/
AccessFuTest.addSequence = function AccessFuTest_addSequence(aSequence) {
aSequence.forEach(function add(step) {
function fireEvent() {
eventMap[step.type](step.target, step.type);
}
function runStep() {
if (step.expectedGestures) {
testMozAccessFuGesture(step.expectedGestures);
fireEvent();
} else {
fireEvent();
AccessFuTest.nextTest();
}
}
AccessFuTest.addFunc(function() {
if (step.delay) {
window.setTimeout(runStep, step.delay);
} else {
runStep();
}
});
});
AccessFuTest.addFunc(function() {
// In order to isolate sequences of touch/mouse/etc events run them with 1s
// timeout.
window.setTimeout(AccessFuTest.nextTest, 1000);
});
};
/**
* 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();
}

View File

@ -0,0 +1,132 @@
[
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchend", "delay": 100, "expectedGestures": "tap"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0.03, "y": 0.02}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "tap"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}],
"expectedGestures": "dwell"},
{"type": "touchend", "delay": 600, "expectedGestures": "dwellend"},
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0.03, "y": 0.02}],
"delay": 50},
{"type": "touchend", "delay": 100},
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 100},
{"type": "touchmove", "target": [{"base": "button", "x": -0.03, "y": 0.01}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "doubletap"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchend", "delay": 100},
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 100},
{"type": "touchend", "delay": 100},
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 100},
{"type": "touchend", "delay": 100, "expectedGestures": "tripletap"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchend", "delay": 100},
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 100},
{"type": "touchend", "delay": 100},
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 100, "expectedGestures": "doubletaphold"},
{"type": "touchend", "delay": 600, "expectedGestures": "dwellend"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchend", "delay": 100},
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 100, "expectedGestures": "taphold"},
{"type": "touchend", "delay": 600, "expectedGestures": "dwellend"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0.5, "y": 0}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swiperight"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0.5, "y": 0}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swipeleft"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0, "y": 0.5}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swipedown"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0.5}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swipeup"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0.5, "y": 0.1}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swiperight"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0.5, "y": 0.1}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0, "y": -0.05}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swipeleft"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0}]},
{"type": "touchmove", "target": [{"base": "button", "x": -0.1, "y": 0.5}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swipedown"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0.1, "y": 0.5}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swipeup"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0.1, "y": 0.5}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 450, "expectedGestures": "explore"},
{"type": "touchend", "delay": 100, "expectedGestures": "exploreend"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0.1, "y": 0.5}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0, "y": 0}],
"delay": 450, "expectedGestures": "explore"},
{"type": "touchmove", "target": [{"base": "button", "x": 0.1, "y": 0.5}],
"delay": 150, "expectedGestures": "explore"},
{"type": "touchend", "delay": 100, "expectedGestures": "exploreend"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0},
{"base": "button", "x": 0, "y": 0.5}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0.5, "y": 0},
{"base": "button", "x": 0.5, "y": 0.5}], "delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swiperight"}
],
[
{"type": "touchstart", "target": [{"base": "button", "x": 0, "y": 0},
{"base": "button", "x": 0, "y": 0.5},
{"base": "button", "x": 0, "y": 1}]},
{"type": "touchmove", "target": [{"base": "button", "x": 0.5, "y": 0},
{"base": "button", "x": 0.5, "y": 0.5},
{"base": "button", "x": 0.5, "y": 1}],
"delay": 50},
{"type": "touchend", "delay": 100, "expectedGestures": "swiperight"}
]
]

View File

@ -1,5 +1,10 @@
// A common module to run tests on the AccessFu module
'use strict';
/*global isDeeply, getMainChromeWindow, SimpleTest, SpecialPowers, Logger,
AccessFu, Utils, addMessageListener, currentTabDocument, currentBrowser*/
/**
* A global variable holding an array of test functions.
*/
@ -117,12 +122,12 @@ var AccessFuTest = {
runTests: function AccessFuTest_runTests() {
if (gTestFuncs.length === 0) {
ok(false, "No tests specified!");
simpleTest.finish();
SimpleTest.finish();
return;
}
// Create an Iterator for gTestFuncs array.
gIterator = Iterator(gTestFuncs);
gIterator = Iterator(gTestFuncs); // jshint ignore:line
// Start AccessFu and put it in stand-by.
Components.utils.import("resource://gre/modules/accessibility/AccessFu.jsm");
@ -144,7 +149,7 @@ var AccessFuTest = {
AccessFuTest.nextTest();
} else {
// Run all test functions synchronously.
[testFunc() for (testFunc of gTestFuncs)];
[testFunc() for (testFunc of gTestFuncs)]; // jshint ignore:line
AccessFuTest.finish();
}
});
@ -199,7 +204,7 @@ AccessFuContentTest.prototype = {
}
aMessageManager.addMessageListener('AccessFu:Present', this);
aMessageManager.addMessageListener('AccessFu:Ready', function (aMessage) {
aMessageManager.addMessageListener('AccessFu:Ready', function () {
aMessageManager.addMessageListener('AccessFu:ContentStarted', aCallback);
aMessageManager.sendAsyncMessage('AccessFu:Start', { buildApp: 'browser' });
});
@ -226,7 +231,7 @@ AccessFuContentTest.prototype = {
}
} else if (this.finishedCallback) {
for (var mm of this.mms) {
mm.sendAsyncMessage('AccessFu:Stop');
mm.sendAsyncMessage('AccessFu:Stop');
}
this.finishedCallback();
}

View File

@ -0,0 +1,54 @@
<html>
<head>
<title>AccessFu tests for touch adapters.</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="../common.js"></script>
<script type="application/javascript" src="../layout.js"></script>
<script type="application/javascript" src="./jsatcommon.js"></script>
<script type="application/javascript" src="./dom_helper.js"></script>
<script type="application/javascript">
Components.utils.import(
"resource://gre/modules/accessibility/TouchAdapter.jsm");
function startComponents() {
TouchAdapter.start();
AccessFuTest.nextTest();
}
function stopComponents() {
TouchAdapter.stop();
AccessFuTest.finish();
}
function doTest() {
loadJSON("./gestures.json", function onSuccess(gestures) {
AccessFuTest.addFunc(startComponents);
gestures.forEach(AccessFuTest.addSequence);
AccessFuTest.addFunc(stopComponents);
AccessFuTest.waitForExplicitFinish();
AccessFuTest.runTests();
});
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body id="root">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=976082"
title="[AccessFu] Provide tests for touch adapter.">
Mozilla Bug 976082
</a>
<div>
<button id="button">I am a button</button>
</div>
</body>
</html>