PageRenderTime 26ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/unit/event/event_core.js

https://github.com/dannyc/jquery-mobile
JavaScript | 548 lines | 381 code | 127 blank | 40 comment | 0 complexity | e1ed099cdd379f9d463e839522c47f6e MD5 | raw file
  1. /*
  2. * mobile event unit tests
  3. */
  4. (function($){
  5. var libName = "jquery.mobile.event.js",
  6. absFn = Math.abs,
  7. originalEventFn = $.Event.prototype.originalEvent,
  8. preventDefaultFn = $.Event.prototype.preventDefault,
  9. events = ("touchstart touchmove touchend orientationchange tap taphold " +
  10. "swipe swipeleft swiperight scrollstart scrollstop").split( " " );
  11. module(libName, {
  12. setup: function(){
  13. // ensure bindings are removed
  14. $.each(events + "vmouseup vmousedown".split(" "), function(i, name){
  15. $("#qunit-fixture").unbind();
  16. });
  17. //NOTE unmock
  18. Math.abs = absFn;
  19. $.Event.prototype.originalEvent = originalEventFn;
  20. $.Event.prototype.preventDefault = preventDefaultFn;
  21. // make sure the event objects respond to touches to simulate
  22. // the collections existence in non touch enabled test browsers
  23. $.Event.prototype.touches = [{pageX: 1, pageY: 1 }];
  24. $($.mobile.pageContainer).unbind( "throttledresize" );
  25. }
  26. });
  27. $.testHelper.excludeFileProtocol(function(){
  28. test( "new events defined on the jquery object", function(){
  29. $.each(events, function( i, name ) {
  30. delete $.fn[name];
  31. same($.fn[name], undefined);
  32. });
  33. $.testHelper.reloadLib(libName);
  34. $.each(events, function( i, name ) {
  35. ok($.fn[name] !== undefined, name + " is not undefined");
  36. });
  37. });
  38. });
  39. asyncTest( "defined event functions bind a closure when passed", function(){
  40. expect( 1 );
  41. $('#qunit-fixture').bind(events[0], function(){
  42. ok(true, "event fired");
  43. start();
  44. });
  45. $('#qunit-fixture').trigger(events[0]);
  46. });
  47. asyncTest( "defined event functions trigger the event with no arguments", function(){
  48. expect( 1 );
  49. $('#qunit-fixture').bind('touchstart', function(){
  50. ok(true, "event fired");
  51. start();
  52. });
  53. $('#qunit-fixture').touchstart();
  54. });
  55. test( "defining event functions sets the attrFn to true", function(){
  56. $.each(events, function(i, name){
  57. ok($.attrFn[name], "attribute function is true");
  58. });
  59. });
  60. test( "scrollstart enabled defaults to true", function(){
  61. $.event.special.scrollstart.enabled = false;
  62. $.testHelper.reloadLib(libName);
  63. ok($.event.special.scrollstart.enabled, "scrollstart enabled");
  64. });
  65. asyncTest( "scrollstart setup binds a function that returns when its disabled", function(){
  66. expect( 1 );
  67. $.event.special.scrollstart.enabled = false;
  68. $( "#qunit-fixture" ).bind("scrollstart", function(){
  69. ok(false, "scrollstart fired");
  70. });
  71. $( "#qunit-fixture" ).bind("touchmove", function(){
  72. ok(true, "touchmove fired");
  73. start();
  74. });
  75. $( "#qunit-fixture" ).trigger("touchmove");
  76. });
  77. asyncTest( "scrollstart setup binds a function that triggers scroll start when enabled", function(){
  78. $.event.special.scrollstart.enabled = true;
  79. $( "#qunit-fixture" ).bind("scrollstart", function(){
  80. ok(true, "scrollstart fired");
  81. start();
  82. });
  83. $( "#qunit-fixture" ).trigger("touchmove");
  84. });
  85. asyncTest( "scrollstart setup binds a function that triggers scroll stop after 50 ms", function(){
  86. var triggered = false;
  87. $.event.special.scrollstart.enabled = true;
  88. $( "#qunit-fixture" ).bind("scrollstop", function(){
  89. triggered = true;
  90. });
  91. ok(!triggered, "not triggered");
  92. $( "#qunit-fixture" ).trigger("touchmove");
  93. setTimeout(function(){
  94. ok(triggered, "triggered");
  95. start();
  96. }, 50);
  97. });
  98. var forceTouchSupport = function(){
  99. $.support.touch = true;
  100. $.testHelper.reloadLib(libName);
  101. //mock originalEvent information
  102. $.Event.prototype.originalEvent = {
  103. touches: [{ 'pageX' : 0 }, { 'pageY' : 0 }]
  104. };
  105. };
  106. asyncTest( "long press fires tap hold after 750 ms", function(){
  107. var taphold = false;
  108. forceTouchSupport();
  109. $( "#qunit-fixture" ).bind("taphold", function(){
  110. taphold = true;
  111. });
  112. $( "#qunit-fixture" ).trigger("vmousedown");
  113. setTimeout(function(){
  114. ok(taphold);
  115. start();
  116. }, 751);
  117. });
  118. //NOTE used to simulate movement when checked
  119. //TODO find a better way ...
  120. var mockAbs = function(value){
  121. Math.abs = function(){
  122. return value;
  123. };
  124. };
  125. asyncTest( "move prevents taphold", function(){
  126. expect( 1 );
  127. var taphold = false;
  128. forceTouchSupport();
  129. mockAbs(100);
  130. //NOTE record taphold event
  131. $( "#qunit-fixture" ).bind("taphold", function(){
  132. ok(false, "taphold fired");
  133. taphold = true;
  134. });
  135. //NOTE start the touch events
  136. $( "#qunit-fixture" ).trigger("vmousedown");
  137. //NOTE fire touchmove to push back taphold
  138. setTimeout(function(){
  139. $( "#qunit-fixture" ).trigger("vmousecancel");
  140. }, 100);
  141. //NOTE verify that the taphold hasn't been fired
  142. // with the normal timing
  143. setTimeout(function(){
  144. ok(!taphold, "taphold not fired");
  145. start();
  146. }, 751);
  147. });
  148. asyncTest( "tap event fired without movement", function(){
  149. expect( 1 );
  150. var tap = false,
  151. checkTap = function(){
  152. ok(true, "tap fired");
  153. };
  154. forceTouchSupport();
  155. //NOTE record the tap event
  156. $( "#qunit-fixture" ).bind("tap", checkTap);
  157. $( "#qunit-fixture" ).trigger("vmousedown");
  158. $( "#qunit-fixture" ).trigger("vmouseup");
  159. $( "#qunit-fixture" ).trigger("vclick");
  160. setTimeout(function(){
  161. start();
  162. }, 400);
  163. });
  164. asyncTest( "tap event not fired when there is movement", function(){
  165. expect( 1 );
  166. var tap = false;
  167. forceTouchSupport();
  168. //NOTE record tap event
  169. $( "#qunit-fixture" ).bind("tap", function(){
  170. ok(false, "tap fired");
  171. tap = true;
  172. });
  173. //NOTE make sure movement is recorded
  174. mockAbs(100);
  175. //NOTE start and move right away
  176. $( "#qunit-fixture" ).trigger("touchstart");
  177. $( "#qunit-fixture" ).trigger("touchmove");
  178. //NOTE end touch sequence after 20 ms
  179. setTimeout(function(){
  180. $( "#qunit-fixture" ).trigger("touchend");
  181. }, 20);
  182. setTimeout(function(){
  183. ok(!tap, "not tapped");
  184. start();
  185. }, 40);
  186. });
  187. asyncTest( "tap event propagates up DOM tree", function(){
  188. var tap = 0,
  189. $qf = $( "#qunit-fixture" ),
  190. $doc = $( document ),
  191. docTapCB = function(){
  192. same(++tap, 2, "document tap callback called once after #qunit-fixture callback");
  193. };
  194. $qf.bind( "tap", function() {
  195. same(++tap, 1, "#qunit-fixture tap callback called once");
  196. });
  197. $doc.bind( "tap", docTapCB );
  198. $qf.trigger( "vmousedown" )
  199. .trigger( "vmouseup" )
  200. .trigger( "vclick" );
  201. // tap binding should be triggered twice, once for
  202. // #qunit-fixture, and a second time for document.
  203. same( tap, 2, "final tap callback count is 2" );
  204. $doc.unbind( "tap", docTapCB );
  205. start();
  206. });
  207. asyncTest( "stopPropagation() prevents tap from propagating up DOM tree", function(){
  208. var tap = 0,
  209. $qf = $( "#qunit-fixture" ),
  210. $doc = $( document ),
  211. docTapCB = function(){
  212. ok(false, "tap should NOT be triggered on document");
  213. };
  214. $qf.bind( "tap", function(e) {
  215. same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
  216. e.stopPropagation();
  217. })
  218. .bind( "tap", function(e) {
  219. same(++tap, 2, "tap callback 2 triggered once on #qunit-fixture");
  220. });
  221. $doc.bind( "tap", docTapCB);
  222. $qf.trigger( "vmousedown" )
  223. .trigger( "vmouseup" )
  224. .trigger( "vclick" );
  225. // tap binding should be triggered twice.
  226. same( tap, 2, "final tap count is 2" );
  227. $doc.unbind( "tap", docTapCB );
  228. start();
  229. });
  230. asyncTest( "stopImmediatePropagation() prevents tap propagation and execution of 2nd handler", function(){
  231. var tap = 0,
  232. $cf = $( "#qunit-fixture" );
  233. $doc = $( document ),
  234. docTapCB = function(){
  235. ok(false, "tap should NOT be triggered on document");
  236. };
  237. // Bind 2 tap callbacks on qunit-fixture. Only the first
  238. // one should ever be called.
  239. $cf.bind( "tap", function(e) {
  240. same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
  241. e.stopImmediatePropagation();
  242. })
  243. .bind( "tap", function(e) {
  244. ok(false, "tap callback 2 should NOT be triggered on #qunit-fixture");
  245. });
  246. $doc.bind( "tap", docTapCB);
  247. $cf.trigger( "vmousedown" )
  248. .trigger( "vmouseup" )
  249. .trigger( "vclick" );
  250. // tap binding should be triggered once.
  251. same( tap, 1, "final tap count is 1" );
  252. $doc.unbind( "tap", docTapCB );
  253. start();
  254. });
  255. var swipeTimedTest = function(opts){
  256. var swipe = false;
  257. forceTouchSupport();
  258. $( "#qunit-fixture" ).bind('swipe', function(){
  259. swipe = true;
  260. });
  261. //NOTE bypass the trigger source check
  262. $.Event.prototype.originalEvent = {
  263. touches: false
  264. };
  265. $( "#qunit-fixture" ).trigger("touchstart");
  266. //NOTE make sure the coordinates are calculated within range
  267. // to be registered as a swipe
  268. mockAbs(opts.coordChange);
  269. setTimeout(function(){
  270. $( "#qunit-fixture" ).trigger("touchmove");
  271. $( "#qunit-fixture" ).trigger("touchend");
  272. }, opts.timeout + 100);
  273. setTimeout(function(){
  274. same(swipe, opts.expected, "swipe expected");
  275. start();
  276. }, opts.timeout + 200);
  277. stop();
  278. };
  279. test( "swipe fired when coordinate change in less than a second", function(){
  280. swipeTimedTest({ timeout: 10, coordChange: 35, expected: true });
  281. });
  282. test( "swipe not fired when coordinate change takes more than a second", function(){
  283. swipeTimedTest({ timeout: 1000, coordChange: 35, expected: false });
  284. });
  285. test( "swipe not fired when coordinate change <= 30", function(){
  286. swipeTimedTest({ timeout: 1000, coordChange: 30, expected: false });
  287. });
  288. test( "swipe not fired when coordinate change >= 75", function(){
  289. swipeTimedTest({ timeout: 1000, coordChange: 75, expected: false });
  290. });
  291. asyncTest( "scrolling prevented when coordinate change > 10", function(){
  292. expect( 1 );
  293. forceTouchSupport();
  294. // ensure the swipe custome event is setup
  295. $( "#qunit-fixture" ).bind('swipe', function(){});
  296. //NOTE bypass the trigger source check
  297. $.Event.prototype.originalEvent = {
  298. touches: false
  299. };
  300. $.Event.prototype.preventDefault = function(){
  301. ok(true, "prevent default called");
  302. start();
  303. };
  304. mockAbs(11);
  305. $( "#qunit-fixture" ).trigger("touchstart");
  306. $( "#qunit-fixture" ).trigger("touchmove");
  307. });
  308. asyncTest( "move handler returns when touchstart has been fired since touchstop", function(){
  309. expect( 1 );
  310. // bypass triggered event check
  311. $.Event.prototype.originalEvent = {
  312. touches: false
  313. };
  314. forceTouchSupport();
  315. // ensure the swipe custome event is setup
  316. $( "#qunit-fixture" ).bind('swipe', function(){});
  317. $( "#qunit-fixture" ).trigger("touchstart");
  318. $( "#qunit-fixture" ).trigger("touchend");
  319. $( "#qunit-fixture" ).bind("touchmove", function(){
  320. ok(true, "touchmove bound functions are fired");
  321. start();
  322. });
  323. Math.abs = function(){
  324. ok(false, "shouldn't compare coordinates");
  325. };
  326. $( "#qunit-fixture" ).trigger("touchmove");
  327. });
  328. var nativeSupportTest = function(opts){
  329. $.support.orientation = opts.orientationSupport;
  330. same($.event.special.orientationchange[opts.method](), opts.returnValue);
  331. };
  332. test( "orientation change setup should do nothing when natively supported", function(){
  333. nativeSupportTest({
  334. method: 'setup',
  335. orientationSupport: true,
  336. returnValue: false
  337. });
  338. });
  339. test( "orientation change setup should bind resize when not supported natively", function(){
  340. nativeSupportTest({
  341. method: 'setup',
  342. orientationSupport: false,
  343. returnValue: undefined //NOTE result of bind function call
  344. });
  345. });
  346. test( "orientation change teardown should do nothing when natively supported", function(){
  347. nativeSupportTest({
  348. method: 'teardown',
  349. orientationSupport: true,
  350. returnValue: false
  351. });
  352. });
  353. test( "orientation change teardown should unbind resize when not supported natively", function(){
  354. nativeSupportTest({
  355. method: 'teardown',
  356. orientationSupport: false,
  357. returnValue: undefined //NOTE result of unbind function call
  358. });
  359. });
  360. /* The following 4 tests are async so that the throttled event triggers don't interfere with subsequent tests */
  361. asyncTest( "throttledresize event proxies resize events", function(){
  362. $( window ).one( "throttledresize", function(){
  363. ok( true, "throttledresize called");
  364. start();
  365. });
  366. $( window ).trigger( "resize" );
  367. });
  368. asyncTest( "throttledresize event prevents resize events from firing more frequently than 250ms", function(){
  369. var called = 0;
  370. $(window).bind( "throttledresize", function(){
  371. called++;
  372. });
  373. // NOTE 250 ms * 3 = 750ms which is plenty of time
  374. // for the events to trigger before the next test, but
  375. // not so much time that the second resize will be triggered
  376. // before the call to same() is made
  377. $.testHelper.sequence([
  378. function(){
  379. $(window).trigger( "resize" ).trigger( "resize" );
  380. },
  381. // verify that only one throttled resize was called after 250ms
  382. function(){ same( called, 1 ); },
  383. function(){
  384. start();
  385. }
  386. ], 250);
  387. });
  388. asyncTest( "throttledresize event promises that a held call will execute only once after throttled timeout", function(){
  389. var called = 0;
  390. expect( 2 );
  391. $.testHelper.eventSequence( "throttledresize", [
  392. // ignore the first call
  393. $.noop,
  394. function(){
  395. ok( true, "second throttled resize should run" );
  396. },
  397. function(timedOut){
  398. ok( timedOut, "third throttled resize should not run");
  399. start();
  400. }
  401. ]);
  402. $.mobile.pageContainer
  403. .trigger( "resize" )
  404. .trigger( "resize" )
  405. .trigger( "resize" );
  406. });
  407. asyncTest( "mousedown mouseup and click events should add a which when its not defined", function() {
  408. var whichDefined = function( event ){
  409. same(event.which, 1);
  410. };
  411. $( document ).bind( "vclick", whichDefined);
  412. $( document ).trigger( "click" );
  413. $( document ).bind( "vmousedown", whichDefined);
  414. $( document ).trigger( "mousedown" );
  415. $( document ).bind( "vmouseup", function( event ){
  416. same(event.which, 1);
  417. start();
  418. });
  419. $( document ).trigger( "mouseup" );
  420. });
  421. })(jQuery);