这是我的测试:
it('add.user() should POST to /users/, failure', function() {
mockBackend.expectPOST("/users/", {username:'u', password: 'p', email: 'e', location: 'loc'}).respond(400, {msg: "bad request"});
BaseService.add.user({username:'u', password: 'p', email: 'e', location: 'loc'});
mockBackend.flush();
});
afterEach(function() {
mockBackend.verifyNoOutstandingExpectation();
mockBackend.verifyNoOutstandingRequest();
});
当我运行此测试时,我收到此错误:
Chromium 53.0.2785 (Ubuntu 0.0.0) Factory: BaseService add.user() should POST to /users/, failure FAILED
[object Object] thrown
Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.3.15/$rootScope/inprog?p0=%24digest
at /home/user/Documents/ebdjango/ebdjangoapp/static/js/angular.js:63:12
at beginPhase (/home/user/Documents/ebdjango/ebdjangoapp/static/js/angular.js:14820:15)
at Scope.$digest (/home/user/Documents/ebdjango/ebdjangoapp/static/js/angular.js:14262:9)
at Function.$httpBackend.verifyNoOutstandingExpectation (node_modules/angular-mocks/angular-mocks.js:1557:38)
at Object.<anonymous> (tests/test_base.js:61:21)
这是BaseService.add.user()
:
self.add = {
user: function(user) {
return $http.post("/users/", user)
.then(function successHandler(response) {
return $http.post("/custom-api-auth/login", user)
}).then(function successHandler(response) {
$window.location.href = "/";
// if there are errors, rewrite the error messages
}).catch(function rejectHandler(errorResponse) {
for (prop in errorResponse.data) {
if (prop == "email") {
errorResponse.data[prop] = "Please enter a valid email address.";
} else if (prop == "username") {
errorResponse.data[prop] = "Username can only contain alphanumeric characters and '.'";
} else if (prop == "password") {
errorResponse.data[prop] = "Please enter a valid password";
}
}
throw errorResponse;
};
如何防止发生$digest already in progress
错误?
编辑:如果我删除throw errorResponse;
,测试工作但我需要throw errorResponse;
因为我需要在前端显示错误(另一个控制器负责... {{1} }基本上重写应该在前端显示的错误。)
编辑2:当错误消息显示BaseService.add.user().catch()
时,它指向该行:at Object.<anonymous> (tests/test_base.js:61:21)
答案 0 :(得分:1)
上面代码的问题是它会抛出$httpBackend.flush()
块。与其他承诺实现相反,在$ q中抛出和拒绝并不是一回事。
考虑到同步在摘要(catch
)上执行$ q promise链,抛出$q.reject
块将导致未被捕获的错误,而不是被拒绝的承诺。它可能会阻止摘要完成,并导致下一个摘要中的 $ digest已在进行中错误。
因此,一般throw
应该用于承诺中的预期错误,而return $q.reject(errorResponse);
应该仅用于严重错误。它应该是
expect(BaseService.add.user({ ... }).toBeRejectedWith({ ... });
建议使用Jasmine promise matchers对其进行测试:
var noError = new Error;
BaseService.add.user({ ... })
.then(() => $q.reject(noError))
.catch((err) => {
expect(err).not.toBe(noError);
expect(err).toEqual(...);
});
$rootScope.$digest();
否则必须通过更复杂的承诺链进行测试:
module({ $window: {
location: jasmine.spyObj(['href'])
} })
位置更改应该在测试中存根,因为在测试中更改实际位置是最不需要的:
$location
最好在Angular应用中使用location
服务,而不是直接访问$location.path('/...')
,除非另有证明,location.href = '/...'
代替$location.path
。
在测试中使用已经安全了,虽然total = total + x;
可以另外进行测试。