如何在控制器中测试 angular 元素绑定
how to test angular element bind in controller
我有以下控制器...
angular.module('jobBoard').controller('JobListController', ['$scope','$window', function($scope, $window){
$scope.keywordPlaceholder = 'What kind of job?';
$scope.locationPlaceholder = 'Where? (city, state or zip)';
$scope.onResize = function(){
if ($window.innerWidth <= 480){
$scope.keywordPlaceholder = 'What?';
$scope.locationPlaceholder = 'Where?';
}
}
angular.element($window).bind('resize', function(){
$scope.onResize();
$scope.$apply();
})
$scope.onResize();
$scope.loadJobs();
}]);
这是茉莉花测试...
describe('JobListController', function(){
var scope, controller;
describe('binding resize to window', function(){
var mockWindow = {
resize: function(){}
}
beforeEach(inject(function($rootScope, $controller){
scope = $rootScope.$new();
$controller('JobListController', { $scope:scope, $window: mockWindow});
}))
it('binds to the resize function', function(){
spyOn(scope, 'onResize');
spyOn(scope, '$apply');
mockWindow.resize();
expect(scope.onResize).toHaveBeenCalled();
expect(scope.$apply).toHaveBeenCalled();
})
})
})
但它没有达到 scope.onResize 的预期。我疯狂地搜索如何正确执行此操作,但似乎找不到正确的答案。有任何想法吗?谢谢
老实说,我从来没有尝试过这个,所以我不能告诉你它是否有效。但是 - 您将调用函数与触发事件混淆了。您的 bind
语句绑定到事件,而不是函数调用。
从 the MDN docs on javascript events 开始,您应该可以像这样创建一个名为 "resize" 的事件并触发它:
describe('binding resize to window', function(){
// Get a DOM element (there's probably a better way to do this...)
var mockWindow = angular.element('<div>')[0];
// create the event
var resizeEvent = new Event('resize');
beforeEach(inject(function($rootScope, $controller){
scope = $rootScope.$new();
$controller('JobListController', { $scope:scope, $window: mockWindow});
}))
it('binds to the resize function', function(){
spyOn(scope, 'onResize');
spyOn(scope, '$apply');
// call the event.
mockWindow.dispatchEvent(event);
expect(scope.onResize).toHaveBeenCalled();
expect(scope.$apply).toHaveBeenCalled();
})
})
如果您想测试您是否附加到该事件,Angular 的 $window
服务可以很好地满足这个目的:
describe('JobListController', function(){
var scope, controller;
describe('binding resize to window', function(){
beforeEach(inject(function($rootScope, $controller){
scope = $rootScope.$new();
spyOn($window, 'addEventListener').and.callThrough();
$controller('JobListController', { $scope:scope });
}))
it('binds to the resize function', function() {
expect($window.addEventListener).toHaveBeenCalledWith('resize', scope.onResize);
})
})
})
在您的控制器中,改为使用 addEventListener
绑定:
$window.addEventListener('resize', scope.onResize);
它也允许在您取消绑定事件时进行测试:
it('stop listening to window resize', function () {
compileDirective();
spyOn($window, 'removeEventListener');
scope.$destroy();
expect($window.removeEventListener).toHaveBeenCalledWith('resize', scope.onResize);
});
之后,您可以自由地独立测试您的 scope.onResize
逻辑。
优点:
- 很容易做到。
- 允许测试事件的解除绑定
- 适用于任何浏览器(甚至 PhantomJS)
缺点:
- 它不测试每个部分(事件、侦听器、处理程序)之间的交互。我依靠更高级别的测试(即:E2E)。
我有以下控制器...
angular.module('jobBoard').controller('JobListController', ['$scope','$window', function($scope, $window){
$scope.keywordPlaceholder = 'What kind of job?';
$scope.locationPlaceholder = 'Where? (city, state or zip)';
$scope.onResize = function(){
if ($window.innerWidth <= 480){
$scope.keywordPlaceholder = 'What?';
$scope.locationPlaceholder = 'Where?';
}
}
angular.element($window).bind('resize', function(){
$scope.onResize();
$scope.$apply();
})
$scope.onResize();
$scope.loadJobs();
}]);
这是茉莉花测试...
describe('JobListController', function(){
var scope, controller;
describe('binding resize to window', function(){
var mockWindow = {
resize: function(){}
}
beforeEach(inject(function($rootScope, $controller){
scope = $rootScope.$new();
$controller('JobListController', { $scope:scope, $window: mockWindow});
}))
it('binds to the resize function', function(){
spyOn(scope, 'onResize');
spyOn(scope, '$apply');
mockWindow.resize();
expect(scope.onResize).toHaveBeenCalled();
expect(scope.$apply).toHaveBeenCalled();
})
})
})
但它没有达到 scope.onResize 的预期。我疯狂地搜索如何正确执行此操作,但似乎找不到正确的答案。有任何想法吗?谢谢
老实说,我从来没有尝试过这个,所以我不能告诉你它是否有效。但是 - 您将调用函数与触发事件混淆了。您的 bind
语句绑定到事件,而不是函数调用。
从 the MDN docs on javascript events 开始,您应该可以像这样创建一个名为 "resize" 的事件并触发它:
describe('binding resize to window', function(){
// Get a DOM element (there's probably a better way to do this...)
var mockWindow = angular.element('<div>')[0];
// create the event
var resizeEvent = new Event('resize');
beforeEach(inject(function($rootScope, $controller){
scope = $rootScope.$new();
$controller('JobListController', { $scope:scope, $window: mockWindow});
}))
it('binds to the resize function', function(){
spyOn(scope, 'onResize');
spyOn(scope, '$apply');
// call the event.
mockWindow.dispatchEvent(event);
expect(scope.onResize).toHaveBeenCalled();
expect(scope.$apply).toHaveBeenCalled();
})
})
如果您想测试您是否附加到该事件,Angular 的 $window
服务可以很好地满足这个目的:
describe('JobListController', function(){
var scope, controller;
describe('binding resize to window', function(){
beforeEach(inject(function($rootScope, $controller){
scope = $rootScope.$new();
spyOn($window, 'addEventListener').and.callThrough();
$controller('JobListController', { $scope:scope });
}))
it('binds to the resize function', function() {
expect($window.addEventListener).toHaveBeenCalledWith('resize', scope.onResize);
})
})
})
在您的控制器中,改为使用 addEventListener
绑定:
$window.addEventListener('resize', scope.onResize);
它也允许在您取消绑定事件时进行测试:
it('stop listening to window resize', function () {
compileDirective();
spyOn($window, 'removeEventListener');
scope.$destroy();
expect($window.removeEventListener).toHaveBeenCalledWith('resize', scope.onResize);
});
之后,您可以自由地独立测试您的 scope.onResize
逻辑。
优点:
- 很容易做到。
- 允许测试事件的解除绑定
- 适用于任何浏览器(甚至 PhantomJS)
缺点:
- 它不测试每个部分(事件、侦听器、处理程序)之间的交互。我依靠更高级别的测试(即:E2E)。