2 * mobile event unit tests
6 var libName = "jquery.mobile.event.js",
8 originalEventFn = $.Event.prototype.originalEvent,
9 preventDefaultFn = $.Event.prototype.preventDefault,
10 events = ("touchstart touchmove touchend orientationchange tap taphold " +
11 "swipe swipeleft swiperight scrollstart scrollstop").split( " " );
16 // ensure bindings are removed
17 $.each(events + "vmouseup vmousedown".split(" "), function(i, name){
18 $("#qunit-fixture").unbind();
23 $.Event.prototype.originalEvent = originalEventFn;
24 $.Event.prototype.preventDefault = preventDefaultFn;
26 // make sure the event objects respond to touches to simulate
27 // the collections existence in non touch enabled test browsers
28 $.Event.prototype.touches = [{pageX: 1, pageY: 1 }];
30 $($.mobile.pageContainer).unbind( "throttledresize" );
34 $.testHelper.excludeFileProtocol(function(){
35 test( "new events defined on the jquery object", function(){
36 $.each(events, function( i, name ) {
38 same($.fn[name], undefined);
41 $.testHelper.reloadLib(libName);
43 $.each(events, function( i, name ) {
44 ok($.fn[name] !== undefined, name + " is not undefined");
49 asyncTest( "defined event functions bind a closure when passed", function(){
52 $('#qunit-fixture').bind(events[0], function(){
53 ok(true, "event fired");
57 $('#qunit-fixture').trigger(events[0]);
60 asyncTest( "defined event functions trigger the event with no arguments", function(){
63 $('#qunit-fixture').bind('touchstart', function(){
64 ok(true, "event fired");
68 $('#qunit-fixture').touchstart();
71 test( "defining event functions sets the attrFn to true", function(){
72 $.each(events, function(i, name){
73 ok($.attrFn[name], "attribute function is true");
77 test( "scrollstart enabled defaults to true", function(){
78 $.event.special.scrollstart.enabled = false;
79 $.testHelper.reloadLib(libName);
80 ok($.event.special.scrollstart.enabled, "scrollstart enabled");
83 asyncTest( "scrollstart setup binds a function that returns when its disabled", function(){
85 $.event.special.scrollstart.enabled = false;
87 $( "#qunit-fixture" ).bind("scrollstart", function(){
88 ok(false, "scrollstart fired");
91 $( "#qunit-fixture" ).bind("touchmove", function(){
92 ok(true, "touchmove fired");
96 $( "#qunit-fixture" ).trigger("touchmove");
99 asyncTest( "scrollstart setup binds a function that triggers scroll start when enabled", function(){
100 $.event.special.scrollstart.enabled = true;
102 $( "#qunit-fixture" ).bind("scrollstart", function(){
103 ok(true, "scrollstart fired");
107 $( "#qunit-fixture" ).trigger("touchmove");
110 asyncTest( "scrollstart setup binds a function that triggers scroll stop after 50 ms", function(){
111 var triggered = false;
112 $.event.special.scrollstart.enabled = true;
114 $( "#qunit-fixture" ).bind("scrollstop", function(){
118 ok(!triggered, "not triggered");
120 $( "#qunit-fixture" ).trigger("touchmove");
122 setTimeout(function(){
123 ok(triggered, "triggered");
128 var forceTouchSupport = function(){
129 $.support.touch = true;
130 $.testHelper.reloadLib(libName);
132 //mock originalEvent information
133 $.Event.prototype.originalEvent = {
134 touches: [{ 'pageX' : 0 }, { 'pageY' : 0 }]
138 asyncTest( "long press fires tap hold after 750 ms", function(){
143 $( "#qunit-fixture" ).bind("taphold", function(){
147 $( "#qunit-fixture" ).trigger("vmousedown");
149 setTimeout(function(){
155 //NOTE used to simulate movement when checked
156 //TODO find a better way ...
157 var mockAbs = function(value){
158 Math.abs = function(){
163 asyncTest( "move prevents taphold", function(){
170 //NOTE record taphold event
171 $( "#qunit-fixture" ).bind("taphold", function(){
172 ok(false, "taphold fired");
176 //NOTE start the touch events
177 $( "#qunit-fixture" ).trigger("vmousedown");
179 //NOTE fire touchmove to push back taphold
180 setTimeout(function(){
181 $( "#qunit-fixture" ).trigger("vmousecancel");
184 //NOTE verify that the taphold hasn't been fired
185 // with the normal timing
186 setTimeout(function(){
187 ok(!taphold, "taphold not fired");
192 asyncTest( "tap event fired without movement", function(){
195 checkTap = function(){
196 ok(true, "tap fired");
201 //NOTE record the tap event
202 $( "#qunit-fixture" ).bind("tap", checkTap);
204 $( "#qunit-fixture" ).trigger("vmousedown");
205 $( "#qunit-fixture" ).trigger("vmouseup");
206 $( "#qunit-fixture" ).trigger("vclick");
208 setTimeout(function(){
213 asyncTest( "tap event not fired when there is movement", function(){
218 //NOTE record tap event
219 $( "#qunit-fixture" ).bind("tap", function(){
220 ok(false, "tap fired");
224 //NOTE make sure movement is recorded
227 //NOTE start and move right away
228 $( "#qunit-fixture" ).trigger("touchstart");
229 $( "#qunit-fixture" ).trigger("touchmove");
231 //NOTE end touch sequence after 20 ms
232 setTimeout(function(){
233 $( "#qunit-fixture" ).trigger("touchend");
236 setTimeout(function(){
237 ok(!tap, "not tapped");
242 asyncTest( "tap event propagates up DOM tree", function(){
244 $qf = $( "#qunit-fixture" ),
245 $doc = $( document ),
246 docTapCB = function(){
247 same(++tap, 2, "document tap callback called once after #qunit-fixture callback");
250 $qf.bind( "tap", function() {
251 same(++tap, 1, "#qunit-fixture tap callback called once");
254 $doc.bind( "tap", docTapCB );
256 $qf.trigger( "vmousedown" )
257 .trigger( "vmouseup" )
258 .trigger( "vclick" );
260 // tap binding should be triggered twice, once for
261 // #qunit-fixture, and a second time for document.
262 same( tap, 2, "final tap callback count is 2" );
264 $doc.unbind( "tap", docTapCB );
269 asyncTest( "stopPropagation() prevents tap from propagating up DOM tree", function(){
271 $qf = $( "#qunit-fixture" ),
272 $doc = $( document ),
273 docTapCB = function(){
274 ok(false, "tap should NOT be triggered on document");
277 $qf.bind( "tap", function(e) {
278 same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
281 .bind( "tap", function(e) {
282 same(++tap, 2, "tap callback 2 triggered once on #qunit-fixture");
285 $doc.bind( "tap", docTapCB);
287 $qf.trigger( "vmousedown" )
288 .trigger( "vmouseup" )
289 .trigger( "vclick" );
291 // tap binding should be triggered twice.
292 same( tap, 2, "final tap count is 2" );
294 $doc.unbind( "tap", docTapCB );
299 asyncTest( "stopImmediatePropagation() prevents tap propagation and execution of 2nd handler", function(){
301 $cf = $( "#qunit-fixture" );
302 $doc = $( document ),
303 docTapCB = function(){
304 ok(false, "tap should NOT be triggered on document");
307 // Bind 2 tap callbacks on qunit-fixture. Only the first
308 // one should ever be called.
309 $cf.bind( "tap", function(e) {
310 same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
311 e.stopImmediatePropagation();
313 .bind( "tap", function(e) {
314 ok(false, "tap callback 2 should NOT be triggered on #qunit-fixture");
317 $doc.bind( "tap", docTapCB);
319 $cf.trigger( "vmousedown" )
320 .trigger( "vmouseup" )
321 .trigger( "vclick" );
323 // tap binding should be triggered once.
324 same( tap, 1, "final tap count is 1" );
326 $doc.unbind( "tap", docTapCB );
331 var swipeTimedTest = function(opts){
336 $( "#qunit-fixture" ).bind('swipe', function(){
340 //NOTE bypass the trigger source check
341 $.Event.prototype.originalEvent = {
345 $( "#qunit-fixture" ).trigger("touchstart");
347 //NOTE make sure the coordinates are calculated within range
348 // to be registered as a swipe
349 mockAbs(opts.coordChange);
351 setTimeout(function(){
352 $( "#qunit-fixture" ).trigger("touchmove");
353 $( "#qunit-fixture" ).trigger("touchend");
354 }, opts.timeout + 100);
356 setTimeout(function(){
357 same(swipe, opts.expected, "swipe expected");
359 }, opts.timeout + 200);
364 test( "swipe fired when coordinate change in less than a second", function(){
365 swipeTimedTest({ timeout: 10, coordChange: 35, expected: true });
368 test( "swipe not fired when coordinate change takes more than a second", function(){
369 swipeTimedTest({ timeout: 1000, coordChange: 35, expected: false });
372 test( "swipe not fired when coordinate change <= 30", function(){
373 swipeTimedTest({ timeout: 1000, coordChange: 30, expected: false });
376 test( "swipe not fired when coordinate change >= 75", function(){
377 swipeTimedTest({ timeout: 1000, coordChange: 75, expected: false });
380 asyncTest( "scrolling prevented when coordinate change > 10", function(){
385 // ensure the swipe custome event is setup
386 $( "#qunit-fixture" ).bind('swipe', function(){});
388 //NOTE bypass the trigger source check
389 $.Event.prototype.originalEvent = {
393 $.Event.prototype.preventDefault = function(){
394 ok(true, "prevent default called");
400 $( "#qunit-fixture" ).trigger("touchstart");
401 $( "#qunit-fixture" ).trigger("touchmove");
404 asyncTest( "move handler returns when touchstart has been fired since touchstop", function(){
407 // bypass triggered event check
408 $.Event.prototype.originalEvent = {
414 // ensure the swipe custome event is setup
415 $( "#qunit-fixture" ).bind('swipe', function(){});
417 $( "#qunit-fixture" ).trigger("touchstart");
418 $( "#qunit-fixture" ).trigger("touchend");
420 $( "#qunit-fixture" ).bind("touchmove", function(){
421 ok(true, "touchmove bound functions are fired");
425 Math.abs = function(){
426 ok(false, "shouldn't compare coordinates");
429 $( "#qunit-fixture" ).trigger("touchmove");
432 var nativeSupportTest = function(opts){
433 $.support.orientation = opts.orientationSupport;
434 same($.event.special.orientationchange[opts.method](), opts.returnValue);
437 test( "orientation change setup should do nothing when natively supported", function(){
440 orientationSupport: true,
445 test( "orientation change setup should bind resize when not supported natively", function(){
448 orientationSupport: false,
449 returnValue: undefined //NOTE result of bind function call
453 test( "orientation change teardown should do nothing when natively supported", function(){
456 orientationSupport: true,
461 test( "orientation change teardown should unbind resize when not supported natively", function(){
464 orientationSupport: false,
465 returnValue: undefined //NOTE result of unbind function call
469 /* The following 4 tests are async so that the throttled event triggers don't interfere with subsequent tests */
471 asyncTest( "throttledresize event proxies resize events", function(){
472 $( window ).one( "throttledresize", function(){
473 ok( true, "throttledresize called");
477 $( window ).trigger( "resize" );
480 asyncTest( "throttledresize event prevents resize events from firing more frequently than 250ms", function(){
483 $(window).bind( "throttledresize", function(){
487 // NOTE 250 ms * 3 = 750ms which is plenty of time
488 // for the events to trigger before the next test, but
489 // not so much time that the second resize will be triggered
490 // before the call to same() is made
491 $.testHelper.sequence([
493 $(window).trigger( "resize" ).trigger( "resize" );
496 // verify that only one throttled resize was called after 250ms
497 function(){ same( called, 1 ); },
505 asyncTest( "throttledresize event promises that a held call will execute only once after throttled timeout", function(){
510 $.testHelper.eventSequence( "throttledresize", [
511 // ignore the first call
515 ok( true, "second throttled resize should run" );
519 ok( timedOut, "third throttled resize should not run");
524 $.mobile.pageContainer
527 .trigger( "resize" );
530 asyncTest( "mousedown mouseup and click events should add a which when its not defined", function() {
531 var whichDefined = function( event ){
532 same(event.which, 1);
535 $( document ).bind( "vclick", whichDefined);
536 $( document ).trigger( "click" );
538 $( document ).bind( "vmousedown", whichDefined);
539 $( document ).trigger( "mousedown" );
541 $( document ).bind( "vmouseup", function( event ){
542 same(event.which, 1);
546 $( document ).trigger( "mouseup" );