2 * mobile event unit tests
6 var libName = "jquery.mobile.events.js",
7 components = [ "events/touch.js", "events/throttledresize.js", "events/orientationchange.js" ],
9 originalEventFn = $.Event.prototype.originalEvent,
10 preventDefaultFn = $.Event.prototype.preventDefault,
11 events = ("touchstart touchmove touchend tap taphold " +
12 "swipe swipeleft swiperight scrollstart scrollstop orientationchange").split( " " );
17 // ensure bindings are removed
18 $.each(events + "vmouseup vmousedown".split(" "), function(i, name){
19 $("#qunit-fixture").unbind();
24 $.Event.prototype.originalEvent = originalEventFn;
25 $.Event.prototype.preventDefault = preventDefaultFn;
27 // make sure the event objects respond to touches to simulate
28 // the collections existence in non touch enabled test browsers
29 $.Event.prototype.touches = [{pageX: 1, pageY: 1 }];
31 $($.mobile.pageContainer).unbind( "throttledresize" );
35 $.testHelper.excludeFileProtocol(function(){
36 test( "new events defined on the jquery object", function(){
37 $.each(events, function( i, name ) {
39 deepEqual($.fn[name], undefined);
42 $.each( components, function( index, value ) { $.testHelper.reloadLib( value ); });
44 $.each(events, function( i, name ) {
45 ok( $.fn[name] !== undefined, name + " should NOT be undefined");
50 asyncTest( "defined event functions bind a closure when passed", function(){
53 $('#qunit-fixture').bind(events[0], function(){
54 ok(true, "event fired");
58 $('#qunit-fixture').trigger(events[0]);
61 asyncTest( "defined event functions trigger the event with no arguments", function(){
64 $('#qunit-fixture').bind('touchstart', function(){
65 ok(true, "event fired");
69 $('#qunit-fixture').touchstart();
74 test( "defining event functions sets the attrFn to true", function(){
75 $.each( events, function( index, name ) {
76 ok( $.attrFn[ name ], "attribute function is true" );
82 test( "scrollstart enabled defaults to true", function(){
83 $.event.special.scrollstart.enabled = false;
84 $.each( components, function( index, value ) { $.testHelper.reloadLib( value ); });
85 ok($.event.special.scrollstart.enabled, "scrollstart enabled");
88 asyncTest( "scrollstart setup binds a function that returns when its disabled", function(){
90 $.event.special.scrollstart.enabled = false;
92 $( "#qunit-fixture" ).bind("scrollstart", function(){
93 ok(false, "scrollstart fired");
96 $( "#qunit-fixture" ).bind("touchmove", function(){
97 ok(true, "touchmove fired");
101 $( "#qunit-fixture" ).trigger("touchmove");
104 asyncTest( "scrollstart setup binds a function that triggers scroll start when enabled", function(){
105 $.event.special.scrollstart.enabled = true;
107 $( "#qunit-fixture" ).bind("scrollstart", function(){
108 ok(true, "scrollstart fired");
112 $( "#qunit-fixture" ).trigger("touchmove");
115 asyncTest( "scrollstart setup binds a function that triggers scroll stop after 50 ms", function(){
116 var triggered = false;
117 $.event.special.scrollstart.enabled = true;
119 $( "#qunit-fixture" ).bind("scrollstop", function(){
123 ok(!triggered, "not triggered");
125 $( "#qunit-fixture" ).trigger("touchmove");
127 setTimeout(function(){
128 ok(triggered, "triggered");
133 var forceTouchSupport = function(){
134 document.ontouchend = function() {};
135 $.testHelper.reloadLib( "jquery.mobile.support.touch.js" );
136 $.each( components, function( index, value ) { $.testHelper.reloadLib( value ); });
138 //mock originalEvent information
139 $.Event.prototype.originalEvent = {
140 touches: [{ 'pageX' : 0 }, { 'pageY' : 0 }]
144 asyncTest( "long press fires tap hold after taphold duration", function(){
150 $( "#qunit-fixture" ).bind("taphold", function( e ){
155 $( "#qunit-fixture" ).trigger("vmousedown");
156 // tapholdThreshold has been changed from 100 to 2000
157 setTimeout(function(){
158 ok( !taphold, "taphold not fired" );
159 deepEqual( target, undefined, "taphold target should be #qunit-fixture!" );
160 }, $.event.special.tap.tapholdThreshold - 2000);
162 setTimeout(function(){
163 ok( taphold, "taphold fired" );
164 equal( target, $( "#qunit-fixture" ).get( 0 ), "taphold target should be #qunit-fixture!" );
166 }, $.event.special.tap.tapholdThreshold + 2000);
169 //NOTE used to simulate movement when checked
170 //TODO find a better way ...
171 var mockAbs = function(value){
172 Math.abs = function(){
177 asyncTest( "move prevents taphold", function(){
184 //NOTE record taphold event
185 $( "#qunit-fixture" ).bind("taphold", function(){
186 ok(false, "taphold fired");
190 //NOTE start the touch events
191 $( "#qunit-fixture" ).trigger("vmousedown");
193 //NOTE fire touchmove to push back taphold
194 setTimeout(function(){
195 $( "#qunit-fixture" ).trigger("vmousecancel");
198 //NOTE verify that the taphold hasn't been fired
199 // with the normal timing
200 setTimeout(function(){
201 ok(!taphold, "taphold not fired");
206 asyncTest( "tap event fired without movement", function(){
209 checkTap = function(){
210 ok(true, "tap fired");
215 //NOTE record the tap event
216 $( "#qunit-fixture" ).bind("tap", checkTap);
218 $( "#qunit-fixture" ).trigger("vmousedown");
219 $( "#qunit-fixture" ).trigger("vmouseup");
220 $( "#qunit-fixture" ).trigger("vclick");
222 setTimeout(function(){
227 asyncTest( "tap event not fired when there is movement", function(){
232 //NOTE record tap event
233 $( "#qunit-fixture" ).bind("tap", function(){
234 ok(false, "tap fired");
238 //NOTE make sure movement is recorded
241 //NOTE start and move right away
242 $( "#qunit-fixture" ).trigger("touchstart");
243 $( "#qunit-fixture" ).trigger("touchmove");
245 //NOTE end touch sequence after 20 ms
246 setTimeout(function(){
247 $( "#qunit-fixture" ).trigger("touchend");
250 setTimeout(function(){
251 ok(!tap, "not tapped");
256 asyncTest( "tap event propagates up DOM tree", function(){
258 $qf = $( "#qunit-fixture" ),
259 $doc = $( document ),
260 docTapCB = function(){
261 deepEqual(++tap, 2, "document tap callback called once after #qunit-fixture callback");
264 $qf.bind( "tap", function() {
265 deepEqual(++tap, 1, "#qunit-fixture tap callback called once");
268 $doc.bind( "tap", docTapCB );
270 $qf.trigger( "vmousedown" )
271 .trigger( "vmouseup" )
272 .trigger( "vclick" );
274 // tap binding should be triggered twice, once for
275 // #qunit-fixture, and a second time for document.
276 deepEqual( tap, 2, "final tap callback count is 2" );
278 $doc.unbind( "tap", docTapCB );
283 asyncTest( "stopPropagation() prevents tap from propagating up DOM tree", function(){
285 $qf = $( "#qunit-fixture" ),
286 $doc = $( document ),
287 docTapCB = function(){
288 ok(false, "tap should NOT be triggered on document");
291 $qf.bind( "tap", function(e) {
292 deepEqual(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
295 .bind( "tap", function(e) {
296 deepEqual(++tap, 2, "tap callback 2 triggered once on #qunit-fixture");
299 $doc.bind( "tap", docTapCB);
301 $qf.trigger( "vmousedown" )
302 .trigger( "vmouseup" )
303 .trigger( "vclick" );
305 // tap binding should be triggered twice.
306 deepEqual( tap, 2, "final tap count is 2" );
308 $doc.unbind( "tap", docTapCB );
313 asyncTest( "stopImmediatePropagation() prevents tap propagation and execution of 2nd handler", function(){
315 $cf = $( "#qunit-fixture" );
316 $doc = $( document ),
317 docTapCB = function(){
318 ok(false, "tap should NOT be triggered on document");
321 // Bind 2 tap callbacks on qunit-fixture. Only the first
322 // one should ever be called.
323 $cf.bind( "tap", function(e) {
324 deepEqual(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
325 e.stopImmediatePropagation();
327 .bind( "tap", function(e) {
328 ok(false, "tap callback 2 should NOT be triggered on #qunit-fixture");
331 $doc.bind( "tap", docTapCB);
333 $cf.trigger( "vmousedown" )
334 .trigger( "vmouseup" )
335 .trigger( "vclick" );
337 // tap binding should be triggered once.
338 deepEqual( tap, 1, "final tap count is 1" );
340 $doc.unbind( "tap", docTapCB );
345 var swipeTimedTest = function(opts){
350 $( "#qunit-fixture" ).bind('swipe', function(){
354 //NOTE bypass the trigger source check
355 $.Event.prototype.originalEvent = {
362 $( "#qunit-fixture" ).trigger("touchstart");
364 //NOTE make sure the coordinates are calculated within range
365 // to be registered as a swipe
366 mockAbs(opts.coordChange);
368 setTimeout(function(){
369 $( "#qunit-fixture" ).trigger("touchmove");
370 $( "#qunit-fixture" ).trigger("touchend");
371 }, opts.timeout + 100);
373 setTimeout(function(){
374 deepEqual(swipe, opts.expected, "swipe expected");
376 }, opts.timeout + 200);
381 test( "swipe fired when coordinate change in less than a second", function(){
382 swipeTimedTest({ timeout: 10, coordChange: 35, expected: true });
385 test( "swipe not fired when coordinate change takes more than a second", function(){
386 swipeTimedTest({ timeout: 1000, coordChange: 35, expected: false });
389 test( "swipe not fired when coordinate change <= 30", function(){
390 swipeTimedTest({ timeout: 1000, coordChange: 30, expected: false });
393 test( "swipe not fired when coordinate change >= 75", function(){
394 swipeTimedTest({ timeout: 1000, coordChange: 75, expected: false });
397 asyncTest( "scrolling prevented when coordinate change > 10", function(){
402 // ensure the swipe custome event is setup
403 $( "#qunit-fixture" ).bind('swipe', function(){});
405 $.Event.prototype.preventDefault = function(){
406 ok(true, "prevent default called");
410 //NOTE bypass the trigger source check
411 $.Event.prototype.originalEvent = {
418 $( "#qunit-fixture" ).trigger("touchstart");
420 //NOTE bypass the trigger source check
421 $.Event.prototype.originalEvent = {
428 $( "#qunit-fixture" ).trigger("touchmove");
431 asyncTest( "move handler returns when touchstart has been fired since touchstop", function(){
434 // bypass triggered event check
435 $.Event.prototype.originalEvent = {
441 // ensure the swipe custome event is setup
442 $( "#qunit-fixture" ).bind('swipe', function(){});
444 $( "#qunit-fixture" ).trigger("touchstart");
445 $( "#qunit-fixture" ).trigger("touchend");
447 $( "#qunit-fixture" ).bind("touchmove", function(){
448 ok(true, "touchmove bound functions are fired");
452 Math.abs = function(){
453 ok(false, "shouldn't compare coordinates");
456 $( "#qunit-fixture" ).trigger("touchmove");
459 var nativeSupportTest = function(opts){
460 $.support.orientation = opts.orientationSupport;
461 deepEqual($.event.special.orientationchange[opts.method](), opts.returnValue);
464 test( "orientation change setup should do nothing when natively supported", function(){
467 orientationSupport: true,
472 test( "orientation change setup should bind resize when not supported natively", function(){
475 orientationSupport: false,
476 returnValue: undefined //NOTE result of bind function call
480 test( "orientation change teardown should do nothing when natively supported", function(){
483 orientationSupport: true,
488 test( "orientation change teardown should unbind resize when not supported natively", function(){
491 orientationSupport: false,
492 returnValue: undefined //NOTE result of unbind function call
496 /* The following 4 tests are async so that the throttled event triggers don't interfere with subsequent tests */
498 asyncTest( "throttledresize event proxies resize events", function(){
499 $( window ).one( "throttledresize", function(){
500 ok( true, "throttledresize called");
504 $( window ).trigger( "resize" );
507 asyncTest( "throttledresize event prevents resize events from firing more frequently than one per 250ms", function(){
510 $(window).bind( "throttledresize", function(){
514 // NOTE 400 ms between two triggers and the check for one callback
515 // is enough time for the first to fire but not enough for a second
516 $.testHelper.sequence([
518 $(window).trigger( "resize" ).trigger( "resize" );
521 // verify that only one throttled resize was called after 250ms
522 function(){ deepEqual( called, 1 ); },
530 asyncTest( "throttledresize event promises that a held call will execute only once after throttled timeout", function(){
535 $.testHelper.eventSequence( "throttledresize", [
536 // ignore the first call
540 ok( true, "second throttled resize should run" );
544 ok( timedOut, "third throttled resize should not run");
549 $.mobile.pageContainer
552 .trigger( "resize" );
555 asyncTest( "mousedown mouseup and click events should add a which when its not defined", function() {
556 var whichDefined = function( event ){
557 deepEqual(event.which, 1);
560 $( document ).bind( "vclick", whichDefined);
561 $( document ).trigger( "click" );
563 $( document ).bind( "vmousedown", whichDefined);
564 $( document ).trigger( "mousedown" );
566 $( document ).bind( "vmouseup", function( event ){
567 deepEqual(event.which, 1);
571 $( document ).trigger( "mouseup" );