我一直在为我打算编写的应用程序创建一个 angularjs 框架。目前我正在开发一个示例应用程序,我正在编写一个教程,以便将我所做的一切都放在一个地方。
我目前正在尝试使用 karma 和 jasmine 为我正在呈现的模态对话框创建单元测试。这个模态对话框是使用 angular-bootstrap 的 $dialog 服务创建的。我认为这个对话框使用了一个承诺将数据传递到对话框控制器,我想解决这个承诺,这样我就可以在我的单元测试中检查传入的数据是否符合预期。我在弄清楚如何解决这个问题时遇到了一点困难,我看到了使用 scope.$apply 或 scope.$digest 的示例,它们似乎都不起作用,坦率地说,我不太明白它在做什么。我担心在单元测试中我已将此承诺分配给一个变量,并且一旦分配给一个变量,它可能无法解决。我看到提到这个“解决”
我既在寻找使它起作用的东西,又在寻找它为什么起作用的解释。
我要测试的控制器如下所示:
.controller( 'ClubCtrl', function ClubController( $scope, ClubRes, $dialog ) {
$scope.clubs = ClubRes.query();
/* this is called from a button, which passes one of the clubs from $scope.clubs */
$scope.editClub = function(club) {
$scope.myDialog = $dialog.dialog({dialogFade: false, resolve: {club: function(){return angular.copy(club);}}});
$scope.myDialog.open('club/club_edit.tpl.html', 'ClubEditCtrl').then(function(result){
if (result === 'cancel'){}
else {
$scope.clubs = ClubRes.query();
}
});
};
})
我现在尝试进行的单元测试旨在模拟整个对话框,并检查是否使用正确的输入参数调用了对话框:
describe( 'Base club controller', function() {
var scope, httpBackend;
//mock Application to allow us to inject our own dependencies
beforeEach(angular.mock.module('league'));
//mock the controller for the same reason and include $rootScope and $controller
beforeEach(angular.mock.inject(function($rootScope, $controller, _$httpBackend_ ){
//create an empty scope
scope = $rootScope.$new();
// setup a mock for the resource - instead of calling the server always return a pre-canned response
httpBackend = _$httpBackend_;
httpBackend.when('GET', '../clubs.json').respond([
{"contact_officer":"Officer 1","created_at":"2012-02-02T00:00:00Z","date_created":"2012-01-01T00:00:00Z","id":1,"name":"Club 1","updated_at":"2012-03-03T00:00:00Z"},
{"contact_officer":"Officer 2","created_at":"2012-02-02T00:00:00Z","date_created":"2012-01-01T00:00:00Z","id":2,"name":"Club 2","updated_at":"2012-03-03T00:00:00Z"}]);
// setup a mock for the dialog - when called it returns the value that was input when it was instantiated
scope.fakeDialog = {
parameters: null,
response: null,
template: null,
controller: null,
dialog: function(parameters) {
this.parameters = parameters;
return this;
},
open: function(template, controller) {
this.template = template;
this.controller = controller;
return this;
},
then: function(callBack){
callBack(this.response);
}
};
//declare the controller and inject our empty scope
$controller('ClubCtrl', {$scope: scope, $dialog: scope.fakeDialog});
}));
it('Calls edit on first row', function() {
// check nothing set beforehand
expect(scope.fakeDialog.parameters).toBe(null);
expect(scope.fakeDialog.template).toBe(null);
expect(scope.fakeDialog.controller).toBe(null);
// call edit
scope.editClub(scope.clubs[0]);
scope.$digest();
httpBackend.flush();
// expect stuff to have happened
expect(scope.fakeDialog.parameters.club.name).toBe('Club 1');
expect(scope.fakeDialog.template).toBe('club/club_edit.tpl.html');
expect(scope.fakeDialog.controller).toBe('ClubEditCtrl');
});
});
我在 console.log(scope.fakeDialog.parameters) 中实际得到的是:
Object{dialogFade: false, resolve: Object{club: function (){ ... }}}
所以我的club被埋在了“resolve: Object……”里面,我认为这是一个承诺。我认为我需要的是一种触发解决问题的方法-但我不确定那是什么。