blob: 79c6a00f0a6d4e34a30b6fb75c158c6072a4b48e [file] [log] [blame]
Sangwhan Moon70f1aa22014-04-08 11:10:471<!DOCTYPE HTML>
2<html>
3<!--
4 Test cases for Touch Events v1 Recommendation
5 http://www.w3.org/TR/touch-events/
6
7 These tests are based on Matt Bruebeck's single-touch tests.
8 There are NO multi-touch tests in this document.
Sangwhan Moon70f1aa22014-04-08 11:10:479
10 This document references Test Assertions (abbrev TA below) written by Cathy Chan
11 http://www.w3.org/2010/webevents/wiki/TestAssertions
12-->
13
14<head>
15 <title>Touch Events Single Touch Tests</title>
16 <meta name="viewport" content="width=device-width">
17 <script src="/resources/testharness.js"></script>
18 <script>
19 setup({explicit_done: true});
20
21 // Check a Touch object's atttributes for existence and correct type
22 // TA: 1.1.2, 1.1.3
23 function check_Touch_object (t) {
24 test(function() {
25 assert_equals(Object.prototype.toString.call(t), "[object Touch]", name + " attribute of type TouchList");
26 }, "touch point is a Touch object");
27 [
28 ["long", "identifier"],
29 ["EventTarget", "target"],
30 ["long", "screenX"],
31 ["long", "screenY"],
32 ["long", "clientX"],
33 ["long", "clientY"],
34 ["long", "pageX"],
35 ["long", "pageY"],
36 ].forEach(function(attr) {
37 var type = attr[0];
38 var name = attr[1];
39
40 // existence check
41 test(function() {
42 assert_true(name in t, name + " attribute in Touch object");
43 }, "Touch." + name + " attribute exists");
44
45 // type check
46 switch(type) {
47 case "long":
48 test(function() {
49 assert_equals(typeof t[name], "number", name + " attribute of type long");
50 }, "Touch." + name + " attribute is of type number (long)");
51 break;
52 case "EventTarget":
53 // An event target is some type of Element
54 test(function() {
55 assert_true(t[name] instanceof Element, "EventTarget must be an Element.");
56 }, "Touch." + name + " attribute is of type Element");
57 break;
58 default:
59 break;
60 }
61 });
62 }
63
64 // Check a TouchList object's attributes and methods for existence and proper type
65 // Also make sure all of the members of the list are Touch objects
66 // TA: 1.2.1, 1.2.2, 1.2.5
67 function check_TouchList_object (tl) {
68 test(function() {
69 assert_equals(Object.prototype.toString.call(tl), "[object TouchList]", name + " attribute of type TouchList");
70 }, "touch list is a TouchList object");
71 [
72 ["unsigned long", "length"],
73 ["function", "item"],
74 ].forEach(function(attr) {
75 var type = attr[0];
76 var name = attr[1];
77
78 // existence check
79 test(function() {
80 assert_true(name in tl, name + " attribute in TouchList");
81 }, "TouchList." + name + " attribute exists");
82
83 // type check
84 switch(type) {
85 case "unsigned long":
86 test(function() {
87 assert_equals(typeof tl[name], "number", name + " attribute of type long");
88 }, "TouchList." + name + " attribute is of type number (unsigned long)");
89 break;
90 case "function":
91 test(function() {
92 assert_equals(typeof tl[name], "function", name + " attribute of type function");
93 }, "TouchList." + name + " attribute is of type function");
94 break;
95 default:
96 break;
97 }
98 });
99 // Each member of tl should be a proper Touch object
100 for (var i=0; i < tl.length; i++) {
101 check_Touch_object(tl.item(i));
102 }
103 }
104
105 // Check a TouchEvent event's attributes for existence and proper type
106 // Also check that each of the event's TouchList objects are valid
107 // TA: 1.{3,4,5}.1.1, 1.{3,4,5}.1.2
108 function check_TouchEvent(ev) {
109 test(function() {
110 assert_true(ev instanceof TouchEvent, "event is a TouchEvent event");
111 }, ev.type + " event is a TouchEvent event");
112 [
113 ["TouchList", "touches"],
114 ["TouchList", "targetTouches"],
115 ["TouchList", "changedTouches"],
116 ["boolean", "altKey"],
117 ["boolean", "metaKey"],
118 ["boolean", "ctrlKey"],
119 ["boolean", "shiftKey"],
120 ].forEach(function(attr) {
121 var type = attr[0];
122 var name = attr[1];
123
124 // existence check
125 test(function() {
126 assert_true(name in ev, name + " attribute in " + ev.type + " event");
127 }, ev.type + "." + name + " attribute exists");
128
129 // type check
130 switch(type) {
131 case "boolean":
132 test(function() {
133 assert_equals(typeof ev[name], "boolean", name + " attribute of type boolean");
134 }, ev.type + "." + name + " attribute is of type boolean");
135 break;
136 case "TouchList":
137 test(function() {
138 assert_equals(Object.prototype.toString.call(ev[name]), "[object TouchList]", name + " attribute of type TouchList");
139 }, ev.type + "." + name + " attribute is of type TouchList");
140 // Now check the validity of the TouchList
141 check_TouchList_object(ev[name]);
142 break;
143 default:
144 break;
145 }
146 });
147 }
148
149 function is_touch_over_element(touch, element) {
150 var bounds = element.getBoundingClientRect();
151 return touch.pageX >= bounds.left && touch.pageX <= bounds.right &&
152 touch.pageY >= bounds.top && touch.pageY <= bounds.bottom;
153 }
154
155 function check_touch_clientXY(touch) {
156 assert_equals(touch.clientX, touch.pageX - window.pageXOffset, "touch.clientX is touch.pageX - window.pageXOffset.");
157 assert_equals(touch.clientY, touch.pageY - window.pageYOffset, "touch.clientY is touch.pageY - window.pageYOffset.");
158 }
159
160 function run() {
161 var target0 = document.getElementById("target0");
162 var target1 = document.getElementById("target1");
163
164 var test_touchstart = async_test("touchstart event received");
165 var test_touchmove = async_test("touchmove event received");
166 var test_touchend = async_test("touchend event received");
167 var test_mousedown = async_test("Interaction with mouse events");
168
169 var touchstart_received = false;
170 var touchmove_received = false;
171 var touchend_received = false;
172 var invalid_touchmove_received = false;
173 var touchstart_identifier;
174
175 on_event(target0, "touchstart", function onTouchStart(ev) {
176 ev.preventDefault();
177
178 // Check event ordering TA: 1.6.2
179 test_touchstart.step(function() {
180 assert_false(touchstart_received, "duplicate touchstart event");
181 assert_false(touchmove_received, "touchstart precedes touchmove");
182 assert_false(touchend_received, "touchstart precedes touchend");
183 });
184 test_touchstart.done();
185 if (touchstart_received)
186 return;
187 touchstart_received = true;
188 test_mousedown.done(); // If we got here, then the mouse event test is not needed.
189
190 check_TouchEvent(ev);
191
192 // TA: 1.3.2.1, 1.3.3.1, 1.3.4.1
193 test(function() {
194 assert_equals(ev.touches.length, 1, "One touch point.");
195 assert_equals(ev.changedTouches.length, 1, "One changed touch point.");
196 assert_equals(ev.targetTouches.length, 1, "One target touch point.");
197 }, "touchstart: all TouchList lengths are correct");
198
199 var t = ev.touches[0];
200 var ct = ev.changedTouches[0];
201 var tt = ev.targetTouches[0];
202
203 touchstart_identifier = t.identifier;
204 // TA: 1.3.3.3, 1.3.2.3, 1.3.3.4 (indirect (transitive))
205 test(function() {
206 assert_equals(ct.identifier, touchstart_identifier, "changedTouches identifier matches.");
207 assert_equals(tt.identifier, touchstart_identifier, "targetTouches identifier matches.");
208 }, "touchstart: all TouchList identifiers are consistent");
209
210 // TA: 1.3.3.9
211 test(function() {
212 assert_equals(tt.target, ev.target, "event target same as targetTouches target.");
213 }, "touchstart: event target same as targetTouches target");
214
215 test(function() {
216 assert_true(is_touch_over_element(t, target0), "touch.pageX/pageY is over target0.");
217 }, "touchstart: touch pageX/pageY inside of target element");
218 test(function() {
219 check_touch_clientXY(t);
220 }, "touchstart: touch clientX/clientY is consistent with pageX/pageY");
221 // Note we don't bother testing screenX/screenY values - there's no reliable way to
222 // verify they are consistent with clientX/clientY (due to unknown amount of window
223 // chrome), and also various forms of scaling mean they are in different units.
224 });
225
226 on_event(target0, "touchmove", function onTouchMove(ev) {
227 ev.preventDefault();
228
229 if (touchmove_received)
230 return;
231 touchmove_received = true;
232
233 test_touchmove.step(function() {
234 assert_true(touchstart_received, "touchmove follows touchstart");
235 assert_false(touchend_received, "touchmove precedes touchend");
236 });
237 test_touchmove.done();
238
239 check_TouchEvent(ev);
240
241 // TA: 1.4.2.1, 1.4.3.1
242 test(function() {
243 assert_equals(ev.touches.length, 1, "One touch point.");
244 assert_equals(ev.changedTouches.length, 1, "One changed touch point.");
245 assert_equals(ev.targetTouches.length, 1, "One target touch point.");
246 }, "touchmove: all TouchList lengths are correct");
247
248 // 1.4.2.3, 1.4.3.3, 1.4.3.5, 1.4.4.3
249 test(function() {
250 assert_equals(ev.touches[0].identifier, touchstart_identifier, "Touch identifier matches.");
251 assert_equals(ev.changedTouches[0].identifier, touchstart_identifier, "Changed touch identifier matches.");
252 assert_equals(ev.targetTouches[0].identifier, touchstart_identifier, "Target touch identifier matches.");
253 }, "touchmove: all TouchList identifiers matches touchstart identifier");
254
255 // TA: 1.4.3.8
256 var tt = ev.targetTouches[0];
257 test(function() {
258 assert_equals(tt.target, ev.target, "event target same as targetTouches target.");
259 }, "touchmove: event target same as targetTouches target");
260
261 test(function() {
262 assert_true(is_touch_over_element(tt, target0) || is_touch_over_element(tt, target1),
263 "touch.pageX/pageY is over one of the targets.");
264 }, "touchmove: touch pageX/pageY inside of one of the target elements");
265 test(function() {
266 check_touch_clientXY(tt);
267 }, "touchmove: touch clientX/clientY is consistent with pageX/pageY");
268
269 });
270
271 on_event(target1, "touchmove", function onTouchMove(ev) {
272 invalid_touchmove_received = true;
273 });
274
275 on_event(window, "touchend", function onTouchEnd(ev) {
276 touchend_received = true;
277
278 test_touchend.step(function() {
279 assert_equals(ev.target, target0, "touchend is dispatched to the original target");
280 assert_true(touchstart_received, "touchend follows touchstart");
281 assert_true(touchmove_received, "touchend follows touchmove");
282 assert_false(invalid_touchmove_received, "touchmove dispatched to correct target");
283 });
284 test_touchend.done();
285
286 check_TouchEvent(ev);
287
288 // TA: 1.5.1.2, 1.5.3.1, 1.5.4.1
289 test(function() {
290 assert_equals(ev.touches.length, 0, "Zero touch points.");
291 assert_equals(ev.changedTouches.length, 1, "One changed touch point.");
292 assert_equals(ev.targetTouches.length, 0, "Zero target touch points.");
293 }, "touchend: all TouchList lengths are correct");
294
295 var t = ev.changedTouches[0];
296
297 // TA: 1.5.2.6, 1.5.2.3
298 test(function() {
299 assert_equals(t.identifier, touchstart_identifier, "changedTouches identifier matches.");
300 }, "touchend: touches identifier matches changedTouches identifier");
301
302 test(function() {
303 assert_true(is_touch_over_element(t, target1),
304 "touch.pageX/pageY is over target1.");
305 }, "touchend: touch pageX/pageY inside expected element");
306 test(function() {
307 check_touch_clientXY(t);
308 }, "touchend: touch clientX/clientY is consistent with pageX/pageY");
309
310 done();
311 });
312
313 on_event(target0, "mousedown", function onMouseDown(ev) {
314 test_mousedown.step(function() {
315 assert_true(touchstart_received,
316 "The touchstart event must be dispatched before any mouse " +
317 "events. (If this fails, it might mean that the user agent does " +
318 "not implement W3C touch events at all.)"
319 );
320 });
321 test_mousedown.done();
322
323 if (!touchstart_received) {
324 // Abort the tests. If touch events are not supported, then most of
325 // the other event handlers will never be called, and the test will
326 // time out with misleading results.
327 done();
328 }
329 });
330 }
331 </script>
332 <style>
333 div {
334 margin: 0em;
335 padding: 2em;
336 }
337 #target0 {
338 background: yellow;
339 border: 1px solid orange;
340 }
341 #target1 {
342 background: lightblue;
343 border: 1px solid blue;
344 }
345 </style>
346</head>
347<body onload="run()">
348 <h1>Touch Events: single-touch tests</h1>
349 <div id="target0">
350 Touch this box with one finger (or other pointing device)...
351 </div>
352 <div id="target1">
353 ...then drag to this box and lift your finger.
354 </div>
355 <div id="log"></div>
356</body>
357</html>