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

Commit f98e038

Browse files
committed
feat(ngAnimate): introduce $animate.flush for unit testing
1 parent ec98c94 commit f98e038

File tree

9 files changed

+472
-288
lines changed

9 files changed

+472
-288
lines changed

src/ngMock/angular-mocks.js

+48-10
Original file line numberDiff line numberDiff line change
@@ -782,8 +782,8 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
782782
};
783783
});
784784

785-
$provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser',
786-
function($delegate, $$asyncCallback, $timeout, $browser) {
785+
$provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser', '$rootScope', '$$rAF',
786+
function($delegate, $$asyncCallback, $timeout, $browser, $rootScope, $$rAF) {
787787
var animate = {
788788
queue: [],
789789
cancel: $delegate.cancel,
@@ -803,6 +803,43 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
803803
fn();
804804
});
805805
reflowQueue = [];
806+
},
807+
flush: function() {
808+
$rootScope.$digest();
809+
var doNextRun, somethingFlushed = false;
810+
do {
811+
doNextRun = false;
812+
if (reflowQueue.length) {
813+
doNextRun = somethingFlushed = true;
814+
this.triggerReflow();
815+
}
816+
if ($$rAF.queue.length) {
817+
doNextRun = somethingFlushed = true;
818+
$$rAF.flush();
819+
}
820+
if ($$asyncCallback.queue.length) {
821+
doNextRun = somethingFlushed = true;
822+
this.triggerCallbackEvents();
823+
}
824+
if (timeoutsRemaining()) {
825+
var oldValue = timeoutsRemaining();
826+
this.triggerCallbackPromise();
827+
var newValue = timeoutsRemaining();
828+
if (newValue < oldValue) {
829+
doNextRun = somethingFlushed = true;
830+
}
831+
}
832+
} while (doNextRun);
833+
834+
if (!somethingFlushed) {
835+
throw new Error('No pending animations ready to be closed or flushed');
836+
}
837+
838+
$rootScope.$digest();
839+
840+
function timeoutsRemaining() {
841+
return $browser.deferredFns.length;
842+
}
806843
}
807844
};
808845

@@ -1752,15 +1789,16 @@ angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $
17521789
}];
17531790

17541791
angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
1755-
var queue = [];
1756-
var rafFn = function(fn) {
1792+
var queue, rafFn = function(fn) {
17571793
var index = queue.length;
17581794
queue.push(fn);
17591795
return function() {
17601796
queue.splice(index, 1);
17611797
};
17621798
};
17631799

1800+
queue = rafFn.queue = [];
1801+
17641802
rafFn.supported = $delegate.supported;
17651803

17661804
rafFn.flush = function() {
@@ -1773,22 +1811,22 @@ angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
17731811
queue[i]();
17741812
}
17751813

1776-
queue = [];
1814+
queue.length = 0;
17771815
};
17781816

17791817
return rafFn;
17801818
}];
17811819

17821820
angular.mock.$AsyncCallbackDecorator = ['$delegate', function($delegate) {
1783-
var callbacks = [];
1784-
var addFn = function(fn) {
1785-
callbacks.push(fn);
1821+
var queue, addFn = function(fn) {
1822+
queue.push(fn);
17861823
};
1824+
queue = addFn.queue = [];
17871825
addFn.flush = function() {
1788-
angular.forEach(callbacks, function(fn) {
1826+
angular.forEach(queue, function(fn) {
17891827
fn();
17901828
});
1791-
callbacks = [];
1829+
queue.length = 0;
17921830
};
17931831
return addFn;
17941832
}];

test/.jshintrc

+2-1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
"spyOnlyCallsWithArgs": false,
166166
"createMockStyleSheet": false,
167167
"browserTrigger": false,
168-
"jqLiteCacheSize": false
168+
"jqLiteCacheSize": false,
169+
"browserSupportsCssAnimations": false
169170
}
170171
}

test/helpers/privateMocks.js

+9
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,12 @@ function createMockStyleSheet(doc, wind) {
5656
}
5757
};
5858
}
59+
60+
function browserSupportsCssAnimations() {
61+
var nav = window.navigator.appVersion;
62+
if (nav.indexOf('MSIE') >= 0) {
63+
var version = parseInt(navigator.appVersion.match(/MSIE ([\d.]+)/)[1]);
64+
return version >= 10; //only IE10+ support keyframes / transitions
65+
}
66+
return true;
67+
}

test/ng/directive/ngClassSpec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ describe('ngClass animations', function() {
472472
//is spaced-out then it is required so that the original digestion
473473
//is kicked into gear
474474
$rootScope.$digest();
475-
$animate.triggerCallbacks();
475+
$animate.flush();
476476

477477
expect(element.data('state')).toBe('crazy-enter');
478478
expect(enterComplete).toBe(true);

test/ng/directive/ngIncludeSpec.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ describe('ngInclude', function() {
433433

434434
expect(autoScrollSpy).not.toHaveBeenCalled();
435435
expect($animate.queue.shift().event).toBe('enter');
436-
$animate.triggerCallbacks();
436+
$animate.flush();
437437

438438
expect(autoScrollSpy).toHaveBeenCalledOnce();
439439
}));
@@ -450,7 +450,7 @@ describe('ngInclude', function() {
450450
});
451451

452452
expect($animate.queue.shift().event).toBe('enter');
453-
$animate.triggerCallbacks();
453+
$animate.flush();
454454

455455
$rootScope.$apply(function() {
456456
$rootScope.tpl = 'another.html';
@@ -459,7 +459,7 @@ describe('ngInclude', function() {
459459

460460
expect($animate.queue.shift().event).toBe('leave');
461461
expect($animate.queue.shift().event).toBe('enter');
462-
$animate.triggerCallbacks();
462+
$animate.flush();
463463

464464
$rootScope.$apply(function() {
465465
$rootScope.tpl = 'template.html';
@@ -468,7 +468,7 @@ describe('ngInclude', function() {
468468

469469
expect($animate.queue.shift().event).toBe('leave');
470470
expect($animate.queue.shift().event).toBe('enter');
471-
$animate.triggerCallbacks();
471+
$animate.flush();
472472

473473
expect(autoScrollSpy).toHaveBeenCalled();
474474
expect(autoScrollSpy.callCount).toBe(3);
@@ -484,7 +484,7 @@ describe('ngInclude', function() {
484484
});
485485

486486
expect($animate.queue.shift().event).toBe('enter');
487-
$animate.triggerCallbacks();
487+
$animate.flush();
488488
expect(autoScrollSpy).not.toHaveBeenCalled();
489489
}));
490490

@@ -500,7 +500,7 @@ describe('ngInclude', function() {
500500
});
501501

502502
expect($animate.queue.shift().event).toBe('enter');
503-
$animate.triggerCallbacks();
503+
$animate.flush();
504504

505505
$rootScope.$apply(function() {
506506
$rootScope.tpl = 'template.html';
@@ -522,7 +522,7 @@ describe('ngInclude', function() {
522522

523523
$rootScope.$apply("tpl = 'template.html'");
524524
expect($animate.queue.shift().event).toBe('enter');
525-
$animate.triggerCallbacks();
525+
$animate.flush();
526526

527527
expect(autoScrollSpy).toHaveBeenCalledOnce();
528528
}

test/ng/directive/ngRepeatSpec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1486,7 +1486,7 @@ describe('ngRepeat animations', function() {
14861486
$rootScope.$digest();
14871487

14881488
expect(element.text()).toBe('123'); // the original order should be preserved
1489-
$animate.triggerReflow();
1489+
$animate.flush();
14901490
$timeout.flush(1500); // 1s * 1.5 closing buffer
14911491
expect(element.text()).toBe('13');
14921492

0 commit comments

Comments
 (0)