angular/angular.js · error · Error
No pending animations ready to be closed or flushed
Error message
No pending animations ready to be closed or flushed
What it means
ngMock's mock $animate queues element animations; its flush() closes everything queued by repeatedly draining $$rAF and $$animateAsyncRun queues (looping until a pass flushes nothing) and finishes with a $digest. If a full pass flushes nothing and hideErrors is falsy, there was no queued animation work, so flush() throws 'No pending animations ready to be closed or flushed'.
Source
Thrown at src/ngMock/angular-mocks.js:1033
flush: function(hideErrors) {
$rootScope.$digest();
var doNextRun, somethingFlushed = false;
do {
doNextRun = false;
if ($$rAF.queue.length) {
$$rAF.flush();
doNextRun = somethingFlushed = true;
}
if ($$animateAsyncRun.flush()) {
doNextRun = somethingFlushed = true;
}
} while (doNextRun);
if (!somethingFlushed && !hideErrors) {
throw new Error('No pending animations ready to be closed or flushed');
}
$rootScope.$digest();
}
};
angular.forEach(
['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
animate[method] = function() {
animate.queue.push({
event: method,
element: arguments[0],
options: arguments[arguments.length - 1],
args: arguments
});
return $delegate[method].apply($delegate, arguments);
};
});View on GitHub (pinned to d8f77817eb)
Solutions
- Trigger the DOM/class change that queues the animation (run the scope/digest path that calls $animate) before calling $animate.flush().
- Guard the flush: only call it when $animate.queue.length > 0 or $$rAF.queue.length > 0.
- If an empty queue is legitimate in the test's flow, call $animate.flush(true) to skip the throw — but then you are only paying for the closing $digest.
Example fix
// before
it('adds .highlight', inject(function($animate, $rootScope) {
$rootScope.$apply('vm.active = false'); // condition false: nothing queued
$animate.flush(); // throws
}));
// after
it('adds .highlight', inject(function($animate, $rootScope) {
$rootScope.$apply('vm.active = true'); // directive queues addClass
$animate.flush();
})); Defensive patterns
Strategy: validation
Validate before calling
// Only flush when animation work is actually queued
inject(function($animate) {
if ($animate.queue.length > 0) {
$animate.flush();
}
}); Prevention
- Make the scope/class change that queues the animation before flushing.
- Check $animate.enabled(false) is not set globally in the test module.
- Use $animate.flush(true) only when an empty queue is a legitimate outcome.
When it happens
Trigger: Calling $animate.flush() before any $animate operation (animate/enter/leave/move/addClass/removeClass/setClass) has queued work; calling flush after a previous flush already drained the queues; the animation was disabled ($animate.enabled(false)) or the element/class change never happened, so nothing queued.
Common situations: Testing a directive whose $animate.addClass only runs when a scope condition is true, but the test never made the condition true; the code path triggering the animation sits inside a $timeout or event handler that has not run yet; passing flush(true) suppresses the throw (hideErrors), which hides both the error and any assumption mistake.
Related errors
- No rAF callbacks present
- No deferred tasks to be flushed
- No pending request to flush !
- No more pending request to flush !
- Unflushed requests: {} {}
AI-assisted analysis of angular/angular.js@d8f77817eb (2026-08-21).
Data as JSON: /api/errors/30bb18970af9d79d.
Report an issue: GitHub.