ac644f72db63c44e34d8e50f62325c3ab024b055
[platform/framework/web/web-ui-fw.git] / libs / js / jquery-mobile-1.0.1pre / tests / unit / event / event_core.js
1 /*
2  * mobile event unit tests
3  */
4
5 (function($){
6         var libName = "jquery.mobile.event.js",
7                         absFn = Math.abs,
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( " " );
12
13         module(libName, {
14                 setup: function(){
15
16                         // ensure bindings are removed
17                         $.each(events + "vmouseup vmousedown".split(" "), function(i, name){
18                                 $("#qunit-fixture").unbind();
19                         });
20
21                         //NOTE unmock
22                         Math.abs = absFn;
23                         $.Event.prototype.originalEvent = originalEventFn;
24                         $.Event.prototype.preventDefault = preventDefaultFn;
25
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 }];
29
30                         $($.mobile.pageContainer).unbind( "throttledresize" );
31                 }
32         });
33
34         $.testHelper.excludeFileProtocol(function(){
35                 test( "new events defined on the jquery object", function(){
36                         $.each(events, function( i, name ) {
37                                 delete $.fn[name];
38                                 same($.fn[name], undefined);
39                         });
40
41                         $.testHelper.reloadLib(libName);
42
43                         $.each(events, function( i, name ) {
44                                 ok($.fn[name] !== undefined, name + " is not undefined");
45                         });
46                 });
47         });
48
49         asyncTest( "defined event functions bind a closure when passed", function(){
50                 expect( 1 );
51
52                 $('#qunit-fixture').bind(events[0], function(){
53                         ok(true, "event fired");
54                         start();
55                 });
56
57                 $('#qunit-fixture').trigger(events[0]);
58         });
59
60         asyncTest( "defined event functions trigger the event with no arguments", function(){
61                 expect( 1 );
62
63                 $('#qunit-fixture').bind('touchstart', function(){
64                         ok(true, "event fired");
65                         start();
66                 });
67
68                 $('#qunit-fixture').touchstart();
69         });
70
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");
74                 });
75         });
76
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");
81         });
82
83         asyncTest( "scrollstart setup binds a function that returns when its disabled", function(){
84                 expect( 1 );
85                 $.event.special.scrollstart.enabled = false;
86
87                 $( "#qunit-fixture" ).bind("scrollstart", function(){
88                         ok(false, "scrollstart fired");
89                 });
90
91                 $( "#qunit-fixture" ).bind("touchmove", function(){
92                         ok(true, "touchmove fired");
93                         start();
94                 });
95
96                 $( "#qunit-fixture" ).trigger("touchmove");
97         });
98
99         asyncTest( "scrollstart setup binds a function that triggers scroll start when enabled", function(){
100                 $.event.special.scrollstart.enabled = true;
101
102                 $( "#qunit-fixture" ).bind("scrollstart", function(){
103                         ok(true, "scrollstart fired");
104                         start();
105                 });
106
107                 $( "#qunit-fixture" ).trigger("touchmove");
108         });
109
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;
113
114                 $( "#qunit-fixture" ).bind("scrollstop", function(){
115                         triggered = true;
116                 });
117
118                 ok(!triggered, "not triggered");
119
120                 $( "#qunit-fixture" ).trigger("touchmove");
121
122                 setTimeout(function(){
123                         ok(triggered, "triggered");
124                         start();
125                 }, 50);
126         });
127
128         var forceTouchSupport = function(){
129                 $.support.touch = true;
130                 $.testHelper.reloadLib(libName);
131
132                 //mock originalEvent information
133                 $.Event.prototype.originalEvent = {
134                         touches: [{ 'pageX' : 0 }, { 'pageY' : 0 }]
135                 };
136         };
137
138         asyncTest( "long press fires tap hold after 750 ms", function(){
139                 var taphold = false;
140
141                 forceTouchSupport();
142
143                 $( "#qunit-fixture" ).bind("taphold", function(){
144                         taphold = true;
145                 });
146
147                 $( "#qunit-fixture" ).trigger("vmousedown");
148
149                 setTimeout(function(){
150                         ok(taphold);
151                         start();
152                 }, 751);
153         });
154
155         //NOTE used to simulate movement when checked
156         //TODO find a better way ...
157         var mockAbs = function(value){
158                 Math.abs = function(){
159                         return value;
160                 };
161         };
162
163         asyncTest( "move prevents taphold", function(){
164                 expect( 1 );
165                 var taphold = false;
166
167                 forceTouchSupport();
168                 mockAbs(100);
169
170                 //NOTE record taphold event
171                 $( "#qunit-fixture" ).bind("taphold", function(){
172                         ok(false, "taphold fired");
173                         taphold = true;
174                 });
175
176                 //NOTE start the touch events
177                 $( "#qunit-fixture" ).trigger("vmousedown");
178
179                 //NOTE fire touchmove to push back taphold
180                 setTimeout(function(){
181                         $( "#qunit-fixture" ).trigger("vmousecancel");
182                 }, 100);
183
184                 //NOTE verify that the taphold hasn't been fired
185                 //               with the normal timing
186                 setTimeout(function(){
187                         ok(!taphold, "taphold not fired");
188                         start();
189                 }, 751);
190         });
191
192         asyncTest( "tap event fired without movement", function(){
193                 expect( 1 );
194                 var tap = false,
195                                 checkTap = function(){
196                                         ok(true, "tap fired");
197                                 };
198
199                 forceTouchSupport();
200
201                 //NOTE record the tap event
202                 $( "#qunit-fixture" ).bind("tap", checkTap);
203
204                 $( "#qunit-fixture" ).trigger("vmousedown");
205                 $( "#qunit-fixture" ).trigger("vmouseup");
206                 $( "#qunit-fixture" ).trigger("vclick");
207
208                 setTimeout(function(){
209                         start();
210                 }, 400);
211         });
212
213         asyncTest( "tap event not fired when there is movement", function(){
214                 expect( 1 );
215                 var tap = false;
216                 forceTouchSupport();
217
218                 //NOTE record tap event
219                 $( "#qunit-fixture" ).bind("tap", function(){
220                         ok(false, "tap fired");
221                         tap = true;
222                 });
223
224                 //NOTE make sure movement is recorded
225                 mockAbs(100);
226
227                 //NOTE start and move right away
228                 $( "#qunit-fixture" ).trigger("touchstart");
229                 $( "#qunit-fixture" ).trigger("touchmove");
230
231                 //NOTE end touch sequence after 20 ms
232                 setTimeout(function(){
233                         $( "#qunit-fixture" ).trigger("touchend");
234                 }, 20);
235
236                 setTimeout(function(){
237                         ok(!tap, "not tapped");
238                         start();
239                 }, 40);
240         });
241
242         asyncTest( "tap event propagates up DOM tree", function(){
243                 var tap = 0,
244                         $qf = $( "#qunit-fixture" ),
245                         $doc = $( document ),
246                         docTapCB = function(){
247                                 same(++tap, 2, "document tap callback called once after #qunit-fixture callback");
248                         };
249
250                 $qf.bind( "tap", function() {
251                         same(++tap, 1, "#qunit-fixture tap callback called once");
252                 });
253
254                 $doc.bind( "tap", docTapCB );
255
256                 $qf.trigger( "vmousedown" )
257                         .trigger( "vmouseup" )
258                         .trigger( "vclick" );
259
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" );
263
264                 $doc.unbind( "tap", docTapCB );
265
266                 start();
267         });
268
269         asyncTest( "stopPropagation() prevents tap from propagating up DOM tree", function(){
270                 var tap = 0,
271                         $qf = $( "#qunit-fixture" ),
272                         $doc = $( document ),
273                         docTapCB = function(){
274                                 ok(false, "tap should NOT be triggered on document");
275                         };
276
277                 $qf.bind( "tap", function(e) {
278                         same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
279                         e.stopPropagation();
280                 })
281                 .bind( "tap", function(e) {
282                         same(++tap, 2, "tap callback 2 triggered once on #qunit-fixture");
283                 });
284
285                 $doc.bind( "tap", docTapCB);
286
287                 $qf.trigger( "vmousedown" )
288                         .trigger( "vmouseup" )
289                         .trigger( "vclick" );
290
291                 // tap binding should be triggered twice.
292                 same( tap, 2, "final tap count is 2" );
293
294                 $doc.unbind( "tap", docTapCB );
295
296                 start();
297         });
298
299         asyncTest( "stopImmediatePropagation() prevents tap propagation and execution of 2nd handler", function(){
300                 var tap = 0,
301                         $cf = $( "#qunit-fixture" );
302                         $doc = $( document ),
303                         docTapCB = function(){
304                                 ok(false, "tap should NOT be triggered on document");
305                         };
306
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();
312                 })
313                 .bind( "tap", function(e) {
314                         ok(false, "tap callback 2 should NOT be triggered on #qunit-fixture");
315                 });
316
317                 $doc.bind( "tap", docTapCB);
318
319                 $cf.trigger( "vmousedown" )
320                         .trigger( "vmouseup" )
321                         .trigger( "vclick" );
322
323                 // tap binding should be triggered once.
324                 same( tap, 1, "final tap count is 1" );
325
326                 $doc.unbind( "tap", docTapCB );
327
328                 start();
329         });
330
331         var swipeTimedTest = function(opts){
332                 var swipe = false;
333
334                 forceTouchSupport();
335
336                 $( "#qunit-fixture" ).bind('swipe', function(){
337                         swipe = true;
338                 });
339
340                 //NOTE bypass the trigger source check
341                 $.Event.prototype.originalEvent = {
342                         touches: false
343                 };
344
345                 $( "#qunit-fixture" ).trigger("touchstart");
346
347                 //NOTE make sure the coordinates are calculated within range
348                 //               to be registered as a swipe
349                 mockAbs(opts.coordChange);
350
351                 setTimeout(function(){
352                         $( "#qunit-fixture" ).trigger("touchmove");
353                         $( "#qunit-fixture" ).trigger("touchend");
354                 }, opts.timeout + 100);
355
356                 setTimeout(function(){
357                         same(swipe, opts.expected, "swipe expected");
358                         start();
359                 }, opts.timeout + 200);
360
361                 stop();
362         };
363
364         test( "swipe fired when coordinate change in less than a second", function(){
365                 swipeTimedTest({ timeout: 10, coordChange: 35, expected: true });
366         });
367
368         test( "swipe not fired when coordinate change takes more than a second", function(){
369                 swipeTimedTest({ timeout: 1000, coordChange: 35, expected: false });
370         });
371
372         test( "swipe not fired when coordinate change <= 30", function(){
373                 swipeTimedTest({ timeout: 1000, coordChange: 30, expected: false });
374         });
375
376         test( "swipe not fired when coordinate change >= 75", function(){
377                 swipeTimedTest({ timeout: 1000, coordChange: 75, expected: false });
378         });
379
380         asyncTest( "scrolling prevented when coordinate change > 10", function(){
381                 expect( 1 );
382
383                 forceTouchSupport();
384
385                 // ensure the swipe custome event is setup
386                 $( "#qunit-fixture" ).bind('swipe', function(){});
387
388                 //NOTE bypass the trigger source check
389                 $.Event.prototype.originalEvent = {
390                         touches: false
391                 };
392
393                 $.Event.prototype.preventDefault = function(){
394                         ok(true, "prevent default called");
395                         start();
396                 };
397
398                 mockAbs(11);
399
400                 $( "#qunit-fixture" ).trigger("touchstart");
401                 $( "#qunit-fixture" ).trigger("touchmove");
402         });
403
404         asyncTest( "move handler returns when touchstart has been fired since touchstop", function(){
405                 expect( 1 );
406
407                 // bypass triggered event check
408                 $.Event.prototype.originalEvent = {
409                         touches: false
410                 };
411
412                 forceTouchSupport();
413
414                 // ensure the swipe custome event is setup
415                 $( "#qunit-fixture" ).bind('swipe', function(){});
416
417                 $( "#qunit-fixture" ).trigger("touchstart");
418                 $( "#qunit-fixture" ).trigger("touchend");
419
420                 $( "#qunit-fixture" ).bind("touchmove", function(){
421                         ok(true, "touchmove bound functions are fired");
422                         start();
423                 });
424
425                 Math.abs = function(){
426                         ok(false, "shouldn't compare coordinates");
427                 };
428
429                 $( "#qunit-fixture" ).trigger("touchmove");
430         });
431
432         var nativeSupportTest = function(opts){
433                 $.support.orientation = opts.orientationSupport;
434                 same($.event.special.orientationchange[opts.method](), opts.returnValue);
435         };
436
437         test( "orientation change setup should do nothing when natively supported", function(){
438                 nativeSupportTest({
439                         method: 'setup',
440                         orientationSupport: true,
441                         returnValue: false
442                 });
443         });
444
445         test( "orientation change setup should bind resize when not supported natively", function(){
446                 nativeSupportTest({
447                         method: 'setup',
448                         orientationSupport: false,
449                         returnValue: undefined //NOTE result of bind function call
450                 });
451         });
452
453         test( "orientation change teardown should do nothing when natively supported", function(){
454                 nativeSupportTest({
455                         method: 'teardown',
456                         orientationSupport: true,
457                         returnValue: false
458                 });
459         });
460
461         test( "orientation change teardown should unbind resize when not supported natively", function(){
462                 nativeSupportTest({
463                         method: 'teardown',
464                         orientationSupport: false,
465                         returnValue: undefined //NOTE result of unbind function call
466                 });
467         });
468
469         /* The following 4 tests are async so that the throttled event triggers don't interfere with subsequent tests */
470
471         asyncTest( "throttledresize event proxies resize events", function(){
472                 $( window ).one( "throttledresize", function(){
473                         ok( true, "throttledresize called");
474                         start();
475                 });
476
477                 $( window ).trigger( "resize" );
478         });
479
480         asyncTest( "throttledresize event prevents resize events from firing more frequently than 250ms", function(){
481                 var called = 0;
482
483                 $(window).bind( "throttledresize", function(){
484                         called++;
485                 });
486
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([
492                         function(){
493                                 $(window).trigger( "resize" ).trigger( "resize" );
494                         },
495
496                         // verify that only one throttled resize was called after 250ms
497                         function(){ same( called, 1 ); },
498
499                         function(){
500                                 start();
501                         }
502                 ], 250);
503         });
504
505         asyncTest( "throttledresize event promises that a held call will execute only once after throttled timeout", function(){
506                 var called = 0;
507
508                 expect( 2 );
509
510                 $.testHelper.eventSequence( "throttledresize", [
511                         // ignore the first call
512                         $.noop,
513
514                         function(){
515                                 ok( true, "second throttled resize should run" );
516                         },
517
518                         function(timedOut){
519                                 ok( timedOut, "third throttled resize should not run");
520                                 start();
521                         }
522                 ]);
523
524                 $.mobile.pageContainer
525                         .trigger( "resize" )
526                         .trigger( "resize" )
527                         .trigger( "resize" );
528         });
529
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);
533                 };
534
535                 $( document ).bind( "vclick", whichDefined);
536                 $( document ).trigger( "click" );
537
538                 $( document ).bind( "vmousedown", whichDefined);
539                 $( document ).trigger( "mousedown" );
540
541                 $( document ).bind( "vmouseup", function( event ){
542                         same(event.which, 1);
543                         start();
544                 });
545
546                 $( document ).trigger( "mouseup" );
547         });
548 })(jQuery);