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(){
144 $( "#qunit-fixture" ).bind("taphold", function( e ){
149 $( "#qunit-fixture" ).trigger("vmousedown");
151 setTimeout(function(){
153 equal( target, $( "#qunit-fixture" ).get( 0 ), "taphold target should be #qunit-fixture" );
158 //NOTE used to simulate movement when checked
159 //TODO find a better way ...
160 var mockAbs = function(value){
161 Math.abs = function(){
166 asyncTest( "move prevents taphold", function(){
173 //NOTE record taphold event
174 $( "#qunit-fixture" ).bind("taphold", function(){
175 ok(false, "taphold fired");
179 //NOTE start the touch events
180 $( "#qunit-fixture" ).trigger("vmousedown");
182 //NOTE fire touchmove to push back taphold
183 setTimeout(function(){
184 $( "#qunit-fixture" ).trigger("vmousecancel");
187 //NOTE verify that the taphold hasn't been fired
188 // with the normal timing
189 setTimeout(function(){
190 ok(!taphold, "taphold not fired");
195 asyncTest( "tap event fired without movement", function(){
198 checkTap = function(){
199 ok(true, "tap fired");
204 //NOTE record the tap event
205 $( "#qunit-fixture" ).bind("tap", checkTap);
207 $( "#qunit-fixture" ).trigger("vmousedown");
208 $( "#qunit-fixture" ).trigger("vmouseup");
209 $( "#qunit-fixture" ).trigger("vclick");
211 setTimeout(function(){
216 asyncTest( "tap event not fired when there is movement", function(){
221 //NOTE record tap event
222 $( "#qunit-fixture" ).bind("tap", function(){
223 ok(false, "tap fired");
227 //NOTE make sure movement is recorded
230 //NOTE start and move right away
231 $( "#qunit-fixture" ).trigger("touchstart");
232 $( "#qunit-fixture" ).trigger("touchmove");
234 //NOTE end touch sequence after 20 ms
235 setTimeout(function(){
236 $( "#qunit-fixture" ).trigger("touchend");
239 setTimeout(function(){
240 ok(!tap, "not tapped");
245 asyncTest( "tap event propagates up DOM tree", function(){
247 $qf = $( "#qunit-fixture" ),
248 $doc = $( document ),
249 docTapCB = function(){
250 same(++tap, 2, "document tap callback called once after #qunit-fixture callback");
253 $qf.bind( "tap", function() {
254 same(++tap, 1, "#qunit-fixture tap callback called once");
257 $doc.bind( "tap", docTapCB );
259 $qf.trigger( "vmousedown" )
260 .trigger( "vmouseup" )
261 .trigger( "vclick" );
263 // tap binding should be triggered twice, once for
264 // #qunit-fixture, and a second time for document.
265 same( tap, 2, "final tap callback count is 2" );
267 $doc.unbind( "tap", docTapCB );
272 asyncTest( "stopPropagation() prevents tap from propagating up DOM tree", function(){
274 $qf = $( "#qunit-fixture" ),
275 $doc = $( document ),
276 docTapCB = function(){
277 ok(false, "tap should NOT be triggered on document");
280 $qf.bind( "tap", function(e) {
281 same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
284 .bind( "tap", function(e) {
285 same(++tap, 2, "tap callback 2 triggered once on #qunit-fixture");
288 $doc.bind( "tap", docTapCB);
290 $qf.trigger( "vmousedown" )
291 .trigger( "vmouseup" )
292 .trigger( "vclick" );
294 // tap binding should be triggered twice.
295 same( tap, 2, "final tap count is 2" );
297 $doc.unbind( "tap", docTapCB );
302 asyncTest( "stopImmediatePropagation() prevents tap propagation and execution of 2nd handler", function(){
304 $cf = $( "#qunit-fixture" );
305 $doc = $( document ),
306 docTapCB = function(){
307 ok(false, "tap should NOT be triggered on document");
310 // Bind 2 tap callbacks on qunit-fixture. Only the first
311 // one should ever be called.
312 $cf.bind( "tap", function(e) {
313 same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
314 e.stopImmediatePropagation();
316 .bind( "tap", function(e) {
317 ok(false, "tap callback 2 should NOT be triggered on #qunit-fixture");
320 $doc.bind( "tap", docTapCB);
322 $cf.trigger( "vmousedown" )
323 .trigger( "vmouseup" )
324 .trigger( "vclick" );
326 // tap binding should be triggered once.
327 same( tap, 1, "final tap count is 1" );
329 $doc.unbind( "tap", docTapCB );
334 var swipeTimedTest = function(opts){
339 $( "#qunit-fixture" ).bind('swipe', function(){
343 //NOTE bypass the trigger source check
344 $.Event.prototype.originalEvent = {
348 $( "#qunit-fixture" ).trigger("touchstart");
350 //NOTE make sure the coordinates are calculated within range
351 // to be registered as a swipe
352 mockAbs(opts.coordChange);
354 setTimeout(function(){
355 $( "#qunit-fixture" ).trigger("touchmove");
356 $( "#qunit-fixture" ).trigger("touchend");
357 }, opts.timeout + 100);
359 setTimeout(function(){
360 same(swipe, opts.expected, "swipe expected");
362 }, opts.timeout + 200);
367 test( "swipe fired when coordinate change in less than a second", function(){
368 swipeTimedTest({ timeout: 10, coordChange: 35, expected: true });
371 test( "swipe not fired when coordinate change takes more than a second", function(){
372 swipeTimedTest({ timeout: 1000, coordChange: 35, expected: false });
375 test( "swipe not fired when coordinate change <= 30", function(){
376 swipeTimedTest({ timeout: 1000, coordChange: 30, expected: false });
379 test( "swipe not fired when coordinate change >= 75", function(){
380 swipeTimedTest({ timeout: 1000, coordChange: 75, expected: false });
383 asyncTest( "scrolling prevented when coordinate change > 10", function(){
388 // ensure the swipe custome event is setup
389 $( "#qunit-fixture" ).bind('swipe', function(){});
391 //NOTE bypass the trigger source check
392 $.Event.prototype.originalEvent = {
396 $.Event.prototype.preventDefault = function(){
397 ok(true, "prevent default called");
403 $( "#qunit-fixture" ).trigger("touchstart");
404 $( "#qunit-fixture" ).trigger("touchmove");
407 asyncTest( "move handler returns when touchstart has been fired since touchstop", function(){
410 // bypass triggered event check
411 $.Event.prototype.originalEvent = {
417 // ensure the swipe custome event is setup
418 $( "#qunit-fixture" ).bind('swipe', function(){});
420 $( "#qunit-fixture" ).trigger("touchstart");
421 $( "#qunit-fixture" ).trigger("touchend");
423 $( "#qunit-fixture" ).bind("touchmove", function(){
424 ok(true, "touchmove bound functions are fired");
428 Math.abs = function(){
429 ok(false, "shouldn't compare coordinates");
432 $( "#qunit-fixture" ).trigger("touchmove");
435 var nativeSupportTest = function(opts){
436 $.support.orientation = opts.orientationSupport;
437 same($.event.special.orientationchange[opts.method](), opts.returnValue);
440 test( "orientation change setup should do nothing when natively supported", function(){
443 orientationSupport: true,
448 test( "orientation change setup should bind resize when not supported natively", function(){
451 orientationSupport: false,
452 returnValue: undefined //NOTE result of bind function call
456 test( "orientation change teardown should do nothing when natively supported", function(){
459 orientationSupport: true,
464 test( "orientation change teardown should unbind resize when not supported natively", function(){
467 orientationSupport: false,
468 returnValue: undefined //NOTE result of unbind function call
472 /* The following 4 tests are async so that the throttled event triggers don't interfere with subsequent tests */
474 asyncTest( "throttledresize event proxies resize events", function(){
475 $( window ).one( "throttledresize", function(){
476 ok( true, "throttledresize called");
480 $( window ).trigger( "resize" );
483 asyncTest( "throttledresize event prevents resize events from firing more frequently than 250ms", function(){
486 $(window).bind( "throttledresize", function(){
490 // NOTE 250 ms * 3 = 750ms which is plenty of time
491 // for the events to trigger before the next test, but
492 // not so much time that the second resize will be triggered
493 // before the call to same() is made
494 $.testHelper.sequence([
496 $(window).trigger( "resize" ).trigger( "resize" );
499 // verify that only one throttled resize was called after 250ms
500 function(){ same( called, 1 ); },
508 asyncTest( "throttledresize event promises that a held call will execute only once after throttled timeout", function(){
513 $.testHelper.eventSequence( "throttledresize", [
514 // ignore the first call
518 ok( true, "second throttled resize should run" );
522 ok( timedOut, "third throttled resize should not run");
527 $.mobile.pageContainer
530 .trigger( "resize" );
533 asyncTest( "mousedown mouseup and click events should add a which when its not defined", function() {
534 var whichDefined = function( event ){
535 same(event.which, 1);
538 $( document ).bind( "vclick", whichDefined);
539 $( document ).trigger( "click" );
541 $( document ).bind( "vmousedown", whichDefined);
542 $( document ).trigger( "mousedown" );
544 $( document ).bind( "vmouseup", function( event ){
545 same(event.which, 1);
549 $( document ).trigger( "mouseup" );