gpt4 book ai didi

angularjs - 使用 Jasmine 2.0 在异步测试中获取 "$digest already in progress"

转载 作者:行者123 更新时间:2023-12-02 20:14:01 24 4
gpt4 key购买 nike

我知道在摘要周期期间手动调用 $digest$apply 会导致“$digest已经在进行中”错误,但我不知道为什么在这里获取它。

这是对包装$http的服务的单元测试,该服务足够简单,它只是防止对服务器进行重复调用,同时确保尝试执行调用的代码仍然得到它预期的数据。

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

单元测试也非常简单,它使用 $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();
});

done() 被调用并出现“$digest已经在进行中”错误时,这个问题就会爆发。我不知道为什么。我可以通过将 done() 包装在像这样的超时中来解决这个问题

setTimeout(function() { done() }, 1);

这意味着 done() 将排队并在 $digest 完成后运行,但这解决了我的问题,我想知道

  • 为什么 Angular 会处于摘要循环中?
  • 为什么调用 done() 会触发此错误?

我在 Jasmine 1.3 上进行了完全相同的绿色测试,这只发生在我升级到 Jasmine 2.0 并重写测试以使用新的异步语法之后。

最佳答案

$httpBacked.flush() 实际上启动并完成了一个 $digest() 循环。昨天我花了一整天的时间去挖掘 ngResource 和 Angular-Mocks 的源码来深究这一点,但仍然没有完全理解它。

据我所知,$httpBackend.flush()的目的是完全避免上面的异步结构。换句话说,it('should do some',function(done){});$httpBackend.flush() 的语法不能很好地结合在一起。 .flush() 的真正目的是推送待处理的异步回调,然后返回。它就像一个大的 done 包装器,围绕着所有异步回调。

因此,如果我理解正确(现在它对我有用),正确的方法是在使用 $httpBackend.flush() 时删除 done() 处理器:

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 语句,您会发现所有回调始终在 flush() 周期内发生:

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-flush

async callback begin

async callback end

post-flush

每次。如果您确实想查看它,请捕获范围并查看 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-get undefined

pre-flush undefined

async callback begin $digest

async callback end $digest

post-flush undefined

关于angularjs - 使用 Jasmine 2.0 在异步测试中获取 "$digest already in progress",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24341544/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com