Getting “$digest already in progress” in async test with Jasmine 2.0

$httpBacked.flush() actually starts and completes a $digest() cycle. I spent all day yesterday digging into the source of ngResource and angular-mocks to get to the bottom of this, and still don’t fully understand it.

As far as I can tell, the purpose of $httpBackend.flush() is to avoid the async structure above entirely. In other words, the syntax of it('should do something',function(done){}); and $httpBackend.flush() do not play nicely together. The very purpose of .flush() is to push through the pending async callbacks and then return. It is like one big done wrapper around all of your async callbacks.

So if I understood correctly (and it works for me now) the correct method would be to remove the done() processor when using $httpBackend.flush():

it('does GET 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 you add console.log statements, you will find that all of the callbacks consistently happen during the flush() cycle:

it('does GET 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 the output will be:

pre-get

pre-flush

async callback begin

async callback end

post-flush

Every time. If you really want to see it, grab the scope and look at scope.$$phase

var scope;
beforeEach(function(){
    inject(function($rootScope){
        scope = $rootScope;
    });
});
it('does GET 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 you will see the output:

pre-get undefined

pre-flush undefined

async callback begin $digest

async callback end $digest

post-flush undefined

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)