我试图测试我为验证输入而编写的指令而我遇到了一些麻烦。 由指令管理的输入应包含有效的十六进制颜色值,如果用户使用无效值修改它,我想取消此修改。我的指令如下,并按预期工作:
module.directive('colorValidate', function() {
return {
restrict: 'A',
scope: {
color: '=ngModel'
},
link: function(scope, element) {
var previousValue = '#ffffff';
//pattern that accept #ff0000 or #f00
var colorPattern = new RegExp('^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$');
element.on('focus', function() {
previousValue = scope.color;
});
element.on('blur', function() {
if (!colorPattern.test(scope.color)) {
scope.$apply(function() {
scope.color = previousValue;
});
}
else {
scope.$apply(function() {
scope.color = scope.color.toLowerCase();
});
}
});
}
};
});
以下是使用此指令的输入示例:
<input color-validate type="text" ng-model="color.color"/>
第一个问题:这种访问和修改元素的ngModel的方式是否正确?
然后我的主要问题是测试部分。以下是我编写的两个简单的测试,但这些测试并没有真正起作用:
describe('colorValidate directive', function() {
var scope,
elem,
compiled,
html;
beforeEach(function() {
html = '<input color-validate type="text" ng-model="color.color"/>';
inject(function($compile, $rootScope) {
scope = $rootScope.$new();
scope.color = {color: '#aaaaaa'};
elem = angular.element(html);
compiled = $compile(elem);
compiled(scope);
scope.$digest();
});
});
it('should permit valid 6-chars color value', function() {
elem.triggerHandler('focus');
elem.val('#FF0000');
elem.triggerHandler('blur');
scope.$digest();
expect(elem.val()).toBe('#FF0000');
});
it('should reject non valid color values', function() {
elem.triggerHandler('focus');
elem.val('#F00F');
scope.$digest();
elem.triggerHandler('blur');
expect(elem.val()).toBe('#aaaaaa');
});
});
第一次测试成功,第二次测试失败,因为测试值是&#39;#F00F&#39;而不是#aaaaaa&#39;。基本上,我的测试都没有实际修改指令处理的ngModel值...
答案 0 :(得分:7)
调用elem.val()实际上并不会导致scope.color得到更新。换句话说,这个测试将失败:
it("should set scope", function () {
elem.triggerHandler("focus");
elem.val("#FF0000");
scope.$digest();
elem.triggerHandler("blur");
//Will fail: expected #aaaaaa to be #ff0000
expect(scope.color.color).toBe("#ff0000");
});
这是因为ngModel绑定到输入上的键事件并在那时更新模型(范围)。在元素上调用val()或value不会触发angular会认为某些内容发生变化的事件(即使在$ digest循环中)。因此,您应该通过更改模型值并声明它们被接受或重置来运行测试:
it('should permit valid 6-chars color value', function() {
elem.triggerHandler('focus');
scope.color.color = '#FF0000';
//need to trigger a digest here for the two-way binding
scope.$digest();
elem.triggerHandler('blur');
//Don't need a $digest here because you call scope.$apply() within the blur in both if/else conditions
//scope.$digest();
expect(scope.color.color).toBe('#ff0000');
});
it('should reject non valid color values', function() {
elem.triggerHandler('focus');
scope.color.color = '#F00F';
//need to trigger a digest here for the two-way binding
scope.$digest();
elem.triggerHandler('blur');
expect(scope.color.color).toBe('#aaaaaa');
});
您不需要测试该值是否已更新,因为大概是angular已经编写了测试以确保当指令具有双向绑定(= ngModel)时,当范围值发生变化时视图会更新指令。