Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 0d764b5

Browse files
committed
fix(ngAnimate): safe-guard against missing document
In tests, the $document service might be mocked out without providing a real document, which can lead to errors when the animator is attempting to read properties from it. This commit provides an object {hidden: true}, if the $document service doesn't have a document. This will prevent the animation process from trying to run any animations. This commit also changes the check for document.hidden slightly. It should be accessed independently of the current animationsEnabled state. Since animations are only enabled after two digests, it's possible that some tests never reach the animationsEnabled = true state and therefore aren't actually checking the document.hidden state, which means that the previous fix only works if no more than two digests happen in the test. (#14633)
1 parent 57a37fc commit 0d764b5

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

src/ngAnimate/animateQueue.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
103103
var activeAnimationsLookup = new $$HashMap();
104104
var disabledElementsLookup = new $$HashMap();
105105
var animationsEnabled = null;
106+
// $document might be mocked out in tests and won't include a real document.
107+
// Providing an empty object with hidden = true will prevent animations from running
108+
var rawDocument = $document[0] || {hidden: true};
106109

107110
function postDigestTaskFactory() {
108111
var postDigestCalled = false;
@@ -331,7 +334,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
331334

332335
var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
333336

334-
var documentHidden = animationsEnabled && $document[0].hidden;
337+
var documentHidden = rawDocument.hidden;
335338

336339
// this is a hard disable of all animations for the application or on
337340
// the element itself, therefore there is no need to continue further
@@ -583,7 +586,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
583586
* d) the element is not a child of the $rootElement
584587
*/
585588
function areAnimationsAllowed(element, parentElement, event) {
586-
var bodyElement = jqLite($document[0].body);
589+
var bodyElement = jqLite(rawDocument.body);
587590
var bodyElementDetected = isMatchingElement(element, bodyElement) || element[0].nodeName === 'HTML';
588591
var rootElementDetected = isMatchingElement(element, $rootElement);
589592
var parentAnimationDetected = false;

test/ngAnimate/animateSpec.js

+30
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,36 @@ describe("animations", function() {
14041404
});
14051405
});
14061406

1407+
1408+
it('should not run animations if the document is unavailable', function() {
1409+
var capturedAnimation;
1410+
1411+
module(function($provide) {
1412+
$provide.value('$document', {});
1413+
1414+
$provide.factory('$$animation', function($$AnimateRunner) {
1415+
return function(element, method, options) {
1416+
capturedAnimation = arguments;
1417+
return new $$AnimateRunner();
1418+
};
1419+
});
1420+
});
1421+
1422+
inject(function($animate, $rootScope, $rootElement, $document) {
1423+
$animate.enabled(true);
1424+
1425+
var spy = jasmine.createSpy();
1426+
1427+
element = jqLite('<div></div>');
1428+
var runner = $animate.enter(element, $rootElement);
1429+
$rootScope.$digest();
1430+
1431+
$animate.flush();
1432+
1433+
expect(capturedAnimation).toBeUndefined();
1434+
});
1435+
});
1436+
14071437
describe('[ng-animate-children]', function() {
14081438
var parent, element, child, capturedAnimation, captureLog;
14091439
beforeEach(module(function($provide) {

0 commit comments

Comments
 (0)