angularjs - Getting "$digest already in progress" in async test with Jasmine 2.0 -
i know calling $digest or $apply manually during digest cycle cause "$digest in progress" error have no thought why getting here.
this unit test service wraps $http, service simple enough, prevents making duplicate calls server while ensuring code attempts calls still gets info expected.
angular.module('services') .factory('httpservice', ['$http', function($http) { var pendingcalls = {}; var createkey = function(url, data, method) { homecoming method + url + json.stringify(data); }; var send = function(url, data, method) { var key = createkey(url, data, method); if (pendingcalls[key]) { homecoming pendingcalls[key]; } var promise = $http({ method: method, url: url, data: info }); pendingcalls[key] = promise; promise.then(function() { delete pendingcalls[key]; }); homecoming promise; }; homecoming { post: function(url, data) { homecoming send(url, data, 'post'); }, get: function(url, data) { homecoming send(url, data, 'get'); }, _delete: function(url, data) { homecoming send(url, data, 'delete'); } }; }]); the unit-test pretty straight forward, uses $httpbackend expect request.
it('does 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 sone done() gets called "$digest in progress" error. i've no thought why. can solve wrapping done() in timeout this
settimeout(function() { done() }, 1); that means done() queued , run after $digest done while solves problem want know
done() trigger error? i had exact same test running greenish jasmine 1.3, happened after upgraded jasmine 2.0 , rewrote test utilize new async-syntax.
$httpbacked.flush() starts , completes $digest() cycle. spent day yesterday digging source of ngresource , angular-mocks bottom of this, , still don't understand it.
as far can tell, purpose of $httpbackend.flush() avoid async construction above entirely. in other words, syntax of it('should something',function(done){}); , $httpbackend.flush() not play nicely together. purpose of .flush() force through pending async callbacks , return. 1 big done wrapper around of async callbacks.
so if understood correctly (and works me now) right method remove done() processor when using $httpbackend.flush():
it('does requests', function() { $httpbackend.expectget('/some/random/url').respond('the response'); service.get('/some/random/url').then(function(result) { expect(result.data).toequal('the response'); }); $httpbackend.flush(); }); if add together console.log statements, find of callbacks consistently happen during flush() cycle:
it('does requests', function() { $httpbackend.expectget('/some/random/url').respond('the response'); console.log("pre-get"); service.get('/some/random/url').then(function(result) { console.log("async callback begin"); expect(result.data).toequal('the response'); console.log("async callback end"); }); console.log("pre-flush"); $httpbackend.flush(); console.log("post-flush"); }); then output be:
pre-get
pre-flush
async callback begin
async callback end
post-flush
every time. if want see it, grab scope , @ scope.$$phase
var scope; beforeeach(function(){ inject(function($rootscope){ scope = $rootscope; }); }); it('does requests', function() { $httpbackend.expectget('/some/random/url').respond('the response'); console.log("pre-get "+scope.$$phase); service.get('/some/random/url').then(function(result) { console.log("async callback begin "+scope.$$phase); expect(result.data).toequal('the response'); console.log("async callback end "+scope.$$phase); }); console.log("pre-flush "+scope.$$phase); $httpbackend.flush(); console.log("post-flush "+scope.$$phase); }); and see output:
pre-get undefined
pre-flush undefined
async callback begin $digest
async callback end $digest
post-flush undefined
angularjs jasmine jasmine2.0
No comments:
Post a Comment