I know that calling $digest
or $apply
manually during a digest cycle will cause a "$digest already in progress" error but I have no idea why I am getting it here.
This is a unit test for a service that wraps $http
, the service is simple enough, it just prevents making duplicate calls to the server while ensuring that code that attempts to do the calls still gets the data it expected.
angular.module('services')
.factory('httpService', ['$http', function($http) {
var pendingCalls = {};
var createKey = function(url, data, method) {
return method + url + JSON.stringify(data);
};
var send = function(url, data, method) {
var key = createKey(url, data, method);
if (pendingCalls[key]) {
return pendingCalls[key];
}
var promise = $http({
method: method,
url: url,
data: data
});
pendingCalls[key] = promise;
promise.then(function() {
delete pendingCalls[key];
});
return promise;
};
return {
post: function(url, data) {
return send(url, data, 'POST');
},
get: function(url, data) {
return send(url, data, 'GET');
},
_delete: function(url, data) {
return send(url, data, 'DELETE');
}
};
}]);
The unit-test is also pretty straight forward, it uses $httpBackend
to expect the request.
it('does GET requests', function(done) {
$httpBackend.expectGET('/some/random/url').respond('The response');
service.get('/some/random/url').then(function(result) {
expect(result.data).toEqual('The response');
done();
});
$httpBackend.flush();
});
This blows up as sone as done()
gets called with a "$digest already in progress" error. I've no idea why. I can solve this by wrapping done()
in a timeout like this
setTimeout(function() { done() }, 1);
That means done()
will get queued up and run after the $digest is done but while that solves my problem I want to know
- Why is Angular in a digest-cycle in the first place?
- Why does calling
done()
trigger this error?
I had the exact same test running green with Jasmine 1.3, this only happened after I upgraded to Jasmine 2.0 and rewrote the test to use the new async-syntax.