测试自定义验证angularjs指令


76

此自定义验证指令是官方角度网站上提供的示例。 http://docs.angularjs.org/guide/forms会 检查文本输入是否为数字格式。

var INTEGER_REGEXP = /^\-?\d*$/;
app.directive('integer', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue) {
        if (INTEGER_REGEXP.test(viewValue)) {
          // it is valid
          ctrl.$setValidity('integer', true);
          return viewValue;
        } else {
          // it is invalid, return undefined (no model update)
          ctrl.$setValidity('integer', false);
          return undefined;
        }
      });
    }
  };
});

为了对该代码进行单元测试,我编写了以下代码:

describe('directives', function() {
  beforeEach(module('exampleDirective'));

  describe('integer', function() {
    it('should validate an integer', function() {
      inject(function($compile, $rootScope) {
        var element = angular.element(
          '<form name="form">' +
            '<input ng-model="someNum" name="someNum" integer>' +
          '</form>'
          );
        $compile(element)($rootScope);
        $rootScope.$digest();
        element.find('input').val(5);
        expect($rootScope.someNum).toEqual(5);
      });
    });
  });
});

然后我得到这个错误:

Expected undefined to equal 5.
Error: Expected undefined to equal 5.

我随处都可以看到print语句,以查看发生了什么,而且该指令似乎从未被调用过。测试像这样的简单指令的正确方法是什么?


感谢您抽出宝贵的时间来回答问题!仅供参考,您可以提取答案并将其标记为以后的搜索者可以接受的答案-在这里是可以接受的;-)
肖恩·维埃拉2013年

感谢您的提示。我移动了答案。
ghiden

Answers:


88

另一个答案的测试应写为:

describe('directives', function() {
  var $scope, form;
  beforeEach(module('exampleDirective'));
  beforeEach(inject(function($compile, $rootScope) {
    $scope = $rootScope;
    var element = angular.element(
      '<form name="form">' +
      '<input ng-model="model.somenum" name="somenum" integer />' +
      '</form>'
    );
    $scope.model = { somenum: null }
    $compile(element)($scope);
    form = $scope.form;
  }));

  describe('integer', function() {
    it('should pass with integer', function() {
      form.somenum.$setViewValue('3');
      $scope.$digest();
      expect($scope.model.somenum).toEqual('3');
      expect(form.somenum.$valid).toBe(true);
    });
    it('should not pass with string', function() {
      form.somenum.$setViewValue('a');
      $scope.$digest();
      expect($scope.model.somenum).toBeUndefined();
      expect(form.somenum.$valid).toBe(false);
    });
  });
});

请注意,$scope.$digest()now是在之后调用的$setViewValue。这会将表单设置为“脏”状态,否则将保持“原始”状态,这可能不是您想要的。


非常感谢,今天对我有很大帮助!但是我直接使用范围模型而不是$setViewValue(),我不知道是否遗漏了很多情况...?
Florent Destremau

67

我通过阅读angular-app代码https://github.com/angular-app/angular-app弄清楚了 这部视频也有帮助http://youtu.be/ZhfUv0spHCY?t=31m17s

我犯了两个错误:

  • 做ng-model时不要直接绑定到范围
  • 使用表单控制器直接操纵指令传递的内容

这是更新的版本。指令是相同的,只是我更改了测试。

describe('directives', function() {
  var $scope, form;
  beforeEach(module('exampleDirective'));
  beforeEach(inject(function($compile, $rootScope) {
    $scope = $rootScope;
    var element = angular.element(
      '<form name="form">' +
        '<input ng-model="model.somenum" name="somenum" integer />' +
      '</form>'
    );
    $scope.model = { somenum: null }
    $compile(element)($scope);
    $scope.$digest();
    form = $scope.form;
  }));

  describe('integer', function() {
    it('should pass with integer', function() {
      form.somenum.$setViewValue('3');
      expect($scope.model.somenum).toEqual('3');
      expect(form.somenum.$valid).toBe(true);
    });
    it('should not pass with string', function() {
      form.somenum.$setViewValue('a');
      expect($scope.model.somenum).toBeUndefined();
      expect(form.somenum.$valid).toBe(false);
    });
  });
});

@ghiden这确实对我有所帮助,但是,您是否遇到过链接多个指令并进行测试的经历?就像您对电话或电子邮件发出指令一样?每当尝试并添加其他指令时,我都会收到很多错误。有什么想法吗?
科学家,2013年

链接多个指令?我想即使将多个指令应用于一个元素,您仍要分别测试它们,对吗?如果每个人都能正常工作并且优先级设置正确,我想它们应该可以工作。有时我会先执行类似模型验证的操作,然后再以非常低的优先级执行视觉效果指令。
ghiden 2013年

@ghiden我发现了我的问题,我正在测试一个表单验证指令,并使用ng-model,并且我认为我的主要问题还在于使用name作为指令以及输入元素上的属性。我现在一切都很好,并进行测试!非常感谢您的示例。真的有很大帮助。
科学家,2013年

1
直到我$scope.$digest()打电话后加了,这对我没用$setViewValue。我是在做些奇怪的事情还是您的示例中缺少了这个?编辑:对不起,没有看到下面的答案。
AndyPerlitch 2014年

我永远无法通过使用1.3.12的第二个测试通过(始终正确)即时消息,有什么变化吗?
莫克斯

2

我测试了在对象“ $ error”中搜索自定义验证名称的自定义指令。例:

  'use strict';

describe('Directive: validadorCorreo', function () {

  // load the directive's module
  beforeEach(module('sistemaRegistroProCivilApp'));

  var inputCorreo, formulario, elementoFormulario, scope, $compile;

  beforeEach(inject(function ($rootScope, _$compile_) {
    scope = $rootScope.$new();
    $compile = _$compile_;

    elementoFormulario = angular.element('<form name="formulario">' + 
      '<input type="text" name="correo" data-ng-model="correo" required data-validador-correo/>' + 
      '</form');
    scope.correo = '';
    elementoFormulario = $compile(elementoFormulario)(scope);
    scope.$digest();
    inputCorreo = elementoFormulario.find('input');
    formulario = scope.formulario;
    console.log(formulario.correo.$error);
  }));

  it('Deberia Validar si un correo ingresado en el input es correcto e incorrecto', inject(function ($compile) {

    inputCorreo.val('eric+@eric.com').triggerHandler('input');
    expect(formulario.correo.$error.email).toBe(true); //Here, the name of the custom validation appears in the $error object.
    console.log(formulario.correo.$error);

    inputCorreo.val('eric@eric.com').triggerHandler('input');
    expect(formulario.correo.$error.email).toBeUndefined();//Here, the name of the custom validation disappears in the $error object. Is Undefined
    console.log(formulario.correo.$error.email)
  }));
});

希望我能为您服务!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.