This custom validation directive is an example presented at the official angular site. http://docs.angularjs.org/guide/forms It checks a text input is in number format or not.
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; } }); } }; });
To unit test this code, I wrote this:
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); }); }); }); });
Then I get this error:
Expected undefined to equal 5. Error: Expected undefined to equal 5.
I put print statements everywhere to see what is going on, and it looks like the directive is never called. What is a proper way to test a simple directive like this?
Testing in AngularJS is achieved by using the karma framework, a framework which has been developed by Google itself. The karma framework is installed using the node package manager. The key modules which are required to be installed for basic testing are karma, karma-chrome-launcher ,karma-jasmine, and karma-cli.
The other answer's tests should be written as:
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); }); }); });
Note that $scope.$digest()
now is invoked after $setViewValue
. This sets the form into “dirty” state, otherwise it would remain “pristine”, which probably is not what you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With