Нет описания

tween.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. ( function() {
  2. // Can't test what ain't there
  3. if ( !jQuery.fx ) {
  4. return;
  5. }
  6. var oldRaf = window.requestAnimationFrame;
  7. QUnit.module( "tween", {
  8. beforeEach: function() {
  9. window.requestAnimationFrame = null;
  10. this.sandbox = sinon.sandbox.create();
  11. this.clock = this.sandbox.useFakeTimers( 505877050 );
  12. this._oldInterval = jQuery.fx.interval;
  13. jQuery.fx.step = {};
  14. jQuery.fx.interval = 10;
  15. },
  16. afterEach: function() {
  17. this.sandbox.restore();
  18. jQuery.fx.stop();
  19. jQuery.fx.interval = this._oldInterval;
  20. window.requestAnimationFrame = oldRaf;
  21. return moduleTeardown.apply( this, arguments );
  22. }
  23. } );
  24. QUnit.test( "jQuery.Tween - Default propHooks on plain objects", function( assert ) {
  25. assert.expect( 8 );
  26. var propHooks, defaultHook, testObject, fakeTween, stepSpy;
  27. propHooks = jQuery.Tween.propHooks;
  28. assert.equal( typeof propHooks, "object", "jQuery.Tween.propHooks exists" );
  29. defaultHook = propHooks._default;
  30. assert.ok( defaultHook, "_default propHook exists" );
  31. testObject = { test: 0 };
  32. fakeTween = { elem: testObject, prop: "test", now: 10, unit: "px" };
  33. assert.equal( defaultHook.get( fakeTween ), 0, "Can get property of object" );
  34. fakeTween.prop = "testMissing";
  35. assert.equal( defaultHook.get( fakeTween ), undefined, "Can get missing property on object" );
  36. defaultHook.set( fakeTween );
  37. assert.equal( testObject.testMissing, 10, "Sets missing value properly on plain object" );
  38. fakeTween.prop = "opacity";
  39. defaultHook.set( fakeTween );
  40. assert.equal( testObject.opacity, 10, "Correctly set opacity on plain object" );
  41. fakeTween.prop = "test";
  42. stepSpy = jQuery.fx.step.test = this.sandbox.spy();
  43. defaultHook.set( fakeTween );
  44. assert.ok( stepSpy.calledWith( fakeTween ), "Step function called with Tween" );
  45. assert.equal( testObject.test, 0, "Because step didn't set, value is unchanged" );
  46. } );
  47. QUnit.test( "jQuery.Tween - Default propHooks on elements", function( assert ) {
  48. assert.expect( 19 );
  49. var propHooks, defaultHook, testElement, fakeTween, cssStub, styleStub, stepSpy;
  50. propHooks = jQuery.Tween.propHooks;
  51. assert.equal( typeof propHooks, "object", "jQuery.Tween.propHooks exists" );
  52. defaultHook = propHooks._default;
  53. assert.ok( defaultHook, "_default propHook exists" );
  54. testElement = jQuery( "<div>" )[ 0 ];
  55. fakeTween = { elem: testElement, prop: "height", now: 10, unit: "px" };
  56. cssStub = this.sandbox.stub( jQuery, "css" ).returns( 10 );
  57. assert.equal( defaultHook.get( fakeTween ), 10, "Gets expected style value" );
  58. assert.ok( cssStub.calledWith( testElement, "height", "" ), "Calls jQuery.css correctly" );
  59. fakeTween.prop = "testOpti";
  60. testElement.testOpti = 15;
  61. cssStub.resetHistory();
  62. assert.equal( defaultHook.get( fakeTween ), 15, "Gets expected value not defined on style" );
  63. assert.equal( cssStub.callCount, 0, "Did not call jQuery.css" );
  64. fakeTween.prop = "testMissing";
  65. assert.equal( defaultHook.get( fakeTween ), 10, "Can get missing property on element" );
  66. assert.ok( cssStub.calledWith( testElement, "testMissing", "" ), "...using jQuery.css" );
  67. cssStub.returns( "" );
  68. assert.equal( defaultHook.get( fakeTween ), 0, "Uses 0 for empty string" );
  69. cssStub.returns( "auto" );
  70. assert.equal( defaultHook.get( fakeTween ), 0, "Uses 0 for 'auto'" );
  71. cssStub.returns( null );
  72. assert.equal( defaultHook.get( fakeTween ), 0, "Uses 0 for null" );
  73. cssStub.returns( undefined );
  74. assert.equal( defaultHook.get( fakeTween ), 0, "Uses 0 for undefined" );
  75. cssStub.resetHistory();
  76. // Setters
  77. styleStub = this.sandbox.stub( jQuery, "style" );
  78. fakeTween.prop = "height";
  79. defaultHook.set( fakeTween );
  80. assert.ok( styleStub.calledWith( testElement, "height", "10px" ),
  81. "Calls jQuery.style with elem, prop, now+unit" );
  82. styleStub.resetHistory();
  83. fakeTween.prop = "testMissing";
  84. defaultHook.set( fakeTween );
  85. assert.equal( styleStub.callCount, 0, "Did not call jQuery.style for non css property" );
  86. assert.equal( testElement.testMissing, 10, "Instead, set value on element directly" );
  87. jQuery.cssHooks.testMissing = jQuery.noop;
  88. fakeTween.now = 11;
  89. defaultHook.set( fakeTween );
  90. delete jQuery.cssHooks.testMissing;
  91. assert.ok( styleStub.calledWith( testElement, "testMissing", "11px" ),
  92. "Presence of cssHooks causes jQuery.style with elem, prop, now+unit" );
  93. assert.equal( testElement.testMissing, 10, "And value was unchanged" );
  94. stepSpy = jQuery.fx.step.test = this.sandbox.spy();
  95. styleStub.resetHistory();
  96. fakeTween.prop = "test";
  97. defaultHook.set( fakeTween );
  98. assert.ok( stepSpy.calledWith( fakeTween ), "Step function called with Tween" );
  99. assert.equal( styleStub.callCount, 0, "Did not call jQuery.style" );
  100. } );
  101. QUnit.test( "jQuery.Tween - Plain Object", function( assert ) {
  102. assert.expect( 13 );
  103. var testObject = { test: 100 },
  104. testOptions = { duration: 100 },
  105. tween, easingSpy;
  106. tween = jQuery.Tween( testObject, testOptions, "test", 0, "linear" );
  107. assert.equal( tween.elem, testObject, "Sets .element" );
  108. assert.equal( tween.options, testOptions, "sets .options" );
  109. assert.equal( tween.prop, "test", "sets .prop" );
  110. assert.equal( tween.end, 0, "sets .end" );
  111. assert.equal( tween.easing, "linear", "sets .easing when provided" );
  112. assert.equal( tween.start, 100, "Reads .start value during construction" );
  113. assert.equal( tween.now, 100, "Reads .now value during construction" );
  114. easingSpy = this.sandbox.spy( jQuery.easing, "linear" );
  115. assert.equal( tween.run( 0.1 ), tween, ".run() returns this" );
  116. assert.equal( tween.now, 90, "Calculated tween" );
  117. assert.ok( easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ),
  118. "...using jQuery.easing.linear with back-compat arguments" );
  119. assert.equal( testObject.test, 90, "Set value" );
  120. tween.run( 1 );
  121. assert.equal( testObject.test, 0, "Checking another value" );
  122. tween.run( 0 );
  123. assert.equal( testObject.test, 100, "Can even go back in time" );
  124. } );
  125. QUnit.test( "jQuery.Tween - Element", function( assert ) {
  126. assert.expect( 15 );
  127. var testElement = jQuery( "<div>" ).css( "height", 100 )[ 0 ],
  128. testOptions = { duration: 100 },
  129. tween, easingSpy, eased;
  130. tween = jQuery.Tween( testElement, testOptions, "height", 0 );
  131. assert.equal( tween.elem, testElement, "Sets .element" );
  132. assert.equal( tween.options, testOptions, "sets .options" );
  133. assert.equal( tween.prop, "height", "sets .prop" );
  134. assert.equal( tween.end, 0, "sets .end" );
  135. assert.equal(
  136. tween.easing,
  137. jQuery.easing._default,
  138. "sets .easing to default when not provided"
  139. );
  140. assert.equal( tween.unit, "px", "sets .unit to px when not provided" );
  141. assert.equal( tween.start, 100, "Reads .start value during construction" );
  142. assert.equal( tween.now, 100, "Reads .now value during construction" );
  143. easingSpy = this.sandbox.spy( jQuery.easing, "swing" );
  144. assert.equal( tween.run( 0.1 ), tween, ".run() returns this" );
  145. assert.equal( tween.pos, jQuery.easing.swing( 0.1 ), "set .pos" );
  146. eased = 100 - ( jQuery.easing.swing( 0.1 ) * 100 );
  147. assert.equal( tween.now, eased, "Calculated tween" );
  148. assert.ok(
  149. easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ),
  150. "...using jQuery.easing.linear with back-compat arguments"
  151. );
  152. assert.equal(
  153. parseFloat( testElement.style.height ).toFixed( 2 ),
  154. eased.toFixed( 2 ), "Set value"
  155. );
  156. tween.run( 1 );
  157. assert.equal( testElement.style.height, "0px", "Checking another value" );
  158. tween.run( 0 );
  159. assert.equal( testElement.style.height, "100px", "Can even go back in time" );
  160. } );
  161. QUnit.test( "jQuery.Tween - No duration", function( assert ) {
  162. assert.expect( 3 );
  163. var testObject = { test: 100 },
  164. testOptions = { duration: 0 },
  165. tween, easingSpy;
  166. tween = jQuery.Tween( testObject, testOptions, "test", 0 );
  167. easingSpy = this.sandbox.spy( jQuery.easing, "swing" );
  168. tween.run( 0.5 );
  169. assert.equal( tween.pos, 0.5, "set .pos correctly" );
  170. assert.equal( testObject.test, 50, "set value on object correctly" );
  171. assert.equal( easingSpy.callCount, 0, "didn't ease the value" );
  172. } );
  173. QUnit.test( "jQuery.Tween - step function option", function( assert ) {
  174. assert.expect( 4 );
  175. var testObject = { test: 100 },
  176. testOptions = { duration: 100, step: this.sandbox.spy() },
  177. tween, propHookSpy;
  178. propHookSpy = this.sandbox.spy( jQuery.Tween.propHooks._default, "set" );
  179. tween = jQuery.Tween( testObject, testOptions, "test", 0, "linear" );
  180. assert.equal( testOptions.step.callCount, 0, "didn't call step on create" );
  181. tween.run( 0.5 );
  182. assert.ok(
  183. testOptions.step.calledOn( testObject ),
  184. "Called step function in context of animated object"
  185. );
  186. assert.ok(
  187. testOptions.step.calledWith( 50, tween ),
  188. "Called step function with correct parameters"
  189. );
  190. assert.ok(
  191. testOptions.step.calledBefore( propHookSpy ),
  192. "Called step function before calling propHook.set"
  193. );
  194. } );
  195. QUnit.test( "jQuery.Tween - custom propHooks", function( assert ) {
  196. assert.expect( 3 );
  197. var testObject = {},
  198. testOptions = { duration: 100, step: this.sandbox.spy() },
  199. propHook = {
  200. get: sinon.stub().returns( 100 ),
  201. set: sinon.stub()
  202. },
  203. tween;
  204. jQuery.Tween.propHooks.testHooked = propHook;
  205. tween = jQuery.Tween( testObject, testOptions, "testHooked", 0, "linear" );
  206. assert.ok( propHook.get.calledWith( tween ), "called propHook.get on create" );
  207. assert.equal( tween.now, 100, "Used return value from propHook.get" );
  208. tween.run( 0.5 );
  209. assert.ok(
  210. propHook.set.calledWith( tween ),
  211. "Called propHook.set function with correct parameters"
  212. );
  213. delete jQuery.Tween.propHooks.testHooked;
  214. } );
  215. QUnit.test( "jQuery.Tween - custom propHooks - advanced values", function( assert ) {
  216. assert.expect( 5 );
  217. var testObject = {},
  218. testOptions = { duration: 100, step: this.sandbox.spy() },
  219. propHook = {
  220. get: sinon.stub().returns( [ 0, 0 ] ),
  221. set: sinon.spy()
  222. },
  223. tween;
  224. jQuery.Tween.propHooks.testHooked = propHook;
  225. tween = jQuery.Tween( testObject, testOptions, "testHooked", [ 1, 1 ], "linear" );
  226. assert.ok( propHook.get.calledWith( tween ), "called propHook.get on create" );
  227. assert.deepEqual( tween.start, [ 0, 0 ], "Used return value from get" );
  228. tween.run( 0.5 );
  229. // Some day this NaN assumption might change - perhaps add a "calc" helper to the hooks?
  230. assert.ok( isNaN( tween.now ), "Used return value from propHook.get" );
  231. assert.equal( tween.pos, 0.5, "But the eased percent is still available" );
  232. assert.ok(
  233. propHook.set.calledWith( tween ),
  234. "Called propHook.set function with correct parameters"
  235. );
  236. delete jQuery.Tween.propHooks.testHooked;
  237. } );
  238. } )();