While trying to update our application to use Angular 1.4, we ran into some troubles.
Unit tests started failing without a clear reason (oh yes, we have unit tests). Some hours of debugging later we found out `useApplyAsync` was the cause of our troubles.
useApplyAsync is a method to enable/disable the combined processing of http responses. Basically, with this option enabled, only one $digest cycle is triggered for multiple http request around the same time. (https://docs.angularjs.org/api/ng/provider/$httpProvider)
This is supposed to be a huge performance improvement for big Angular applications, which actually totally makes sense after reading the explanation, so we enabled this option.
Once we found out disabling `applyAsync `fixed our unit tests, we found out pretty soon, that using multiple `$httpBackend.flush()` calls fixed our tests when `applyAsync` is enabled. I have a small jsfiddle here which recreates the problem: http://jsfiddle.net/klaascuvelier/q752t51q/
If you edit the source code you’ll see the multiple flushes or disabling `applyAsync` fixes the test.
Knowing the multiple flushes fixes the issue, I dove into the source code of the $httpBackend service of the angular-mocks.
This is how the flush method looks:
By default, a `$rootScope.$digest` is triggered, and then the code loops over the responses (either all, or some), and executes those.
Those responses are actually callbacks created by the wrapResponse method, which point to the `done` method in the angular $http service:
The interesting part here are the last lines; when using `applyAsync`, a `$digest` is scheduled through `$applyAsync`, when not using `applyAsync`, a digest is triggered immediately.
This is the explanation for the problem we are seeing;
When not using `applyAsync`, this is the flow, in psuedo code:
And this is the pseudo code for using `applyAsync`
So our issue is that there is no next tick which flushes the applyAsync queue before we’re moving to the next item of the responses array.
We can easily solve this by adding `$rootScope.$digest` at the end of the loop.
In my opinion it would make sense to trigger a `$digest` at that point. When you don’t have `applyAsync` enabled, angular (mocks) will execute your first http call, take care of the other promises, execute the second http call and take care of the other promises in 1 flush.
Why would the `applyAsync` option require the unit test to do a double flush to make sure all http calls are done? Shouldn’t it be the httpBackend which takes care of the applyAsync changes instead of the unit test?