Để kiểm tra chỉ thị anglejs xác thực tùy chỉnh


76

Chỉ thị xác thực tùy chỉnh này là một ví dụ được trình bày tại trang web góc chính thức. http://docs.angularjs.org/guide/forms Nó kiểm tra đầu vào văn bản có ở định dạng số hay không.

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

Để kiểm tra đơn vị mã này, tôi đã viết như sau:

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

Sau đó, tôi nhận được lỗi này:

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

Tôi đặt các câu lệnh in ở khắp mọi nơi để xem điều gì đang xảy ra, và có vẻ như chỉ thị không bao giờ được gọi. Cách thích hợp để kiểm tra một chỉ thị đơn giản như thế này là gì?


Cảm ơn bạn đã dành thời gian để mang lại câu trả lời! Chỉ cần FYI, bạn có thể trích xuất câu trả lời của mình và đánh dấu nó là câu trả lời được chấp nhận cho những người tìm kiếm sau này - điều đó có thể chấp nhận được ở đây ;-)
Sean Vieira

Cảm ơn về lời khiên của bạn. Tôi đã chuyển câu trả lời của mình.
ghiden

Câu trả lời:


88

Các bài kiểm tra của câu trả lời khác nên được viết là:

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

Lưu ý rằng $scope.$digest()bây giờ được gọi sau $setViewValue. Điều này đặt biểu mẫu thành trạng thái “bẩn”, nếu không nó sẽ vẫn ở trạng thái “nguyên sơ”, điều này có thể không phải là điều bạn muốn.


Cảm ơn bạn rất nhiều, đã giúp tôi rất nhiều ngày hôm nay! Nhưng tôi đang sử dụng trực tiếp mô hình phạm vi hơn là $setViewValue(), tôi không biết liệu tôi có thiếu nhiều trường hợp không ...?
Florent Destremau

67

Tôi đã tìm ra nó bằng cách đọc mã ứng dụng góc https://github.com/angular-app/angular-app Video này cũng hữu ích http://youtu.be/ZhfUv0spHCY?t=31m17s

Hai sai lầm mà tôi đã mắc phải:

  • Không ràng buộc trực tiếp với phạm vi khi bạn đang làm ng-model
  • Sử dụng bộ điều khiển biểu mẫu để thao tác trực tiếp những gì cần chuyển cho các lệnh

Đây là phiên bản cập nhật. Chỉ thị vẫn vậy, chỉ có bài kiểm tra là tôi đã thay đổi.

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 Điều này thực sự giúp ích cho tôi, tuy nhiên, bạn đã từng gặp bất kỳ kinh nghiệm nào về việc xâu chuỗi nhiều lệnh và thử nghiệm điều đó chưa? Giống như nếu bạn thực hiện một chỉ thị cho điện thoại hoặc email? Tôi gặp một loạt lỗi bất cứ khi nào tôi thử và thêm một chỉ thị bổ sung. Suy nghĩ?
thescientist,

Chuỗi nhiều chỉ thị? Tôi đoán ngay cả khi bạn áp dụng nhiều chỉ thị cho một phần tử, bạn vẫn muốn kiểm tra chúng một cách riêng biệt, đúng không? Nếu mỗi cái hoạt động đúng cách và mức độ ưu tiên được đặt chính xác, tôi đoán chúng sẽ hoạt động. Đôi khi tôi thực hiện một số việc như xác thực mô hình trước rồi tiến hành chỉ thị hiệu ứng hình ảnh với mức độ ưu tiên rất thấp.
ghiden

@ghiden Tôi đã tìm thấy vấn đề của mình, tôi đang thử nghiệm một chỉ thị xác thực biểu mẫu và sử dụng ng-model và tôi tin rằng vấn đề chính của tôi cũng đang sử dụng tên làm chỉ thị cũng như một thuộc tính trên phần tử đầu vào. Bây giờ tôi vẫn ổn, và đang thử nghiệm nó! Cảm ơn rất nhiều vì ví dụ của bạn mặc dù. Thực sự đã giúp rất nhiều.
thescientist

1
Điều này không hiệu quả với tôi cho đến khi tôi thêm $scope.$digest()sau khi gọi $setViewValue. Tôi đang làm điều gì đó kỳ lạ hay điều này bị thiếu từ ví dụ của bạn? EDIT: xin lỗi, không thấy câu trả lời bên dưới.
AndyPerlitch

tôi không bao giờ có thể nhận được bài kiểm tra thứ hai để vượt qua (nó luôn đúng) tôi đang sử dụng 1.3.12 có gì thay đổi không?
Mocksy

2

Tôi kiểm tra các lệnh tùy chỉnh của mình khi tìm kiếm tên của xác thực tùy chỉnh trong đối tượng "$ error". Thí dụ:

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

Tôi hy vọng tôi có thể giúp bạn!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.