【问题标题】:Unit test angular directive updating the ngModel更新 ngModel 的单元测试角度指令
【发布时间】:2015-01-24 21:05:13
【问题描述】:

我正在尝试测试我为验证输入而编写的指令,但遇到了一些问题。 指令管理的输入应包含有效的十六进制颜色值,如果用户使用无效值修改它,我想取消此修改。我的指令如下,并且按预期工作:

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');
    });
});

第一次测试成功,第二次失败,因为测试的值是“#F00F”而不是“#aaaaaa”。基本上,我的测试都没有真正修改指令处理的 ngModel 值...

【问题讨论】:

    标签: angularjs unit-testing jasmine karma-runner


    【解决方案1】:

    调用 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) 时,视图会在范围值更改时更新指令。

    【讨论】:

    • 谢谢大佬,帮了大忙!实际上 scope.$digest 的位置也是一个问题,因为我是在模糊线之后调用它的。此外,我更新了我的问题,因为我对 elem.blur() 和 focus() 的使用是错误的,应该是 elem.triggerHandler('focus');
    • 更新了答案中的测试。添加了 cmets... 您仍然需要更改和期望单元测试中的范围值。上面的两个测试都通过了您对 triggerHandler 的更改。
    • 确实他们都通过了。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 2020-11-11
    • 1970-01-01
    • 2013-07-13
    相关资源
    最近更新 更多