Щоб перевірити власну директиву перевірки 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.

Я розміщую заявки для друку скрізь, щоб побачити, що відбувається, і, схоже, директива ніколи не викликається. Який правильний спосіб перевірити таку просту директиву?


Дякуємо, що знайшли час, щоб повернути відповідь! Просто FYI, ви можете витягти свою відповідь і позначити її як прийняту для подальших пошукачів - це прийнятно тут ;-)
Шон Вієйра,

Дякую за поради. Я зрушив свою відповідь.
ghiden

Відповіді:


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()зараз викликається після $setViewValue. Це переводить форму у “брудний” стан, інакше вона залишиться “незайманою”, що, мабуть, не те, що ви хочете.


Щиро дякую, сьогодні мені дуже допомогли! Але я використовую безпосередньо модель обсягу, а не $setViewValue(), я не знаю, чи багато випадків мені не вистачає ...?
Флоран Дестремау,

67

Я зрозумів це, прочитавши код angular-app https://github.com/angular-app/angular-app Це відео також теж допомагає http://youtu.be/ZhfUv0spHCY?t=31m17s

Дві помилки, які я зробив:

  • Не прив'язуйте безпосередньо до області, коли ви робите ng-модель
  • Використовуйте контролер форми, щоб безпосередньо маніпулювати тим, що передавати для директив

Ось оновлена ​​версія. Директива та сама, лише тест, який я змінив.

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 Це мені справді допомогло, однак, чи стикалися ви з ланцюжком кількох директив і тестуванням цього? Як якщо ви зробили вказівку щодо телефону чи електронної пошти? Я отримую купу помилок щоразу, коли намагався, і додаю додаткову директиву. Думки?
вчений

Прив’язка кількох директив? Я думаю, навіть якщо ви застосовуєте кілька директив до одного елемента, ви все одно хочете перевірити їх окремо, правильно? Якщо кожен працює належним чином і пріоритет встановлений правильно, я думаю, вони повинні працювати. Я іноді спочатку роблю щось на зразок перевірки моделі, а потім приступаю до директиви з візуальними ефектами з дуже низьким пріоритетом.
ghiden

@ghiden Я знайшов свою проблему, я тестував директиву перевірки форми та використовував ng-модель, і я вважаю, що моєю основною проблемою було також використання імені як директиви, а також атрибута на вхідному елементі. Зараз у мене все добре, і я тестую це! Дуже дякую за ваш приклад. Дійсно дуже допомогло.
вчений

1
Це не працювало для мене, поки я не додав $scope.$digest()після дзвінка $setViewValue. Я роблю щось дивне, чи цього не вистачає у вашому прикладі? EDIT: вибачте, не бачив відповіді нижче.
AndyPerlitch

я ніколи не можу пройти другий тест (його завжди вірно) im за допомогою 1.3.12 щось змінилося?
Mocksy

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

Сподіваюся, я можу вам допомогти!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.