故障单元测试Angular指令

时间:2015-04-12 15:22:20

标签: javascript angularjs unit-testing jasmine

我在弄清楚如何使用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的值,它总是未定义。

所以我想这里的问题是我无法弄清楚如何选择输入来添加内容。

1 个答案:

答案 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);

});