75 votes

Pour tester une directive angulaire de validation personnalisée

Cette validation personnalisée directive est un exemple présenté à la officiel angulaire site. http://docs.angularjs.org/guide/forms Il vérifie la saisie de texte est en format de nombre ou pas.

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

À l'unité de tester ce code, j'ai écrit ceci:

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

Ensuite, j'obtiens cette erreur:

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

J'ai mis des instructions d'impression partout pour voir ce qui se passe, et il semble que la directive n'est jamais appelée. Ce qui est un bon moyen de tester une directive simple comme ça?

86voto

jrief Points 261

Les tests de l'autre réponse doivent être écrits comme suit:

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

Notez que $scope.$digest() maintenant est appelé après $setViewValue . Ceci place la forme dans un état "sale", sinon elle resterait "vierge", ce qui n'est probablement pas ce que vous voulez.

67voto

ghiden Points 1103

J'ai compris en lisant angulaires-le code de l'application https://github.com/angular-app/angular-app Cette vidéo permet également trop http://youtu.be/ZhfUv0spHCY?t=31m17s

Deux erreurs que j'ai faites:

  • Ne se lie pas directement à la portée lorsque vous faites ng-model
  • Utiliser le formulaire contrôleur de manipuler directement que de passer par les directives

Voici la version mise à jour. La directive est la même, seul le test que j'ai changé.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X