问题
I've been working from this tutorial and have Googled ad nauseum, but I can't seem to get what appears to be a trivial ngAnimate
unit test running.
I have ngAnimate
working well in the app. All Angular core libraries are version 1.4.7.
Module
angular.module 'MyAnimation', [ 'ngAnimate' ]
.animation '.added-class', ->
addClass: (element, className, done) ->
console.log 'add class triggered'
element.css 'opacity', '0.5'
done()
Test
describe 'MyAnimation', ->
beforeEach -> module 'ngAnimate'
beforeEach -> module 'ngAnimateMock'
beforeEach -> module 'MyAnimation'
it 'animates', -> inject ($animate, $rootScope, $rootElement) ->
$animate.enabled(true)
divElement = angular.element '<div>my div</div>'
# Kick off initial digest loop in which no animations are run.
$rootScope.$digest()
# Trigger animation.
$animate.addClass divElement, 'added-class'
$rootScope.$digest()
# Tried this, doesn't seem to do anything.
# $animate.flush()
# Results in AssertionError: expected '' to equal '0.5'
expect(divElement.css('opacity')).to.eq '0.5'
I'm sure that the module is being included in the test, but triggering $animate.enter
doesn't even get me my log
output.
I've tried this with other $animate
functions as well and am getting nowhere. Help?
回答1:
After some serious digging into Angular's source code, it appears that the culprit is the internal check areAnimationsAllowed which Angular uses to determine whether to abort the animation early. Among other things, it checks that the node being animated is a descendant of the $rootElement
and the document body.
You have two options here.
- Plunker. Attach the node you are animating to
$rootElement
and attach the$rootElement
to the body. The latter is necessary becausengMock
actually stubs$rootElement
with a detached<div>
node held in memory. Example:
var element, body, root;
beforeEach(module('ngAnimate', 'ngAnimateMock', 'MyAnimation'));
beforeEach(inject(function ($animate, $document, $rootElement, $rootScope) {
// enable animations globally
$animate.enabled(true);
// create a node to be animated and inject it into the DOM
element = angular.element('<div></div>');
root = $rootElement.append(element)[0];
body = $document[0].body;
body.appendChild(root);
// trigger initial digest
$rootScope.$digest();
}));
afterEach(function () {
// clean up
body.removeChild(root);
});
- Plunker. Do not test your animation using
$animate.addClass
, but instead use the lower-level$$animateJs
service. Angular uses it inside their own tests, I assume to bypass the above check. Example:
it('should animate', inject(function ($animate, $$animateJs) {
// trigger animation
$$animateJs(element, 'addClass', {
addClass: 'added-class'
}).start();
$animate.flush();
}));
If you run the Plunkers and check the console, you should see your "addClass triggered" message. I have also added a couple assertions.
Both solutions are hacky and undocumented, and both become more involved if your addClass
animation does something asynchronous (which I assume it will). Unfortunately, I cannot find a better way to test JS animations. In the past I've actually ignored animation code from coverage because it's so difficult to test.
来源:https://stackoverflow.com/questions/33405666/nganimate-1-4-7-unit-test-not-calling-animation-functions