diff options
| author | Matias Niemelàˆ | 2013-07-22 15:37:45 -0400 |
|---|---|---|
| committer | Misko Hevery | 2013-07-26 23:49:54 -0700 |
| commit | 15389b0e377e2a84b85178e993e4940d8098d0ed (patch) | |
| tree | 06054bded1c252ca0d2c62b1a47267fee4c1eb98 | |
| parent | 7d69d52acff8578e0f7d6fe57a6c45561a05b182 (diff) | |
| download | angular.js-15389b0e377e2a84b85178e993e4940d8098d0ed.tar.bz2 | |
fix(ngAnimate): $timeout integration and cancel callbacks added
| -rw-r--r-- | docs/component-spec/annotationsSpec.js | 39 | ||||
| -rw-r--r-- | src/ng/animate.js | 12 | ||||
| -rw-r--r-- | src/ngAnimate/animate.js | 140 | ||||
| -rw-r--r-- | test/ngAnimate/animateSpec.js | 629 | ||||
| -rw-r--r-- | test/ngRoute/directive/ngViewSpec.js | 32 |
5 files changed, 423 insertions, 429 deletions
diff --git a/docs/component-spec/annotationsSpec.js b/docs/component-spec/annotationsSpec.js index 90c72918..7dd5b696 100644 --- a/docs/component-spec/annotationsSpec.js +++ b/docs/component-spec/annotationsSpec.js @@ -69,16 +69,16 @@ describe('Docs Annotations', function() { beforeEach(function() { module(function($provide, $animateProvider) { $provide.value('$window', window = angular.mock.createMockWindow()); - $animateProvider.register('.foldout', function($window) { + $animateProvider.register('.foldout', function($timeout) { return { enter : function(element, done) { - $window.setTimeout(done, 1000); + $timeout(done, 1000); }, removeClass : function(element, className, done) { - $window.setTimeout(done, 500); + $timeout(done, 500); }, addClass : function(element, className, done) { - $window.setTimeout(done, 200); + $timeout(done, 200); } } }); @@ -112,41 +112,46 @@ describe('Docs Annotations', function() { expect(foldout.html()).toContain('loading'); })); - it('should download a foldout HTML page and animate the contents', inject(function($httpBackend) { + it('should download a foldout HTML page and animate the contents', inject(function($httpBackend, $timeout) { $httpBackend.expect('GET', url).respond('hello'); element.triggerHandler('click'); $httpBackend.flush(); - window.setTimeout.expect(1).process(); - window.setTimeout.expect(1000).process(); + $timeout.flushNext(0); + $timeout.flushNext(1); + $timeout.flushNext(0); + $timeout.flushNext(1000); var kids = body.children(); var foldout = angular.element(kids[kids.length-1]); expect(foldout.text()).toContain('hello'); })); - it('should hide then show when clicked again', inject(function($httpBackend) { + it('should hide then show when clicked again', inject(function($httpBackend, $timeout) { $httpBackend.expect('GET', url).respond('hello'); //enter element.triggerHandler('click'); $httpBackend.flush(); - window.setTimeout.expect(1).process(); - window.setTimeout.expect(1000).process(); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); + $timeout.flushNext(1); + $timeout.flushNext(0); + $timeout.flushNext(1000); //hide element.triggerHandler('click'); - window.setTimeout.expect(1).process(); - window.setTimeout.expect(200).process(); - window.setTimeout.expect(0).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); + $timeout.flushNext(200); + $timeout.flushNext(0); //show element.triggerHandler('click'); - window.setTimeout.expect(1).process(); - window.setTimeout.expect(500).process(); - window.setTimeout.expect(0).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); + $timeout.flushNext(500); + $timeout.flushNext(0); })); }); diff --git a/src/ng/animate.js b/src/ng/animate.js index 206a4b03..7927b12f 100644 --- a/src/ng/animate.js +++ b/src/ng/animate.js @@ -56,7 +56,7 @@ var $AnimateProvider = ['$provide', function($provide) { $provide.factory(name, factory); }; - this.$get = function() { + this.$get = ['$timeout', function($timeout) { return { enter : function(element, parent, after, done) { var afterNode = after && after[after.length - 1]; @@ -66,12 +66,12 @@ var $AnimateProvider = ['$provide', function($provide) { forEach(element, function(node) { parentNode.insertBefore(node, afterNextSibling); }); - (done || noop)(); + $timeout(done || noop, 0, false); }, leave : function(element, done) { element.remove(); - (done || noop)(); + $timeout(done || noop, 0, false); }, move : function(element, parent, after, done) { @@ -85,7 +85,7 @@ var $AnimateProvider = ['$provide', function($provide) { className : isArray(className) ? className.join(' ') : ''; element.addClass(className); - (done || noop)(); + $timeout(done || noop, 0, false); }, removeClass : function(element, className, done) { @@ -93,10 +93,10 @@ var $AnimateProvider = ['$provide', function($provide) { className : isArray(className) ? className.join(' ') : ''; element.removeClass(className); - (done || noop)(); + $timeout(done || noop, 0, false); }, enabled : noop }; - }; + }]; }]; diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js index 201d4aab..28d36629 100644 --- a/src/ngAnimate/animate.js +++ b/src/ngAnimate/animate.js @@ -203,15 +203,15 @@ angular.module('ngAnimate', ['ng']) var NG_ANIMATE_STATE = '$$ngAnimateState'; var rootAnimateState = {running:true}; - $provide.decorator('$animate', ['$delegate', '$injector', '$window', '$sniffer', '$rootElement', - function($delegate, $injector, $window, $sniffer, $rootElement) { + $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', + function($delegate, $injector, $sniffer, $rootElement) { var noop = angular.noop; var forEach = angular.forEach; $rootElement.data(NG_ANIMATE_STATE, rootAnimateState); - function lookup(name) { + function lookup(name) { if (name) { var classes = name.substr(1).split('.'), classMap = {}; @@ -241,7 +241,7 @@ angular.module('ngAnimate', ['ng']) /** * @ngdoc object * @name ngAnimate.$animate - * @requires $window, $sniffer, $rootElement + * @requires $timeout, $sniffer, $rootElement * @function * * @description @@ -444,80 +444,72 @@ angular.module('ngAnimate', ['ng']) and the onComplete callback will be fired once the animation is fully complete. */ function performAnimation(event, className, element, parent, after, onComplete) { - if(nothingToAnimate(className, element)) { - (onComplete || noop)(); - } else { - var classes = ((element.attr('class') || '') + ' ' + className), - animationLookup = (' ' + classes).replace(/\s+/g,'.'), - animations = []; - forEach(lookup(animationLookup), function(animation, index) { - animations.push({ - start : animation[event], - done : false - }); + var classes = ((element.attr('class') || '') + ' ' + className), + animationLookup = (' ' + classes).replace(/\s+/g,'.'), + animations = []; + forEach(lookup(animationLookup), function(animation, index) { + animations.push({ + start : animation[event] }); + }); - if (!parent) { - parent = after ? after.parent() : element.parent(); - } - var disabledAnimation = { running : true }; + if (!parent) { + parent = after ? after.parent() : element.parent(); + } + var disabledAnimation = { running : true }; - //skip the animation if animations are disabled, a parent is already being animated - //or the element is not currently attached to the document body. - if ((parent.inheritedData(NG_ANIMATE_STATE) || disabledAnimation).running) { - //avoid calling done() since there is no need to remove any - //data or className values since this happens earlier than that - (onComplete || noop)(); - return; - } + //skip the animation if animations are disabled, a parent is already being animated + //or the element is not currently attached to the document body. + if ((parent.inheritedData(NG_ANIMATE_STATE) || disabledAnimation).running) { + //avoid calling done() since there is no need to remove any + //data or className values since this happens earlier than that + (onComplete || noop)(); + return; + } - var animationData = element.data(NG_ANIMATE_STATE) || {}; + var ngAnimateState = element.data(NG_ANIMATE_STATE) || {}; - //if an animation is currently running on the element then lets take the steps - //to cancel that animation and fire any required callbacks - if(animationData.running) { - cancelAnimations(animationData.animations); - animationData.done(); - } + //if an animation is currently running on the element then lets take the steps + //to cancel that animation and fire any required callbacks + if(ngAnimateState.running) { + cancelAnimations(ngAnimateState.animations); + ngAnimateState.done(); + } - element.data(NG_ANIMATE_STATE, { - running:true, - animations:animations, - done:done - }); + element.data(NG_ANIMATE_STATE, { + running:true, + animations:animations, + done:done + }); - if(event == 'addClass') { - className = suffixClasses(className, '-add'); - } else if(event == 'removeClass') { - className = suffixClasses(className, '-remove'); - } + if(event == 'addClass') { + className = suffixClasses(className, '-add'); + } else if(event == 'removeClass') { + className = suffixClasses(className, '-remove'); + } - element.addClass(className); + element.addClass(className); - forEach(animations, function(animation, index) { - var fn = function() { - progress(index); - }; + forEach(animations, function(animation, index) { + var fn = function() { + progress(index); + }; - if(animation.start) { - if(event == 'addClass' || event == 'removeClass') { - animation.cancel = animation.start(element, className, fn); - } else { - animation.cancel = animation.start(element, fn); - } + if(animation.start) { + if(event == 'addClass' || event == 'removeClass') { + animation.endFn = animation.start(element, className, fn); } else { - fn(); + animation.endFn = animation.start(element, fn); } - }); - } - - function nothingToAnimate(className, element) { - return !(className && className.length > 0 && element.length > 0); - } + } else { + fn(); + } + }); function cancelAnimations(animations) { + var isCancelledFlag = true; forEach(animations, function(animation) { - (animation.cancel || noop)(element); + (animation.endFn || noop)(isCancelledFlag); }); } @@ -534,6 +526,7 @@ angular.module('ngAnimate', ['ng']) function progress(index) { animations[index].done = true; + (animations[index].endFn || noop)(); for(var i=0;i<animations.length;i++) { if(!animations[i].done) return; } @@ -552,7 +545,7 @@ angular.module('ngAnimate', ['ng']) }]); }]) - .animation('', ['$window','$sniffer', function($window, $sniffer) { + .animation('', ['$window','$sniffer', '$timeout', function($window, $sniffer, $timeout) { return { enter : function(element, done) { return animate(element, 'ng-enter', done); @@ -576,13 +569,13 @@ angular.module('ngAnimate', ['ng']) done(); } else { var activeClassName = ''; - $window.setTimeout(startAnimation, 1); + $timeout(startAnimation, 1, false); //this acts as the cancellation function in case //a new animation is triggered while another animation //is still going on (otherwise the active className //would still hang around until the timer is complete). - return onComplete; + return onEnd; } function parseMaxTime(str) { @@ -643,12 +636,21 @@ angular.module('ngAnimate', ['ng']) } }); - $window.setTimeout(onComplete, duration * 1000); + $timeout(done, duration * 1000, false); } - function onComplete() { + //this will automatically be called by $animate so + //there is no need to attach this internally to the + //timeout done method + function onEnd(cancelled) { element.removeClass(activeClassName); - done(); + + //only when the animation is cancelled is the done() + //function not called for this animation therefore + //this must be also called + if(cancelled) { + done(); + } }; }; }]); diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index e069049f..e896686b 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -18,7 +18,10 @@ describe("ngAnimate", function() { beforeEach(module(function() { // we need to run animation on attached elements; body = jqLite(document.body); - return function($animate) { + return function($animate, $timeout) { + try { + $timeout.flush(); + } catch(e) {}; $animate.enabled(true); }; })); @@ -60,11 +63,10 @@ describe("ngAnimate", function() { describe("with polyfill", function() { - var child, after, window; + var child, after; beforeEach(function() { module(function($animateProvider, $provide) { - $provide.value('$window', window = angular.mock.createMockWindow()); $animateProvider.register('.custom', function() { return { start: function(element, done) { @@ -72,10 +74,10 @@ describe("ngAnimate", function() { } } }); - $animateProvider.register('.custom-delay', function() { + $animateProvider.register('.custom-delay', function($timeout) { function animate(element, done) { done = arguments.length == 3 ? arguments[2] : done; - window.setTimeout(done, 2000); + $timeout(done, 2000, false); return function() { element.addClass('animation-cancelled'); } @@ -86,12 +88,12 @@ describe("ngAnimate", function() { removeClass : animate } }); - $animateProvider.register('.custom-long-delay', function() { + $animateProvider.register('.custom-long-delay', function($timeout) { function animate(element, done) { done = arguments.length == 3 ? arguments[2] : done; - window.setTimeout(done, 20000); - return function() { - element.addClass('animation-cancelled'); + $timeout(done, 20000, false); + return function(cancelled) { + element.addClass(cancelled ? 'animation-cancelled' : 'animation-ended'); } } return { @@ -117,28 +119,30 @@ describe("ngAnimate", function() { }); }) - it("should animate the enter animation event", inject(function($animate, $rootScope, $sniffer) { + it("should animate the enter animation event", + inject(function($animate, $rootScope, $sniffer, $timeout) { + expect(element.contents().length).toBe(0); $animate.enter(child, element); - if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); - } + $timeout.flush($sniffer.transitions ? 1 : 0); + expect(element.contents().length).toBe(1); })); - it("should animate the leave animation event", inject(function($animate, $rootScope, $sniffer) { + it("should animate the leave animation event", + inject(function($animate, $rootScope, $sniffer, $timeout) { + element.append(child); expect(element.contents().length).toBe(1); $animate.leave(child); - if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); - } + $timeout.flush($sniffer.transitions ? 1 : 0); + expect(element.contents().length).toBe(0); })); - it("should animate the move animation event", inject(function($animate, $compile, $rootScope, $sniffer) { + it("should animate the move animation event", + inject(function($animate, $compile, $rootScope, $sniffer, $timeout) { + $rootScope.$digest(); var child1 = $compile('<div>1</div>')($rootScope); var child2 = $compile('<div>2</div>')($rootScope); @@ -148,39 +152,47 @@ describe("ngAnimate", function() { $animate.move(child1, element, child2); expect(element.text()).toBe('21'); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); + $timeout.flushNext(0); + $timeout.flushNext(1); } })); - it("should animate the show animation event", inject(function($animate, $rootScope, $sniffer) { + it("should animate the show animation event", + inject(function($animate, $rootScope, $sniffer, $timeout) { + $rootScope.$digest(); element.addClass('ng-hide'); expect(element).toBeHidden(); $animate.removeClass(element, 'ng-hide'); if($sniffer.transitions) { expect(element.hasClass('ng-hide-remove')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('ng-hide-remove-active')).toBe(true); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); } + expect(element.hasClass('ng-hide-remove')).toBe(false); + expect(element.hasClass('ng-hide-remove-active')).toBe(false); expect(element).toBeShown(); })); - it("should animate the hide animation event", inject(function($animate, $rootScope, $sniffer) { + it("should animate the hide animation event", + inject(function($animate, $rootScope, $sniffer, $timeout) { + $rootScope.$digest(); expect(element).toBeShown(); $animate.addClass(element, 'ng-hide'); if($sniffer.transitions) { expect(element.hasClass('ng-hide-add')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('ng-hide-add-active')).toBe(true); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); } + $timeout.flush(); expect(element).toBeHidden(); })); it("should assign the ngAnimate string to all events if a string is given", - inject(function($animate, $sniffer, $rootScope) { + inject(function($animate, $sniffer, $rootScope, $timeout, $browser) { if (!$sniffer.transitions) return; @@ -188,42 +200,49 @@ describe("ngAnimate", function() { //enter $animate.enter(child, element); + $timeout.flushNext(0); expect(child.attr('class')).toContain('ng-enter'); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(child.attr('class')).toContain('ng-enter-active'); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); - //leave + //move element.append(after); $animate.move(child, element, after); + $timeout.flushNext(0); expect(child.attr('class')).toContain('ng-move'); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(child.attr('class')).toContain('ng-move-active'); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); //hide $animate.addClass(child, 'ng-hide'); expect(child.attr('class')).toContain('ng-hide-add'); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(child.attr('class')).toContain('ng-hide-add-active'); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); + $timeout.flushNext(0); //show $animate.removeClass(child, 'ng-hide'); expect(child.attr('class')).toContain('ng-hide-remove'); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(child.attr('class')).toContain('ng-hide-remove-active'); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); + $timeout.flushNext(0); //leave $animate.leave(child); expect(child.attr('class')).toContain('ng-leave'); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(child.attr('class')).toContain('ng-leave-active'); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); + $timeout.flushNext(0); })); - it("should not run if animations are disabled", inject(function($animate, $rootScope, $sniffer) { + it("should not run if animations are disabled", + inject(function($animate, $rootScope, $sniffer, $timeout) { + $animate.enabled(false); $rootScope.$digest(); @@ -234,19 +253,21 @@ describe("ngAnimate", function() { expect(element.text()).toBe('123'); $animate.removeClass(element, 'ng-hide'); expect(element.text()).toBe('123'); + $timeout.flushNext(0); //fires the addClass callback $animate.enabled(true); $animate.removeClass(element, 'ng-hide'); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(0); expect(element.text()).toBe('memento'); })); it("should only call done() once and right away if another animation takes place in between", - inject(function($animate, $rootScope, $sniffer) { + inject(function($animate, $rootScope, $sniffer, $timeout) { element.append(child); child.addClass('custom-delay'); @@ -254,7 +275,7 @@ describe("ngAnimate", function() { expect(element).toBeShown(); $animate.addClass(child, 'ng-hide'); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); } expect(child).toBeShown(); @@ -265,34 +286,35 @@ describe("ngAnimate", function() { child.css('display','block'); child.removeClass('ng-hide'); - window.setTimeout.expect(2000).process(); if($sniffer.transitions) { - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); } - expect(child).toBeShown(); - - expect(element.children().length).toBe(1); //still animating - + $timeout.flushNext(0); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - } - window.setTimeout.expect(2000).process(); - if($sniffer.transitions) { - window.setTimeout.expect(0).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); } + expect(element.children().length).toBe(1); //still animating + $timeout.flushNext(2000); + $timeout.flushNext(2000); + $timeout.flushNext(0); + expect(child).toBeShown(); + expect(element.children().length).toBe(0); })); it("should call the cancel callback when another animation is called on the same element", - inject(function($animate, $rootScope, $sniffer) { + inject(function($animate, $rootScope, $sniffer, $timeout) { element.append(child); child.addClass('custom-delay ng-hide'); $animate.removeClass(child, 'ng-hide'); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(2000); $animate.addClass(child, 'ng-hide'); @@ -300,15 +322,37 @@ describe("ngAnimate", function() { })); + it("should fire the cancel/end function with the correct flag in the parameters", + inject(function($animate, $rootScope, $sniffer, $timeout) { + + element.append(child); + + $animate.addClass(child, 'custom-delay'); + + if($sniffer.transitions) { + $timeout.flushNext(1); + $timeout.flushNext(0); + } + $animate.addClass(child, 'custom-long-delay'); + + expect(child.hasClass('animation-cancelled')).toBe(true); + expect(child.hasClass('animation-ended')).toBe(false); + + $timeout.flush(); + expect(child.hasClass('animation-ended')).toBe(true); + })); + + it("should NOT clobber all data on an element when animation is finished", - inject(function($animate, $rootScope, $sniffer) { + inject(function($animate, $rootScope, $sniffer, $timeout) { child.css('display','none'); element.data('foo', 'bar'); $animate.removeClass(element, 'ng-hide'); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); } $animate.addClass(element, 'ng-hide'); @@ -318,19 +362,18 @@ describe("ngAnimate", function() { it("should allow multiple JS animations which run in parallel", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { $animate.addClass(element, 'custom-delay custom-long-delay'); if($sniffer.transitions) { expect(element[0].className).toContain('custom-delay-add custom-long-delay-add'); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element[0].className).toContain('custom-delay-add-active custom-long-delay-add-active'); + $timeout.flushNext(0); } - window.setTimeout.expect(2000).process(); - window.setTimeout.expect(20000).process(); - if($sniffer.transitions) { - window.setTimeout.expect(0).process(); //css animation - } + $timeout.flushNext(2000); + $timeout.flushNext(20000); + $timeout.flushNext(0); expect(element.hasClass('custom-delay')).toBe(true); expect(element.hasClass('custom-delay-add')).toBe(false); @@ -342,7 +385,7 @@ describe("ngAnimate", function() { })); it("should allow both multiple JS and CSS animations which run in parallel", - inject(function($animate, $rootScope, $compile, $sniffer, _$rootElement_) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout, _$rootElement_) { $rootElement = _$rootElement_; var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; @@ -356,13 +399,12 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - } - window.setTimeout.expect(2000).process(); //1st JavaScript Animation - window.setTimeout.expect(20000).process(); //2nd JavaScript Animation - if($sniffer.transitions) { - window.setTimeout.expect(1000).process(); //CSS animation + $timeout.flushNext(1); + $timeout.flushNext(1000); } + $timeout.flushNext(2000); + $timeout.flushNext(20000); + $timeout.flushNext(0); expect(element.hasClass('custom-delay')).toBe(true); expect(element.hasClass('custom-delay-add')).toBe(false); @@ -375,11 +417,10 @@ describe("ngAnimate", function() { }); describe("with CSS3", function() { - var window, prefix, vendorPrefix; + var prefix, vendorPrefix; beforeEach(function() { module(function($animateProvider, $provide) { - $provide.value('$window', window = angular.mock.createMockWindow()); return function($sniffer, _$rootElement_, $animate) { vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; $rootElement = _$rootElement_; @@ -389,7 +430,8 @@ describe("ngAnimate", function() { describe("Animations", function() { it("should properly detect and make use of CSS Animations", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { + var style = 'animation: some_animation 4s linear 0s 1 alternate;' + vendorPrefix + 'animation: some_animation 4s linear 0s 1 alternate;'; element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); @@ -399,17 +441,15 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.animations) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(4000).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(4000); } expect(element).toBeShown(); })); it("should properly detect and make use of CSS Animations with multiple iterations", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { + var style = 'animation-duration: 2s;' + 'animation-iteration-count: 3;' + vendorPrefix + 'animation-duration: 2s;' + @@ -421,17 +461,15 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.animations) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(6000).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(6000); } expect(element).toBeShown(); })); it("should fallback to the animation duration if an infinite iteration is provided", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { + var style = 'animation-duration: 2s;' + 'animation-iteration-count: infinite;' + vendorPrefix + 'animation-duration: 2s;' + @@ -443,17 +481,15 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.animations) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(2000).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(2000); } expect(element).toBeShown(); })); it("should consider the animation delay is provided", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { + var style = 'animation-duration: 2s;' + 'animation-delay: 10s;' + 'animation-iteration-count: 5;' + @@ -467,11 +503,8 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(20000).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(20000); } expect(element).toBeShown(); })); @@ -490,7 +523,7 @@ describe("ngAnimate", function() { })); it("should finish the previous animation when a new animation is started", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { var style = 'animation: some_animation 2s linear 0s 1 alternate;' + vendorPrefix + 'animation: some_animation 2s linear 0s 1 alternate;' @@ -499,22 +532,21 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if($sniffer.animations) { - window.setTimeout.expect(1).process(); expect(element.hasClass('ng-hide-remove')).toBe(true); + $timeout.flushNext(1); expect(element.hasClass('ng-hide-remove-active')).toBe(true); } - else { //animation is skipped - expect(window.setTimeout.queue.length).toBe(0); - } $animate.addClass(element, 'ng-hide'); expect(element.hasClass('ng-hide-remove')).toBe(false); //added right away + $timeout.flushNext(0); + if($sniffer.animations) { //cleanup some pending animations - window.setTimeout.expect(2000).process(); - window.setTimeout.expect(1).process(); expect(element.hasClass('ng-hide-add')).toBe(true); + $timeout.flushNext(1); expect(element.hasClass('ng-hide-add-active')).toBe(true); + $timeout.flushNext(2000); } expect(element.hasClass('ng-hide-remove-active')).toBe(false); @@ -523,7 +555,8 @@ describe("ngAnimate", function() { describe("Transitions", function() { it("should skip transitions if disabled and run when enabled", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { + $animate.enabled(false); element = $compile(html('<div style="' + vendorPrefix + 'transition: 1s linear all">1</div>'))($rootScope); @@ -532,6 +565,8 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); expect(element).toBeShown(); + $timeout.flushNext(0); + $animate.enabled(true); element.addClass('ng-hide'); @@ -539,33 +574,28 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(1000).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(1000); } + $timeout.flushNext(0); expect(element).toBeShown(); })); it("should skip animations if disabled and run when enabled picking the longest specified duration", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { element = $compile(html('<div style="' + vendorPrefix + 'transition-duration: 1s, 2000ms, 1s; ' + vendorPrefix + 'transition-property: height, left, opacity">foo</div>'))($rootScope); element.addClass('ng-hide'); $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { expect(element).toBeHidden(); - window.setTimeout.expect(1).process(); - window.setTimeout.expect(2000).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(2000); } expect(element).toBeShown(); })); it("should skip animations if disabled and run when enabled picking the longest specified duration/delay combination", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { $animate.enabled(false); element = $compile(html('<div style="' + vendorPrefix + 'transition-duration: 1s, 0s, 1s; ' + vendorPrefix + @@ -576,6 +606,8 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); expect(element).toBeShown(); + $timeout.flushNext(0); //callback which is called + $animate.enabled(true); element.addClass('ng-hide'); @@ -583,17 +615,15 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(3000).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(3000); } + $timeout.flushNext(0); expect(element).toBeShown(); })); it("should select the highest duration and delay", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { var styles = 'transition:1s linear all 2s;' + vendorPrefix + 'transition:1s linear all 2s;' + 'animation:my_ani 10s 1s;' + @@ -606,17 +636,14 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(11000).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(11000); } expect(element).toBeShown(); })); it("should finish the previous transition when a new animation is started", - inject(function($animate, $rootScope, $compile, $sniffer) { + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { var style = 'transition: 1s linear all;' + vendorPrefix + 'transition: 1s linear all;' @@ -626,13 +653,11 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if($sniffer.transitions) { expect(element.hasClass('ng-hide-remove')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('ng-hide-remove-active')).toBe(true); - window.setTimeout.expect(1000).process(); - } - else { //animation is skipped - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1000); } + $timeout.flushNext(0); expect(element.hasClass('ng-hide-remove')).toBe(false); expect(element.hasClass('ng-hide-remove-active')).toBe(false); expect(element).toBeShown(); @@ -640,23 +665,16 @@ describe("ngAnimate", function() { $animate.addClass(element, 'ng-hide'); if($sniffer.transitions) { expect(element.hasClass('ng-hide-add')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('ng-hide-add-active')).toBe(true); } - else { - expect(window.setTimeout.queue.length).toBe(0); - } })); }); }); describe('animation evaluation', function () { - beforeEach(module(function($provide) { - $provide.value('$window', window = angular.mock.createMockWindow()); - })); - it('should re-evaluate the CSS classes for an animation each time', - inject(function($animate, $rootScope, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); var element = parent.find('span'); @@ -665,27 +683,31 @@ describe("ngAnimate", function() { element[0].className = 'abc'; $animate.enter(element, parent); + $timeout.flushNext(0); + if ($sniffer.transitions) { expect(element.hasClass('abc ng-enter')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('abc ng-enter ng-enter-active')).toBe(true); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); } expect(element.hasClass('abc')).toBe(true); element[0].className = 'xyz'; $animate.enter(element, parent); + $timeout.flushNext(0); + if ($sniffer.transitions) { expect(element.hasClass('xyz')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('xyz ng-enter ng-enter-active')).toBe(true); - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); } expect(element.hasClass('xyz')).toBe(true); })); it('should only append active to the newly append CSS className values', - inject(function($animate, $rootScope, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); var element = parent.find('span'); @@ -695,16 +717,14 @@ describe("ngAnimate", function() { element.attr('class','one two'); $animate.enter(element, parent); + $timeout.flushNext(0); if($sniffer.transitions) { expect(element.hasClass('one two ng-enter')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('one two ng-enter ng-enter-active')).toBe(true); expect(element.hasClass('one-active')).toBe(false); expect(element.hasClass('two-active')).toBe(false); - window.setTimeout.expect(0).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(0); } expect(element.hasClass('one two')).toBe(true); @@ -713,21 +733,20 @@ describe("ngAnimate", function() { describe("Callbacks", function() { - var window, vendorPrefix; + var vendorPrefix; beforeEach(function() { module(function($animateProvider, $provide) { - $provide.value('$window', window = angular.mock.createMockWindow()); - $animateProvider.register('.custom', function() { + $animateProvider.register('.custom', function($timeout) { return { removeClass : function(element, className, done) { - window.setTimeout(done, 2000); + $timeout(done, 2000); } } }); $animateProvider.register('.other', function() { return { enter : function(element, done) { - window.setTimeout(done, 10000); + $timeout(done, 10000); } } }); @@ -738,7 +757,7 @@ describe("ngAnimate", function() { }); it("should fire the enter callback", - inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); var element = parent.find('span'); @@ -750,18 +769,16 @@ describe("ngAnimate", function() { flag = true; }); + $timeout.flushNext(0); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(0); } expect(flag).toBe(true); })); it("should fire the leave callback", - inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); var element = parent.find('span'); @@ -774,17 +791,15 @@ describe("ngAnimate", function() { }); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(0); expect(flag).toBe(true); })); it("should fire the move callback", - inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); var parent2 = jqLite('<div id="nice"></div>'); @@ -797,12 +812,10 @@ describe("ngAnimate", function() { flag = true; }); + $timeout.flushNext(0); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(0); } expect(flag).toBe(true); @@ -810,7 +823,7 @@ describe("ngAnimate", function() { })); it("should fire the addClass/removeClass callbacks", - inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); var element = parent.find('span'); @@ -823,30 +836,26 @@ describe("ngAnimate", function() { }); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(0); $animate.removeClass(element, 'on', function() { signature += 'B'; }); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(0); expect(signature).toBe('AB'); })); it("should fire a done callback when provided with no animation", - inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); var element = parent.find('span'); @@ -858,18 +867,13 @@ describe("ngAnimate", function() { flag = true; }); - if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); - } + var timeoutDelay = $sniffer.transitions ? 1 : 0; + $timeout.flush(timeoutDelay); expect(flag).toBe(true); })); it("should fire a done callback when provided with a css animation/transition", - inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) { var transition = 'transition:1s linear all;'; var style = transition + ' ' + vendorPrefix + transition; @@ -884,17 +888,15 @@ describe("ngAnimate", function() { }); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(1000).process(); - } - else { - expect(window.setTimeout.queue.length).toBe(0); + $timeout.flushNext(1); + $timeout.flushNext(1000); } + $timeout.flushNext(0); expect(flag).toBe(true); })); it("should fire a done callback when provided with a JS animation", - inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); $rootElement.append(parent); @@ -908,17 +910,16 @@ describe("ngAnimate", function() { }); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - } - window.setTimeout.expect(2000).process(); - if($sniffer.transitions) { - window.setTimeout.expect(0).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(2000); + $timeout.flushNext(0); expect(flag).toBe(true); })); it("should fire the callback right away if another animation is called right after", - inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); $rootElement.append(parent); @@ -934,29 +935,33 @@ describe("ngAnimate", function() { }); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); + $timeout.flushNext(0); //callback for removeClass + $timeout.flushNext(1); + $timeout.flushNext(0); + $timeout.flushNext(1); } $animate.addClass(element, 'ng-hide'); //earlier animation cancelled if($sniffer.transitions) { - window.setTimeout.expect(1).process(); + $timeout.flushNext(0); + $timeout.flushNext(0); } + $timeout.flush(); expect(signature).toBe('AB'); })); }); describe("addClass / removeClass", function() { - var window, vendorPrefix; + var vendorPrefix; beforeEach(function() { module(function($animateProvider, $provide) { - $provide.value('$window', window = angular.mock.createMockWindow()); - $animateProvider.register('.klassy', function() { + $animateProvider.register('.klassy', function($timeout) { return { addClass : function(element, className, done) { - window.setTimeout(done, 500); + $timeout(done, 500, false); }, removeClass : function(element, className, done) { - window.setTimeout(done, 3000); + $timeout(done, 3000, false); } } }); @@ -967,7 +972,7 @@ describe("ngAnimate", function() { }); it("should add and remove CSS classes after an animation even if no animation is present", - inject(function($animate, $rootScope, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); $rootElement.append(parent); @@ -978,18 +983,14 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('klass-add')).toBe(true); - } - - if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - expect(element.hasClass('klass-add')).toBe(true); + $timeout.flushNext(1); expect(element.hasClass('klass-add-active')).toBe(true); - expect(element.hasClass('klass')).toBe(false); - - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); expect(element.hasClass('klass-add')).toBe(false); expect(element.hasClass('klass-add-active')).toBe(false); } + $timeout.flushNext(0); + expect(element.hasClass('klass')).toBe(true); $animate.removeClass(element,'klass'); @@ -997,14 +998,11 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('klass')).toBe(true); expect(element.hasClass('klass-remove')).toBe(true); - - window.setTimeout.expect(1).process(); - expect(element.hasClass('klass')).toBe(true); - expect(element.hasClass('klass-remove')).toBe(true); + $timeout.flushNext(1); expect(element.hasClass('klass-remove-active')).toBe(true); - - window.setTimeout.expect(0).process(); + $timeout.flushNext(0); } + $timeout.flushNext(0); expect(element.hasClass('klass')).toBe(false); expect(element.hasClass('klass-remove')).toBe(false); @@ -1012,7 +1010,7 @@ describe("ngAnimate", function() { })); it("should add and remove CSS classes with a callback", - inject(function($animate, $rootScope, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); $rootElement.append(parent); @@ -1027,9 +1025,10 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('klass')).toBe(false); - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(0); expect(element.hasClass('klass')).toBe(true); $animate.removeClass(element,'klass', function() { @@ -1038,16 +1037,17 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('klass')).toBe(true); - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(0); expect(element.hasClass('klass')).toBe(false); expect(signature).toBe('AB'); })); it("should end the current addClass animation, add the CSS class and then run the removeClass animation", - inject(function($animate, $rootScope, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { var parent = jqLite('<div><span></span></div>'); $rootElement.append(parent); @@ -1060,9 +1060,10 @@ describe("ngAnimate", function() { signature += '1'; }); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); expect(element.hasClass('klass')).toBe(false); expect(element.hasClass('klass-add')).toBe(true); + $timeout.flushNext(1); + expect(element.hasClass('klass-add-active')).toBe(true); } //this cancels out the older animation @@ -1076,17 +1077,16 @@ describe("ngAnimate", function() { expect(element.hasClass('klass-add-active')).toBe(false); expect(element.hasClass('klass-remove')).toBe(true); - window.setTimeout.expect(0).process(); - window.setTimeout.expect(1).process(); - window.setTimeout.expect(0).process(); } + $timeout.flush(); expect(element.hasClass('klass')).toBe(false); expect(signature).toBe('12'); })); it("should properly execute JS animations and use callbacks when using addClass / removeClass", - inject(function($animate, $rootScope, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { + var parent = jqLite('<div><span></span></div>'); $rootElement.append(parent); body.append($rootElement); @@ -1098,31 +1098,31 @@ describe("ngAnimate", function() { signature += 'X'; }); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - } - window.setTimeout.expect(500).process(); - if($sniffer.transitions) { - window.setTimeout.expect(0).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(500); + $timeout.flushNext(0); + expect(element.hasClass('klassy')).toBe(true); $animate.removeClass(element,'klassy', function() { signature += 'Y'; }); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - } - window.setTimeout.expect(3000).process(); - if($sniffer.transitions) { - window.setTimeout.expect(0).process(); + $timeout.flushNext(1); + $timeout.flushNext(0); } + $timeout.flushNext(3000); + $timeout.flushNext(0); + expect(element.hasClass('klassy')).toBe(false); expect(signature).toBe('XY'); })); it("should properly execute CSS animations/transitions and use callbacks when using addClass / removeClass", - inject(function($animate, $rootScope, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { var transition = 'transition:11s linear all;'; var style = transition + ' ' + vendorPrefix + transition; @@ -1138,12 +1138,14 @@ describe("ngAnimate", function() { }); if($sniffer.transitions) { expect(element.hasClass('klass-add')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('klass-add-active')).toBe(true); - window.setTimeout.expect(11000).process(); + $timeout.flushNext(11000); expect(element.hasClass('klass-add')).toBe(false); expect(element.hasClass('klass-add-active')).toBe(false); } + + $timeout.flushNext(0); expect(element.hasClass('klass')).toBe(true); $animate.removeClass(element,'klass', function() { @@ -1151,19 +1153,21 @@ describe("ngAnimate", function() { }); if($sniffer.transitions) { expect(element.hasClass('klass-remove')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('klass-remove-active')).toBe(true); - window.setTimeout.expect(11000).process(); + $timeout.flushNext(11000); expect(element.hasClass('klass-remove')).toBe(false); expect(element.hasClass('klass-remove-active')).toBe(false); } + + $timeout.flushNext(0); expect(element.hasClass('klass')).toBe(false); expect(signature).toBe('db'); })); it("should allow for multiple css classes to be animated plus a callback when added", - inject(function($animate, $rootScope, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { var transition = 'transition:7s linear all;'; var style = transition + ' ' + vendorPrefix + transition; @@ -1180,20 +1184,18 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('one-add')).toBe(true); expect(element.hasClass('two-add')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('one-add-active')).toBe(true); expect(element.hasClass('two-add-active')).toBe(true); - window.setTimeout.expect(7000).process(); + $timeout.flushNext(7000); expect(element.hasClass('one-add')).toBe(false); expect(element.hasClass('one-add-active')).toBe(false); expect(element.hasClass('two-add')).toBe(false); expect(element.hasClass('two-add-active')).toBe(false); } - else { - expect(window.setTimeout.queue.length).toBe(0); - } + $timeout.flushNext(0); expect(element.hasClass('one')).toBe(true); expect(element.hasClass('two')).toBe(true); @@ -1202,7 +1204,7 @@ describe("ngAnimate", function() { })); it("should allow for multiple css classes to be animated plus a callback when removed", - inject(function($animate, $rootScope, $sniffer, $rootElement) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { var transition = 'transition:9s linear all;'; var style = transition + ' ' + vendorPrefix + transition; @@ -1223,20 +1225,18 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('one-remove')).toBe(true); expect(element.hasClass('two-remove')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(element.hasClass('one-remove-active')).toBe(true); expect(element.hasClass('two-remove-active')).toBe(true); - window.setTimeout.expect(9000).process(); + $timeout.flushNext(9000); expect(element.hasClass('one-remove')).toBe(false); expect(element.hasClass('one-remove-active')).toBe(false); expect(element.hasClass('two-remove')).toBe(false); expect(element.hasClass('two-remove-active')).toBe(false); } - else { - expect(window.setTimeout.queue.length).toBe(0); - } + $timeout.flushNext(0); expect(element.hasClass('one')).toBe(false); expect(element.hasClass('two')).toBe(false); @@ -1246,10 +1246,8 @@ describe("ngAnimate", function() { }); }); - var $rootElement, $document, window; + var $rootElement, $document; beforeEach(module(function($provide) { - $provide.value('$window', window = angular.mock.createMockWindow()); - return function(_$rootElement_, _$document_, $animate) { $rootElement = _$rootElement_; $document = _$document_; @@ -1265,7 +1263,7 @@ describe("ngAnimate", function() { } it("should properly animate and parse CSS3 transitions", - inject(function($compile, $rootScope, $animate, $sniffer) { + inject(function($compile, $rootScope, $animate, $sniffer, $timeout) { var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; var style = 'transition: 1s linear all;' + @@ -1274,32 +1272,36 @@ describe("ngAnimate", function() { var child = $compile('<div style="' + style + '">...</div>')($rootScope); $animate.enter(child, element); + $timeout.flushNext(0); if($sniffer.transitions) { expect(child.hasClass('ng-enter')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(child.hasClass('ng-enter-active')).toBe(true); - window.setTimeout.expect(1000).process(); + $timeout.flushNext(1000); } + expect(child.hasClass('ng-enter')).toBe(false); expect(child.hasClass('ng-enter-active')).toBe(false); })); it("should properly animate and parse CSS3 animations", - inject(function($compile, $rootScope, $animate, $sniffer) { + inject(function($compile, $rootScope, $animate, $sniffer, $timeout) { var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; var style = 'animation: some_animation 4s linear 1s 2 alternate;' + vendorPrefix + 'animation: some_animation 4s linear 1s 2 alternate;'; var element = html($compile('<div>...</div>')($rootScope)); var child = $compile('<div style="' + style + '">...</div>')($rootScope); + $animate.enter(child, element); + $timeout.flushNext(0); if($sniffer.transitions) { expect(child.hasClass('ng-enter')).toBe(true); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); expect(child.hasClass('ng-enter-active')).toBe(true); - window.setTimeout.expect(9000).process(); + $timeout.flushNext(9000); } expect(child.hasClass('ng-enter')).toBe(false); expect(child.hasClass('ng-enter-active')).toBe(false); @@ -1319,22 +1321,21 @@ describe("ngAnimate", function() { expect(child.hasClass('ng-enter')).toBe(false); $animate.enter(child, element); - expect(window.setTimeout.queue.length).toBe(0); expect(child.hasClass('ng-enter')).toBe(false); })); it("should run other defined animations inline with CSS3 animations", function() { module(function($animateProvider) { - $animateProvider.register('.custom', function($window) { + $animateProvider.register('.custom', function($timeout) { return { enter : function(element, done) { element.addClass('i-was-animated'); - $window.setTimeout(done, 10); + $timeout(done, 10, false); } } }); }) - inject(function($compile, $rootScope, $animate, $sniffer) { + inject(function($compile, $rootScope, $animate, $sniffer, $timeout) { var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; var style = 'transition: 1s linear all;' + vendorPrefix + 'transition: 1s linear all;'; @@ -1345,18 +1346,19 @@ describe("ngAnimate", function() { child.addClass('custom'); $animate.enter(child, element); + $timeout.flushNext(0); - expect(child.hasClass('ng-enter')).toBe(true); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); + expect(child.hasClass('ng-enter')).toBe(true); + $timeout.flushNext(1); expect(child.hasClass('ng-enter-active')).toBe(true); } - window.setTimeout.expect(10).process(); + $timeout.flushNext(10); if($sniffer.transitions) { expect(child.hasClass('ng-enter-active')).toBe(true); - window.setTimeout.expect(1000).process(); + $timeout.flushNext(1000); expect(child.hasClass('ng-enter')).toBe(false); expect(child.hasClass('ng-enter-active')).toBe(false); } @@ -1367,16 +1369,18 @@ describe("ngAnimate", function() { it("should properly cancel CSS transitions or animations if another animation is fired", function() { module(function($animateProvider) { - $animateProvider.register('.usurper', function($window) { + $animateProvider.register('.usurper', function($timeout) { return { leave : function(element, done) { element.addClass('this-is-mine-now'); - $window.setTimeout(done, 55); + $timeout(done, 55, false); } } }); }); inject(function($compile, $rootScope, $animate, $sniffer) { + }) + inject(function($compile, $rootScope, $animate, $sniffer, $timeout) { var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; var style = 'transition: 2s linear all;' + vendorPrefix + 'transition: 2s linear all;'; @@ -1384,9 +1388,12 @@ describe("ngAnimate", function() { var child = $compile('<div style="' + style + '">...</div>')($rootScope); $animate.enter(child, element); + $timeout.flushNext(0); //initial callback + //this is added/removed right away otherwise if($sniffer.transitions) { expect(child.hasClass('ng-enter')).toBe(true); + $timeout.flushNext(1); } expect(child.hasClass('this-is-mine-now')).toBe(false); @@ -1399,16 +1406,16 @@ describe("ngAnimate", function() { expect(child.hasClass('usurper')).toBe(true); expect(child.hasClass('this-is-mine-now')).toBe(true); if($sniffer.transitions) { - window.setTimeout.expect(1).process(); - window.setTimeout.expect(1).process(); + $timeout.flushNext(1); } - window.setTimeout.expect(55).process(); + + $timeout.flushNext(55); if($sniffer.transitions) { - window.setTimeout.expect(2000).process(); + $timeout.flushNext(2000); //even though this exists, the animation will still not happen //since the done function has already been called in the cancellation - window.setTimeout.expect(2000).process(); + $timeout.flushNext(2000); } expect(child.hasClass('usurper-active')).toBe(false); @@ -1416,7 +1423,7 @@ describe("ngAnimate", function() { }); it("should add and remove CSS classes and perform CSS animations during the process", - inject(function($compile, $rootScope, $animate, $sniffer) { + inject(function($compile, $rootScope, $animate, $sniffer, $timeout) { var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; var style = 'transition: 10s linear all;' + @@ -1430,11 +1437,11 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('on')).toBe(false); expect(element.hasClass('on-add')).toBe(true); - window.setTimeout.expect(1).process(); - expect(element.hasClass('on-add-active')).toBe(true); - window.setTimeout.expect(10000).process(); + $timeout.flush(); } + $timeout.flush(); + expect(element.hasClass('on')).toBe(true); expect(element.hasClass('on-add')).toBe(false); expect(element.hasClass('on-add-active')).toBe(false); @@ -1443,11 +1450,10 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('on')).toBe(true); expect(element.hasClass('on-remove')).toBe(true); - window.setTimeout.expect(1).process(); - expect(element.hasClass('on-remove-active')).toBe(true); - window.setTimeout.expect(10000).process(); + $timeout.flush(10000); } + $timeout.flush(); expect(element.hasClass('on')).toBe(false); expect(element.hasClass('on-remove')).toBe(false); expect(element.hasClass('on-remove-active')).toBe(false); @@ -1455,22 +1461,22 @@ describe("ngAnimate", function() { it("should show and hide elements with CSS & JS animations being performed in the process", function() { module(function($animateProvider) { - $animateProvider.register('.displayer', function($window) { + $animateProvider.register('.displayer', function($timeout) { return { removeClass : function(element, className, done) { element.removeClass('hiding'); element.addClass('showing'); - $window.setTimeout(done, 25); + $timeout(done, 25, false); }, addClass : function(element, className, done) { element.removeClass('showing'); element.addClass('hiding'); - $window.setTimeout(done, 555); + $timeout(done, 555, false); } } }); }) - inject(function($compile, $rootScope, $animate, $sniffer) { + inject(function($compile, $rootScope, $animate, $sniffer, $timeout) { var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; var style = 'transition: 5s linear all;' + vendorPrefix + 'transition: 5s linear all;'; @@ -1483,16 +1489,17 @@ describe("ngAnimate", function() { expect(element.hasClass('hiding')).toBe(false); $animate.addClass(element, 'ng-hide'); + return if($sniffer.transitions) { expect(element).toBeShown(); //still showing - window.setTimeout.expect(1).process(); + $timeout.flush(); expect(element).toBeShown(); } - window.setTimeout.expect(555).process(); + $timeout.flushNext(555); if($sniffer.transitions) { expect(element).toBeShown(); - window.setTimeout.expect(5000).process(); + $timeout.flushNext(5000); } expect(element).toBeHidden(); @@ -1502,13 +1509,13 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element).toBeHidden(); - window.setTimeout.expect(1).process(); + $timeout.flush(); expect(element).toBeHidden(); } - window.setTimeout.expect(25).process(); + $timeout.flushNext(25); if($sniffer.transitions) { expect(element).toBeHidden(); - window.setTimeout.expect(5000).process(); + $timeout.flushNext(5000); } expect(element).toBeShown(); diff --git a/test/ngRoute/directive/ngViewSpec.js b/test/ngRoute/directive/ngViewSpec.js index 7d96a581..0cc70bc5 100644 --- a/test/ngRoute/directive/ngViewSpec.js +++ b/test/ngRoute/directive/ngViewSpec.js @@ -623,7 +623,7 @@ describe('ngView animations', function() { }); }); - inject(function($rootScope, $compile, $location, $route, $window, $rootElement, $sniffer, $animate) { + inject(function($rootScope, $compile, $location, $route, $timeout, $rootElement, $sniffer, $animate) { element = $compile(html('<div><ng:view onload="load()" class="my-animation"></ng:view></div>'))($rootScope); $animate.enabled(true); @@ -632,20 +632,12 @@ describe('ngView animations', function() { $animate.process('enter'); //ngView - if($sniffer.transitions) { - $window.setTimeout.expect(1).process(); - $window.setTimeout.expect(0).process(); - } + $timeout.flush(); $animate.process('enter'); //repeat 1 $animate.process('enter'); //repeat 2 - if($sniffer.transitions) { - $window.setTimeout.expect(1).process(); - $window.setTimeout.expect(1).process(); - $window.setTimeout.expect(0).process(); - $window.setTimeout.expect(0).process(); - } + $timeout.flush(); expect(element.text()).toEqual('12'); @@ -653,29 +645,17 @@ describe('ngView animations', function() { $rootScope.$digest(); $animate.process('leave'); //ngView old - if($sniffer.transitions) { - $window.setTimeout.expect(1).process(); - $window.setTimeout.expect(0).process(); - } + $timeout.flush(); $animate.process('enter'); //ngView new - if($sniffer.transitions) { - $window.setTimeout.expect(1).process(); - $window.setTimeout.expect(0).process(); - } + $timeout.flush(); expect(n(element.text())).toEqual(''); //this is midway during the animation $animate.process('enter'); //ngRepeat 3 $animate.process('enter'); //ngRepeat 4 - - if($sniffer.transitions) { - $window.setTimeout.expect(1).process(); - $window.setTimeout.expect(1).process(); - $window.setTimeout.expect(0).process(); - $window.setTimeout.expect(0).process(); - } + $timeout.flush(); expect(element.text()).toEqual('34'); |
