]> source.dussan.org Git - jquery.git/commitdiff
Effects: Adding unit tests for jQuery.Animation 2326/head
authorCorey Frang <gnarf@gnarf.net>
Tue, 19 May 2015 21:48:42 +0000 (17:48 -0400)
committerCorey Frang <gnarf@gnarf.net>
Sat, 27 Jun 2015 00:06:03 +0000 (20:06 -0400)
Closes gh-2326

Gruntfile.js
src/effects.js
test/data/testinit.js
test/unit/animation.js [new file with mode: 0644]

index 8c88370e49bfa5e550bf4771ba56030d8d5c2560..1a6bdac1ac413858a6abea654212a172f867004a 100644 (file)
@@ -103,14 +103,15 @@ module.exports = function( grunt ) {
                        src: "src/**/*.js",
                        gruntfile: "Gruntfile.js",
 
-                       // Right now, check only test helpers
-                       test: [ "test/data/testrunner.js", "test/unit/tween.js" ],
+                       // Check parts of tests that pass
+                       test: [ "test/data/testrunner.js", "test/unit/animation.js", "test/unit/tween.js" ],
                        release: [ "build/*.js", "!build/release-notes.js" ],
                        tasks: "build/tasks/*.js"
                },
                testswarm: {
                        tests: [
                                "ajax",
+                               "animation",
                                "attributes",
                                "callbacks",
                                "core",
index 53b73fd848bdfb2650b6af62c2261883347608d7..40da887053d533f6ddd60a954863f8b194a35e9f 100644 (file)
@@ -2,6 +2,7 @@ define([
        "./core",
        "./var/document",
        "./var/rcssNum",
+       "./var/rnotwhite",
        "./css/var/cssExpand",
        "./css/var/isHidden",
        "./css/var/swap",
@@ -16,20 +17,13 @@ define([
        "./manipulation",
        "./css",
        "./effects/Tween"
-], function( jQuery, document, rcssNum, cssExpand, isHidden, swap, adjustCSS, dataPriv, showHide ) {
+], function( jQuery, document, rcssNum, rnotwhite, cssExpand, isHidden, swap,
+       adjustCSS, dataPriv, showHide ) {
 
 var
        fxNow, timerId,
        rfxtypes = /^(?:toggle|show|hide)$/,
-       rrun = /queueHooks$/,
-       animationPrefilters = [ defaultPrefilter ],
-       tweeners = {
-               "*": [ function( prop, value ) {
-                       var tween = this.createTween( prop, value );
-                       adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
-                       return tween;
-               } ]
-       };
+       rrun = /queueHooks$/;
 
 function raf() {
        if ( timerId ) {
@@ -69,7 +63,7 @@ function genFx( type, includeWidth ) {
 
 function createTween( value, prop, animation ) {
        var tween,
-               collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+               collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
                index = 0,
                length = collection.length;
        for ( ; index < length; index++ ) {
@@ -281,7 +275,7 @@ function Animation( elem, properties, options ) {
        var result,
                stopped,
                index = 0,
-               length = animationPrefilters.length,
+               length = Animation.prefilters.length,
                deferred = jQuery.Deferred().always( function() {
                        // Don't match elem in the :animated selector
                        delete tick.elem;
@@ -357,8 +351,12 @@ function Animation( elem, properties, options ) {
        propFilter( props, animation.opts.specialEasing );
 
        for ( ; index < length ; index++ ) {
-               result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+               result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
                if ( result ) {
+                       if ( jQuery.isFunction( result.stop ) ) {
+                               jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
+                                       jQuery.proxy( result.stop, result );
+                       }
                        return result;
                }
        }
@@ -386,12 +384,20 @@ function Animation( elem, properties, options ) {
 
 jQuery.Animation = jQuery.extend( Animation, {
 
+       tweeners: {
+               "*": [ function( prop, value ) {
+                       var tween = this.createTween( prop, value );
+                       adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
+                       return tween;
+               } ]
+       },
+
        tweener: function( props, callback ) {
                if ( jQuery.isFunction( props ) ) {
                        callback = props;
                        props = [ "*" ];
                } else {
-                       props = props.split(" ");
+                       props = props.match( rnotwhite );
                }
 
                var prop,
@@ -400,16 +406,18 @@ jQuery.Animation = jQuery.extend( Animation, {
 
                for ( ; index < length ; index++ ) {
                        prop = props[ index ];
-                       tweeners[ prop ] = tweeners[ prop ] || [];
-                       tweeners[ prop ].unshift( callback );
+                       Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
+                       Animation.tweeners[ prop ].unshift( callback );
                }
        },
 
+       prefilters: [ defaultPrefilter ],
+
        prefilter: function( callback, prepend ) {
                if ( prepend ) {
-                       animationPrefilters.unshift( callback );
+                       Animation.prefilters.unshift( callback );
                } else {
-                       animationPrefilters.push( callback );
+                       Animation.prefilters.push( callback );
                }
        }
 });
index e59d9db3259f8e91bb78ca7c753bcf1bc8821784..ef90fe45c9afabea19d1c65f716ac7577e42eae5 100644 (file)
@@ -286,6 +286,7 @@ this.loadTests = function() {
                        "unit/effects.js",
                        "unit/offset.js",
                        "unit/dimensions.js",
+                       "unit/animation.js",
                        "unit/tween.js"
                ];
 
diff --git a/test/unit/animation.js b/test/unit/animation.js
new file mode 100644 (file)
index 0000000..6bb0701
--- /dev/null
@@ -0,0 +1,230 @@
+( function() {
+
+// Can't test what ain't there
+if ( !jQuery.fx ) {
+       return;
+}
+
+var oldRaf = window.requestAnimationFrame,
+       defaultPrefilter = jQuery.Animation.prefilters[ 0 ],
+       defaultTweener = jQuery.Animation.tweeners[ "*" ][ 0 ],
+       startTime = 505877050;
+
+// This module tests jQuery.Animation and the corresponding 1.8+ effects APIs
+module( "animation", {
+       setup: function() {
+               window.requestAnimationFrame = null;
+               this.sandbox = sinon.sandbox.create();
+               this.clock = this.sandbox.useFakeTimers( startTime );
+               this._oldInterval = jQuery.fx.interval;
+               jQuery.fx.step = {};
+               jQuery.fx.interval = 10;
+               jQuery.now = Date.now;
+               jQuery.Animation.prefilters = [ defaultPrefilter ];
+               jQuery.Animation.tweeners = { "*": [ defaultTweener ] };
+       },
+       teardown: function() {
+               this.sandbox.restore();
+               jQuery.now = Date.now;
+               jQuery.fx.stop();
+               jQuery.fx.interval = this._oldInterval;
+               window.requestAnimationFrame = oldRaf;
+               return moduleTeardown.apply( this, arguments );
+       }
+} );
+
+test( "Animation( subject, props, opts ) - shape", function() {
+       expect( 20 );
+
+       var subject = { test: 0 },
+               props = { test: 1 },
+               opts = { queue: "fx", duration: 100 },
+               animation = jQuery.Animation( subject, props, opts );
+
+       equal( animation.elem, subject, ".elem is set to the exact object passed" );
+       equal( animation.originalOptions, opts, ".originalOptions is set to options passed" );
+       equal( animation.originalProperties, props, ".originalProperties is set to props passed" );
+
+       notEqual( animation.props, props, ".props is not the original however" );
+       deepEqual( animation.props, props, ".props is a copy of the original" );
+
+       deepEqual( animation.opts, {
+               duration: 100,
+               queue: "fx",
+               specialEasing: { test: undefined },
+               easing: jQuery.easing._default
+       }, ".options is filled with default easing and specialEasing" );
+
+       equal( animation.startTime, startTime, "startTime was set" );
+       equal( animation.duration, 100, ".duration is set" );
+
+       equal( animation.tweens.length, 1, ".tweens has one Tween" );
+       equal( typeof animation.tweens[ 0 ].run, "function", "which has a .run function" );
+
+       equal( typeof animation.createTween, "function", ".createTween is a function" );
+       equal( typeof animation.stop, "function", ".stop is a function" );
+
+       equal( typeof animation.done, "function", ".done is a function" );
+       equal( typeof animation.fail, "function", ".fail is a function" );
+       equal( typeof animation.always, "function", ".always is a function" );
+       equal( typeof animation.progress, "function", ".progress is a function" );
+
+       equal( jQuery.timers.length, 1, "Added a timers function" );
+       equal( jQuery.timers[ 0 ].elem, subject, "...with .elem as the subject" );
+       equal( jQuery.timers[ 0 ].anim, animation, "...with .anim as the animation" );
+       equal( jQuery.timers[ 0 ].queue, opts.queue, "...with .queue" );
+
+       // Cleanup after ourselves by ticking to the end
+       this.clock.tick( 100 );
+} );
+
+test( "Animation.prefilter( fn ) - calls prefilter after defaultPrefilter", function() {
+       expect( 1 );
+
+       var prefilter = this.sandbox.stub(),
+               defaultSpy = this.sandbox.spy( jQuery.Animation.prefilters, 0 );
+
+       jQuery.Animation.prefilter( prefilter );
+
+       jQuery.Animation( {}, {}, {} );
+       ok( prefilter.calledAfter( defaultSpy ), "our prefilter called after" );
+} );
+
+test( "Animation.prefilter( fn, true ) - calls prefilter before defaultPrefilter", function() {
+       expect( 1 );
+
+       var prefilter = this.sandbox.stub(),
+               defaultSpy = this.sandbox.spy( jQuery.Animation.prefilters, 0 );
+
+       jQuery.Animation.prefilter( prefilter, true );
+
+       jQuery.Animation( {}, {}, {} );
+       ok( prefilter.calledBefore( defaultSpy ), "our prefilter called before" );
+} );
+
+test( "Animation.prefilter - prefilter return hooks", function() {
+       expect( 34 );
+
+       var animation, realAnimation, element,
+               sandbox = this.sandbox,
+               ourAnimation = { stop: this.sandbox.spy() },
+               target = { height: 50 },
+               props = { height: 100 },
+               opts = { duration: 100 },
+               prefilter = this.sandbox.spy( function() {
+                       realAnimation = this;
+                       sandbox.spy( realAnimation, "createTween" );
+
+                       deepEqual( realAnimation.originalProperties, props, "originalProperties" );
+                       equal( arguments[ 0 ], this.elem, "first param elem" );
+                       equal( arguments[ 1 ], this.props, "second param props" );
+                       equal( arguments[ 2 ], this.opts, "third param opts" );
+                       return ourAnimation;
+               } ),
+               defaultSpy = sandbox.spy( jQuery.Animation.prefilters, 0 ),
+               queueSpy = sandbox.spy( function( next ) {
+                       next();
+               } ),
+               TweenSpy = sandbox.spy( jQuery, "Tween" );
+
+       jQuery.Animation.prefilter( prefilter, true );
+
+       sandbox.stub( jQuery.fx, "timer" );
+
+       animation = jQuery.Animation( target, props, opts );
+
+       equal( prefilter.callCount, 1, "Called prefilter" );
+
+       equal( defaultSpy.callCount, 0,
+               "Returning something from a prefilter caused remaining prefilters to not run" );
+       equal( jQuery.fx.timer.callCount, 0, "Returning something never queues a timer" );
+       equal( animation, ourAnimation, "Returning something returned it from jQuery.Animation" );
+       equal( realAnimation.createTween.callCount, 0, "Returning something never creates tweens" );
+       equal( TweenSpy.callCount, 0, "Returning something never creates tweens" );
+
+       // Test overriden usage on queues:
+       prefilter.reset();
+       element = jQuery( "<div>" )
+               .css( "height", 50 )
+               .animate( props, 100 )
+               .queue( queueSpy )
+               .animate( props, 100 )
+               .queue( queueSpy )
+               .animate( props, 100 )
+               .queue( queueSpy );
+
+       equal( prefilter.callCount, 1, "Called prefilter" );
+       equal( queueSpy.callCount, 0, "Next function in queue not called" );
+
+       realAnimation.opts.complete.call( realAnimation.elem );
+       equal( queueSpy.callCount, 1, "Next function in queue called after complete" );
+
+       equal( prefilter.callCount, 2, "Called prefilter again - animation #2" );
+       equal( ourAnimation.stop.callCount, 0, ".stop() on our animation hasn't been called" );
+
+       element.stop();
+       equal( ourAnimation.stop.callCount, 1, ".stop() called ourAnimation.stop()" );
+       ok( !ourAnimation.stop.args[ 0 ][ 0 ], ".stop( falsy ) (undefined or false are both valid)" );
+
+       equal( queueSpy.callCount, 2, "Next queue function called" );
+       ok( queueSpy.calledAfter( ourAnimation.stop ), "After our animation was told to stop" );
+
+       // ourAnimation.stop.reset();
+       equal( prefilter.callCount, 3, "Got the next animation" );
+
+       ourAnimation.stop.reset();
+
+       // do not clear queue, gotoEnd
+       element.stop( false, true );
+       ok( ourAnimation.stop.calledWith( true ), ".stop(true) calls .stop(true)" );
+       ok( queueSpy.calledAfter( ourAnimation.stop ),
+               "and the next queue function ran after we were told" );
+} );
+
+test( "Animation.tweener( fn ) - unshifts a * tweener", function() {
+       expect( 2 );
+       var starTweeners = jQuery.Animation.tweeners[ "*" ];
+
+       jQuery.Animation.tweener( jQuery.noop );
+       equal( starTweeners.length, 2 );
+       deepEqual( starTweeners, [ jQuery.noop, defaultTweener ] );
+} );
+
+test( "Animation.tweener( 'prop', fn ) - unshifts a 'prop' tweener", function() {
+       expect( 4 );
+       var tweeners = jQuery.Animation.tweeners,
+               fn = function() {};
+
+       jQuery.Animation.tweener( "prop", jQuery.noop );
+       equal( tweeners.prop.length, 1 );
+       deepEqual( tweeners.prop, [ jQuery.noop ] );
+
+       jQuery.Animation.tweener( "prop", fn );
+       equal( tweeners.prop.length, 2 );
+       deepEqual( tweeners.prop, [ fn, jQuery.noop ] );
+} );
+
+test( "Animation.tweener( 'list of props', fn ) - unshifts a tweener to each prop", function() {
+       expect( 2 );
+       var tweeners = jQuery.Animation.tweeners,
+               fn = function() {};
+
+       jQuery.Animation.tweener( "list of props", jQuery.noop );
+       deepEqual( tweeners, {
+               list: [ jQuery.noop ],
+               of: [ jQuery.noop ],
+               props: [ jQuery.noop ],
+               "*": [ defaultTweener ]
+       } );
+
+       // Test with extra whitespaces
+       jQuery.Animation.tweener( " list\t of \tprops\n*", fn );
+       deepEqual( tweeners, {
+               list: [ fn, jQuery.noop ],
+               of: [ fn, jQuery.noop ],
+               props: [ fn, jQuery.noop ],
+               "*": [ fn, defaultTweener ]
+       } );
+} );
+
+} )();