2014-10-21 126 views
3

我有一个简单的校验,检查对正则表达式的输入:

.directive('test', function() { 
return { 
    restrict: 'A', 
    require: 'ngModel', 
    link: function ($scope, element, attrs, ctrl) { 

     ctrl.$setValidity('namePattern', true); 

     function checkValid(name) { 
      console.log('checkValid executed'); 
      if (!name || ctrl.$pristine) { 
       ctrl.$setValidity('namePattern', true); 
       return name; 
      } 
      var test = /^[A-Za-z0-9_-]+$/; 
      ctrl.$setValidity('namePattern', test.test(name)); 
      return name; 
     } 

     // called when value changes via code/controller 
     ctrl.$formatters.unshift(checkValid); 
     // called when value changes in input element 
     ctrl.$parsers.unshift(checkValid); 
    } 
    }; 
}); 

Live example

我想单元测试此指令,并具备以下条件:

function initState() { 
    angular.mock.module('app'); 
    angular.mock.inject(function($compile, $rootScope, $timeout){ 
    $scope = $rootScope.$new(); 

    $rootScope.safeApply = function(cb) { 
     $timeout(function() { 
     $scope.$digest(); 
     }); 
    }; 

    $scope.model = { 
     instanceName: '' 
    }; 

    var tmpl = angular.element('<form name="form">' + 
     '<input ng-model="model.instanceName" name="instanceName" test>' + 
     '</form>' 
    ); 

    element = $compile(tmpl)($scope); 
    $scope.$apply(); 
    form = $scope.form; 
    }); 
} 
beforeEach(initState); 

但是,对模型的更改不会触发checkValid。我已经试过直接设置属性型号:

it('should trigger a change resulting in an invalid state', function() { 
    $scope.model.instanceName = 'this is an invalid name'; 
    $scope.$digest(); 
    expect(form.instanceName.$valid).to.be.false; 
}); 

以及与周围$modelValue胡闹:

it('should trigger a change resulting in an invalid state', function() { 
    form.instanceName.$modelValue = 'this is an invalid name'; 
    $scope.$digest(); 
    expect(form.instanceName.$valid).to.be.false; 
}); 

我也试图通过element.triggerHandler触发input事件。

如何触发模型更改以便checkValid通过$formatters运行?

通过引用形式名称和输入名称(这是通过使用角1.2.23)

回答

1

它看起来像你的指令设置输入是有效的,如果它是原始的。在你编写的单元测试的情况下,它将永远是原始的,因为用户没有与它进行交互。

如果你想指令继续它的现在,那么在测试测试,你可以强制输入不是原始的:(我用茉莉花这里)

it('should trigger a change resulting in an invalid state', function() { 
    $scope.model.instanceName = 'this is an invalid name'; 
    form.instanceName.$pristine = false; 
    $scope.$digest(); 
    expect(form.instanceName.$valid).toEqual(false); 
}); 

由此可以看出在http://plnkr.co/edit/TEd91POjw9odNHSb6CQP?p=preview

工作由于您的指令明确假设输入有效期为在原始状态的输入模式的转变,那么其实我觉得更有价值的测试是明确的测试:

it('should ignore invalid values on a pristine input', function() { 
    $scope.model.instanceName = 'this is an invalid name'; 
    form.instanceName.$setPristine(); 
    $scope.$digest(); 
    expect(form.instanceName.$valid).toEqual(true); 
}); 
+0

道歉,如果upvote/accept是不可靠的 - SO的应用程序有问题。现在应该解决。谢谢! – SomeKittens 2014-10-22 17:07:32

-1

使用$setViewValue

$scope.form.instanceName.$setViewValue('hello'); 

然后断言。

expect($scope.model.instanceName).toEqual('something'); 
expect($scope.form.instanceName.$valid).toBe(true); 
+0

'$ setViewValue'触发$ parsers和$ validators,而不是$ formatters:https://docs.angularjs.org/api/ng/type/ngModel.NgModelController – SomeKittens 2014-10-21 22:30:15