如何用事件编写指令的单元测试

时间:2014-06-10 13:18:30

标签: angularjs unit-testing jasmine

我有一个指令如下。

maApp.directive('pwCheck', [function () {
    return {
        require: 'ngModel',
        link: function(scope, elem, attrs, ctrl) {
            var firstPassword = '#' + attrs.pwCheck;
            elem.add(firstPassword).on('keyup', function() {
                scope.$apply(function () {
                    ctrl.$setValidity('passwordMatch', elem.val() === $(firstPassword).val());
                });
            });
        }
    };
}]);

我正在尝试为此编写单元测试,但我无法成功触发keyup事件。我能够将文本设置为NewPassword字段并使用范围进行验证。但是,我缺少的部分是当NewPassword和ConfirmPassword字段具有不同的值时,如何将表单设置为无效。

describe('Directives', function() {
    beforeEach(module('maApp'));

    describe('pw-check directive', function() {
        var element, scope, emailForm, html = '<form name="emailForm"><input name="NewPassword" id="NewPassword" ng-model="NewPassword" /><input name="ConfirmPassword" ng-model="ConfirmPassword" pw-check="NewPassword" /><div ng-show="emailForm.$error"><span class="text-danger" ng-show="emailForm.$error.passwordMatch">Passwords don\'t match.</span></div></form>';

        beforeEach(inject(function ($rootScope, $compile) {
            scope = $rootScope;
            element = angular.element(html);
            $compile(element)(scope);
            scope.$digest();
            emailForm = scope.emailForm;
        }));

        it('should show the text from the album template', function () {
            expect(emailForm.$valid).toBe(true);
            emailForm.NewPassword.$setViewValue('a');
            expect(scope.NewPassword).toBe('a');

            var event = angular.element.Event('keyup');
            event.which = 65;
            var newPwdInput = $('#NewPassword');
            $(newPwdInput).trigger(event);
            expect(emailForm.$valid).toBe(false);
        });
    });
});

1 个答案:

答案 0 :(得分:0)

我相信您发现很难测试您的指令,因为当您不需要时,您不应该使用jquery通过id绑定事件。您的指令的正确方法是使用parsers

maApp.directive('pwCheck', [function () {
    return {
        require: 'ngModel',
        link: function(scope, elem, attrs, ctrl) {
            var firstPassword = attrs.pwCheck;
            scope.$watch(attrs.pwCheck, function(newValue, oldValue) {
              ctrl.$setValidity('passwordMatch', ctrl.$modelValue === newValue);
            });

            function passwordCheckerParser(passwordEntered) {
                ctrl.$setValidity('passwordMatch', passwordEntered === scope.$eval(attrs.pwCheck));
                return passwordEntered;
            }
            ctrl.$parsers.push(passwordCheckerParser);
        }
    };
}]);

如果你想触发一个&#39; keyup&#39;事件你只需要做element.trigger(&#39; keyup&#39;)。虽然按照我编写指令的方式,您不需要这样做,实际上这应该可行:

describe('Directives', function() {
    beforeEach(module('maApp'));

    describe('pw-check directive', function() {
        var element, scope, emailForm, html = '<form name="emailForm"><input name="NewPassword" id="NewPassword" ng-model="NewPassword" /><input name="ConfirmPassword" ng-model="ConfirmPassword" pw-check="NewPassword" /><div ng-show="emailForm.$error"><span class="text-danger" ng-show="emailForm.$error.passwordMatch">Passwords don\'t match.</span></div></form>';

        beforeEach(inject(function ($rootScope, $compile) {
            scope = $rootScope;
            element = angular.element(html);
            $compile(element)(scope);
            scope.$digest();
            emailForm = scope.emailForm;
        }));

        it('should show the text from the album template', function () {
            expect(emailForm.$valid).toBe(true);
            emailForm.NewPassword.$setViewValue('a');
            expect(scope.NewPassword).toBe('a');

            expect(emailForm.$valid).toBe(false);
        });
    });
});

如果您有任何问题或某些事情没有按预期的方式运作,请告诉我。

Plnkr