From b3f2e6caa5bc4047af59f730c17fcb5a34f1bc9f Mon Sep 17 00:00:00 2001 From: Chirayu Krishnappa Date: Mon, 30 Jun 2014 11:30:14 -0700 Subject: [PATCH] feat(animate): animationsAllowed property to turn off all animations This is required for writing end-to-end tests against AngularDart apps that use animations. In such tests, you typically want to test the functionality of the application and not necessarily deal with the animations. This allows you to turn off all animations in your production site under test. The Animate class has a new property, animationsAllowed, which can be set to false to disable all animations. When true (the default), whether or not animations occur depend on the animation module installed and the AnimationOptimizer. --- lib/animate/animation_optimizer.dart | 7 +++ lib/animate/css_animate.dart | 5 ++ lib/core_dom/animation.dart | 6 ++ scripts/travis/setup.sh | 3 + test/animate/animation_optimizer_spec.dart | 70 +++++++++++++--------- test/animate/css_animate_spec.dart | 28 +++++++-- 6 files changed, 87 insertions(+), 32 deletions(-) diff --git a/lib/animate/animation_optimizer.dart b/lib/animate/animation_optimizer.dart index 843e21947..5f0c54560 100644 --- a/lib/animate/animation_optimizer.dart +++ b/lib/animate/animation_optimizer.dart @@ -13,6 +13,10 @@ class AnimationOptimizer { final Map _animations = new Map(); + /** + * Toggle to disable all animations through this optimizer. + */ + bool animationsAllowed = true; final Map _alwaysAnimate = new Map(); final Map _alwaysAnimateChildren = new Map(); @@ -103,6 +107,9 @@ class AnimationOptimizer { * and [false] if the optimizer thinks that it should not execute. */ bool shouldAnimate(dom.Node node) { + if (!animationsAllowed) { + return false; + } bool alwaysAnimate = _alwaysAnimate[node]; if (alwaysAnimate != null) { return alwaysAnimate; diff --git a/lib/animate/css_animate.dart b/lib/animate/css_animate.dart index f2c3ed5c0..ec4204b5a 100644 --- a/lib/animate/css_animate.dart +++ b/lib/animate/css_animate.dart @@ -25,6 +25,11 @@ class CssAnimate implements Animate { CssAnimate(this._runner, this._animationMap, this._optimizer); + bool get animationsAllowed => _optimizer.animationsAllowed; + void set animationsAllowed(bool allowed) { + _optimizer.animationsAllowed = allowed; + } + Animation addClass(dom.Element element, String cssClass) { if (!_optimizer.shouldAnimate(element)) { element.classes.add(cssClass); diff --git a/lib/core_dom/animation.dart b/lib/core_dom/animation.dart index 2a6c99b1e..0629e3901 100644 --- a/lib/core_dom/animation.dart +++ b/lib/core_dom/animation.dart @@ -9,6 +9,12 @@ part of angular.core.dom_internal; */ @Injectable() class Animate { + /** + * When set to false, all animations are disabled. When true, animations are + * allowed. + */ + bool animationsAllowed = true; + /** * Add the [cssClass] to the classes on [element] after running any * defined animations. diff --git a/scripts/travis/setup.sh b/scripts/travis/setup.sh index 367c4ca48..c026f2a36 100755 --- a/scripts/travis/setup.sh +++ b/scripts/travis/setup.sh @@ -27,3 +27,6 @@ echo =========================================================================== . ./scripts/env.sh $DART --version $PUB install + +# Record dart version for tests. +echo $'import "dart:js";\n\nmain() {\n context["DART_VERSION"] = \''"$($DART --version 2>&1)"$'\';\n}' > test/dart_version.dart diff --git a/test/animate/animation_optimizer_spec.dart b/test/animate/animation_optimizer_spec.dart index d1be072c0..9f6823f8a 100644 --- a/test/animate/animation_optimizer_spec.dart +++ b/test/animate/animation_optimizer_spec.dart @@ -1,14 +1,15 @@ library animation_optimizer_spec; import '../_specs.dart'; +import 'dart:js' as js; -main() { - describe('AnimationLoop', () { +_run({bool animationsAllowed}) { + describe('animationsAllowed=$animationsAllowed', () { TestBed _; AnimationOptimizer optimizer; beforeEach(inject((TestBed tb, Expando expand) { _ = tb; - optimizer = new AnimationOptimizer(expand); + optimizer = new AnimationOptimizer(expand)..animationsAllowed = animationsAllowed; })); it('should prevent animations on child elements', () { @@ -16,11 +17,11 @@ main() { _.compile('
'); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); optimizer.track(animation, _.rootElement); expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); optimizer.forget(animation); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); }); it('should allow multiple animations on the same element', () { @@ -28,16 +29,16 @@ main() { var animation2 = new NoOpAnimation(); _.compile('
'); - expect(optimizer.shouldAnimate(_.rootElement)).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement)).toBe(animationsAllowed); optimizer.track(animation1, _.rootElement); - expect(optimizer.shouldAnimate(_.rootElement)).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement)).toBe(animationsAllowed); optimizer.track(animation2, _.rootElement); - expect(optimizer.shouldAnimate(_.rootElement)).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement)).toBe(animationsAllowed); expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); optimizer.forget(animation1); expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); optimizer.forget(animation2); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); }); it('should always animate an element', () { @@ -45,22 +46,22 @@ main() { optimizer.alwaysAnimate(_.rootElement.children[0], "never"); expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); optimizer.alwaysAnimate(_.rootElement.children[0], "always"); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); optimizer.alwaysAnimate(_.rootElement.children[0], "auto"); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); }); it('alwaysAnimate should not affect children', () { _.compile('
'); optimizer.alwaysAnimate(_.rootElement, "never"); expect(optimizer.shouldAnimate(_.rootElement)).toBeFalsy(); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); optimizer.alwaysAnimate(_.rootElement, "always"); - expect(optimizer.shouldAnimate(_.rootElement)).toBeTruthy(); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement)).toBe(animationsAllowed); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); optimizer.alwaysAnimate(_.rootElement, "auto"); - expect(optimizer.shouldAnimate(_.rootElement)).toBeTruthy(); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement)).toBe(animationsAllowed); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); }); @@ -68,16 +69,16 @@ main() { _.compile('
'); optimizer.alwaysAnimateChildren(_.rootElement, "never"); - expect(optimizer.shouldAnimate(_.rootElement)).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement)).toBe(animationsAllowed); expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); optimizer.alwaysAnimateChildren(_.rootElement, "always"); - expect(optimizer.shouldAnimate(_.rootElement)).toBeTruthy(); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement)).toBe(animationsAllowed); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); optimizer.alwaysAnimateChildren(_.rootElement, "auto"); - expect(optimizer.shouldAnimate(_.rootElement)).toBeTruthy(); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement)).toBe(animationsAllowed); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); }); it('alwaysAnimate should take priority over alwaysAnimateChildren', () { @@ -85,7 +86,7 @@ main() { optimizer.alwaysAnimateChildren(_.rootElement, "never"); optimizer.alwaysAnimate(_.rootElement.children[0], "always"); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); optimizer.alwaysAnimateChildren(_.rootElement, "always"); optimizer.alwaysAnimate(_.rootElement.children[0], "never"); @@ -100,13 +101,13 @@ main() { expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); optimizer.alwaysAnimate(_.rootElement.children[0], "always"); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); optimizer.alwaysAnimate(_.rootElement.children[0], "auto"); expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); optimizer.forget(animation); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); }); it('alwaysAnimateChildren should take priority over running animations', @@ -118,13 +119,13 @@ main() { expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); optimizer.alwaysAnimateChildren(_.rootElement, "always"); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); optimizer.alwaysAnimateChildren(_.rootElement, "auto"); expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); optimizer.forget(animation); - expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeTruthy(); + expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBe(animationsAllowed); optimizer.alwaysAnimateChildren(_.rootElement, "never"); expect(optimizer.shouldAnimate(_.rootElement.children[0])).toBeFalsy(); @@ -138,7 +139,7 @@ main() { optimizer.alwaysAnimateChildren(_.rootElement, "always"); expect(optimizer.shouldAnimate(_.rootElement.children[0].children[0])) - .toBeTruthy(); + .toBe(animationsAllowed); optimizer.alwaysAnimateChildren(_.rootElement.children[0], "never"); expect(optimizer.shouldAnimate(_.rootElement.children[0].children[0])) @@ -148,7 +149,20 @@ main() { optimizer.alwaysAnimateChildren(_.rootElement, "never"); optimizer.alwaysAnimateChildren(_.rootElement.children[0], "always"); expect(optimizer.shouldAnimate(_.rootElement.children[0].children[0])) - .toBeTruthy(); + .toBe(animationsAllowed); }); }); } + +main() { + describe('AnimationLoop', () { + _run(animationsAllowed: true); + if (!identical(1, 1.0) && js.context['DART_VERSION'].toString().contains("version: 1.5.")) { + // Remove this block when issue #1219 is fixed. + // In Dart 1.5's Dartium, running both describes in any order causes + // ng_model_spec to fails. This is not the case in Dart 1.4 or Dart 1.6. + return; + } + _run(animationsAllowed: false); + }); +} diff --git a/test/animate/css_animate_spec.dart b/test/animate/css_animate_spec.dart index 74dc7a99a..9db4a741e 100644 --- a/test/animate/css_animate_spec.dart +++ b/test/animate/css_animate_spec.dart @@ -1,20 +1,22 @@ library css_animate_spec; import 'dart:async'; +import 'dart:js' as js; import '../_specs.dart'; -main() { - describe('CssAnimate', () { +_run({bool animationsAllowed}) { + describe('animationsAllowed=$animationsAllowed', () { TestBed _; Animate animate; MockAnimationLoop runner; beforeEach(inject((TestBed tb, Expando expand) { _ = tb; - runner = new MockAnimationLoop(); + runner = new MockAnimationLoop(animationsAllowed); animate = new CssAnimate(runner, new CssAnimationMap(), new AnimationOptimizer(expand)); + animate.animationsAllowed = animationsAllowed; })); it('should add a css class to an element node', async(() { @@ -91,7 +93,9 @@ main() { _.compile('
'); animate.addClass(_.rootElement, 'test'); runner.start(); - expect(_.rootElement).toHaveClass('test-add'); + if (animationsAllowed) { + expect(_.rootElement).toHaveClass('test-add'); + } var spans = es('AB'); animate.insert(spans, _.rootElement); runner.start(); @@ -101,8 +105,11 @@ main() { } class MockAnimationLoop extends Mock implements AnimationLoop { + bool animationsAllowed; num time = 0.0; + MockAnimationLoop(this.animationsAllowed); + Future get onCompleted { var cmp = new Completer(); cmp.complete(AnimationResult.COMPLETED); @@ -129,3 +136,16 @@ class MockAnimationLoop extends Mock implements AnimationLoop { noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); } + +main() { + describe('CssAnimate', () { + _run(animationsAllowed: true); + if (!identical(1, 1.0) && js.context['DART_VERSION'].toString().contains("version: 1.5.")) { + // Remove this block when issue #1219 is fixed. + // In Dart 1.5's Dartium, running both describes in any order causes + // ng_model_spec to fails. This is not the case in Dart 1.4 or Dart 1.6. + return; + } + _run(animationsAllowed: false); + }); +}