diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/matchers.js | 12 | ||||
| -rw-r--r-- | test/ng/animateSpec.js | 53 | ||||
| -rw-r--r-- | test/ng/animationSpec.js | 15 | ||||
| -rw-r--r-- | test/ng/animatorSpec.js | 773 | ||||
| -rwxr-xr-x | test/ng/compileSpec.js | 12 | ||||
| -rwxr-xr-x | test/ng/directive/ngIfSpec.js | 86 | ||||
| -rw-r--r-- | test/ng/directive/ngIncludeSpec.js | 98 | ||||
| -rw-r--r-- | test/ng/directive/ngRepeatSpec.js | 216 | ||||
| -rw-r--r-- | test/ng/directive/ngShowHideSpec.js | 159 | ||||
| -rw-r--r-- | test/ng/directive/ngSwitchSpec.js | 112 | ||||
| -rw-r--r-- | test/ngAnimate/animateSpec.js | 1524 | ||||
| -rw-r--r-- | test/ngRoute/directive/ngViewSpec.js | 183 | ||||
| -rw-r--r-- | test/testabilityPatch.js | 2 | 
13 files changed, 1846 insertions, 1399 deletions
| diff --git a/test/matchers.js b/test/matchers.js index 67efd3e7..ef89e3ee 100644 --- a/test/matchers.js +++ b/test/matchers.js @@ -30,11 +30,23 @@ beforeEach(function() {      return -1;    } +  function isNgElementHidden(element) { +    return angular.element(element).hasClass('ng-hide'); +  }; +    this.addMatchers({      toBeInvalid: cssMatcher('ng-invalid', 'ng-valid'),      toBeValid: cssMatcher('ng-valid', 'ng-invalid'),      toBeDirty: cssMatcher('ng-dirty', 'ng-pristine'),      toBePristine: cssMatcher('ng-pristine', 'ng-dirty'), +    toBeShown: function() { +      this.message = valueFn("Expected element to not have 'ng-hide' class"); +      return !isNgElementHidden(this.actual); +    }, +    toBeHidden: function() { +      this.message = valueFn("Expected element to have 'ng-hide' class"); +      return isNgElementHidden(this.actual); +    },      toEqual: function(expected) {        if (this.actual && this.actual.$$log) { diff --git a/test/ng/animateSpec.js b/test/ng/animateSpec.js new file mode 100644 index 00000000..7f440bb5 --- /dev/null +++ b/test/ng/animateSpec.js @@ -0,0 +1,53 @@ +describe("$animate", function() { + +  describe("without animation", function() { +    beforeEach(inject(function($compile, _$rootElement_, $rootScope) { +      element = $compile('<div></div>')($rootScope); +      $rootElement = _$rootElement_; +    })); + +    it("should add element at the start of enter animation", inject(function($animate, $compile, $rootScope) { +      var child = $compile('<div></div>')($rootScope); +      expect(element.contents().length).toBe(0); +      $animate.enter(child, element); +      expect(element.contents().length).toBe(1); +    })); + +    it("should remove the element at the end of leave animation", inject(function($animate, $compile, $rootScope) { +      var child = $compile('<div></div>')($rootScope); +      element.append(child); +      expect(element.contents().length).toBe(1); +      $animate.leave(child); +      expect(element.contents().length).toBe(0); +    })); + +    it("should reorder the move animation", inject(function($animate, $compile, $rootScope) { +      var child1 = $compile('<div>1</div>')($rootScope); +      var child2 = $compile('<div>2</div>')($rootScope); +      element.append(child1); +      element.append(child2); +      expect(element.text()).toBe('12'); +      $animate.move(child1, element, child2); +      expect(element.text()).toBe('21'); +    })); + +    it("should animate the show animation event", inject(function($animate) { +      element.addClass('ng-hide'); +      $animate.show(element); +      expect(element).toBeShown(); +    })); + +    it("should animate the hide animation event", inject(function($animate) { +      expect(element).toBeShown(); +      $animate.hide(element); +      expect(element).toBeHidden(); +    })); + +    it("should still perform DOM operations even if animations are disabled", inject(function($animate) { +      $animate.enabled(false); +      expect(element).toBeShown(); +      $animate.hide(element); +      expect(element).toBeHidden(); +    })); +  }); +}); diff --git a/test/ng/animationSpec.js b/test/ng/animationSpec.js deleted file mode 100644 index 86592643..00000000 --- a/test/ng/animationSpec.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -describe('$animation', function() { - -  it('should allow animation registration', function() { -    var noopCustom = function(){}; -    module(function($animationProvider) { -      $animationProvider.register('noop-custom', valueFn(noopCustom)); -    }); -    inject(function($animation) { -      expect($animation('noop-custom')).toBe(noopCustom); -    });  -  }); - -}); diff --git a/test/ng/animatorSpec.js b/test/ng/animatorSpec.js deleted file mode 100644 index 8fb9f05f..00000000 --- a/test/ng/animatorSpec.js +++ /dev/null @@ -1,773 +0,0 @@ -'use strict'; - -describe("$animator", function() { - -  var body, element, $rootElement; - -  function html(html) { -    body.append($rootElement); -    $rootElement.html(html); -    element = $rootElement.children().eq(0); -    return element; -  } - -  beforeEach(function() { -    // we need to run animation on attached elements; -    body = jqLite(document.body); -  }); - -  afterEach(function(){ -    dealoc(body); -  }); - -  describe("enable / disable", function() { - -    beforeEach(function() { -      module(function($animationProvider, $provide) { -        $provide.value('$window', angular.mock.createMockWindow()); -      }); -    }); - -    it("should disable and enable the animations", function() { -      var initialState = null; -      var animator; - -      angular.bootstrap(body, [function() { -        return function($animator) { -          animator = $animator; -          initialState = $animator.enabled(); -        } -      }]); - -      expect(initialState).toBe(false); - -      expect(animator.enabled()).toBe(true); - -      expect(animator.enabled(0)).toBe(false); -      expect(animator.enabled()).toBe(false); - -      expect(animator.enabled(1)).toBe(true); -      expect(animator.enabled()).toBe(true); -    }); - -  }); - -  describe("without animation", function() { -    var window, animator; - -    beforeEach(function() { -      module(function($animationProvider, $provide) { -        $provide.value('$window', window = angular.mock.createMockWindow()); -      }) -      inject(function($animator, $compile, $rootScope, _$rootElement_) { -        animator = $animator($rootScope, {}); -        element = $compile('<div></div>')($rootScope); -        $rootElement = _$rootElement_; -      }) -    }); - -    it("should add element at the start of enter animation", inject(function($animator, $compile, $rootScope) { -      var child = $compile('<div></div>')($rootScope); -      expect(element.contents().length).toBe(0); -      animator.enter(child, element); -      expect(element.contents().length).toBe(1); -    })); - -    it("should remove the element at the end of leave animation", inject(function($animator, $compile, $rootScope) { -      var child = $compile('<div></div>')($rootScope); -      element.append(child); -      expect(element.contents().length).toBe(1); -      animator.leave(child, element); -      expect(element.contents().length).toBe(0); -    })); - -    it("should reorder the move animation", inject(function($animator, $compile, $rootScope) { -      var child1 = $compile('<div>1</div>')($rootScope); -      var child2 = $compile('<div>2</div>')($rootScope); -      element.append(child1); -      element.append(child2); -      expect(element.text()).toBe('12'); -      animator.move(child1, element, child2); -      expect(element.text()).toBe('21'); -    })); - -    it("should animate the show animation event", inject(function() { -      element.css('display','none'); -      expect(element.css('display')).toBe('none'); -      animator.show(element); -      expect(element[0].style.display).toBe(''); -    })); - -    it("should animate the hide animation event", inject(function() { -      element.css('display','block'); -      expect(element.css('display')).toBe('block'); -      animator.hide(element); -      expect(element.css('display')).toBe('none'); -    })); - -    it("should still perform DOM operations even if animations are disabled", inject(function($animator) { -      $animator.enabled(false); -      element.css('display','block'); -      expect(element.css('display')).toBe('block'); -      animator.hide(element); -      expect(element.css('display')).toBe('none'); -    })); -  }); - -  describe("with polyfill", function() { - -    var child, after, window, animator; - -    beforeEach(function() { -      module(function($animationProvider, $provide) { -        $provide.value('$window', window = angular.mock.createMockWindow()); -        $animationProvider.register('custom', function() { -          return { -            start: function(element, done) { -              done(); -            } -          } -        }); -       $animationProvider.register('custom-delay', function() { -          return { -            start: function(element, done) { -              window.setTimeout(done, 2000); -            }, -            cancel : function(element) { -              element.addClass('animation-cancelled'); -            } -          } -        }); -       $animationProvider.register('setup-memo', function() { -          return { -            setup: function(element) { -              return "memento"; -            }, -            start: function(element, done, memento) { -              element.text(memento); -              done(); -            } -          } -        }); -      }) -      inject(function($animator, $compile, $rootScope, $rootElement) { -        element = $compile('<div></div>')($rootScope); -        child   = $compile('<div></div>')($rootScope); -        after   = $compile('<div></div>')($rootScope); -        $rootElement.append(element); -      }); -    }) - -    it("should animate the enter animation event", inject(function($animator, $rootScope) { -      $animator.enabled(true); -      animator = $animator($rootScope, { -        ngAnimate : '{enter: \'custom\'}' -      }); - -      expect(element.contents().length).toBe(0); -      animator.enter(child, element); -      window.setTimeout.expect(1).process(); -    })); - -    it("should animate the leave animation event", inject(function($animator, $rootScope) { -      $animator.enabled(true); -      animator = $animator($rootScope, { -        ngAnimate : '{leave: \'custom\'}' -      }); - -      element.append(child); -      expect(element.contents().length).toBe(1); -      animator.leave(child, element); -      window.setTimeout.expect(1).process(); -      expect(element.contents().length).toBe(0); -    })); - -    it("should animate the move animation event", inject(function($animator, $compile, $rootScope) { -      $animator.enabled(true); -      animator = $animator($rootScope, { -        ngAnimate : '{move: \'custom\'}' -      }); -      $rootScope.$digest(); -      var child1 = $compile('<div>1</div>')($rootScope); -      var child2 = $compile('<div>2</div>')($rootScope); -      element.append(child1); -      element.append(child2); -      expect(element.text()).toBe('12'); -      animator.move(child1, element, child2); -      expect(element.text()).toBe('21'); -      window.setTimeout.expect(1).process(); -    })); - -    it("should animate the show animation event", inject(function($animator, $rootScope) { -      $animator.enabled(true); -      animator = $animator($rootScope, { -        ngAnimate : '{show: \'custom\'}' -      }); -      $rootScope.$digest(); -      element.css('display','none'); -      expect(element.css('display')).toBe('none'); -      animator.show(element); -      expect(element[0].style.display).toBe(''); -      window.setTimeout.expect(1).process(); -      expect(element[0].style.display).toBe(''); -    })); - -    it("should animate the hide animation event", inject(function($animator, $rootScope) { -      $animator.enabled(true); -      animator = $animator($rootScope, { -        ngAnimate : '{hide: \'custom\'}' -      }); -      $rootScope.$digest(); -      element.css('display','block'); -      expect(element.css('display')).toBe('block'); -      animator.hide(element); -      expect(element.css('display')).toBe('block'); -      window.setTimeout.expect(1).process(); -      expect(element.css('display')).toBe('none'); -    })); - -    it("should assign the ngAnimate string to all events if a string is given", -        inject(function($animator, $sniffer, $rootScope) { -      $animator.enabled(true); -      if (!$sniffer.transitions) return; -      animator = $animator($rootScope, { -        ngAnimate : '"custom"' -      }); - -      $rootScope.$digest(); - -      //enter -      animator.enter(child, element); -      expect(child.attr('class')).toContain('custom-enter'); -      window.setTimeout.expect(1).process(); -      expect(child.attr('class')).toContain('custom-enter-active'); -      window.setTimeout.expect(0).process(); - -      //leave -      element.append(after); -      animator.move(child, element, after); -      expect(child.attr('class')).toContain('custom-move'); -      window.setTimeout.expect(1).process(); -      expect(child.attr('class')).toContain('custom-move-active'); -      window.setTimeout.expect(0).process(); - -      //hide -      animator.hide(child); -      expect(child.attr('class')).toContain('custom-hide'); -      window.setTimeout.expect(1).process(); -      expect(child.attr('class')).toContain('custom-hide-active'); -      window.setTimeout.expect(0).process(); - -      //show -      animator.show(child); -      expect(child.attr('class')).toContain('custom-show'); -      window.setTimeout.expect(1).process(); -      expect(child.attr('class')).toContain('custom-show-active'); -      window.setTimeout.expect(0).process(); - -      //leave -      animator.leave(child); -      expect(child.attr('class')).toContain('custom-leave'); -      window.setTimeout.expect(1).process(); -      expect(child.attr('class')).toContain('custom-leave-active'); -      window.setTimeout.expect(0).process(); -    })); - -    it("should run polyfillSetup and return the memento", inject(function($animator, $rootScope) { -      $animator.enabled(true); -      animator = $animator($rootScope, { -        ngAnimate : '{show: \'setup-memo\'}' -      }); -      $rootScope.$digest(); -      expect(element.text()).toEqual(''); -      animator.show(element); -      window.setTimeout.expect(1).process(); -      expect(element.text()).toBe('memento'); -    })); - -    it("should not run if animations are disabled", inject(function($animator, $rootScope) { -      $animator.enabled(false); - -      animator = $animator($rootScope, { -        ngAnimate : '{show: \'setup-memo\'}' -      }); -      $rootScope.$digest(); - -      element.text('123'); -      expect(element.text()).toBe('123'); -      animator.show(element); -      expect(element.text()).toBe('123'); - -      $animator.enabled(true); - -      animator.show(element); -      window.setTimeout.expect(1).process(); -      expect(element.text()).toBe('memento'); -    })); - -    it("should only call done() once and right away if another animation takes place in between", -      inject(function($animator, $rootScope) { -      $animator.enabled(true); - -      animator = $animator($rootScope, { -        ngAnimate : '{hide: \'custom-delay\', leave: \'custom-delay\'}' -      }); - -      element.append(child); - -      child.css('display','block'); -      animator.hide(child); -      window.setTimeout.expect(1).process(); -      expect(child.css('display')).toBe('block'); - -      animator.leave(child); -      expect(child.css('display')).toBe('none'); //hides instantly - -      //lets change this to prove that done doesn't fire anymore for the previous hide() operation -      child.css('display','block');  - -      window.setTimeout.expect(2000).process(); -      expect(child.css('display')).toBe('block'); //doesn't run the done() method to hide it - -      expect(element.children().length).toBe(1); //still animating - -      window.setTimeout.expect(1).process(); -      window.setTimeout.expect(2000).process(); -      expect(element.children().length).toBe(0); -    })); - -    it("should call the cancel callback when another animation is called on the same element", -      inject(function($animator, $rootScope) { -      $animator.enabled(true); - -      animator = $animator($rootScope, { -        ngAnimate : '{hide: \'custom-delay\', show: \'custom-delay\'}' -      }); - -      child.css('display','none'); -      element.data('foo', 'bar'); -      animator.show(element); -      window.setTimeout.expect(1).process(); - -      animator.hide(element); - -      expect(element.hasClass('animation-cancelled')).toBe(true); -      expect(element.data('foo')).toEqual('bar'); -    })); - -    it("should NOT clobber all data on an element when animation is finished", -      inject(function($animator, $rootScope) { -      $animator.enabled(true); - -      animator = $animator($rootScope, { -        ngAnimate : '{hide: \'custom-delay\', show: \'custom-delay\'}' -      }); - -      child.css('display','none'); -      element.data('foo', 'bar'); - -      animator.show(element); -      window.setTimeout.expect(1).process(); - -      animator.hide(element); - -      expect(element.data('foo')).toEqual('bar'); -    })); - - -    it("should properly animate custom animation events", inject(function($animator, $rootScope) { -      $animator.enabled(true); -      animator = $animator($rootScope, { -        ngAnimate : '{custom: \'setup-memo\'}' -      }); - -      element.text('123'); -      animator.animate('custom',element); -      window.setTimeout.expect(1).process(); -      expect(element.text()).toBe('memento'); -    })); -  }); - -  describe("with CSS3", function() { -    var window, animator, prefix, vendorPrefix; - -    beforeEach(function() { -      module(function($animationProvider, $provide) { -        $provide.value('$window', window = angular.mock.createMockWindow()); -        return function($sniffer, _$rootElement_, $animator) { -          vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; -          $rootElement = _$rootElement_; -          $animator.enabled(true); -        }; -      }) -    }); - -    it("should properly animate custom animations for specific animation events", -      inject(function($animator, $rootScope, $compile, $sniffer) { - -      $animator.enabled(true); -      var element = $compile(html('<div></div>'))($rootScope); - -      animator = $animator($rootScope, { -        ngAnimate : '{custom: \'special\'}' -      }); - -      animator.animate('custom',element); -      if($sniffer.transitions) { -        expect(element.hasClass('special')).toBe(true); -        window.setTimeout.expect(1).process(); -        expect(element.hasClass('special-active')).toBe(true); -      } -      else { -        expect(window.setTimeout.queue.length).toBe(0); -      } -    })); - -    it("should not animate custom animations if not specifically defined", -      inject(function($animator, $rootScope, $compile) { - -      $animator.enabled(true); -      var element = $compile(html('<div></div>'))($rootScope); - -      animator = $animator($rootScope, { -        ngAnimate : '{custom: \'special\'}' -      }); - -      expect(window.setTimeout.queue.length).toBe(0); -      animator.animate('custom1',element); -      expect(element.hasClass('special')).toBe(false); -      expect(window.setTimeout.queue.length).toBe(0); -    })); - -    it("should properly animate custom animations for general animation events", -      inject(function($animator, $rootScope, $compile, $sniffer) { - -      $animator.enabled(true); -      var element = $compile(html('<div></div>'))($rootScope); - -      animator = $animator($rootScope, { -        ngAnimate : "'special'" -      }); - -      animator.animate('custom',element); -      if($sniffer.transitions) { -        expect(element.hasClass('special-custom')).toBe(true); -        window.setTimeout.expect(1).process(); -        expect(element.hasClass('special-custom-active')).toBe(true); -      } -      else { -        expect(window.setTimeout.queue.length).toBe(0); -      } -    })); - -    describe("Animations", function() { -      it("should properly detect and make use of CSS Animations", -          inject(function($animator, $rootScope, $compile, $sniffer) { -        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); -        var animator = $animator($rootScope, { -          ngAnimate : '{show: \'inline-show\'}' -        }); - -        element.css('display','none'); -        expect(element.css('display')).toBe('none'); - -        animator.show(element); -        if ($sniffer.animations) { -          window.setTimeout.expect(1).process(); -          window.setTimeout.expect(4000).process(); -        } -        else { -          expect(window.setTimeout.queue.length).toBe(0); -        } -        expect(element[0].style.display).toBe(''); -      })); - -      it("should properly detect and make use of CSS Animations with multiple iterations", -          inject(function($animator, $rootScope, $compile, $sniffer) { -        var style = 'animation-duration: 2s;' +  -                    'animation-iteration-count: 3;' + -                    vendorPrefix + 'animation-duration: 2s;' +  -                    vendorPrefix + 'animation-iteration-count: 3;'; -        element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); -        var animator = $animator($rootScope, { -          ngAnimate : '{show: \'inline-show\'}' -        }); - -        element.css('display','none'); -        expect(element.css('display')).toBe('none'); - -        animator.show(element); -        if ($sniffer.animations) { -          window.setTimeout.expect(1).process(); -          window.setTimeout.expect(6000).process(); -        } -        else { -          expect(window.setTimeout.queue.length).toBe(0); -        } -        expect(element[0].style.display).toBe(''); -      })); - -      it("should fallback to the animation duration if an infinite iteration is provided", -          inject(function($animator, $rootScope, $compile, $sniffer) { -        var style = 'animation-duration: 2s;' +  -                    'animation-iteration-count: infinite;' + -                    vendorPrefix + 'animation-duration: 2s;' +  -                    vendorPrefix + 'animation-iteration-count: infinite;'; -        element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); -        var animator = $animator($rootScope, { -          ngAnimate : '{show: \'inline-show\'}' -        }); - -        element.css('display','none'); -        expect(element.css('display')).toBe('none'); - -        animator.show(element); -        if ($sniffer.animations) { -          window.setTimeout.expect(1).process(); -          window.setTimeout.expect(2000).process(); -        } -        else { -          expect(window.setTimeout.queue.length).toBe(0); -        } -        expect(element[0].style.display).toBe(''); -      })); - -      it("should consider the animation delay is provided", -          inject(function($animator, $rootScope, $compile, $sniffer) { -        var style = 'animation-duration: 2s;' +  -                    'animation-delay: 10s;' + -                    'animation-iteration-count: 5;' + -                    vendorPrefix + 'animation-duration: 2s;' +  -                    vendorPrefix + 'animation-delay: 10s;' + -                    vendorPrefix + 'animation-iteration-count: 5;'; -        element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); -        var animator = $animator($rootScope, { -          ngAnimate : '{show: \'inline-show\'}' -        }); - -        element.css('display','none'); -        expect(element.css('display')).toBe('none'); - -        animator.show(element); -        if ($sniffer.transitions) { -          window.setTimeout.expect(1).process(); -          window.setTimeout.expect(20000).process(); -        } -        else { -          expect(window.setTimeout.queue.length).toBe(0); -        } -        expect(element[0].style.display).toBe(''); -      })); - -      it("should skip animations if disabled and run when enabled", -          inject(function($animator, $rootScope, $compile, $sniffer) { -        $animator.enabled(false); -        var style = 'animation: some_animation 2s linear 0s 1 alternate;' + -                    vendorPrefix + 'animation: some_animation 2s linear 0s 1 alternate;' - -        element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); -        var animator = $animator($rootScope, { -          ngAnimate : '{show: \'inline-show\'}' -        }); -        element.css('display','none'); -        expect(element.css('display')).toBe('none'); -        animator.show(element); -        expect(element[0].style.display).toBe(''); -      })); - -      it("should finish the previous animation when a new animation is started", -        inject(function($animator, $rootScope, $compile, $sniffer) { -          var style = 'animation: some_animation 2s linear 0s 1 alternate;' + -                      vendorPrefix + 'animation: some_animation 2s linear 0s 1 alternate;' - -          element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); -          var animator = $animator($rootScope, { -            ngAnimate : '{show: \'show\', hide: \'hide\'}' -          }); - -          animator.show(element); -          if($sniffer.animations) { -            window.setTimeout.expect(1).process(); -            expect(element.hasClass('show')).toBe(true); -            expect(element.hasClass('show-active')).toBe(true); -          } -          else { //animation is skipped -            expect(window.setTimeout.queue.length).toBe(0); -          } - -          animator.hide(element); -          if(!$sniffer.animations) { -            expect(window.setTimeout.queue.length).toBe(0); -          } -          expect(element.hasClass('show')).toBe(false); -          expect(element.hasClass('show-active')).toBe(false); -      })); -    }); - -    describe("Transitions", function() { -      it("should skip transitions if disabled and run when enabled", -          inject(function($animator, $rootScope, $compile, $sniffer) { -        $animator.enabled(false); -        element = $compile(html('<div style="' + vendorPrefix + 'transition: 1s linear all">1</div>'))($rootScope); -        var animator = $animator($rootScope, { -          ngAnimate : '{show: \'inline-show\'}' -        }); - -        element.css('display','none'); -        expect(element.css('display')).toBe('none'); -        animator.show(element); -        expect(element[0].style.display).toBe(''); - -        $animator.enabled(true); - -        element.css('display','none'); -        expect(element.css('display')).toBe('none'); - -        animator.show(element); -        if ($sniffer.transitions) { -          window.setTimeout.expect(1).process(); -          window.setTimeout.expect(1000).process(); -        } -        else { -          expect(window.setTimeout.queue.length).toBe(0); -        } -        expect(element[0].style.display).toBe(''); -      })); - -      it("should skip animations if disabled and run when enabled picking the longest specified duration", -        inject(function($animator, $rootScope, $compile, $sniffer) { -          $animator.enabled(true); -          element = $compile(html('<div style="' + vendorPrefix + 'transition-duration: 1s, 2000ms, 1s; ' + vendorPrefix + 'transition-property: height, left, opacity">foo</div>'))($rootScope); -          var animator = $animator($rootScope, { -            ngAnimate : '{show: \'inline-show\'}' -          }); -          element.css('display','none'); -          animator.show(element); -          if ($sniffer.transitions) { -            window.setTimeout.expect(1).process(); -            window.setTimeout.expect(2000).process(); -          } -          else { -            expect(window.setTimeout.queue.length).toBe(0); -          } -          expect(element[0].style.display).toBe(''); -        })); - -      it("should skip animations if disabled and run when enabled picking the longest specified duration/delay combination", -        inject(function($animator, $rootScope, $compile, $sniffer) { -          $animator.enabled(false); -          element = $compile(html('<div style="' + vendorPrefix +  -            'transition-duration: 1s, 0s, 1s; ' + vendorPrefix + -            'transition-delay: 2s, 1000ms, 2s; ' + vendorPrefix +  -            'transition-property: height, left, opacity">foo</div>'))($rootScope); - -          var animator = $animator($rootScope, { -            ngAnimate : '{show: \'inline-show\'}' -          }); - -          element.css('display','none'); -          expect(element.css('display')).toBe('none'); -          animator.show(element); -          expect(element[0].style.display).toBe(''); - -          $animator.enabled(true); - -          element.css('display','none'); -          expect(element.css('display')).toBe('none'); - -          animator.show(element); -          if ($sniffer.transitions) { -            window.setTimeout.expect(1).process(); -            window.setTimeout.expect(3000).process(); -          } -          else { -            expect(window.setTimeout.queue.length).toBe(0); -          } -          expect(element[0].style.display).toBe(''); -      })); - -      it("should select the highest duration and delay", -        inject(function($animator, $rootScope, $compile, $sniffer) { -          var styles = 'transition:1s linear all 2s;' +  -                       vendorPrefix + 'transition:1s linear all 2s;' +  -                       'animation:my_ani 10s 1s;' +  -                       vendorPrefix + 'animation:my_ani 10s 1s;'; - -          element = $compile(html('<div style="' + styles + '">foo</div>'))($rootScope); - -          var animator = $animator($rootScope, { -            ngAnimate : '{show: \'inline-show\'}' -          }); - -          element.css('display','none'); -          expect(element.css('display')).toBe('none'); - -          animator.show(element); -          if ($sniffer.transitions) { -            window.setTimeout.expect(1).process(); -            window.setTimeout.expect(11000).process(); -          } -          else { -            expect(window.setTimeout.queue.length).toBe(0); -          } -          expect(element[0].style.display).toBe(''); -      })); - -      it("should finish the previous transition when a new animation is started", -        inject(function($animator, $rootScope, $compile, $sniffer) { -          var style = 'transition: 1s linear all;' + -                      vendorPrefix + 'transition: 1s linear all;' - -          element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); -          var animator = $animator($rootScope, { -            ngAnimate : '{show: \'show\', hide: \'hide\'}' -          }); - -          animator.show(element); -          if($sniffer.transitions) { -            window.setTimeout.expect(1).process(); -            expect(element.hasClass('show')).toBe(true); -            expect(element.hasClass('show-active')).toBe(true); -          } -          else { //animation is skipped -            expect(window.setTimeout.queue.length).toBe(0); -          } - -          animator.hide(element); -          if(!$sniffer.transitions) { -            expect(window.setTimeout.queue.length).toBe(0); -          } -          expect(element.hasClass('show')).toBe(false); -          expect(element.hasClass('show-active')).toBe(false); -      })); -    }); -  }); - -  describe('anmation evaluation', function () { -    it('should re-evaluate the animation expression on each animation', inject(function($animator, $rootScope) { -      var parent = jqLite('<div><span></span></div>'); -      var element = parent.find('span'); - -      $rootScope.animationFn = function () { throw new Error('too early'); }; -      var animate = $animator($rootScope, { ngAnimate: 'animationFn()' }); -      var log = ''; - -      $rootScope.animationFn = function () { log = 'abc' }; -      animate.enter(element, parent); -      expect(log).toEqual('abc'); - -      $rootScope.animationFn = function () { log = 'xyz' }; -      animate.enter(element, parent); -      expect(log).toEqual('xyz'); -    })); -  }); - -  it("should throw an error when an invalid ng-animate syntax is provided", inject(function($animator, $rootScope) { -    expect(function() { -      var animate = $animator($rootScope, { ngAnimate: ':' }); -      animate.enter(); -    }).toThrow("[$parse:syntax] Syntax Error: Token ':' not a primary expression at column 1 of the expression [:] starting at [:]."); -  })); -}); diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 1f5aae95..74090932 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -3096,8 +3096,8 @@ describe('$compile', function() {            '</div>')($rootScope);        $rootScope.$digest();        var spans = element.find('span'); -      expect(spans.eq(0).css('display')).toBe('none'); -      expect(spans.eq(1).css('display')).toBe('none'); +      expect(spans.eq(0)).toBeHidden(); +      expect(spans.eq(1)).toBeHidden();      })); @@ -3216,10 +3216,10 @@ describe('$compile', function() {            '</div>')($rootScope);        $rootScope.$digest();        var spans = element.find('span'); -      expect(spans.eq(0).css('display')).toBe('none'); -      expect(spans.eq(1).css('display')).toBe('none'); -      expect(spans.eq(2).css('display')).toBe('none'); -      expect(spans.eq(3).css('display')).toBe('none'); +      expect(spans.eq(0)).toBeHidden(); +      expect(spans.eq(1)).toBeHidden(); +      expect(spans.eq(2)).toBeHidden(); +      expect(spans.eq(3)).toBeHidden();      }));    });  }); diff --git a/test/ng/directive/ngIfSpec.js b/test/ng/directive/ngIfSpec.js index 0cca57d5..8f2cb793 100755 --- a/test/ng/directive/ngIfSpec.js +++ b/test/ng/directive/ngIfSpec.js @@ -75,8 +75,7 @@ describe('ngIf', function () {  }); -describe('ngIf ngAnimate', function () { -  var vendorPrefix, window; +describe('ngIf animations', function () {    var body, element, $rootElement;    function html(html) { @@ -85,6 +84,8 @@ describe('ngIf ngAnimate', function () {      return element;    } +  beforeEach(module('mock.animate')); +    beforeEach(module(function() {      // we need to run animation on attached elements;      return function(_$rootElement_) { @@ -99,97 +100,52 @@ describe('ngIf ngAnimate', function () {      dealoc(element);    }); -  beforeEach(module(function($animationProvider, $provide) { -    $provide.value('$window', window = angular.mock.createMockWindow()); -    return function($sniffer, $animator) { -      vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; -      $animator.enabled(true); +  beforeEach(module(function($animateProvider, $provide) { +    return function($animate) { +      $animate.enabled(true);      };    })); -  it('should fire off the enter animation + add and remove the css classes', -    inject(function($compile, $rootScope, $sniffer) { +  it('should fire off the enter animation', +    inject(function($compile, $rootScope, $animate) { +      var item;        var $scope = $rootScope.$new(); -      var style = vendorPrefix + 'transition: 1s linear all';        element = $compile(html(          '<div>' + -          '<div ng-if="value" style="' + style + '" ng-animate="{enter: \'custom-enter\', leave: \'custom-leave\'}"><div>Hi</div></div>' + +          '<div ng-if="value"><div>Hi</div></div>' +          '</div>'        ))($scope);        $rootScope.$digest();        $scope.$apply('value = true'); +      item = $animate.process('enter').element; +      expect(item.text()).toBe('Hi');        expect(element.children().length).toBe(1); -      var first = element.children()[0]; - -      if ($sniffer.transitions) { -        expect(first.className).toContain('custom-enter'); -        window.setTimeout.expect(1).process(); -        expect(first.className).toContain('custom-enter-active'); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(first.className).not.toContain('custom-enter'); -      expect(first.className).not.toContain('custom-enter-active');    })); -  it('should fire off the leave animation + add and remove the css classes', -    inject(function ($compile, $rootScope, $sniffer) { +  it('should fire off the leave animation', +    inject(function ($compile, $rootScope, $animate) { +      var item;        var $scope = $rootScope.$new(); -      var style = vendorPrefix + 'transition: 1s linear all';        element = $compile(html(          '<div>' + -          '<div ng-if="value" style="' + style + '" ng-animate="{enter: \'custom-enter\', leave: \'custom-leave\'}"><div>Hi</div></div>' + +          '<div ng-if="value"><div>Hi</div></div>' +          '</div>'        ))($scope);        $scope.$apply('value = true'); -      expect(element.children().length).toBe(1); -      var first = element.children()[0]; - -      if ($sniffer.transitions) { -        window.setTimeout.expect(1).process(); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } +      item = $animate.process('enter').element; +      expect(item.text()).toBe('Hi');        $scope.$apply('value = false'); -      expect(element.children().length).toBe($sniffer.transitions ? 1 : 0); +      expect(element.children().length).toBe(1); -      if ($sniffer.transitions) { -        expect(first.className).toContain('custom-leave'); -        window.setTimeout.expect(1).process(); -        expect(first.className).toContain('custom-leave-active'); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } +      item = $animate.process('leave').element; +      expect(item.text()).toBe('Hi');        expect(element.children().length).toBe(0);    })); -  it('should catch and use the correct duration for animation', -    inject(function ($compile, $rootScope, $sniffer) { -      var $scope = $rootScope.$new(); -      var style = vendorPrefix + 'transition: 0.5s linear all'; -      element = $compile(html( -        '<div>' + -          '<div ng-if="value" style="' + style + '" ng-animate="{enter: \'custom-enter\', leave: \'custom-leave\'}"><div>Hi</div></div>' + -        '</div>' -      ))($scope); -      $scope.$apply('value = true'); - -      if ($sniffer.transitions) { -        window.setTimeout.expect(1).process(); -        window.setTimeout.expect(500).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } -  })); -  }); diff --git a/test/ng/directive/ngIncludeSpec.js b/test/ng/directive/ngIncludeSpec.js index 6cb78755..286ee5af 100644 --- a/test/ng/directive/ngIncludeSpec.js +++ b/test/ng/directive/ngIncludeSpec.js @@ -341,8 +341,7 @@ describe('ngInclude', function() {    });  }); -describe('ngInclude ngAnimate', function() { -  var vendorPrefix, window; +describe('ngInclude animations', function() {    var body, element, $rootElement;    function html(html) { @@ -351,11 +350,6 @@ describe('ngInclude ngAnimate', function() {      return element;    } -  function applyCSS(element, cssProp, cssValue) { -    element.css(cssProp, cssValue); -    element.css(vendorPrefix + cssProp, cssValue); -  } -    beforeEach(module(function() {      // we need to run animation on attached elements;      return function(_$rootElement_) { @@ -370,107 +364,51 @@ describe('ngInclude ngAnimate', function() {      dealoc(element);    }); -  beforeEach(module(function($animationProvider, $provide) { -    $provide.value('$window', window = angular.mock.createMockWindow()); -    return function($sniffer, $animator) { -      vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; -      $animator.enabled(true); -    }; -  })); +  beforeEach(module('mock.animate'));    afterEach(function(){      dealoc(element);    }); -  it('should fire off the enter animation + add and remove the css classes', -    inject(function($compile, $rootScope, $templateCache, $sniffer) { +  it('should fire off the enter animation', +    inject(function($compile, $rootScope, $templateCache, $animate) { +      var item;        $templateCache.put('enter', [200, '<div>data</div>', {}]);        $rootScope.tpl = 'enter';        element = $compile(html(          '<div ' + -          'ng-include="tpl" ' + -          'ng-animate="{enter: \'custom-enter\'}">' + +          'ng-include="tpl">' +          '</div>'        ))($rootScope);        $rootScope.$digest(); -      //if we add the custom css stuff here then it will get picked up before the animation takes place -      var child = jqLite(element.children()[0]); -      applyCSS(child, 'transition', '1s linear all'); - -      if ($sniffer.transitions) { -        expect(child.attr('class')).toContain('custom-enter'); -        window.setTimeout.expect(1).process(); - -        expect(child.attr('class')).toContain('custom-enter-active'); -        window.setTimeout.expect(1000).process(); -      } else { -       expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(child.attr('class')).not.toContain('custom-enter'); -      expect(child.attr('class')).not.toContain('custom-enter-active'); +      item = $animate.process('leave').element; +      item = $animate.process('enter').element; +      expect(item.text()).toBe('data');    })); -  it('should fire off the leave animation + add and remove the css classes', -    inject(function($compile, $rootScope, $templateCache, $sniffer) { +  it('should fire off the leave animation', +    inject(function($compile, $rootScope, $templateCache, $animate) { +      var item;        $templateCache.put('enter', [200, '<div>data</div>', {}]);        $rootScope.tpl = 'enter';        element = $compile(html(          '<div ' + -          'ng-include="tpl" ' + -          'ng-animate="{leave: \'custom-leave\'}">' + +          'ng-include="tpl">' +          '</div>'        ))($rootScope);        $rootScope.$digest(); -      //if we add the custom css stuff here then it will get picked up before the animation takes place -      var child = jqLite(element.children()[0]); -      applyCSS(child, 'transition', '1s linear all'); +      item = $animate.process('leave').element; +      item = $animate.process('enter').element; +      expect(item.text()).toBe('data');        $rootScope.tpl = '';        $rootScope.$digest(); -      if ($sniffer.transitions) { -        expect(child.attr('class')).toContain('custom-leave'); -        window.setTimeout.expect(1).process(); - -        expect(child.attr('class')).toContain('custom-leave-active'); -        window.setTimeout.expect(1000).process(); -      } else { -       expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(child.attr('class')).not.toContain('custom-leave'); -      expect(child.attr('class')).not.toContain('custom-leave-active'); -  })); - -  it('should catch and use the correct duration for animation', -    inject(function($compile, $rootScope, $templateCache, $sniffer) { -      $templateCache.put('enter', [200, '<div>data</div>', {}]); -      $rootScope.tpl = 'enter'; -      element = $compile(html( -        '<div ' + -          'ng-include="tpl" ' + -          'ng-animate="{enter: \'custom-enter\'}">' + -        '</div>' -      ))($rootScope); -      $rootScope.$digest(); - -      //if we add the custom css stuff here then it will get picked up before the animation takes place -      var child = jqLite(element.children()[0]); -      applyCSS(child, 'transition', '0.5s linear all'); - -      $rootScope.tpl = 'enter'; -      $rootScope.$digest(); - -      if ($sniffer.transitions) { -        window.setTimeout.expect(1).process(); -        window.setTimeout.expect(500).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } +      item = $animate.process('leave').element; +      expect(item.text()).toBe('data');    }));  }); diff --git a/test/ng/directive/ngRepeatSpec.js b/test/ng/directive/ngRepeatSpec.js index 26562f4e..a85fd5ab 100644 --- a/test/ng/directive/ngRepeatSpec.js +++ b/test/ng/directive/ngRepeatSpec.js @@ -822,10 +822,30 @@ describe('ngRepeat', function() {        expect(newLis[2]).toEqual(lis[1]);      });    }); + +  it('should grow multi-node repeater', inject(function($compile, $rootScope) { +    $rootScope.show = false; +    $rootScope.books = [ +      {title:'T1', description: 'D1'}, +      {title:'T2', description: 'D2'} +    ]; +    element = $compile( +        '<div>' + +            '<dt ng-repeat-start="book in books">{{book.title}}:</dt>' + +            '<dd ng-repeat-end>{{book.description}};</dd>' + +        '</div>')($rootScope); + +    $rootScope.$digest(); +    expect(element.text()).toEqual('T1:D1;T2:D2;'); +    $rootScope.books.push({title:'T3', description: 'D3'}); +    $rootScope.$digest(); +    expect(element.text()).toEqual('T1:D1;T2:D2;T3:D3;'); +  })); + +  }); -describe('ngRepeat ngAnimate', function() { -  var vendorPrefix, window; +describe('ngRepeat animations', function() {    var body, element, $rootElement;    function html(html) { @@ -834,10 +854,7 @@ describe('ngRepeat ngAnimate', function() {      return element;    } -  function applyCSS(element, cssProp, cssValue) { -    element.css(cssProp, cssValue); -    element.css(vendorPrefix + cssProp, cssValue); -  } +  beforeEach(module('mock.animate'));    beforeEach(module(function() {      // we need to run animation on attached elements; @@ -853,21 +870,14 @@ describe('ngRepeat ngAnimate', function() {      dealoc(element);    }); -  beforeEach(module(function($animationProvider, $provide) { -    $provide.value('$window', window = angular.mock.createMockWindow()); -    return function($sniffer, $animator) { -      vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; -      $animator.enabled(true); -    }; -  })); +  it('should fire off the enter animation', +    inject(function($compile, $rootScope, $animate) { -  it('should fire off the enter animation + add and remove the css classes', -    inject(function($compile, $rootScope, $sniffer) { +    var item;      element = $compile(html(        '<div><div ' + -        'ng-repeat="item in items" ' + -        'ng-animate="{enter: \'custom-enter\'}">' + +        'ng-repeat="item in items">' +          '{{ item }}' +        '</div></div>'      ))($rootScope); @@ -877,40 +887,24 @@ describe('ngRepeat ngAnimate', function() {      $rootScope.items = ['1','2','3'];      $rootScope.$digest(); -    //if we add the custom css stuff here then it will get picked up before the animation takes place -    var kids = element.children(); -    for(var i=0;i<kids.length;i++) { -      kids[i] = jqLite(kids[i]); -      applyCSS(kids[i], 'transition', '1s linear all'); -    } - -    if ($sniffer.transitions) { -      angular.forEach(kids, function(kid) { -        expect(kid.attr('class')).toContain('custom-enter'); -        window.setTimeout.expect(1).process(); -      }); +    item = $animate.process('enter').element; +    expect(item.text()).toBe('1'); -      angular.forEach(kids, function(kid) { -        expect(kid.attr('class')).toContain('custom-enter-active'); -        window.setTimeout.expect(1000).process(); -      }); -    } else { -      expect(window.setTimeout.queue).toEqual([]); -    } +    item = $animate.process('enter').element; +    expect(item.text()).toBe('2'); -    angular.forEach(kids, function(kid) { -      expect(kid.attr('class')).not.toContain('custom-enter'); -      expect(kid.attr('class')).not.toContain('custom-enter-active'); -    }); +    item = $animate.process('enter').element; +    expect(item.text()).toBe('3');    })); -  it('should fire off the leave animation + add and remove the css classes', -    inject(function($compile, $rootScope, $sniffer) { +  it('should fire off the leave animation', +    inject(function($compile, $rootScope, $animate) { + +    var item;      element = $compile(html(        '<div><div ' + -        'ng-repeat="item in items" ' + -        'ng-animate="{leave: \'custom-leave\'}">' + +        'ng-repeat="item in items">' +          '{{ item }}' +        '</div></div>'      ))($rootScope); @@ -918,36 +912,30 @@ describe('ngRepeat ngAnimate', function() {      $rootScope.items = ['1','2','3'];      $rootScope.$digest(); -    //if we add the custom css stuff here then it will get picked up before the animation takes place -    var kids = element.children(); -    for(var i=0;i<kids.length;i++) { -      kids[i] = jqLite(kids[i]); -      applyCSS(kids[i], 'transition', '1s linear all'); -    } +    item = $animate.process('enter').element; +    expect(item.text()).toBe('1'); + +    item = $animate.process('enter').element; +    expect(item.text()).toBe('2'); + +    item = $animate.process('enter').element; +    expect(item.text()).toBe('3');      $rootScope.items = ['1','3'];      $rootScope.$digest(); -    //the last element gets pushed down when it animates -    var kid = jqLite(element.children()[1]); -    if ($sniffer.transitions) { -      expect(kid.attr('class')).toContain('custom-leave'); -      window.setTimeout.expect(1).process(); -      expect(kid.attr('class')).toContain('custom-leave-active'); -      window.setTimeout.expect(1000).process(); -    } else { -      expect(window.setTimeout.queue).toEqual([]); -    } - -    expect(kid.attr('class')).not.toContain('custom-leave'); -    expect(kid.attr('class')).not.toContain('custom-leave-active'); +    item = $animate.process('leave').element; +    expect(item.text()).toBe('2');    })); -  it('should fire off the move animation + add and remove the css classes', -    inject(function($compile, $rootScope, $sniffer) { +  it('should fire off the move animation', +    inject(function($compile, $rootScope, $animate) { + +      var item; +        element = $compile(html(          '<div>' + -          '<div ng-repeat="item in items" ng-animate="{move: \'custom-move\'}">' + +          '<div ng-repeat="item in items">' +              '{{ item }}' +            '</div>' +          '</div>' @@ -956,97 +944,23 @@ describe('ngRepeat ngAnimate', function() {        $rootScope.items = ['1','2','3'];        $rootScope.$digest(); -      //if we add the custom css stuff here then it will get picked up before the animation takes place -      var kids = element.children(); -      for(var i=0;i<kids.length;i++) { -        kids[i] = jqLite(kids[i]); -        applyCSS(kids[i], 'transition', '1s linear all'); -      } +      item = $animate.process('enter').element; +      expect(item.text()).toBe('1'); -      $rootScope.items = ['2','3','1']; -      $rootScope.$digest(); - -      //the last element gets pushed down when it animates -      kids  = element.children(); -      var first = jqLite(kids[0]); -      var left  = jqLite(kids[1]); -      var right = jqLite(kids[2]); - -      if ($sniffer.transitions) { -        expect(first.attr('class')).toContain('custom-move'); -        window.setTimeout.expect(1).process(); -        expect(left.attr('class')).toContain('custom-move'); -        window.setTimeout.expect(1).process(); - -        expect(first.attr('class')).toContain('custom-move-active'); -        window.setTimeout.expect(1000).process(); -        expect(left.attr('class')).toContain('custom-move-active'); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(first.attr('class')).not.toContain('custom-move'); -      expect(first.attr('class')).not.toContain('custom-move-active'); -      expect(left.attr('class')).not.toContain('custom-move'); -      expect(left.attr('class')).not.toContain('custom-move-active'); -      expect(right.attr('class')).not.toContain('custom-move'); -      expect(right.attr('class')).not.toContain('custom-move-active'); -  })); +      item = $animate.process('enter').element; +      expect(item.text()).toBe('2'); -  it('should catch and use the correct duration for animation', -    inject(function($compile, $rootScope, $sniffer) { +      item = $animate.process('enter').element; +      expect(item.text()).toBe('3'); -      element = $compile(html( -        '<div><div ' + -          'ng-repeat="item in items" ' + -          'ng-animate="{enter: \'custom-enter\'}">' + -          '{{ item }}' + -        '</div></div>' -      ))($rootScope); - -      $rootScope.$digest(); // re-enable the animations; - -      $rootScope.items = ['a','b']; +      $rootScope.items = ['2','3','1'];        $rootScope.$digest(); -      //if we add the custom css stuff here then it will get picked up before the animation takes place -      var kids = element.children(); -      var first = jqLite(kids[0]); -      var second = jqLite(kids[1]); -      var cssProp = 'transition'; -      var cssValue = '0.5s linear all'; -      applyCSS(first, cssProp, cssValue); -      applyCSS(second, cssProp, cssValue); - -      if ($sniffer.transitions) { -        window.setTimeout.expect(1).process(); -        window.setTimeout.expect(1).process(); -        window.setTimeout.expect(500).process(); -        window.setTimeout.expect(500).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } -  })); +      item = $animate.process('move').element; +      expect(item.text()).toBe('2'); -  it('should grow multi-node repeater', inject(function($compile, $rootScope) { -    $rootScope.show = false; -    $rootScope.books = [ -      {title:'T1', description: 'D1'}, -      {title:'T2', description: 'D2'} -    ]; -    element = $compile( -        '<div>' + -            '<dt ng-repeat-start="book in books">{{book.title}}:</dt>' + -            '<dd ng-repeat-end>{{book.description}};</dd>' + -        '</div>')($rootScope); - -    $rootScope.$digest(); -    expect(element.text()).toEqual('T1:D1;T2:D2;'); -    $rootScope.books.push({title:'T3', description: 'D3'}); -    $rootScope.$digest(); -    expect(element.text()).toEqual('T1:D1;T2:D2;T3:D3;'); +      item = $animate.process('move').element; +      expect(item.text()).toBe('1');    })); -  }); diff --git a/test/ng/directive/ngShowHideSpec.js b/test/ng/directive/ngShowHideSpec.js index 9b95440d..f8193a12 100644 --- a/test/ng/directive/ngShowHideSpec.js +++ b/test/ng/directive/ngShowHideSpec.js @@ -13,20 +13,20 @@ describe('ngShow / ngHide', function() {        element = jqLite('<div ng-show="exp"></div>');        element = $compile(element)($rootScope);        $rootScope.$digest(); -      expect(isCssVisible(element)).toEqual(false); +      expect(element).toBeHidden();        $rootScope.exp = true;        $rootScope.$digest(); -      expect(isCssVisible(element)).toEqual(true); +      expect(element).toBeShown();      }));      it('should make hidden element visible', inject(function($rootScope, $compile) { -      element = jqLite('<div style="display: none" ng-show="exp"></div>'); +      element = jqLite('<div class="ng-hide" ng-show="exp"></div>');        element = $compile(element)($rootScope); -      expect(isCssVisible(element)).toBe(false); +      expect(element).toBeHidden();        $rootScope.exp = true;        $rootScope.$digest(); -      expect(isCssVisible(element)).toBe(true); +      expect(element).toBeShown();      }));    }); @@ -34,17 +34,15 @@ describe('ngShow / ngHide', function() {      it('should hide an element', inject(function($rootScope, $compile) {        element = jqLite('<div ng-hide="exp"></div>');        element = $compile(element)($rootScope); -      expect(isCssVisible(element)).toBe(true); +      expect(element).toBeShown();        $rootScope.exp = true;        $rootScope.$digest(); -      expect(isCssVisible(element)).toBe(false); +      expect(element).toBeHidden();      }));    });  }); -describe('ngShow / ngHide - ngAnimate', function() { -  var window; -  var vendorPrefix; +describe('ngShow / ngHide animations', function() {    var body, element, $rootElement;    function html(html) { @@ -65,152 +63,57 @@ describe('ngShow / ngHide - ngAnimate', function() {      body.removeAttr('ng-animation-running');    }); -  beforeEach(module(function($animationProvider, $provide) { -    $provide.value('$window', window = angular.mock.createMockWindow()); -    return function($sniffer, _$rootElement_, $animator) { -      vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; +  beforeEach(module('mock.animate')); + +  beforeEach(module(function($animateProvider, $provide) { +    return function(_$rootElement_) {        $rootElement = _$rootElement_; -      $animator.enabled(true);      };    }));    describe('ngShow', function() { -    it('should fire off the animator.show and animator.hide animation', inject(function($compile, $rootScope, $sniffer) { +    it('should fire off the $animate.show and $animate.hide animation', inject(function($compile, $rootScope, $animate) { +      var item;        var $scope = $rootScope.$new();        $scope.on = true;        element = $compile(html( -        '<div ' + -          'style="'+vendorPrefix+'transition: 1s linear all"' + -          'ng-show="on" ' + -          'ng-animate="{show: \'custom-show\', hide: \'custom-hide\', animateFirst: true}">' + -        '</div>' +        '<div ng-show="on">data</div>'        ))($scope);        $scope.$digest(); -      if ($sniffer.transitions) { -        expect(element.attr('class')).toContain('custom-show'); -        window.setTimeout.expect(1).process(); - -        expect(element.attr('class')).toContain('custom-show-active'); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(element.attr('class')).not.toContain('custom-show-active'); -      expect(element.attr('class')).not.toContain('custom-show'); +      item = $animate.process('show').element; +      expect(item.text()).toBe('data'); +      expect(item).toBeShown();        $scope.on = false;        $scope.$digest(); -      if ($sniffer.transitions) { -        expect(element.attr('class')).toContain('custom-hide'); -        window.setTimeout.expect(1).process(); -        expect(element.attr('class')).toContain('custom-hide-active'); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(element.attr('class')).not.toContain('custom-hide-active'); -      expect(element.attr('class')).not.toContain('custom-hide'); -    })); -    it('should skip animation if parent animation running', function() { -      var fired = false; -      inject(function($animator, $compile, $rootScope, $sniffer) { -        $animator.enabled(true); -        $rootScope.$digest(); -        $rootScope.val = true; -        var element = $compile(html('<div ng-show="val" ng-animate="\'animation\'">123</div>'))($rootScope); -        $rootElement.controller('ngAnimate').running = true; -        element.css('display','none'); -        expect(element.css('display')).toBe('none'); - -        $rootScope.$digest(); -        expect(element[0].style.display).toBe(''); -        expect(fired).toBe(false); - -        $rootElement.controller('ngAnimate').running = false; -        $rootScope.val = false; -        $rootScope.$digest(); -        if ($sniffer.transitions) { -          window.setTimeout.expect(1).process(); -          window.setTimeout.expect(0).process(); -        } else { -          expect(window.setTimeout.queue).toEqual([]); -        } -        expect(element[0].style.display).toBe('none'); -      }); -    }); +      item = $animate.process('hide').element; +      expect(item.text()).toBe('data'); +      expect(item).toBeHidden(); +    }));    });    describe('ngHide', function() { -    it('should fire off the animator.show and animator.hide animation', inject(function($compile, $rootScope, $sniffer) { +    it('should fire off the $animate.show and $animate.hide animation', inject(function($compile, $rootScope, $animate) { +      var item;        var $scope = $rootScope.$new();        $scope.off = true;        element = $compile(html( -          '<div ' + -              'style="'+vendorPrefix+'transition: 1s linear all"' + -              'ng-hide="off" ' + -              'ng-animate="{show: \'custom-show\', hide: \'custom-hide\', animateFirst: true}">' + -          '</div>' +          '<div ng-hide="off">datum</div>'        ))($scope);        $scope.$digest(); -      if ($sniffer.transitions) { -        expect(element.attr('class')).toContain('custom-hide'); -        window.setTimeout.expect(1).process(); - -        expect(element.attr('class')).toContain('custom-hide-active'); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(element.attr('class')).not.toContain('custom-hide-active'); -      expect(element.attr('class')).not.toContain('custom-hide'); +      item = $animate.process('hide').element; +      expect(item.text()).toBe('datum'); +      expect(item).toBeHidden();        $scope.off = false;        $scope.$digest(); -      if ($sniffer.transitions) { -        expect(element.attr('class')).toContain('custom-show'); -        window.setTimeout.expect(1).process(); -        expect(element.attr('class')).toContain('custom-show-active'); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(element.attr('class')).not.toContain('custom-show-active'); -      expect(element.attr('class')).not.toContain('custom-show'); +      item = $animate.process('show').element; +      expect(item.text()).toBe('datum'); +      expect(item).toBeShown();      })); - -    it('should disable animation when parent animation is running', function() { -      var fired = false; -      module(function($animationProvider) { -        $animationProvider.register('destructive-animation', function() { -          return { -            setup : function() {}, -            start : function(element, done) { -              fired = true; -            } -          }; -        }); -      }); -      inject(function($compile, $rootScope) { -        $rootScope.val = false; -        var element = $compile(html('<div ng-hide="val" ng-animate="{ hide:\'destructive-animation\' }">123</div>'))($rootScope); -        $rootElement.controller('ngAnimate').running = true; -        element.css('display','block'); -        expect(element.css('display')).toBe('block'); - -        $rootScope.val = true; -        $rootScope.$digest(); - -        expect(element.css('display')).toBe('none'); -        expect(fired).toBe(false); -      }); -    });    });  }); diff --git a/test/ng/directive/ngSwitchSpec.js b/test/ng/directive/ngSwitchSpec.js index ab231ec2..8750b187 100644 --- a/test/ng/directive/ngSwitchSpec.js +++ b/test/ng/directive/ngSwitchSpec.js @@ -214,8 +214,7 @@ describe('ngSwitch', function() {    }));  }); -describe('ngSwitch ngAnimate', function() { -  var vendorPrefix, window; +describe('ngSwitch animations', function() {    var body, element, $rootElement;    function html(html) { @@ -224,6 +223,8 @@ describe('ngSwitch ngAnimate', function() {      return element;    } +  beforeEach(module('mock.animate')); +    beforeEach(module(function() {      // we need to run animation on attached elements;      return function(_$rootElement_) { @@ -238,23 +239,15 @@ describe('ngSwitch ngAnimate', function() {      dealoc(element);    }); -  beforeEach(module(function($animationProvider, $provide) { -    $provide.value('$window', window = angular.mock.createMockWindow()); -    return function($sniffer, $animator) { -      vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; -      $animator.enabled(true); -    }; -  })); - -  it('should fire off the enter animation + set and remove the classes', -    inject(function($compile, $rootScope, $sniffer) { +  it('should fire off the enter animation', +    inject(function($compile, $rootScope, $animate) { +      var item;        var $scope = $rootScope.$new(); -      var style = vendorPrefix + 'transition: 1s linear all';        element = $compile(html( -        '<div ng-switch on="val" ng-animate="{enter: \'cool-enter\', leave: \'cool-leave\'}">' + -          '<div ng-switch-when="one" style="' + style + '">one</div>' + -          '<div ng-switch-when="two" style="' + style + '">two</div>' + -          '<div ng-switch-when="three" style="' + style + '">three</div>' + +        '<div ng-switch on="val">' + +          '<div ng-switch-when="one">one</div>' + +          '<div ng-switch-when="two">two</div>' + +          '<div ng-switch-when="three">three</div>' +          '</div>'        ))($scope); @@ -262,33 +255,20 @@ describe('ngSwitch ngAnimate', function() {        $scope.val = 'one';        $scope.$digest(); -      expect(element.children().length).toBe(1); -      var first = element.children()[0]; - -      if ($sniffer.transitions) { -        expect(first.className).toContain('cool-enter'); -        window.setTimeout.expect(1).process(); - -        expect(first.className).toContain('cool-enter-active'); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(first.className).not.toContain('cool-enter'); -      expect(first.className).not.toContain('cool-enter-active'); +      item = $animate.process('enter').element; +      expect(item.text()).toBe('one');    })); -  it('should fire off the leave animation + set and remove the classes', -    inject(function($compile, $rootScope, $sniffer) { +  it('should fire off the leave animation', +    inject(function($compile, $rootScope, $animate) { +      var item;        var $scope = $rootScope.$new(); -      var style = vendorPrefix + 'transition: 1s linear all';        element = $compile(html( -        '<div ng-switch on="val" ng-animate="{enter: \'cool-enter\', leave: \'cool-leave\'}">' + -          '<div ng-switch-when="one" style="' + style + '">one</div>' + -          '<div ng-switch-when="two" style="' + style + '">two</div>' + -          '<div ng-switch-when="three" style="' + style + '">three</div>' + +        '<div ng-switch on="val">' + +          '<div ng-switch-when="one">one</div>' + +          '<div ng-switch-when="two">two</div>' + +          '<div ng-switch-when="three">three</div>' +          '</div>'        ))($scope); @@ -296,59 +276,17 @@ describe('ngSwitch ngAnimate', function() {        $scope.val = 'two';        $scope.$digest(); -      if ($sniffer.transitions) { -        window.setTimeout.expect(1).process(); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } +      item = $animate.process('enter').element; +      expect(item.text()).toBe('two');        $scope.val = 'three';        $scope.$digest(); -      expect(element.children().length).toBe($sniffer.transitions ? 2 : 1); -      var first = element.children()[0]; - - -      if ($sniffer.transitions) { -        expect(first.className).toContain('cool-leave'); -        window.setTimeout.expect(1).process(); -        window.setTimeout.expect(1).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } +      item = $animate.process('leave').element; +      expect(item.text()).toBe('two'); - -      if ($sniffer.transitions) { -        expect(first.className).toContain('cool-leave-active'); -        window.setTimeout.expect(1000).process(); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } - -      expect(first.className).not.toContain('cool-leave'); -      expect(first.className).not.toContain('cool-leave-active'); -  })); - -  it('should catch and use the correct duration for animation', -    inject(function($compile, $rootScope, $sniffer) { -      element = $compile(html( -        '<div ng-switch on="val" ng-animate="{enter: \'cool-enter\', leave: \'cool-leave\'}">' + -          '<div ng-switch-when="one" style="' + vendorPrefix + 'transition: 0.5s linear all">one</div>' + -        '</div>' -      ))($rootScope); - -      $rootScope.$digest(); // re-enable the animations; -      $rootScope.val = 'one'; -      $rootScope.$digest(); - -      if ($sniffer.transitions) { -        window.setTimeout.expect(1).process(); -        window.setTimeout.expect(500).process(); -      } else { -       expect(window.setTimeout.queue).toEqual([]); -      } +      item = $animate.process('enter').element; +      expect(item.text()).toBe('three');    }));  }); diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js new file mode 100644 index 00000000..52bf5e0b --- /dev/null +++ b/test/ngAnimate/animateSpec.js @@ -0,0 +1,1524 @@ +'use strict'; + +describe("ngAnimate", function() { + +  beforeEach(module('ngAnimate')); + +  describe("$animate", function() { + +    var body, element, $rootElement; + +    function html(html) { +      body.append($rootElement); +      $rootElement.html(html); +      element = $rootElement.children().eq(0); +      return element; +    } + +    beforeEach(module(function() { +      // we need to run animation on attached elements; +      body = jqLite(document.body); +      return function($animate) { +        $animate.enabled(true); +      }; +    })); + +    afterEach(function(){ +      dealoc(body); +    }); + +    describe("enable / disable", function() { + +      beforeEach(function() { +        module(function($animateProvider, $provide) { +          $provide.value('$window', angular.mock.createMockWindow()); +        }); +      }); + +      it("should disable and enable the animations", function() { +        var $animate, initialState = null; + +        angular.bootstrap(body, ['ngAnimate',function() { +          return function(_$animate_) { +            $animate = _$animate_; +            initialState = $animate.enabled(); +          } +        }]); + +        expect(initialState).toBe(false); + +        expect($animate.enabled()).toBe(true); + +        expect($animate.enabled(0)).toBe(false); +        expect($animate.enabled()).toBe(false); + +        expect($animate.enabled(1)).toBe(true); +        expect($animate.enabled()).toBe(true); +      }); + +    }); + +    describe("with polyfill", function() { + +      var child, after, window; + +      beforeEach(function() { +        module(function($animateProvider, $provide) { +          $provide.value('$window', window = angular.mock.createMockWindow()); +          $animateProvider.register('.custom', function() { +            return { +              start: function(element, done) { +                done(); +              } +            } +          }); +         $animateProvider.register('.custom-delay', function() { +            function animate(element, done) { +              done = arguments.length == 3 ? arguments[2] : done; +              window.setTimeout(done, 2000); +              return function() { +                element.addClass('animation-cancelled'); +              } +            } +            return { +              show : animate, +              hide : animate, +              leave : animate, +              addClass : animate, +              removeClass : animate +            } +          }); +         $animateProvider.register('.custom-long-delay', function() { +            function animate(element, done) { +              done = arguments.length == 3 ? arguments[2] : done; +              window.setTimeout(done, 20000); +              return function() { +                element.addClass('animation-cancelled'); +              } +            } +            return { +              show : animate, +              hide : animate, +              leave : animate, +              addClass : animate, +              removeClass : animate +            } +          }); +         $animateProvider.register('.setup-memo', function() { +            return { +              show: function(element, done) { +                element.text('memento'); +                done(); +              } +            } +          }); +          return function($animate, $compile, $rootScope, $rootElement) { +            element = $compile('<div></div>')($rootScope); +            child   = $compile('<div></div>')($rootScope); +            after   = $compile('<div></div>')($rootScope); +            $rootElement.append(element); +          }; +        }); +      }) + +      it("should animate the enter animation event", inject(function($animate, $rootScope, $sniffer) { +        expect(element.contents().length).toBe(0); +        $animate.enter(child, element); +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(0).process(); +        } +        expect(element.contents().length).toBe(1); +      })); + +      it("should animate the leave animation event", inject(function($animate, $rootScope, $sniffer) { +        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(); +        } +        expect(element.contents().length).toBe(0); +      })); + +      it("should animate the move animation event", inject(function($animate, $compile, $rootScope, $sniffer) { +        $rootScope.$digest(); +        var child1 = $compile('<div>1</div>')($rootScope); +        var child2 = $compile('<div>2</div>')($rootScope); +        element.append(child1); +        element.append(child2); +        expect(element.text()).toBe('12'); +        $animate.move(child1, element, child2); +        expect(element.text()).toBe('21'); +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +        } +      })); + +      it("should animate the show animation event", inject(function($animate, $rootScope, $sniffer) { +        $rootScope.$digest(); +        element.addClass('ng-hide'); +        expect(element).toBeHidden(); +        $animate.show(element); +        if($sniffer.transitions) { +          expect(element.hasClass('ng-hide-remove')).toBe(true); +          window.setTimeout.expect(1).process(); +          expect(element.hasClass('ng-hide-remove-active')).toBe(true); +          window.setTimeout.expect(0).process(); +        } +        expect(element).toBeShown(); +      })); + +      it("should animate the hide animation event", inject(function($animate, $rootScope, $sniffer) { +        $rootScope.$digest(); +        expect(element).toBeShown(); +        $animate.hide(element); +        if($sniffer.transitions) { +          expect(element.hasClass('ng-hide-add')).toBe(true); +          window.setTimeout.expect(1).process(); +          expect(element.hasClass('ng-hide-add-active')).toBe(true); +          window.setTimeout.expect(0).process(); +        } +        expect(element).toBeHidden(); +      })); + +      it("should assign the ngAnimate string to all events if a string is given", +        inject(function($animate, $sniffer, $rootScope) { + +        if (!$sniffer.transitions) return; + +        $rootScope.$digest(); + +        //enter +        $animate.enter(child, element); +        expect(child.attr('class')).toContain('ng-enter'); +        window.setTimeout.expect(1).process(); +        expect(child.attr('class')).toContain('ng-enter-active'); +        window.setTimeout.expect(0).process(); + +        //leave +        element.append(after); +        $animate.move(child, element, after); +        expect(child.attr('class')).toContain('ng-move'); +        window.setTimeout.expect(1).process(); +        expect(child.attr('class')).toContain('ng-move-active'); +        window.setTimeout.expect(0).process(); + +        //hide +        $animate.hide(child); +        expect(child.attr('class')).toContain('ng-hide-add'); +        window.setTimeout.expect(1).process(); +        expect(child.attr('class')).toContain('ng-hide-add-active'); +        window.setTimeout.expect(0).process(); + +        //show +        $animate.show(child); +        expect(child.attr('class')).toContain('ng-hide-remove'); +        window.setTimeout.expect(1).process(); +        expect(child.attr('class')).toContain('ng-hide-remove-active'); +        window.setTimeout.expect(0).process(); + +        //leave +        $animate.leave(child); +        expect(child.attr('class')).toContain('ng-leave'); +        window.setTimeout.expect(1).process(); +        expect(child.attr('class')).toContain('ng-leave-active'); +        window.setTimeout.expect(0).process(); +      })); + +      it("should not run if animations are disabled", inject(function($animate, $rootScope, $sniffer) { +        $animate.enabled(false); + +        $rootScope.$digest(); + +        element.addClass('setup-memo'); + +        element.text('123'); +        expect(element.text()).toBe('123'); +        $animate.show(element); +        expect(element.text()).toBe('123'); + +        $animate.enabled(true); + +        $animate.show(element); +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(0).process(); +        } +        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) { + +        element.append(child); +        child.addClass('custom-delay'); + +        expect(element).toBeShown(); +        $animate.hide(child); +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +        } +        expect(child).toBeShown(); + +        $animate.leave(child); +        expect(child).toBeHidden(); //hides instantly + +        //lets change this to prove that done doesn't fire anymore for the previous hide() operation +        child.css('display','block');  +        child.removeClass('ng-hide'); + +        window.setTimeout.expect(2000).process(); +        if($sniffer.transitions) { +          window.setTimeout.expect(0).process(); +        } +        expect(child).toBeShown(); + +        expect(element.children().length).toBe(1); //still animating + +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +        } +        window.setTimeout.expect(2000).process(); +        if($sniffer.transitions) { +          window.setTimeout.expect(0).process(); +        } +        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) { + +        element.append(child); + +        child.addClass('custom-delay ng-hide'); +        $animate.show(child); +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +        } + +        $animate.hide(child); + +        expect(child.hasClass('animation-cancelled')).toBe(true); +      })); + + +      it("should NOT clobber all data on an element when animation is finished", +        inject(function($animate, $rootScope, $sniffer) { + +        child.css('display','none'); +        element.data('foo', 'bar'); + +        $animate.show(element); +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +        } + +        $animate.hide(element); + +        expect(element.data('foo')).toEqual('bar'); +      })); + + +      it("should allow multiple JS animations which run in parallel", +        inject(function($animate, $rootScope, $compile, $sniffer) { + +          $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(); +            expect(element[0].className).toContain('custom-delay-add-active custom-long-delay-add-active'); +          } +          window.setTimeout.expect(2000).process(); +          window.setTimeout.expect(20000).process(); +          if($sniffer.transitions) { +            window.setTimeout.expect(0).process(); //css animation +          } + +          expect(element.hasClass('custom-delay')).toBe(true); +          expect(element.hasClass('custom-delay-add')).toBe(false); +          expect(element.hasClass('custom-delay-add-active')).toBe(false); + +          expect(element.hasClass('custom-long-delay')).toBe(true); +          expect(element.hasClass('custom-long-delay-add')).toBe(false); +          expect(element.hasClass('custom-long-delay-add-active')).toBe(false); +      })); + +      it("should allow both multiple JS and CSS animations which run in parallel", +        inject(function($animate, $rootScope, $compile, $sniffer, _$rootElement_) { +        $rootElement = _$rootElement_; + +        var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; +        var style = 'transition: 1s linear all;' + +                    vendorPrefix + 'transition: 1s linear all;' + +        element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); +        element.addClass('custom-delay custom-long-delay'); +        $rootScope.$digest(); + +        $animate.show(element);  + +        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 +        } + +        expect(element.hasClass('custom-delay')).toBe(true); +        expect(element.hasClass('custom-delay-add')).toBe(false); +        expect(element.hasClass('custom-delay-add-active')).toBe(false); + +        expect(element.hasClass('custom-long-delay')).toBe(true); +        expect(element.hasClass('custom-long-delay-add')).toBe(false); +        expect(element.hasClass('custom-long-delay-add-active')).toBe(false); +      })); +    }); + +    describe("with CSS3", function() { +      var window, 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_; +          }; +        }) +      }); + +      describe("Animations", function() { +        it("should properly detect and make use of CSS Animations", +            inject(function($animate, $rootScope, $compile, $sniffer) { +          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); + +          element.addClass('ng-hide'); +          expect(element).toBeHidden(); + +          $animate.show(element); +          if ($sniffer.animations) { +            window.setTimeout.expect(1).process(); +            window.setTimeout.expect(4000).process(); +          } +          else { +            expect(window.setTimeout.queue.length).toBe(0); +          } +          expect(element).toBeShown(); +        })); + +        it("should properly detect and make use of CSS Animations with multiple iterations", +            inject(function($animate, $rootScope, $compile, $sniffer) { +          var style = 'animation-duration: 2s;' +  +                      'animation-iteration-count: 3;' + +                      vendorPrefix + 'animation-duration: 2s;' +  +                      vendorPrefix + 'animation-iteration-count: 3;'; +          element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); + +          element.addClass('ng-hide'); +          expect(element).toBeHidden(); + +          $animate.show(element); +          if ($sniffer.animations) { +            window.setTimeout.expect(1).process(); +            window.setTimeout.expect(6000).process(); +          } +          else { +            expect(window.setTimeout.queue.length).toBe(0); +          } +          expect(element).toBeShown(); +        })); + +        it("should fallback to the animation duration if an infinite iteration is provided", +            inject(function($animate, $rootScope, $compile, $sniffer) { +          var style = 'animation-duration: 2s;' +  +                      'animation-iteration-count: infinite;' + +                      vendorPrefix + 'animation-duration: 2s;' +  +                      vendorPrefix + 'animation-iteration-count: infinite;'; +          element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); + +          element.addClass('ng-hide'); +          expect(element).toBeHidden(); + +          $animate.show(element); +          if ($sniffer.animations) { +            window.setTimeout.expect(1).process(); +            window.setTimeout.expect(2000).process(); +          } +          else { +            expect(window.setTimeout.queue.length).toBe(0); +          } +          expect(element).toBeShown(); +        })); + +        it("should consider the animation delay is provided", +            inject(function($animate, $rootScope, $compile, $sniffer) { +          var style = 'animation-duration: 2s;' +  +                      'animation-delay: 10s;' + +                      'animation-iteration-count: 5;' + +                      vendorPrefix + 'animation-duration: 2s;' +  +                      vendorPrefix + 'animation-delay: 10s;' + +                      vendorPrefix + 'animation-iteration-count: 5;'; +          element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); + +          element.addClass('ng-hide'); +          expect(element).toBeHidden(); + +          $animate.show(element); +          if ($sniffer.transitions) { +            window.setTimeout.expect(1).process(); +            window.setTimeout.expect(20000).process(); +          } +          else { +            expect(window.setTimeout.queue.length).toBe(0); +          } +          expect(element).toBeShown(); +        })); + +        it("should skip animations if disabled and run when enabled", +            inject(function($animate, $rootScope, $compile, $sniffer) { +          $animate.enabled(false); +          var style = 'animation: some_animation 2s linear 0s 1 alternate;' + +                      vendorPrefix + 'animation: some_animation 2s linear 0s 1 alternate;' + +          element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); +          element.addClass('ng-hide'); +          expect(element).toBeHidden(); +          $animate.show(element); +          expect(element).toBeShown(); +        })); + +        it("should finish the previous animation when a new animation is started", +          inject(function($animate, $rootScope, $compile, $sniffer) { +            var style = 'animation: some_animation 2s linear 0s 1 alternate;' + +                        vendorPrefix + 'animation: some_animation 2s linear 0s 1 alternate;' + +            element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); +            element.addClass('custom'); + +            $animate.show(element); +            if($sniffer.animations) { +              window.setTimeout.expect(1).process(); +              expect(element.hasClass('ng-hide-remove')).toBe(true); +              expect(element.hasClass('ng-hide-remove-active')).toBe(true); +            } +            else { //animation is skipped +              expect(window.setTimeout.queue.length).toBe(0); +            } + +            $animate.hide(element); +            expect(element.hasClass('ng-hide-remove')).toBe(false); //added right away + +            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); +              expect(element.hasClass('ng-hide-add-active')).toBe(true); +            } + +            expect(element.hasClass('ng-hide-remove-active')).toBe(false); +        })); +      }); + +      describe("Transitions", function() { +        it("should skip transitions if disabled and run when enabled", +            inject(function($animate, $rootScope, $compile, $sniffer) { +          $animate.enabled(false); +          element = $compile(html('<div style="' + vendorPrefix + 'transition: 1s linear all">1</div>'))($rootScope); + +          element.addClass('ng-hide'); +          expect(element).toBeHidden(); +          $animate.show(element); +          expect(element).toBeShown(); + +          $animate.enabled(true); + +          element.addClass('ng-hide'); +          expect(element).toBeHidden(); + +          $animate.show(element); +          if ($sniffer.transitions) { +            window.setTimeout.expect(1).process(); +            window.setTimeout.expect(1000).process(); +          } +          else { +            expect(window.setTimeout.queue.length).toBe(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) { +            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.show(element); +            if ($sniffer.transitions) { +              expect(element).toBeHidden(); +              window.setTimeout.expect(1).process(); +              window.setTimeout.expect(2000).process(); +            } +            else { +              expect(window.setTimeout.queue.length).toBe(0); +            } +            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) { +            $animate.enabled(false); +            element = $compile(html('<div style="' + vendorPrefix +  +              'transition-duration: 1s, 0s, 1s; ' + vendorPrefix + +              'transition-delay: 2s, 1000ms, 2s; ' + vendorPrefix +  +              'transition-property: height, left, opacity">foo</div>'))($rootScope); + +            element.addClass('ng-hide'); +            $animate.show(element); +            expect(element).toBeShown(); + +            $animate.enabled(true); + +            element.addClass('ng-hide'); +            expect(element).toBeHidden(); + +            $animate.show(element); +            if ($sniffer.transitions) { +              window.setTimeout.expect(1).process(); +              window.setTimeout.expect(3000).process(); +            } +            else { +              expect(window.setTimeout.queue.length).toBe(0); +            } +            expect(element).toBeShown(); +        })); + +        it("should select the highest duration and delay", +          inject(function($animate, $rootScope, $compile, $sniffer) { +            var styles = 'transition:1s linear all 2s;' +  +                         vendorPrefix + 'transition:1s linear all 2s;' +  +                         'animation:my_ani 10s 1s;' +  +                         vendorPrefix + 'animation:my_ani 10s 1s;'; + +            element = $compile(html('<div style="' + styles + '">foo</div>'))($rootScope); + +            element.addClass('ng-hide'); +            expect(element).toBeHidden(); + +            $animate.show(element); +            if ($sniffer.transitions) { +              window.setTimeout.expect(1).process(); +              window.setTimeout.expect(11000).process(); +            } +            else { +              expect(window.setTimeout.queue.length).toBe(0); +            } +            expect(element).toBeShown(); +        })); + +        it("should finish the previous transition when a new animation is started", +          inject(function($animate, $rootScope, $compile, $sniffer) { +            var style = 'transition: 1s linear all;' + +                        vendorPrefix + 'transition: 1s linear all;' + +            element = $compile(html('<div style="' + style + '">1</div>'))($rootScope); + +            element.addClass('ng-hide'); +            $animate.show(element); +            if($sniffer.transitions) { +              expect(element.hasClass('ng-hide-remove')).toBe(true); +              window.setTimeout.expect(1).process(); +              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); +            } +            expect(element.hasClass('ng-hide-remove')).toBe(false); +            expect(element.hasClass('ng-hide-remove-active')).toBe(false); +            expect(element).toBeShown(); + +            $animate.hide(element); +            if($sniffer.transitions) { +              expect(element.hasClass('ng-hide-add')).toBe(true); +              window.setTimeout.expect(1).process(); +              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) { + +        var parent = jqLite('<div><span></span></div>'); +        var element = parent.find('span'); +        $rootElement.append(parent); +        angular.element(document.body).append($rootElement); + +        element[0].className = 'abc'; +        $animate.enter(element, parent); +        if ($sniffer.transitions) { +          expect(element.hasClass('abc ng-enter')).toBe(true); +          window.setTimeout.expect(1).process(); +          expect(element.hasClass('abc ng-enter ng-enter-active')).toBe(true); +          window.setTimeout.expect(0).process(); +        } +        expect(element.hasClass('abc')).toBe(true); + +        element[0].className = 'xyz'; +        $animate.enter(element, parent); +        if ($sniffer.transitions) { +          expect(element.hasClass('xyz')).toBe(true); +          window.setTimeout.expect(1).process(); +          expect(element.hasClass('xyz ng-enter ng-enter-active')).toBe(true); +          window.setTimeout.expect(0).process(); +        } +        expect(element.hasClass('xyz')).toBe(true); +      })); + +      it('should only append active to the newly append CSS className values', +        inject(function($animate, $rootScope, $sniffer, $rootElement) { + +        var parent = jqLite('<div><span></span></div>'); +        var element = parent.find('span'); +        $rootElement.append(parent); +        angular.element(document.body).append($rootElement); + +        element.attr('class','one two'); + +        $animate.enter(element, parent); +        if($sniffer.transitions) { +          expect(element.hasClass('one two ng-enter')).toBe(true); +          window.setTimeout.expect(1).process(); +          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); +        } + +        expect(element.hasClass('one two')).toBe(true); +      })); +    }); + +    describe("Callbacks", function() { + +      var window, vendorPrefix; +      beforeEach(function() { +        module(function($animateProvider, $provide) { +          $provide.value('$window', window = angular.mock.createMockWindow()); +          $animateProvider.register('.custom', function() { +            return { +              show : function(element, done) { +                window.setTimeout(done, 2000); +              } +            } +          }); +          $animateProvider.register('.other', function() { +            return { +              start : function(element, done) { +                window.setTimeout(done, 10000); +              } +            } +          }); +        }) +        inject(function($sniffer, $animate) { +          vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; +        }); +      }); + +      it("should fire the enter callback", +        inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + +        var parent = jqLite('<div><span></span></div>'); +        var element = parent.find('span'); +        $rootElement.append(parent); +        body.append($rootElement); + +        var flag = false; +        $animate.enter(element, parent, null, function() { +          flag = true; +        }); + +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(0).process(); +        } +        else { +          expect(window.setTimeout.queue.length).toBe(0); +        } +        expect(flag).toBe(true); +      })); + +      it("should fire the leave callback", +        inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + +        var parent = jqLite('<div><span></span></div>'); +        var element = parent.find('span'); +        $rootElement.append(parent); +        body.append($rootElement); + +        var flag = false; +        $animate.leave(element, function() { +          flag = true; +        }); + +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(0).process(); +        } +        else { +          expect(window.setTimeout.queue.length).toBe(0); +        } +        expect(flag).toBe(true); +      })); + +      it("should fire the move callback", +        inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + +        var parent = jqLite('<div><span></span></div>'); +        var parent2 = jqLite('<div id="nice"></div>'); +        var element = parent.find('span'); +        $rootElement.append(parent); +        body.append($rootElement); + +        var flag = false; +        $animate.move(element, parent, parent2, function() { +          flag = true; +        }); + +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(0).process(); +        } +        else { +          expect(window.setTimeout.queue.length).toBe(0); +        } + +        expect(flag).toBe(true); +        expect(element.parent().id).toBe(parent2.id); +      })); + +      it("should fire the addClass/removeClass callbacks", +        inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + +        var parent = jqLite('<div><span></span></div>'); +        var element = parent.find('span'); +        $rootElement.append(parent); +        body.append($rootElement); + +        var signature = ''; +        $animate.addClass(element, 'on', function() { +          signature += 'A'; +        }); + +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(0).process(); +        } +        else { +          expect(window.setTimeout.queue.length).toBe(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); +        } + +        expect(signature).toBe('AB'); +      })); + +      it("should fire a done callback when provided with no animation", +        inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + +        var parent = jqLite('<div><span></span></div>'); +        var element = parent.find('span'); +        $rootElement.append(parent); +        body.append($rootElement); + +        var flag = false; +        $animate.show(element, function() { +          flag = true; +        }); + +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(0).process(); +        } +        else { +          expect(window.setTimeout.queue.length).toBe(0); +        } +        expect(flag).toBe(true); +      })); + +      it("should fire a done callback when provided with a css animation/transition", +        inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + +        var transition = 'transition:1s linear all;'; +        var style = transition + ' ' + vendorPrefix + transition; +        var parent = jqLite('<div><span style="' + style + '"></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = parent.find('span'); + +        var flag = false; +        $animate.show(element, function() { +          flag = true; +        }); + +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(1000).process(); +        } +        else { +          expect(window.setTimeout.queue.length).toBe(0); +        } +        expect(flag).toBe(true); +      })); + +      it("should fire a done callback when provided with a JS animation", +        inject(function($animate, $rootScope, $compile, $sniffer, $rootElement) { + +        var parent = jqLite('<div><span></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = parent.find('span'); +        element.addClass('custom'); + +        var flag = false; +        $animate.show(element, function() { +          flag = true; +        }); + +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +        } +        window.setTimeout.expect(2000).process(); +        if($sniffer.transitions) { +          window.setTimeout.expect(0).process(); +        } +        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) { + +        var parent = jqLite('<div><span></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = parent.find('span'); + +        var signature = ''; +        $animate.show(element, function() { +          signature += 'A'; +        }); +        $animate.hide(element, function() { +          signature += 'B'; +        }); + +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +        } +        $animate.hide(element); //earlier animation cancelled +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +        } +        expect(signature).toBe('AB'); +      })); +    }); + +    describe("addClass / removeClass", function() { + +      var window, vendorPrefix; +      beforeEach(function() { +        module(function($animateProvider, $provide) { +          $provide.value('$window', window = angular.mock.createMockWindow()); +          $animateProvider.register('.klassy', function() { +            return { +              addClass : function(element, className, done) { +                window.setTimeout(done, 500); +              }, +              removeClass : function(element, className, done) { +                window.setTimeout(done, 3000); +              } +            } +          }); +        }) +        inject(function($sniffer, $animate) { +          vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; +        }); +      }); + +      it("should add and remove CSS classes after an animation even if no animation is present", +        inject(function($animate, $rootScope, $sniffer, $rootElement) { + +        var parent = jqLite('<div><span></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = jqLite(parent.find('span')); + +        $animate.addClass(element,'klass'); + +        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); +          expect(element.hasClass('klass-add-active')).toBe(true); +          expect(element.hasClass('klass')).toBe(false); + +          window.setTimeout.expect(0).process(); +          expect(element.hasClass('klass-add')).toBe(false); +          expect(element.hasClass('klass-add-active')).toBe(false); +        } +        expect(element.hasClass('klass')).toBe(true); + +        $animate.removeClass(element,'klass'); + +        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); +          expect(element.hasClass('klass-remove-active')).toBe(true); + +          window.setTimeout.expect(0).process(); +        } + +        expect(element.hasClass('klass')).toBe(false); +        expect(element.hasClass('klass-remove')).toBe(false); +        expect(element.hasClass('klass-remove-active')).toBe(false); +      })); + +      it("should add and remove CSS classes with a callback", +        inject(function($animate, $rootScope, $sniffer, $rootElement) { + +        var parent = jqLite('<div><span></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = jqLite(parent.find('span')); + +        var signature = ''; + +        $animate.addClass(element,'klass', function() { +          signature += 'A'; +        }); + +        if($sniffer.transitions) { +          expect(element.hasClass('klass')).toBe(false); +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(0).process(); +        } +        expect(element.hasClass('klass')).toBe(true); + +        $animate.removeClass(element,'klass', function() { +          signature += 'B'; +        }); + +        if($sniffer.transitions) { +          expect(element.hasClass('klass')).toBe(true); +          window.setTimeout.expect(1).process(); +          window.setTimeout.expect(0).process(); +        } +        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) { + +        var parent = jqLite('<div><span></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = jqLite(parent.find('span')); + +        var signature = ''; + +        $animate.addClass(element,'klass', function() { +          signature += '1'; +        }); +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +          expect(element.hasClass('klass')).toBe(false); +          expect(element.hasClass('klass-add')).toBe(true); +        } + +        //this cancels out the older animation +        $animate.removeClass(element,'klass', function() { +          signature += '2'; +        }); + +        if($sniffer.transitions) { +          expect(element.hasClass('klass')).toBe(true); +          expect(element.hasClass('klass-add')).toBe(false); +          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(); +        } + +        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) { +        var parent = jqLite('<div><span></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = jqLite(parent.find('span')); + +        var signature = ''; + +        $animate.addClass(element,'klassy', function() { +          signature += 'X'; +        }); +        if($sniffer.transitions) { +          window.setTimeout.expect(1).process(); +        } +        window.setTimeout.expect(500).process(); +        if($sniffer.transitions) { +          window.setTimeout.expect(0).process(); +        } +        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(); +        } +        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) { + +        var transition = 'transition:11s linear all;'; +        var style = transition + ' ' + vendorPrefix + transition; +        var parent = jqLite('<div><span style="' + style + '"></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = jqLite(parent.find('span')); + +        var signature = ''; + +        $animate.addClass(element,'klass', function() { +          signature += 'd'; +        }); +        if($sniffer.transitions) { +          expect(element.hasClass('klass-add')).toBe(true); +          window.setTimeout.expect(1).process(); +          expect(element.hasClass('klass-add-active')).toBe(true); +          window.setTimeout.expect(11000).process(); +          expect(element.hasClass('klass-add')).toBe(false); +          expect(element.hasClass('klass-add-active')).toBe(false); +        } +        expect(element.hasClass('klass')).toBe(true); + +        $animate.removeClass(element,'klass', function() { +          signature += 'b'; +        }); +        if($sniffer.transitions) { +          expect(element.hasClass('klass-remove')).toBe(true); +          window.setTimeout.expect(1).process(); +          expect(element.hasClass('klass-remove-active')).toBe(true); +          window.setTimeout.expect(11000).process(); +          expect(element.hasClass('klass-remove')).toBe(false); +          expect(element.hasClass('klass-remove-active')).toBe(false); +        } +        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) { + +        var transition = 'transition:7s linear all;'; +        var style = transition + ' ' + vendorPrefix + transition; +        var parent = jqLite('<div><span style="' + style + '"></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = jqLite(parent.find('span')); + +        var flag = false; +        $animate.addClass(element,'one two', function() { +          flag = true; +        }); + +        if($sniffer.transitions) { +          expect(element.hasClass('one-add')).toBe(true); +          expect(element.hasClass('two-add')).toBe(true); +          window.setTimeout.expect(1).process(); + +          expect(element.hasClass('one-add-active')).toBe(true); +          expect(element.hasClass('two-add-active')).toBe(true); +          window.setTimeout.expect(7000).process(); + +          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); +        } + +        expect(element.hasClass('one')).toBe(true); +        expect(element.hasClass('two')).toBe(true); + +        expect(flag).toBe(true); +      })); + +      it("should allow for multiple css classes to be animated plus a callback when removed", +        inject(function($animate, $rootScope, $sniffer, $rootElement) { + +        var transition = 'transition:9s linear all;'; +        var style = transition + ' ' + vendorPrefix + transition; +        var parent = jqLite('<div><span style="' + style + '"></span></div>'); +        $rootElement.append(parent); +        body.append($rootElement); +        var element = jqLite(parent.find('span')); + +        element.addClass('one two'); +        expect(element.hasClass('one')).toBe(true); +        expect(element.hasClass('two')).toBe(true); + +        var flag = false; +        $animate.removeClass(element,'one two', function() { +          flag = true; +        }); + +        if($sniffer.transitions) { +          expect(element.hasClass('one-remove')).toBe(true); +          expect(element.hasClass('two-remove')).toBe(true); +          window.setTimeout.expect(1).process(); + +          expect(element.hasClass('one-remove-active')).toBe(true); +          expect(element.hasClass('two-remove-active')).toBe(true); +          window.setTimeout.expect(9000).process(); + +          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); +        } + +        expect(element.hasClass('one')).toBe(false); +        expect(element.hasClass('two')).toBe(false); + +        expect(flag).toBe(true); +      })); +    }); +  }); +     +  var $rootElement, $document, window; +  beforeEach(module(function($provide) { +    $provide.value('$window', window = angular.mock.createMockWindow()); + +    return function(_$rootElement_, _$document_, $animate) { +      $rootElement = _$rootElement_; +      $document = _$document_; +      $animate.enabled(true); +    } +  })); + +  function html(element) { +    var body = jqLite($document[0].body); +    $rootElement.append(element); +    body.append($rootElement); +    return element; +  } + +  it("should properly animate and parse CSS3 transitions", +    inject(function($compile, $rootScope, $animate, $sniffer) { + +    var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; +    var style = 'transition: 1s linear all;' + +                vendorPrefix + 'transition: 1s linear all;'; +    var element = html($compile('<div>...</div>')($rootScope)); +    var child = $compile('<div style="' + style + '">...</div>')($rootScope); + +    $animate.enter(child, element); + +    if($sniffer.transitions) { +      expect(child.hasClass('ng-enter')).toBe(true); +      window.setTimeout.expect(1).process(); +      expect(child.hasClass('ng-enter-active')).toBe(true); +      window.setTimeout.expect(1000).process(); +    } +    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) { + +    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); + +    if($sniffer.transitions) { +      expect(child.hasClass('ng-enter')).toBe(true); +      window.setTimeout.expect(1).process(); +      expect(child.hasClass('ng-enter-active')).toBe(true); +      window.setTimeout.expect(9000).process(); +    } +    expect(child.hasClass('ng-enter')).toBe(false); +    expect(child.hasClass('ng-enter-active')).toBe(false); +  })); + +  it("should skip animations if the browser does not support CSS3 transitions and CSS3 animations", +    inject(function($compile, $rootScope, $animate, $sniffer) { + +    $sniffer.animations = false; +    $sniffer.transitions = false; + +    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); + +    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) { +        return { +          enter : function(element, done) { +            element.addClass('i-was-animated'); +            $window.setTimeout(done, 10); +          } +        } +      }); +    }) +    inject(function($compile, $rootScope, $animate, $sniffer) { +      var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; +      var style = 'transition: 1s linear all;' + +                  vendorPrefix + 'transition: 1s linear all;'; +      var element = html($compile('<div>...</div>')($rootScope)); +      var child = $compile('<div style="' + style + '">...</div>')($rootScope); + +      expect(child.hasClass('i-was-animated')).toBe(false); + +      child.addClass('custom'); +      $animate.enter(child, element); + +      expect(child.hasClass('ng-enter')).toBe(true); +      if($sniffer.transitions) { +        window.setTimeout.expect(1).process(); +        expect(child.hasClass('ng-enter-active')).toBe(true); +      } + +      window.setTimeout.expect(10).process(); + +      if($sniffer.transitions) { +        expect(child.hasClass('ng-enter-active')).toBe(true); +        window.setTimeout.expect(1000).process(); +        expect(child.hasClass('ng-enter')).toBe(false); +        expect(child.hasClass('ng-enter-active')).toBe(false); +      } + +      expect(child.hasClass('i-was-animated')).toBe(true); +    }); +  }); + +  it("should properly cancel CSS transitions or animations if another animation is fired", function() { +    module(function($animateProvider) { +      $animateProvider.register('.usurper', function($window) { +        return { +          leave : function(element, done) { +            element.addClass('this-is-mine-now'); +            $window.setTimeout(done, 55); +          } +        } +      }); +    }); +    inject(function($compile, $rootScope, $animate, $sniffer) { +      var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; +      var style = 'transition: 2s linear all;' + +                  vendorPrefix + 'transition: 2s linear all;'; +      var element = html($compile('<div>...</div>')($rootScope)); +      var child = $compile('<div style="' + style + '">...</div>')($rootScope); + +      $animate.enter(child, element); + +      if($sniffer.transitions) { +        expect(child.hasClass('ng-enter')).toBe(true); +      } + +      expect(child.hasClass('this-is-mine-now')).toBe(false); +      child.addClass('usurper'); +      $animate.leave(child); + +      expect(child.hasClass('ng-enter')).toBe(false); +      expect(child.hasClass('ng-enter-active')).toBe(false); + +      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(); +      } +      window.setTimeout.expect(55).process(); +      if($sniffer.transitions) { +        window.setTimeout.expect(2000).process(); + +        //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(); +      } + +      expect(child.hasClass('usurper-active')).toBe(false); +    }); +  }); + +  it("should add and remove CSS classes and perform CSS animations during the process", +    inject(function($compile, $rootScope, $animate, $sniffer) { + +    var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; +    var style = 'transition: 10s linear all;' + +                vendorPrefix + 'transition: 10s linear all;'; +    var element = html($compile('<div style="' + style + '"></div>')($rootScope)); + +    expect(element.hasClass('on')).toBe(false); + +    $animate.addClass(element, 'on'); + +    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(); +    } + +    expect(element.hasClass('on')).toBe(true); +    expect(element.hasClass('on-add')).toBe(false); +    expect(element.hasClass('on-add-active')).toBe(false); + +    $animate.removeClass(element, 'on'); +    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(); +    } + +    expect(element.hasClass('on')).toBe(false); +    expect(element.hasClass('on-remove')).toBe(false); +    expect(element.hasClass('on-remove-active')).toBe(false); +  })); + +  it("should show and hide elements with CSS & JS animations being performed in the process", function() { +    module(function($animateProvider) { +      $animateProvider.register('.displayer', function($window) { +        return { +          show : function(element, done) { +            element.removeClass('hiding'); +            element.addClass('showing'); +            $window.setTimeout(done, 25); +          }, +          hide : function(element, done) { +            element.removeClass('showing'); +            element.addClass('hiding'); +            $window.setTimeout(done, 555); +          } +        } +      }); +    }) +    inject(function($compile, $rootScope, $animate, $sniffer) { +      var vendorPrefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-'; +      var style = 'transition: 5s linear all;' + +                  vendorPrefix + 'transition: 5s linear all;'; +      var element = html($compile('<div style="' + style + '"></div>')($rootScope)); + +      element.addClass('displayer'); + +      expect(element).toBeShown(); +      expect(element.hasClass('showing')).toBe(false); +      expect(element.hasClass('hiding')).toBe(false); + +      $animate.hide(element); + +      if($sniffer.transitions) { +        expect(element).toBeShown(); //still showing +        window.setTimeout.expect(1).process(); +        expect(element).toBeShown(); +      } +      window.setTimeout.expect(555).process(); +      if($sniffer.transitions) { +        expect(element).toBeShown(); +        window.setTimeout.expect(5000).process(); +      } +      expect(element).toBeHidden(); + +      expect(element.hasClass('showing')).toBe(false); +      expect(element.hasClass('hiding')).toBe(true); +      $animate.show(element); + +      if($sniffer.transitions) { +        expect(element).toBeHidden(); +        window.setTimeout.expect(1).process(); +        expect(element).toBeHidden(); +      } +      window.setTimeout.expect(25).process(); +      if($sniffer.transitions) { +        expect(element).toBeHidden(); +        window.setTimeout.expect(5000).process(); +      } +      expect(element).toBeShown(); + +      expect(element.hasClass('showing')).toBe(true); +      expect(element.hasClass('hiding')).toBe(false); +    }); +  }); + +}); diff --git a/test/ngRoute/directive/ngViewSpec.js b/test/ngRoute/directive/ngViewSpec.js index 50531c18..5f021f2d 100644 --- a/test/ngRoute/directive/ngViewSpec.js +++ b/test/ngRoute/directive/ngViewSpec.js @@ -7,9 +7,9 @@ describe('ngView', function() {    beforeEach(module(function($provide) {      $provide.value('$window', angular.mock.createMockWindow()); -    return function($rootScope, $compile, $animator) { +    return function($rootScope, $compile, $animate) {        element = $compile('<ng:view onload="load()"></ng:view>')($rootScope); -      $animator.enabled(true); +      $animate.enabled(true);      };    })); @@ -509,8 +509,7 @@ describe('ngView', function() {      });    }); -  describe('ngAnimate ', function() { -    var window, vendorPrefix; +  describe('animations', function() {      var body, element, $rootElement;      function html(html) { @@ -520,11 +519,6 @@ describe('ngView', function() {        return element;      } -    function applyCSS(element, cssProp, cssValue) { -      element.css(cssProp, cssValue); -      element.css(vendorPrefix + cssProp, cssValue); -    } -      beforeEach(module(function() {        // we need to run animation on attached elements;        return function(_$rootElement_) { @@ -540,128 +534,131 @@ describe('ngView', function() {      beforeEach(module(function($provide, $routeProvider) { -      $provide.value('$window', window = angular.mock.createMockWindow());        $routeProvider.when('/foo', {controller: noop, templateUrl: '/foo.html'}); -      return function($sniffer, $templateCache, $animator) { -        vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; +      return function($templateCache) {          $templateCache.put('/foo.html', [200, '<div>data</div>', {}]); -        $animator.enabled(true);        }      })); -    it('should fire off the enter animation + add and remove the css classes', -        inject(function($compile, $rootScope, $sniffer, $location) { -          element = $compile(html('<div ng-view ng-animate="{enter: \'custom-enter\'}"></div>'))($rootScope); +    describe('hooks', function() { +      beforeEach(module('mock.animate')); -          $location.path('/foo'); -          $rootScope.$digest(); +      it('should fire off the enter animation', +          inject(function($compile, $rootScope, $location, $animate) { +            var item; +            element = $compile(html('<div ng-view></div>'))($rootScope); -          //if we add the custom css stuff here then it will get picked up before the animation takes place -          var child = jqLite(element.children()[0]); -          applyCSS(child, 'transition', '1s linear all'); +            $location.path('/foo'); +            $rootScope.$digest(); -          if ($sniffer.transitions) { -            expect(child.attr('class')).toContain('custom-enter'); -            window.setTimeout.expect(1).process(); - -            expect(child.attr('class')).toContain('custom-enter-active'); -            window.setTimeout.expect(1000).process(); -          } else { -            expect(window.setTimeout.queue).toEqual([]); -          } +            item = $animate.process('leave').element; +            item = $animate.process('leave').element; +            item = $animate.process('leave').element; -          expect(child.attr('class')).not.toContain('custom-enter'); -          expect(child.attr('class')).not.toContain('custom-enter-active'); -        })); - -    it('should fire off the leave animation + add and remove the css classes', -        inject(function($compile, $rootScope, $sniffer, $location, $templateCache) { -      $templateCache.put('/foo.html', [200, '<div>foo</div>', {}]); -      element = $compile(html('<div ng-view ng-animate="{leave: \'custom-leave\'}"></div>'))($rootScope); - -      $location.path('/foo'); -      $rootScope.$digest(); +            item = $animate.process('enter').element; +            expect(item.text()).toBe('data'); -      //if we add the custom css stuff here then it will get picked up before the animation takes place -      var child = jqLite(element.children()[0]); -      applyCSS(child, 'transition', '1s linear all'); +            item = $animate.process('leave').element; +            item = $animate.process('enter').element; +            expect(item.text()).toBe('data'); +          })); -      $location.path('/'); -      $rootScope.$digest(); +      it('should fire off the leave animation', +          inject(function($compile, $rootScope, $location, $templateCache, $animate) { -      if ($sniffer.transitions) { -        expect(child.attr('class')).toContain('custom-leave'); -        window.setTimeout.expect(1).process(); +        var item; +        $templateCache.put('/foo.html', [200, '<div>foo</div>', {}]); +        element = $compile(html('<div ng-view></div>'))($rootScope); -        expect(child.attr('class')).toContain('custom-leave-active'); -        window.setTimeout.expect(1000).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } +        $location.path('/foo'); +        $rootScope.$digest(); -      expect(child.attr('class')).not.toContain('custom-leave'); -      expect(child.attr('class')).not.toContain('custom-leave-active'); -    })); +        item = $animate.process('leave').element; +        item = $animate.process('leave').element; +        item = $animate.process('leave').element; -    it('should catch and use the correct duration for animations', -        inject(function($compile, $rootScope, $sniffer, $location, $templateCache) { -      $templateCache.put('/foo.html', [200, '<div>foo</div>', {}]); -      element = $compile(html( -          '<div ' + -              'ng-view ' + -              'ng-animate="{enter: \'customEnter\'}">' + -            '</div>' -      ))($rootScope); +        item = $animate.process('enter').element; +        expect(item.text()).toBe('foo'); -      $location.path('/foo'); -      $rootScope.$digest(); +        item = $animate.process('leave').element; +        item = $animate.process('enter').element; +        expect(item.text()).toBe('foo'); -      //if we add the custom css stuff here then it will get picked up before the animation takes place -      var child = jqLite(element.children()[0]); -      applyCSS(child, 'transition', '0.5s linear all'); +        $location.path('/'); +        $rootScope.$digest(); -      if($sniffer.transitions) { -        window.setTimeout.expect(1).process(); -        window.setTimeout.expect($sniffer.transitions ? 500 : 0).process(); -      } else { -        expect(window.setTimeout.queue).toEqual([]); -      } -    })); +        item = $animate.process('leave').element; +        expect(item.text()).toBe('foo'); +        item = $animate.process('leave').element; +        expect(item.text()).toBe('foo'); +      })); +    });      it('should not double compile when route changes', function() { -      module(function($routeProvider, $animationProvider, $provide) { +      module('ngAnimate'); +      module('mock.animate'); +      module(function($routeProvider, $animateProvider, $provide) {          $routeProvider.when('/foo', {template: '<div ng-repeat="i in [1,2]">{{i}}</div>'});          $routeProvider.when('/bar', {template: '<div ng-repeat="i in [3,4]">{{i}}</div>'}); -        $animationProvider.register('my-animation-leave', function() { +        $animateProvider.register('.my-animation', function() {            return { -            start: function(element, done) { +            leave: function(element, done) { +              dump('yes');                done();              }            };          });        }); -      inject(function($rootScope, $compile, $location, $route, $window, $rootElement, $sniffer) { -        element = $compile(html('<ng:view onload="load()" ng-animate="\'my-animation\'"></ng:view>'))($rootScope); +      inject(function($rootScope, $compile, $location, $route, $window, $rootElement, $sniffer, $animate) { +        if (!$sniffer.transitions) return; + +        element = $compile(html('<ng:view onload="load()"></ng:view>'))($rootScope);          $location.path('/foo');          $rootScope.$digest(); -        if ($sniffer.transitions) { -          $window.setTimeout.expect(1).process(); -          $window.setTimeout.expect(0).process(); -        } + +        $animate.process('leave'); +        $animate.process('leave'); +        $animate.process('leave'); +        $animate.process('enter'); +        $animate.process('leave'); +        $animate.process('enter'); +        $animate.process('enter'); +        $animate.process('enter'); +        $animate.process('enter'); +        $animate.process('enter'); +        $window.setTimeout.expect(1).process(); +        $window.setTimeout.expect(1).process(); +        $window.setTimeout.expect(1).process(); +        $window.setTimeout.expect(0).process(); +        $window.setTimeout.expect(0).process(); +        $window.setTimeout.expect(0).process(); +          expect(element.text()).toEqual('12');          $location.path('/bar');          $rootScope.$digest(); +        $animate.process('leave'); +        $animate.process('enter'); +        $animate.process('leave'); +        $animate.process('enter'); +        $animate.process('enter'); +        $animate.process('enter'); +        $animate.process('enter'); +        $animate.process('enter');          expect(n(element.text())).toEqual('1234'); -        if ($sniffer.transitions) { -          $window.setTimeout.expect(1).process(); -          $window.setTimeout.expect(1).process(); -        } else { -          $window.setTimeout.expect(1).process(); -        } + +        $window.setTimeout.expect(1).process(); +        $window.setTimeout.expect(1).process(); +        $window.setTimeout.expect(1).process(); +        $window.setTimeout.expect(1).process(); +        $window.setTimeout.expect(0).process(); +        $window.setTimeout.expect(0).process(); +        $window.setTimeout.expect(0).process(); +        $window.setTimeout.expect(0).process(); +          expect(element.text()).toEqual('34');          function n(text) { diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js index d97d88a1..32dd75ea 100644 --- a/test/testabilityPatch.js +++ b/test/testabilityPatch.js @@ -233,7 +233,7 @@ function sortedHtml(element, showNgClass) {   */  function isCssVisible(node) {    var display = node.css('display'); -  return display != 'none'; +  return !node.hasClass('ng-hide') && display != 'none';  }  function assertHidden(node) { | 
