获得" $消化正在进行"在茉莉花2.0异步测试 [英] Getting "$digest already in progress" in async test with Jasmine 2.0

查看:88
本文介绍了获得" $消化正在进行"在茉莉花2.0异步测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道,叫 $消化 $适用摘要周期期间手动将导致$摘要已经正在进行错误,但我不知道为什么我在这里得到了。

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.

这是为包装服务 $ HTTP ,服务是很简单的一个单元测试,它只是prevents使得重复调用服务器同时确保code,试图还是做的呼吁得到它期望的数据。

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');
            }
        };
    }]);

该单元测试也pretty直线前进,它使用 $ httpBackend 期望的要求。

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?

我有完全相同的测试运行绿色茉莉花1.3,这只是发生后,我升级到2.0茉莉和改写了测试,使用新的异步语法。

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.

推荐答案

$ httpBacked.flush()实际启动并完成 $消化( )周期。我昨天花了一整天挖掘ngResource和角嘲笑的来源去的这条底线,仍然不完全了解它。

$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.

据我所知, $ httpBackend.flush的目的()是为了避免上述完全异步结构。换句话说,的语法,它('应该做的事,功能(完成){}); $ httpBackend.flush()不很好地一起玩。 .flush的非常的目的的()通过挂起异步回调推,然后返回。它像周围所有的异步回调的一大完成包装。

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.

所以,如果我理解正确的(现在它为我的作品),正确的方法是删除()完成用时处理器 $ httpBackend.flush()

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();
});

如果您添加的console.log语句,你会发现,所有的回调的刷新()周期中持续发生的:

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");
});

那么输出将是:

pre-GET

pre-冲洗

异步回调开始

异步回调结束

后冲洗

每一次。如果你真的想看到它,抓住范围,并期待在范围。$$阶段

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);
});

你会看到输出:

pre-得到了一个未定义

pre-get undefined

pre-冲洗未定义

异步回调开始$消化

异步回调结束$摘要

后冲洗未定义

这篇关于获得" $消化正在进行"在茉莉花2.0异步测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆