我在弄清楚如何使用Jasmine对基本Angular指令进行单元测试时遇到了一些麻烦。
基本上所有指令都检查两个密码输入是否相等并设置
指令如下所示:
angular.module('jhApp')
.directive('jhEquals', function() {
return {
restrict: 'A',
require: '?ngModel',
link: linker
};
function linker(scope, elem, attrs, ngModel) {
if(!ngModel) {
return false;
}
//watch own value and re-validate
scope.$watch(attrs.ngModel, function() {
validate();
});
//observe other value and re-validate on change
attrs.$observe('jhEquals', function() {
validate();
});
var validate = function() {
var val1 = ngModel.$viewValue;
var val2 = attrs.jhEquals;
//set validity
if(val1 && val2) {
ngModel.$setValidity('jhEquals', !val1 || !val2 || val1 === val2);
}
};
}
});
并且规范看起来像这样:
var scope,
dirElement;
beforeEach(function() {
module('jhApp');
module('templates');
inject(function($rootScope, $compile) {
scope = $rootScope;
scope.user = {};
dirElement = angular.element('<input id="password" type="password" name="password" ng-model="user.password" jh-equals="{{user.passwordconfirm}}"><input id="newpasswordconfirm" type="password" name="newpasswordconfirm" ng-model="user.passwordconfirm" jh-equals="{{user.password}}>');
$compile(dirElement)(scope);
});
scope.$digest();
});
it('should check if values are equal', function() {
var passwordInput = dirElement.find('#password');
var confirmPasswordInput = dirElement.find('#newpasswordconfirm');
angular.element(passwordInput).val('testpassword').trigger('input');
angular.element(confirmPasswordInput).val('nottestpassword').trigger('input');
scope.$digest();
//expect this to be invalid
});
passwordInput&amp; confirmPasswordInput - 在我console.log出来时显示一个空对象,如果我在指令中检查validate()中的val1和val2的值,它总是未定义。
所以我想这里的问题是我无法弄清楚如何选择输入来添加内容。
答案 0 :(得分:0)
你几乎就在那里,但仍然有一些小问题发生。
首先,您需要将指令放在表单中以测试有效性。还要检查绑定它的最后一个jh-equals值是否错过了“。
其次是jqlite find函数,它只适用于元素选择器。因此无法选择像dirElement.find('#testpassword')这样的元素,但是可以选择dirElement.find('input')。他们从jqlite中取消这个功能的原因是为了让它更轻松。相反,您可以创建一个dirElement.find('input')并按索引选择所需的输入。这似乎是一项艰巨的任务,但无论如何大多数时候你需要在jqlite中选择一个元素,它将在dom树中的一个小集合中,就像在测试环境中或在某个指令的内部厄运中一样。
最后,jqlite触发器被称为triggerHandler而不是触发器。
最终的图片应该是这样的:
var scope, dirElement;
beforeEach(function() {
module('jhApp');
module('templates');
inject(function($rootScope, $compile) {
scope = $rootScope;
scope.user = {};
dirElement = $compile([
'<form name="form">',
'<input id="password" type="password" name="password"',
' ng-model="user.password" jh-equals="{{user.passwordconfirm}}" />',
'<input id="newpasswordconfirm" type="password"',
' name="newpasswordconfirm" ng-model="user.passwordconfirm"',
' jh-equals="{{user.password}}" />',
'</form>',
].join(''))(scope);
scope.$digest();
});
});
it('invalid if the values are not equal', function() {
var passwordInput = dirElement.find('input');
var confirmPasswordInput = dirElement.find('input')[1];
angular.element(passwordInput)
.val('testpassword')
.triggerHandler('input');
angular.element(confirmPasswordInput)
.val('nottestpassword')
.triggerHandler('input');
expect(scope.form.password.$invalid).toBe(true);
expect(scope.form.password.$valid).toBe(false);
expect(scope.form.password.$dirty).toBe(true);
expect(scope.form.newpasswordconfirm.$invalid).toBe(true);
expect(scope.form.newpasswordconfirm.$valid).toBe(false);
expect(scope.form.newpasswordconfirm.$dirty).toBe(true);
});
it('valid if the values are equal', function() {
var passwordInput = dirElement.find('input');
var confirmPasswordInput = dirElement.find('input')[1];
angular.element(passwordInput)
.val('testpassword')
.triggerHandler('input');
angular.element(confirmPasswordInput)
.val('testpassword')
.triggerHandler('input');
expect(scope.form.password.$invalid).toBe(false);
expect(scope.form.password.$valid).toBe(true);
expect(scope.form.password.$dirty).toBe(true);
expect(scope.form.newpasswordconfirm.$invalid).toBe(false);
expect(scope.form.newpasswordconfirm.$valid).toBe(true);
expect(scope.form.newpasswordconfirm.$dirty).toBe(true);
});