Javascript AngularJS jasmine promise测试因超时而失败
我正在尝试测试我的登录控制器,如下所示:Javascript AngularJS jasmine promise测试因超时而失败,javascript,angularjs,jasmine,promise,q,Javascript,Angularjs,Jasmine,Promise,Q,我正在尝试测试我的登录控制器,如下所示: describe('LoginController', function() { beforeEach(module('task6')); var $controller, LoginService; beforeEach(inject(function(_$controller_, _LoginService_) { $controller = _$controller_; LoginServ
describe('LoginController', function() {
beforeEach(module('task6'));
var $controller, LoginService;
beforeEach(inject(function(_$controller_, _LoginService_) {
$controller = _$controller_;
LoginService = _LoginService_;
}));
describe('LoginController.submitLogin', function() {
it('tests if such user exists', function(done) {
var $scope = {};
var controller = $controller('LoginController', {$scope: $scope});
var resultValue;
controller.loginField = 'John';
controller.password = 'Smith';
LoginService.signIn(controller.loginField,
controller.password)
.then(function() {
expect(true).toBe(true);
done();
});
});
});
});
其中,signIn函数为:
function signIn(loginField, password) {
var defer = $q.defer();
if (loginField && password) {
defer.resolve("nice one");
} else {
defer.reject("oh dear");
}
return defer.promise;
}
但如果在指定的超时时间内未调用异步回调,则始终会失败…您需要为控制器创建scope对象作为$rootScope的实例:
您需要为控制器创建scope对象作为$rootScope的实例:
您需要在测试结束时调用$scope.$digest一次。承诺永远不会在其创建的同一个摘要周期内得到解决
解释
虽然框架可能允许这样做,但开发人员选择不这样做。请参见此示例,但它可能存在问题:
function login(login, password) {
LoginService.signIn(login, password)
.then(function() {
cancelLoadingAnimation();
});
startLoadingAnimation();
}
通常承诺是异步解决的,所以这里没有问题。加载动画在登录功能中启动,并在登录成功时取消。但是想象一下,这个承诺在一个像你这样的测试中立即得到了解决!现在,动画可能在开始之前就被取消了
当然,这可以通过将startLoadingAnimation调用移到signIn调用之上来解决。然而,当承诺总是异步解析时,对代码进行推理就容易多了
更新:正如@gnerkus在他的回答中所说的,您必须创建$scope作为$rootScope的子级。然而,单靠这一点并不能解决问题。您必须同时执行这两项操作。您需要在测试结束时调用$scope.$digest一次。承诺永远不会在其创建的同一个摘要周期内得到解决
解释
虽然框架可能允许这样做,但开发人员选择不这样做。请参见此示例,但它可能存在问题:
function login(login, password) {
LoginService.signIn(login, password)
.then(function() {
cancelLoadingAnimation();
});
startLoadingAnimation();
}
通常承诺是异步解决的,所以这里没有问题。加载动画在登录功能中启动,并在登录成功时取消。但是想象一下,这个承诺在一个像你这样的测试中立即得到了解决!现在,动画可能在开始之前就被取消了
当然,这可以通过将startLoadingAnimation调用移到signIn调用之上来解决。然而,当承诺总是异步解析时,对代码进行推理就容易多了
更新:正如@gnerkus在他的回答中所说的,您必须创建$scope作为$rootScope的子级。然而,单靠这一点并不能解决问题。您必须同时执行这两项操作。我想,@gnerkus和@lex82都是正确的-我需要运行$digest cycle以获得承诺,但我仍然需要一个对实际范围的引用来执行此操作。以下是我的代码的最终工作版本:
describe('LoginController', function() {
beforeEach(module('task6'));
var $rootScope, $controller, LoginService;
beforeEach(inject(function(_$rootScope_, _$controller_, _LoginService_) {
$rootScope = _$rootScope_;
$controller = _$controller_;
LoginService = _LoginService_;
}));
describe('LoginController.submitLogin', function() {
it('tests if such user exists', function(done) {
var $scope = $rootScope.$new();
var controller = $controller('LoginController',
{$scope: $scope});
controller.loginField = 'John';
controller.password = 'Smith';
LoginService.signIn(controller.loginField,
controller.password)
.then(function(logged) {
expect(true).toBe(true);
done();
})
$scope.$digest();
});
});
});
谢谢大家 我想,@gnerkus和@lex82都是对的-我需要运行$digest cycle来获得承诺,但我仍然需要一个对真实范围的引用来完成这项工作。以下是我的代码的最终工作版本:
describe('LoginController', function() {
beforeEach(module('task6'));
var $rootScope, $controller, LoginService;
beforeEach(inject(function(_$rootScope_, _$controller_, _LoginService_) {
$rootScope = _$rootScope_;
$controller = _$controller_;
LoginService = _LoginService_;
}));
describe('LoginController.submitLogin', function() {
it('tests if such user exists', function(done) {
var $scope = $rootScope.$new();
var controller = $controller('LoginController',
{$scope: $scope});
controller.loginField = 'John';
controller.password = 'Smith';
LoginService.signIn(controller.loginField,
controller.password)
.then(function(logged) {
expect(true).toBe(true);
done();
})
$scope.$digest();
});
});
});
谢谢大家