Sunday, 15 June 2014

angularjs - Getting "$digest already in progress" in async test with Jasmine 2.0 -



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

why angular in digest-cycle in first place? why calling 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