Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 <!DOCTYPE HTML>
2 <html>
3 <!--
4 https://bugzilla.mozilla.org/show_bug.cgi?id=508906
5 -->
6 <head>
7 <title>Test for Bug 603008</title>
8 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
9 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
10 </head>
11 <body>
12 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=508906">Mozilla Bug 603008</a>
13 <p id="display"></p>
14 <div id="content" style="display: none">
16 </div>
17 <pre id="test">
18 <script class="testbody" type="application/javascript;version=1.8">
20 /** Test for Bug 306008 - Touch* Events **/
22 let tests = [], testTarget, parent;
24 let touch = {
25 id: 0,
26 point: {x: 0, y: 0},
27 radius: {x: 0, y: 0},
28 rotation: 0,
29 force: 0.5,
30 target: null
31 }
33 function nextTest() {
34 if (tests.length)
35 SimpleTest.executeSoon(tests.shift());
36 }
38 function random() {
39 return Math.floor(Math.random() * 100);
40 }
42 function checkEvent(aFakeEvent) {
43 return function(aEvent) {
44 is(aFakeEvent.ctrlKey, aEvent.ctrlKey, "Correct ctrlKey");
45 is(aFakeEvent.altKey, aEvent.altKey, "Correct altKey");
46 is(aFakeEvent.shiftKey, aEvent.shiftKey, "Correct shiftKey");
47 is(aFakeEvent.metaKey, aEvent.metaKey, "Correct metaKey");
48 checkTouches(aFakeEvent.touches, aEvent.touches);
49 checkTouches(aFakeEvent.targetTouches, aEvent.targetTouches);
50 checkTouches(aFakeEvent.changedTouches, aEvent.changedTouches);
51 }
52 }
54 function checkTouches(aTouches1, aTouches2) {
55 is(aTouches1.length, aTouches2.length, "Correct touches length");
56 for (var i = 0; i < aTouches1.length; i++) {
57 checkTouch(aTouches1[i], aTouches2[i]);
58 }
59 }
61 function checkTouch(aFakeTouch, aTouch) {
62 is(aFakeTouch.identifier, aTouch.identifier, "Touch has correct identifier");
63 is(aFakeTouch.target, aTouch.target, "Touch has correct target");
64 is(aFakeTouch.page.x, aTouch.pageX, "Touch has correct pageX");
65 is(aFakeTouch.page.y, aTouch.pageY, "Touch has correct pageY");
66 is(aFakeTouch.page.x + Math.round(window.mozInnerScreenX), aTouch.screenX, "Touch has correct screenX");
67 is(aFakeTouch.page.y + Math.round(window.mozInnerScreenY), aTouch.screenY, "Touch has correct screenY");
68 is(aFakeTouch.page.x, aTouch.clientX, "Touch has correct clientX");
69 is(aFakeTouch.page.y, aTouch.clientY, "Touch has correct clientY");
70 is(aFakeTouch.radius.x, aTouch.radiusX, "Touch has correct radiusX");
71 is(aFakeTouch.radius.y, aTouch.radiusY, "Touch has correct radiusY");
72 is(aFakeTouch.rotationAngle, aTouch.rotationAngle, "Touch has correct rotationAngle");
73 is(aFakeTouch.force, aTouch.force, "Touch has correct force");
74 }
76 function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
77 var ids = [], xs=[], ys=[], rxs = [], rys = [],
78 rotations = [], forces = [];
80 for (var touchType of ["touches", "changedTouches", "targetTouches"]) {
81 for (var i = 0; i < aEvent[touchType].length; i++) {
82 if (ids.indexOf(aEvent[touchType][i].identifier) == -1) {
83 ids.push(aEvent[touchType][i].identifier);
84 xs.push(aEvent[touchType][i].page.x);
85 ys.push(aEvent[touchType][i].page.y);
86 rxs.push(aEvent[touchType][i].radius.x);
87 rys.push(aEvent[touchType][i].radius.y);
88 rotations.push(aEvent[touchType][i].rotationAngle);
89 forces.push(aEvent[touchType][i].force);
90 }
91 }
92 }
93 return windowUtils.sendTouchEvent(aType,
94 ids, xs, ys, rxs, rys,
95 rotations, forces,
96 ids.length, aModifiers, 0);
97 }
99 function touchEvent(aOptions) {
100 if (!aOptions) {
101 aOptions = {};
102 }
103 this.ctrlKey = aOptions.ctrlKey || false;
104 this.altKey = aOptions.altKey || false;
105 this.shiftKey = aOptions.shiftKey || false;
106 this.metaKey = aOptions.metaKey || false;
107 this.touches = aOptions.touches || [];
108 this.targetTouches = aOptions.targetTouches || [];
109 this.changedTouches = aOptions.changedTouches || [];
110 }
112 function testtouch(aOptions) {
113 if (!aOptions)
114 aOptions = {};
115 this.identifier = aOptions.identifier || 0;
116 this.target = aOptions.target || 0;
117 this.page = aOptions.page || {x: 0, y: 0};
118 this.radius = aOptions.radius || {x: 0, y: 0};
119 this.rotationAngle = aOptions.rotationAngle || 0;
120 this.force = aOptions.force || 1;
121 }
123 function testSingleTouch(name) {
124 let cwu = SpecialPowers.getDOMWindowUtils(window);
125 let target = document.getElementById("testTarget");
126 let target2 = document.getElementById("testTarget2");
127 let bcr = target.getBoundingClientRect();
128 let bcr2 = target2.getBoundingClientRect();
130 let touch1 = new testtouch({
131 page: {x: Math.round(bcr.left + bcr.width/2),
132 y: Math.round(bcr.top + bcr.height/2)},
133 target: target
134 });
135 let event = new touchEvent({
136 touches: [touch1],
137 targetTouches: [touch1],
138 changedTouches: [touch1]
139 });
141 // test touchstart event fires correctly
142 var checkFunction = checkEvent(event);
143 window.addEventListener("touchstart", checkFunction, false);
144 sendTouchEvent(cwu, "touchstart", event, 0);
145 window.removeEventListener("touchstart", checkFunction, false);
147 // test touchmove event fires correctly
148 event.touches[0].page.x -= 1;
149 event.targetTouches[0].page.x -= 1;
150 event.changedTouches[0].page.x -= 1;
151 checkFunction = checkEvent(event);
152 window.addEventListener("touchmove", checkFunction, false);
153 sendTouchEvent(cwu, "touchmove", event, 0);
154 window.removeEventListener("touchmove", checkFunction, false);
156 // test touchend event fires correctly
157 event.touches = [];
158 event.targetTouches = [];
159 checkFunction = checkEvent(event);
160 window.addEventListener("touchend", checkFunction, false);
161 sendTouchEvent(cwu, "touchend", event, 0);
162 window.removeEventListener("touchend", checkFunction, false);
164 nextTest();
165 }
167 function testSingleTouch2(name) {
168 // firing a touchstart that includes only one touch will evict any touches in the queue with touchend messages
169 let cwu = SpecialPowers.getDOMWindowUtils(window);
170 let target = document.getElementById("testTarget");
171 let target2 = document.getElementById("testTarget2");
172 let bcr = target.getBoundingClientRect();
173 let bcr2 = target2.getBoundingClientRect();
175 let touch1 = new testtouch({
176 identifier: 0,
177 page: {x: Math.round(bcr.left + bcr.width/2),
178 y: Math.round(bcr.top + bcr.height/2)},
179 target: target
180 });
181 let event1 = new touchEvent({
182 touches: [touch1],
183 targetTouches: [touch1],
184 changedTouches: [touch1]
185 });
186 let touch2 = new testtouch({
187 identifier: 1,
188 page: {x: Math.round(bcr2.left + bcr2.width/2),
189 y: Math.round(bcr2.top + bcr2.height/2)},
190 target: target2
191 });
192 let event2 = new touchEvent({
193 touches: [touch2],
194 targetTouches: [touch2],
195 changedTouches: [touch2]
196 });
198 // test touchstart event fires correctly
199 var checkFunction1 = checkEvent(event1);
200 window.addEventListener("touchstart", checkFunction1, false);
201 sendTouchEvent(cwu, "touchstart", event1, 0);
202 window.removeEventListener("touchstart", checkFunction1, false);
204 event1.touches = [];
205 event1.targetTouches = [];
206 checkFunction1 = checkEvent(event1);
207 var checkFunction2 = checkEvent(event2);
209 window.addEventListener("touchend", checkFunction1, false);
210 window.addEventListener("touchstart", checkFunction2, false);
211 sendTouchEvent(cwu, "touchstart", event2, 0);
212 window.removeEventListener("touchend", checkFunction1, false);
213 window.removeEventListener("touchstart", checkFunction2, false);
215 sendTouchEvent(cwu, "touchstart", event1, 0);
217 nextTest();
218 }
221 function testMultiTouch(name) {
222 let cwu = SpecialPowers.getDOMWindowUtils(window);
223 let target1 = document.getElementById("testTarget");
224 let target2 = document.getElementById("testTarget2");
225 let bcr = target1.getBoundingClientRect();
226 let bcr2 = target2.getBoundingClientRect();
228 let touch1 = new testtouch({
229 identifier: 0,
230 page: {x: Math.round(bcr.left + bcr.width/2),
231 y: Math.round(bcr.top + bcr.height/2)},
232 target: target1
233 });
234 let touch2 = new testtouch({
235 identifier: 1,
236 page: {x: Math.round(bcr2.left + bcr2.width/2),
237 y: Math.round(bcr2.top + bcr2.height/2)},
238 target: target2
239 });
240 let event = new touchEvent({
241 touches: [touch1],
242 targetTouches: [touch1],
243 changedTouches: [touch1]
244 });
246 // test touchstart event fires correctly
247 var checkFunction = checkEvent(event);
248 window.addEventListener("touchstart", checkFunction, false);
249 sendTouchEvent(cwu, "touchstart", event, 0);
250 window.removeEventListener("touchstart", checkFunction, false);
252 event.touches.push(touch2);
253 event.targetTouches = [touch2];
254 event.changedTouches = [touch2];
255 window.addEventListener("touchstart", checkFunction, false);
256 sendTouchEvent(cwu, "touchstart", event, 0);
257 window.removeEventListener("touchstart", checkFunction, false);
259 // test moving one touch point
260 event.touches[0].page.x -= 1;
261 event.targetTouches = [event.touches[0]];
262 event.changedTouches = [event.touches[0]];
263 window.addEventListener("touchmove", checkFunction, false);
264 sendTouchEvent(cwu, "touchmove", event, 0);
265 window.removeEventListener("touchmove", checkFunction, false);
267 // test moving both touch points -- two touchmove events should fire, one on each target
268 event.touches[0].page.x -= 1;
269 event.touches[1].page.x -= 1;
270 event.targetTouches = event.touches;
271 event.changedTouches = event.touches;
272 var touchMoveEvents = 0;
273 var checkFunction2 = function(aEvent) {
274 is(event.ctrlKey, aEvent.ctrlKey, "Correct ctrlKey");
275 is(event.altKey, aEvent.altKey, "Correct altKey");
276 is(event.shiftKey, aEvent.shiftKey, "Correct shiftKey");
277 is(event.metaKey, aEvent.metaKey, "Correct metaKey");
278 checkTouches(event.touches, aEvent.touches);
279 checkTouches(event.changedTouches, aEvent.changedTouches);
280 if (aEvent.targetTouches[0].target == target1) {
281 checkTouches([event.touches[0]], aEvent.targetTouches);
282 } else if (aEvent.targetTouches[0].target == target2) {
283 checkTouches([event.touches[1]], aEvent.targetTouches);
284 } else
285 ok(false, "Event target is incorrect: " + event.targetTouches[0].target.nodeName + "#" + event.targetTouches[0].target.id);
286 touchMoveEvents++;
287 };
288 window.addEventListener("touchmove", checkFunction2, false);
289 sendTouchEvent(cwu, "touchmove", event, 0);
290 ok(touchMoveEvents, 2, "Correct number of touchmove events fired");
291 window.removeEventListener("touchmove", checkFunction2, false);
293 // test removing just one finger
294 var expected = new touchEvent({
295 touches: [touch2],
296 targetTouches: [],
297 changedTouches: [touch1]
298 });
299 checkFunction = checkEvent(expected);
301 event.touches = [];
302 event.targetTouches = [];
303 event.changedTouches = [touch1];
305 // test removing the other finger
306 window.addEventListener("touchend", checkFunction, false);
307 sendTouchEvent(cwu, "touchend", event, 0);
308 window.removeEventListener("touchend", checkFunction, false);
310 event.touches = [];
311 event.targetTouches = [];
312 event.changedTouches = [touch2];
313 checkFunction = checkEvent(event);
314 window.addEventListener("touchend", checkFunction, false);
315 sendTouchEvent(cwu, "touchend", event, 0);
316 window.removeEventListener("touchend", checkFunction, false);
318 nextTest();
319 }
321 function testTouchChanged() {
322 let cwu = SpecialPowers.getDOMWindowUtils(window);
323 let target1 = document.getElementById("testTarget");
324 let bcr = target1.getBoundingClientRect();
326 let touch1 = new testtouch({
327 identifier: 0,
328 page: {x: Math.round(bcr.left + bcr.width/2),
329 y: Math.round(bcr.top + bcr.height/2)},
330 target: target1
331 });
332 let event = new touchEvent({
333 touches: [touch1],
334 targetTouches: [touch1],
335 changedTouches: [touch1]
336 });
338 var checkFunction = checkEvent(event);
339 sendTouchEvent(cwu, "touchstart", event, 0);
341 var moveEvents = 0;
342 function onMove(aEvent) {
343 moveEvents++;
344 }
346 window.addEventListener("touchmove", onMove, false);
348 // changing nothing should not fire a touchmove event
349 sendTouchEvent(cwu, "touchmove", event, 0);
351 // test moving x
352 event.touches[0].page.x -= 1;
353 sendTouchEvent(cwu, "touchmove", event, 0);
355 // test moving y
356 event.touches[0].page.y -= 1;
357 sendTouchEvent(cwu, "touchmove", event, 0);
359 // test changing y radius
360 event.touches[0].radius.y += 1;
361 sendTouchEvent(cwu, "touchmove", event, 0);
363 // test changing x radius
364 event.touches[0].radius.x += 1;
365 sendTouchEvent(cwu, "touchmove", event, 0);
367 // test changing rotationAngle
368 event.touches[0].rotationAngle += 1;
369 sendTouchEvent(cwu, "touchmove", event, 0);
371 // test changing force
372 event.touches[0].force += 1;
373 sendTouchEvent(cwu, "touchmove", event, 0);
375 // changing nothing again
376 sendTouchEvent(cwu, "touchmove", event, 0);
378 is(moveEvents, 6, "Six move events fired");
380 window.removeEventListener("touchmove", onMove, false);
381 sendTouchEvent(cwu, "touchend", event, 0);
382 nextTest();
383 }
385 function testPreventDefault() {
386 let cwu = SpecialPowers.getDOMWindowUtils(window);
387 let target = document.getElementById("testTarget");
388 let target2 = document.getElementById("testTarget2");
389 let bcr = target.getBoundingClientRect();
390 let bcr2 = target2.getBoundingClientRect();
392 let touch1 = new testtouch({
393 page: {x: bcr.left + bcr.width/2,
394 y: bcr.top + bcr.height/2},
395 target: target
396 });
397 let event = new touchEvent({
398 touches: [touch1],
399 targetTouches: [touch1],
400 changedTouches: [touch1]
401 });
403 let preventFunction = function(aEvent) {
404 aEvent.preventDefault();
405 }
407 let tests = [
408 [{ name: "touchstart", prevent: false },
409 { name: "touchmove", prevent: false },
410 { name: "touchmove", prevent: false },
411 { name: "touchend", prevent: false }],
412 [{ name: "touchstart", prevent: true, doPrevent: true },
413 { name: "touchmove", prevent: true },
414 { name: "touchmove", prevent: true },
415 { name: "touchend", prevent: true }],
416 [{ name: "touchstart", prevent: false },
417 { name: "touchmove", prevent: true, doPrevent: true },
418 { name: "touchmove", prevent: true },
419 { name: "touchend", prevent: true }],
420 [{ name: "touchstart", prevent: false },
421 { name: "touchmove", prevent: false },
422 { name: "touchmove", prevent: false, doPrevent: true },
423 { name: "touchend", prevent: false }],
424 [{ name: "touchstart", prevent: false },
425 { name: "touchmove", prevent: false },
426 { name: "touchmove", prevent: false },
427 { name: "touchend", prevent: false, doPrevent: true }]
428 ];
430 var dotest = function(aTest) {
431 if (aTest.doPrevent) {
432 target.addEventListener(aTest.name, preventFunction, false);
433 }
435 if (aTest.name == "touchmove") {
436 touch1.page.x++;
437 event.touches[0] = touch1;
438 }
440 is(sendTouchEvent(cwu, aTest.name, event, 0), aTest.prevent, "Got correct status");
442 if (aTest.doPrevent)
443 target.removeEventListener(aTest.name, preventFunction, false);
444 }
446 for (var i = 0; i < tests.length; i++) {
447 for (var j = 0; j < tests[i].length; j++) {
448 dotest(tests[i][j]);
449 }
450 }
452 nextTest();
453 }
455 function testRemovingElement() {
456 let cwu = SpecialPowers.getDOMWindowUtils(window);
457 let target = document.getElementById("testTarget");
458 let bcr = document.getElementById("testTarget").getBoundingClientRect();
460 let touch1 = new testtouch({
461 page: {x: bcr.left + bcr.width/2,
462 y: bcr.top + bcr.height/2},
463 });
464 let e = new touchEvent({
465 touches: [touch1],
466 targetTouches: [touch1],
467 changedTouches: [touch1]
468 });
470 var touchEvents = 0;
471 var removeTarget = function(aEvent) {
472 aEvent.target.parentNode.removeChild(aEvent.target);
473 };
475 var checkTarget = function(aEvent) {
476 is(aEvent.target, target, "Event has correct target");
477 touchEvents++;
478 };
480 target.addEventListener("touchstart", removeTarget, false);
481 target.addEventListener("touchmove", checkTarget, false);
482 target.addEventListener("touchend", checkTarget, false);
484 sendTouchEvent(cwu, "touchstart", e, 0);
486 e.touches[0].page.x++;
487 sendTouchEvent(cwu, "touchmove", e, 0);
488 sendTouchEvent(cwu, "touchend", e, 0);
490 target.removeEventListener("touchstart", removeTarget, false);
491 target.removeEventListener("touchmove", checkTarget, false);
492 target.removeEventListener("touchend", checkTarget, false);
494 is(touchEvents, 2, "Check target was called twice");
496 nextTest();
497 }
499 function testNAC() {
500 let cwu = SpecialPowers.getDOMWindowUtils(window);
501 let target = document.getElementById("testTarget3");
502 let bcr = target.getBoundingClientRect();
504 let touch1 = new testtouch({
505 page: {x: Math.round(bcr.left + bcr.width/2),
506 y: Math.round(bcr.top + bcr.height/2)},
507 target: target
508 });
509 let event = new touchEvent({
510 touches: [touch1],
511 targetTouches: [touch1],
512 changedTouches: [touch1]
513 });
515 // test touchstart event fires correctly
516 var checkFunction = checkEvent(event);
517 window.addEventListener("touchstart", checkFunction, false);
518 sendTouchEvent(cwu, "touchstart", event, 0);
519 window.removeEventListener("touchstart", checkFunction, false);
521 sendTouchEvent(cwu, "touchend", event, 0);
523 nextTest();
524 }
526 function doTest() {
527 tests.push(testSingleTouch);
528 tests.push(testSingleTouch2);
529 tests.push(testMultiTouch);
530 tests.push(testPreventDefault);
531 tests.push(testTouchChanged);
532 tests.push(testRemovingElement);
533 tests.push(testNAC);
535 tests.push(function() {
536 SimpleTest.finish();
537 });
539 nextTest();
540 }
542 SimpleTest.waitForExplicitFinish();
543 addLoadEvent(doTest);
545 </script>
546 </pre>
547 <div id="parent">
548 <span id="testTarget" style="padding: 5px; border: 1px solid black;">testTarget</span>
549 <span id="testTarget2" style="padding: 5px; border: 1px solid blue;">testTarget</span>
550 <input type="text" id="testTarget3">
551 </div>
552 </body>
553 </html>