我知道在摘要周期中手动调用$digest
或$Application
会导致$digest已经在进行中错误,但我不知道为什么我在这里得到它。
这是一个包装$超文本传输协议
的服务的单元测试,该服务足够简单,它只是防止对服务器进行重复调用,同时确保试图进行调用的html" target="_blank">代码仍然获得预期的数据。
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 ready in progress”错误,这将导致失败。我不知道为什么。我可以通过在这样的超时中包装done()
来解决这个问题
setTimeout(function() { done() }, 1);
这意味着,done()
将排队并在$digest完成后运行,但这解决了我的问题,我想知道
do()
会触发此错误?我在Jasmine 1.3中运行了完全相同的测试,这只发生在我升级到Jasmine 2.0并重写测试以使用新的异步语法之后。
添加到@deitch的答案中。为了使测试更加健壮,你可以在回调之前添加一个间谍。这应该保证你的回调实际上被调用。
it('does GET requests', function() {
var callback = jasmine.createSpy().and.callFake(function(result) {
expect(result.data).toEqual('The response');
});
$httpBackend.expectGET('/some/random/url').respond('The response');
service.get('/some/random/url').then(callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalled();
});
@deitch是对的,$http pBacked.flush()触发摘要。问题是,当$http pBackend.verifyNoOutstaning期望();
在每个完成后运行时,它也有一个摘要。这是事件的顺序:
您可以调用flush()
,这将触发摘要
- 执行
then()
- 执行
done()
verifyNoOutstandingExpectation()
运行时会触发摘要,但您已经在摘要中,因此会出现错误
done()。如果
then
没有运行,那么您现在可能知道出现了故障。关键是在启动done()
之前确保摘要已完成。
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');
setTimeout(done, 0); // run the done() after the current $digest is complete.
});
$httpBackend.flush();
});
将
done()
放入超时将使其在当前摘要完成后立即执行()。这将确保您想要运行的所有预期的
都将实际运行。
$httpBacked.flush()
实际上启动并完成一个$digest()
循环。我昨天花了一整天的时间来挖掘ngResource和angular Mock的来源,以弄清这一点,但仍然没有完全理解它。
据我所知,$httpBackend.flush()
的目的是完全避免上面的异步结构。换句话说,it('should do something',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");
});
那么输出将是:
预购
预冲洗
异步回调开始
异步回调结束
后冲洗
每一次。如果你真的想看它,抓住范围,看看
范围。$$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);
});
您将看到输出:
预先得到未定义
预冲洗未定义
异步回调开始$摘要
异步回调结束$digest
后冲洗未定义
问题内容: 尝试致电时出现此错误 错误是 问题答案: 复制: 防止在调用$ scope。$ apply()时发生错误$digest。 您收到的错误表明Angular的脏检查已经在进行中。 最新的最佳实践表明,如果要在下一个 摘要 迭代中执行任何代码,则应使用: 上一页反应: (不要使用此方法) 使用安全的申请,例如: 你为什么不反转条件?
我正在尝试用Jasmine和RequireJS做一些测试。一切都进行得很好,直到我注意到我所描述的函数的上下文出现了问题。 有人知道怎么解决这个吗?
所以,我在测试一个依赖于事件发射器的组件。为此,我想出了一个解决方案,使用mocha+chai的承诺: 在控制台上,我得到了一个“unhandledPromiserEjectionWarning”,尽管reject函数正在被调用,因为它会立即显示消息“assertionError:Promise Error" (Node:25754)UnhandledPromiseRejectionWarning
如何在组件返回中使用promise函数,如下所示: 因此,结果将是: 即使我在同一个组件中有几个promise,我也必须使用?