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

Commit 472d076

Browse files
committed
fix(ngAnimateMock): $animate.flush should work for looping animations
1 parent 1ae0be1 commit 472d076

File tree

4 files changed

+205
-12
lines changed

4 files changed

+205
-12
lines changed

src/ngMock/angular-mocks.js

+22-10
Original file line numberDiff line numberDiff line change
@@ -783,9 +783,10 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
783783
return queueFn;
784784
});
785785

786-
$provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF', '$$forceReflow', '$$animateAsyncRun',
787-
function($delegate, $timeout, $browser, $$rAF, $$forceReflow, $$animateAsyncRun) {
788-
786+
$provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF',
787+
'$$forceReflow', '$$animateAsyncRun', '$rootScope',
788+
function($delegate, $timeout, $browser, $$rAF,
789+
$$forceReflow, $$animateAsyncRun, $rootScope) {
789790
var animate = {
790791
queue: [],
791792
cancel: $delegate.cancel,
@@ -797,16 +798,27 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
797798
},
798799
enabled: $delegate.enabled,
799800
flush: function() {
800-
var rafsFlushed = false;
801-
if ($$rAF.queue.length) {
802-
$$rAF.flush();
803-
rafsFlushed = true;
804-
}
801+
$rootScope.$digest();
802+
803+
var doNextRun, somethingFlushed = false;
804+
do {
805+
doNextRun = false;
806+
807+
if ($$rAF.queue.length) {
808+
$$rAF.flush();
809+
doNextRun = somethingFlushed = true;
810+
}
811+
812+
if ($$animateAsyncRun.flush()) {
813+
doNextRun = somethingFlushed = true;
814+
}
815+
} while (doNextRun);
805816

806-
var animatorsFlushed = $$animateAsyncRun.flush();
807-
if (!rafsFlushed && !animatorsFlushed) {
817+
if (!somethingFlushed) {
808818
throw new Error('No pending animations ready to be closed or flushed');
809819
}
820+
821+
$rootScope.$digest();
810822
}
811823
};
812824

test/helpers/testabilityPatch.js

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ afterEach(function() {
4747
if (bod) {
4848
bod.$$hashKey = null;
4949
}
50+
document.$$hashKey = null;
5051

5152
if (this.$injector) {
5253
var $rootScope = this.$injector.get('$rootScope');

test/ngAnimate/animationSpec.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -507,8 +507,7 @@ describe('$$animation', function() {
507507

508508
$rootScope.$digest();
509509

510-
$animate.flush(); // element -> child
511-
$animate.flush(); // child -> grandchild
510+
$animate.flush();
512511

513512
expect(captureLog[0].element).toBe(element);
514513
expect(captureLog[1].element).toBe(child);

test/ngMock/angular-mocksSpec.js

+181
Original file line numberDiff line numberDiff line change
@@ -1828,6 +1828,187 @@ describe('ngMockE2E', function() {
18281828
}));
18291829
});
18301830
});
1831+
1832+
describe('ngAnimateMock', function() {
1833+
1834+
beforeEach(module('ngAnimate'));
1835+
beforeEach(module('ngAnimateMock'));
1836+
1837+
var ss, element, trackedAnimations;
1838+
1839+
afterEach(function() {
1840+
if (element) {
1841+
element.remove();
1842+
}
1843+
if (ss) {
1844+
ss.destroy();
1845+
}
1846+
});
1847+
1848+
beforeEach(module(function($animateProvider) {
1849+
trackedAnimations = [];
1850+
$animateProvider.register('.animate', function() {
1851+
return {
1852+
leave: logFn('leave'),
1853+
addClass: logFn('addClass')
1854+
};
1855+
1856+
function logFn(method) {
1857+
return function(element) {
1858+
trackedAnimations.push(getDoneCallback(arguments));
1859+
};
1860+
}
1861+
1862+
function getDoneCallback(args) {
1863+
for (var i = args.length; i > 0; i--) {
1864+
if (angular.isFunction(args[i])) return args[i];
1865+
}
1866+
}
1867+
});
1868+
1869+
return function($animate, $rootElement, $document, $rootScope, $window) {
1870+
ss = createMockStyleSheet($document, $window);
1871+
1872+
element = angular.element('<div class="animate"></div>');
1873+
$rootElement.append(element);
1874+
angular.element($document[0].body).append($rootElement);
1875+
$animate.enabled(true);
1876+
$rootScope.$digest();
1877+
};
1878+
}));
1879+
1880+
describe('$animate.queue', function() {
1881+
it('should maintain a queue of the executed animations', inject(function($animate) {
1882+
element.removeClass('animate'); // we don't care to test any actual animations
1883+
var options = {};
1884+
1885+
$animate.addClass(element, 'on', options);
1886+
var first = $animate.queue[0];
1887+
expect(first.element).toBe(element);
1888+
expect(first.event).toBe('addClass');
1889+
expect(first.options).toBe(options);
1890+
1891+
$animate.removeClass(element, 'off', options);
1892+
var second = $animate.queue[1];
1893+
expect(second.element).toBe(element);
1894+
expect(second.event).toBe('removeClass');
1895+
expect(second.options).toBe(options);
1896+
1897+
$animate.leave(element, options);
1898+
var third = $animate.queue[2];
1899+
expect(third.element).toBe(element);
1900+
expect(third.event).toBe('leave');
1901+
expect(third.options).toBe(options);
1902+
}));
1903+
});
1904+
1905+
describe('$animate.flush()', function() {
1906+
it('should throw an error if there is nothing to animate', inject(function($animate) {
1907+
expect(function() {
1908+
$animate.flush();
1909+
}).toThrow('No pending animations ready to be closed or flushed');
1910+
}));
1911+
1912+
it('should trigger the animation to start',
1913+
inject(function($animate) {
1914+
1915+
expect(trackedAnimations.length).toBe(0);
1916+
$animate.leave(element);
1917+
$animate.flush();
1918+
expect(trackedAnimations.length).toBe(1);
1919+
}));
1920+
1921+
it('should trigger the animation to end once run and called',
1922+
inject(function($animate) {
1923+
1924+
$animate.leave(element);
1925+
$animate.flush();
1926+
expect(element.parent().length).toBe(1);
1927+
1928+
trackedAnimations[0]();
1929+
$animate.flush();
1930+
expect(element.parent().length).toBe(0);
1931+
}));
1932+
1933+
it('should trigger the animation promise callback to fire once run and closed',
1934+
inject(function($animate) {
1935+
1936+
var doneSpy = jasmine.createSpy();
1937+
$animate.leave(element).then(doneSpy);
1938+
$animate.flush();
1939+
1940+
trackedAnimations[0]();
1941+
expect(doneSpy).not.toHaveBeenCalled();
1942+
$animate.flush();
1943+
expect(doneSpy).toHaveBeenCalled();
1944+
}));
1945+
1946+
it('should trigger a series of CSS animations to trigger and start once run',
1947+
inject(function($animate, $rootScope) {
1948+
1949+
if (!browserSupportsCssAnimations()) return;
1950+
1951+
ss.addRule('.leave-me.ng-leave', 'transition:1s linear all;');
1952+
1953+
var i, elm, elms = [];
1954+
for (i = 0; i < 5; i++) {
1955+
elm = angular.element('<div class="leave-me"></div>');
1956+
element.append(elm);
1957+
elms.push(elm);
1958+
1959+
$animate.leave(elm);
1960+
}
1961+
1962+
$rootScope.$digest();
1963+
1964+
for (i = 0; i < 5; i++) {
1965+
elm = elms[i];
1966+
expect(elm.hasClass('ng-leave')).toBe(true);
1967+
expect(elm.hasClass('ng-leave-active')).toBe(false);
1968+
}
1969+
1970+
$animate.flush();
1971+
1972+
for (i = 0; i < 5; i++) {
1973+
elm = elms[i];
1974+
expect(elm.hasClass('ng-leave')).toBe(true);
1975+
expect(elm.hasClass('ng-leave-active')).toBe(true);
1976+
}
1977+
}));
1978+
1979+
it('should trigger parent and child animations to run within the same flush',
1980+
inject(function($animate, $rootScope) {
1981+
1982+
var child = angular.element('<div class="animate child"></div>');
1983+
element.append(child);
1984+
1985+
expect(trackedAnimations.length).toBe(0);
1986+
1987+
$animate.addClass(element, 'go');
1988+
$animate.addClass(child, 'start');
1989+
$animate.flush();
1990+
1991+
expect(trackedAnimations.length).toBe(2);
1992+
}));
1993+
1994+
it('should trigger animation callbacks when called',
1995+
inject(function($animate, $rootScope) {
1996+
1997+
var spy = jasmine.createSpy();
1998+
$animate.on('addClass', element, spy);
1999+
2000+
$animate.addClass(element, 'on');
2001+
expect(spy).not.toHaveBeenCalled();
2002+
2003+
$animate.flush();
2004+
expect(spy.callCount).toBe(1);
2005+
2006+
trackedAnimations[0]();
2007+
$animate.flush();
2008+
expect(spy.callCount).toBe(2);
2009+
}));
2010+
});
2011+
});
18312012
});
18322013

18332014
describe('make sure that we can create an injector outside of tests', function() {

0 commit comments

Comments
 (0)