UNPKG

angular-ui-form-validation

Version:

A plugin for performing validation in angularjs without writing lots of boilerplate code or duplicating logic.

921 lines (864 loc) 52.9 kB
"use strict;" describe('directives.customvalidation.customValidations', function () { var element, scope, errorMessages, hiddenErrorMessages, visibleErrorMessages, passwordInput, confirmPasswordInput, templateRetriever; beforeEach(function (){ module('directives.customvalidation.customValidationTypes'); inject(function ($injector, $rootScope, $compile, $q, $timeout) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" ' + 'validation-field-required="true" '+ 'validation-min-length="8" ' + 'validation-one-alphabet="true" ' + 'validation-one-number="true" ' + 'validation-one-lower-case-letter="true" '+ 'validation-one-upper-case-letter="true" ' + 'validation-no-special-chars="true" ' + 'validation-no-space="true" />'+ '<input ng-model="user.name" type="text" id="name" name="name" ' + 'validation-field-required="true" ' + 'validation-one-number="true" />'+ '</form>'); passwordInput = element.find('#password'); templateRetriever = $injector.get('templateRetriever'); spyOn(templateRetriever, 'getTemplate').and.callFake(function (templateUrl){ var template; if(templateUrl === 'views/errorTemplateOne.html'){ template = '<div class="ErrorTemplateOne" >{{errorMessage}}</div>' } if(templateUrl === 'views/errorTemplateTwo.html'){ template = '<div class="ErrorTemplateTwo" >{{errorMessage}}</div>' } return $q.when(template); }); scope = $rootScope; angular.extend(scope, { user: { name: null, password: null, confirmPassword: null } }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should contain all error messages', function () { expect(9).toEqual(errorMessages.length); }); it('should contain all hidden error messages', function () { hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(9).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); }); it('should show errors one at a time per field', function () { passwordInput.val('sadffsdaadfsfsda'); scope.$broadcast('runCustomValidations'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(7).toEqual(hiddenErrorMessages.length); expect(2).toEqual(visibleErrorMessages.length); expect('Must contain at least one uppercase letter').toEqual($(visibleErrorMessages[0]).html().trim()); expect('This is a required field').toEqual($(visibleErrorMessages[1]).html().trim()); }); it('should show errors based on the order in the custom validations and hide resolved error messages', function () { passwordInput.val('sadffsdaadfsfsda'); scope.$broadcast('runCustomValidations'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(7).toEqual(hiddenErrorMessages.length); expect(2).toEqual(visibleErrorMessages.length); expect('Must contain at least one uppercase letter').toEqual(visibleErrorMessages.html().trim()); passwordInput.val('sadffsdaadfsfDsda'); scope.$broadcast('runCustomValidations'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(7).toEqual(hiddenErrorMessages.length); expect(2).toEqual(visibleErrorMessages.length); expect('Must contain at least one number').toEqual(visibleErrorMessages.html().trim()); }); describe('getValidationAttributeValue jsol reader', function () { it('should return value property by default', function(){ var val1 = getValidationAttributeValue('5'); var val2 = getValidationAttributeValue("{value: '5'}"); expect(val1).toEqual(val2); }); it('should return specified property', function () { var val = getValidationAttributeValue('{me:5}', 'me'); expect(val).toEqual(5); var val = getValidationAttributeValue('{me:5}', 'me', true); expect(val).toEqual(5); }); it('should default to value property if specified property does not exist and strict is not true', function () { var val = getValidationAttributeValue('{med:5, value: 6}', 'me'); expect(val).toEqual(6); }); it('should return undefined if strict is true and the specified property does not exist', function () { var val = getValidationAttributeValue('{med:5, value: 6}', 'me', true); expect(val).toEqual(undefined); var val = getValidationAttributeValue('5', 'me', true); expect(val).toEqual(undefined); }); }); describe('confirmPassword', function(){ beforeEach(function (){ inject(function ($rootScope, $compile, $timeout){ element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" validation-field-required="true" '+ 'validation-min-length="8" validation-one-alphabet="true" validation-one-number="true" validation-one-lower-case-letter="true" '+ 'validation-one-upper-case-letter="true" validation-no-special-chars="true" validation-no-space="true" />'+ '<input ng-model="user.confirmPassword" type="text" id="confirmPassword" name="confirmPassword" validation-confirm-password="true" />'+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; angular.extend(scope, { user: { password: null, confirmPassword: null } }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should contain nine hidden error messages', function () { hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(8).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); }); it('should show password errors when password is changed', function (){ passwordInput.val('sadffsdaadfsfsda'); scope.$broadcast('runCustomValidations'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(7).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('Must contain at least one uppercase letter').toEqual(visibleErrorMessages.html().trim()); passwordInput.val('sadffsdaadfsSfsda'); scope.$broadcast('runCustomValidations'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(7).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('Must contain at least one number').toEqual(visibleErrorMessages.html().trim()); }); }); describe('validation false', function() { beforeEach(function (){ inject(function ($rootScope, $compile, $timeout){ element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" validation-field-required="false" '+ 'validation-min-length="false" validation-one-alphabet="false" '+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; angular.extend(scope, { user: { password: null, confirmPassword: null } }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should contain zero error messages', function () { hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(0).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); }); }); describe('validationFieldRequired', function() { beforeEach(function (){ inject(function ($rootScope, $compile, $timeout){ element = angular.element('<form name="form">' + '<label for="password">Password</label>'+ '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" '+ 'validation-field-required="true"'+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; angular.extend(scope, { user: { password: null, confirmPassword: null } }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should apply requiredFieldLabel class to label', function () { var label, labelClass; hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); label = element.find('label'); labelClass = label.attr('class'); expect(/requiredFieldLabel/.test(labelClass)).toBe(true); }); }); describe('object literal validation attribute value', function(){ beforeEach(function (){ inject(function ($rootScope, $compile, $timeout){ element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" validation-field-required="true" '+ 'validation-min-length="{ template:\'\', value: 8}" validation-one-alphabet="{ template:\'\', value: true}" validation-one-number="{ template:\'\', value: true}" validation-one-lower-case-letter="true" '+ 'validation-one-upper-case-letter="true" validation-no-special-chars="true" validation-no-space="true" />'+ '<input ng-model="user.confirmPassword" type="text" id="confirmPassword" name="confirmPassword" validation-confirm-password="true" />'+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; angular.extend(scope, { user: { password: null, confirmPassword: null } }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should contain nine hidden error messages', function () { hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(8).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); }); it('should show password errors when password is changed', function (){ passwordInput.val('sadffsdaadfsfsda'); scope.$broadcast('runCustomValidations'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(7).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('Must contain at least one uppercase letter').toEqual(visibleErrorMessages.html().trim()); passwordInput.val('sadffsdaadfsSfsda'); scope.$broadcast('runCustomValidations'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(7).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('Must contain at least one number').toEqual(visibleErrorMessages.html().trim()); }); }); describe('custom message', function(){ beforeEach(function (){ inject(function ($rootScope, $compile, $timeout){ element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" validation-field-required="true" '+ 'validation-min-length="{ message: \'under min length\', value: 8}" '+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; angular.extend(scope, { user: { password: null, confirmPassword: null } }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should show password errors when password is changed', function (){ passwordInput.val('ffasdf'); scope.$broadcast('runCustomValidations'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('under min length').toEqual(visibleErrorMessages.html().trim()); }); }); describe('custom error message template wrap', function () { beforeEach(function (){ inject(function ($rootScope, $compile, $timeout){ element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" validation-field-required="true" '+ 'validation-min-length="{ template:\'views/errorTemplateOne.html\', value: 8}" validation-one-alphabet="{ template:\'views/errorTemplateTwo.html\', value: true}" validation-one-number="{ template:\'views/errorTemplateTwo.html\', value: 8}" validation-one-lower-case-letter="true" '+ 'validation-one-upper-case-letter="{ template:\'views/errorTemplateOne.html\', value: 8}" validation-no-special-chars="true" validation-no-space="true" />'+ '<input ng-model="user.confirmPassword" type="text" id="confirmPassword" name="confirmPassword" validation-confirm-password="true" />'+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; angular.extend(scope, { user: { password: null, confirmPassword: null } }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should contain nine hidden error messages', function () { hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(8).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); }); it('should show password errors when password is changed', function (){ passwordInput.val('sadffsdaadfsfsda'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(7).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('ErrorTemplateOne').toEqual(angular.element(visibleErrorMessages[0]).parents('div').attr('class')); expect('Must contain at least one uppercase letter').toEqual(visibleErrorMessages.html().trim()); passwordInput.val('sadffsdaadfsSfsda'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(7).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('ErrorTemplateTwo').toEqual(angular.element(visibleErrorMessages[0]).parents('div').attr('class')); expect('Must contain at least one number').toEqual(visibleErrorMessages.html().trim()); }); }); describe('maxlength validation', function (){ it('should use the custom message when specified', function () { }); }); describe('error message modified by validator', function() { var customValidationTypes; beforeEach(function (){ inject(function ($injector, $rootScope, $compile, $timeout) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" '+ 'validation-max-length="5"/>'+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should be able to modify error message in validator', function () { passwordInput.val('sadffsdaadfsfsda'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(0).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('Maximum of 5 characters').toEqual(visibleErrorMessages.html().trim()); }); }); describe('uses custom error message when supplied', function() { var customValidationTypes; beforeEach(function () { inject(function ($injector, $rootScope, $compile, $timeout) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" ' + 'validation-max-length=\'{"message":"customMessage", "value":5}\'/>' + '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should be able to modify error message in validator', function () { passwordInput.val('sadffsdaadfsfsda'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(0).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('customMessage').toEqual(visibleErrorMessages.html().trim()); }); }); describe('validation submit validate one required field', function() { var customValidationTypes; beforeEach(function () { inject(function ($injector, $rootScope, $compile, $timeout) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password"' + 'validation-field-required="true" ' + 'validation-max-length=\'{"message":"customMessage", "value":5, "validateWhileEntering": true }\'/>' + '<a validation-submit=\'{"formName":"form", "onSubmit":"onSubmit()"}\' >Submit</a>' + '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; scope.onSubmit = jasmine.createSpy('scope#onValid'); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should have invalid submit given a pristine form with a required field', function () { var form = element; hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(2).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); expect(form.hasClass('ng-invalid')).toBe(false); expect(form.hasClass('ng-valid')).toBe(true); var submit = form.find('a'); expect(submit.hasClass('invalid')).toEqual(true); expect(submit.hasClass('valid')).toEqual(false); }); }); describe('validation submit validate while entering is true', function() { var customValidationTypes; beforeEach(function () { inject(function ($injector, $rootScope, $compile, $timeout) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" ' + 'validation-max-length=\'{"message":"customMessage", "value":5, "validateWhileEntering": true }\'/>' + '<a validation-submit=\'{"formName":"form", "onSubmit":"onSubmit()"}\' >Submit</a>' + '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; scope.onSubmit = jasmine.createSpy('scope#onValid'); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should change element class to invalid', function () { passwordInput.val('sadffsdaadfsfsda'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.removeClass('ng-pristine'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(0).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('customMessage').toEqual(visibleErrorMessages.html().trim()); expect(form.hasClass('ng-invalid')).toBe(true); expect(form.hasClass('ng-valid')).toBe(false); }); it('should change element class to valid', function () { passwordInput.val('asdf'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.removeClass('ng-pristine'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); expect(form.hasClass('ng-invalid')).toBe(false); expect(form.hasClass('ng-valid')).toBe(true); }); it('should not call onSubmit when clicked', function () { passwordInput.val('sadffsdaadfsfsda'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.removeClass('ng-pristine'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(0).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('customMessage').toEqual(visibleErrorMessages.html().trim()); expect(form.hasClass('ng-invalid')).toBe(true); expect(form.hasClass('ng-valid')).toBe(false); form.find('a').click(); expect(scope.onSubmit).not.toHaveBeenCalled(); }); it('should call onSubmit when clicked', function () { passwordInput.val('asdf'); scope.form.$setDirty(); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.scope().$apply(); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); expect(form.hasClass('ng-invalid')).toBe(false); expect(form.hasClass('ng-valid')).toBe(true); form.find('a').click(); expect(scope.onSubmit).toHaveBeenCalled(); }); }); xdescribe('validation submit validate while entering is true with multiple fields', function() { var customValidationTypes, nameInput; beforeEach(function () { inject(function ($injector, $rootScope, $compile, $timeout) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" ' + 'validation-max-length=\'{"message":"customMessage", "value":5, "validateWhileEntering": true }\'/>' + '<input ng-model="user.name" type="text" id="name" name="name" validation-field-required="true" validation-one-number="true" />'+ '<a validation-submit=\'{"formName":"form", "onSubmit":"onSubmit()"}\' >Submit</a>' + '</form>'); passwordInput = element.find('#password'); nameInput = element.find('#name'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; scope.onSubmit = jasmine.createSpy('scope#onValid'); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should have invalid submit given a form with a required field and a valid dirty field', function () { passwordInput.val('dasaa'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.removeClass('ng-pristine'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(2).toEqual(hiddenErrorMessages.length); //runCustomValidations should not invalidate a field that is not dirty expect(0).toEqual(visibleErrorMessages.length); expect(form.hasClass('ng-invalid')).toBe(false); expect(form.hasClass('ng-valid')).toBe(true); var submit = form.find('a'); expect(submit.hasClass('invalid')).toEqual(true); expect(submit.hasClass('valid')).toEqual(false); }); it('should change element class to invalid', function () { passwordInput.val('sadffsdaadfsfsda'); nameInput.val('nelson'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.removeClass('ng-pristine'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); expect(2).toEqual(visibleErrorMessages.length); expect('customMessage').toEqual(visibleErrorMessages.html().trim()); expect(form.hasClass('ng-invalid')).toBe(true); expect(form.hasClass('ng-valid')).toBe(false); nameInput.val('nelso1n'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.removeClass('ng-pristine'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(2).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('customMessage').toEqual(visibleErrorMessages.html().trim()); expect(form.hasClass('ng-invalid')).toBe(true); expect(form.hasClass('ng-valid')).toBe(false); passwordInput.val('fsad'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.removeClass('ng-pristine'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(3).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); expect(form.hasClass('ng-invalid')).toBe(false); expect(form.hasClass('ng-valid')).toBe(true); }); it('should change element class to valid', function () { passwordInput.val('asdf'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.removeClass('ng-pristine'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); expect(form.hasClass('ng-invalid')).toBe(false); expect(form.hasClass('ng-valid')).toBe(true); }); it('should not call onSubmit when clicked', function () { passwordInput.val('sadffsdaadfsfsda'); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.removeClass('ng-pristine'); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(0).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('customMessage').toEqual(visibleErrorMessages.html().trim()); expect(form.hasClass('ng-invalid')).toBe(true); expect(form.hasClass('ng-valid')).toBe(false); form.find('a').click(); expect(scope.onSubmit).not.toHaveBeenCalled(); }); it('should call onSubmit when clicked', function () { passwordInput.val('asdf'); scope.form.$setDirty(); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.scope().$apply(); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); expect(form.hasClass('ng-invalid')).toBe(false); expect(form.hasClass('ng-valid')).toBe(true); form.find('a').click(); expect(scope.onSubmit).toHaveBeenCalled(); }); }); describe('validation submit validate while entering is true when onSubmit is defined on scope model', function() { var customValidationTypes; beforeEach(function () { inject(function ($injector, $rootScope, $compile, $timeout) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" ' + 'validation-max-length=\'{"message":"customMessage", "value":5, "validateWhileEntering": true }\'/>' + '<a validation-submit=\'{"formName":"form", "onSubmit":"model.onSubmit()"}\' >Submit</a>' + '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; scope.model = { onSubmit: jasmine.createSpy('scope#onValid')}; $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should call onSubmit when clicked', function () { passwordInput.val('asdf'); scope.form.$setDirty(); element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); var form = element; form.scope().$apply(); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); expect(form.hasClass('ng-invalid')).toBe(false); expect(form.hasClass('ng-valid')).toBe(true); form.find('a').click(); expect(scope.model.onSubmit).toHaveBeenCalled(); }); }); describe('support selects', function() { var customValidationTypes; beforeEach(function (){ inject(function ($injector, $rootScope, $compile, $timeout) { element = angular.element('<form name="form">' + '<select ng-model="user.password" name="password" id="password" ng-model="user.password"'+ 'ng-options="option for option in selectOptions"'+ 'validation-field-required="true"'+ 'validation-dynamically-defined="locallyDefinedValidations"<select/>'+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; angular.extend(scope, { selectOptions: ['validOption', 'invalidOption1'], user: { password: null, confirmPassword: null }, locallyDefinedValidations: [ { errorMessage: 'Cannot contain the number one', validator: function (errorMessageElement, val){ return /1/.test(val) !== true; } } ] }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should contain 2 hidden error messages', function () { hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(2).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); }); it('should show errors when select value is changed to invalid option', function (){ scope.user.password = 'validOption'; element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(2).toEqual(hiddenErrorMessages.length); expect(0).toEqual(visibleErrorMessages.length); scope.user.password = 'invalidOption1'; element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); expect(1).toEqual(visibleErrorMessages.length); expect('Cannot contain the number one').toEqual(visibleErrorMessages.html().trim()); }); }); describe('validationDynamicallyDefined', function() { var customValidationTypes; beforeEach(function (){ inject(function ($injector, $rootScope, $compile, $timeout) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" '+ 'validation-dynamically-defined="locallyDefinedValidations"/>'+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; angular.extend(scope, { user: { password: null, confirmPassword: null }, locallyDefinedValidations: [ { errorMessage: 'Cannot contain the number one', validator: function (errorMessageElement, val){ return /1/.test(val) !== true; } }, { errorMessage: 'Cannot contain the number two', validator: function (errorMessageElement, val){ return /2/.test(val) !== true; } } ] }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should add dynamically defined validation to customvalidations', function () { var label, labelClass; hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); expect(1).toEqual(hiddenErrorMessages.length); //Multiple validations dynamically displayed using one error message element expect(0).toEqual(visibleErrorMessages.length); }); }); describe('live feedback | success', function() { var successSpy; beforeEach(function (){ inject(function ($injector, $rootScope, $compile, $timeout) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" '+ 'validation-dynamically-defined="locallyDefinedValidations"/>'+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; successSpy = jasmine.createSpy('successSpy'); angular.extend(scope, { user: { password: null, confirmPassword: null }, locallyDefinedValidations: [ { errorMessage: 'Cannot contain the number one', success: successSpy, validator: function (errorMessageElement, val){ return /1/.test(val) !== true; } } ] }); $compile(element)(scope); scope.$digest(); $timeout.flush(); errorMessages = element.find('.CustomValidationError'); }); }); it('should add dynamically defined validation to customvalidations', function () { var label, labelClass; hiddenErrorMessages = element.find('.CustomValidationError[style="display: none;"]'); visibleErrorMessages = element.find('.CustomValidationError[style="display: inline;"], .CustomValidationError[style="display: block;"]'); scope.user.password = 'validOption'; element.scope().$apply(); scope.$broadcast('runCustomValidations'); element.scope().$apply(); expect(1).toEqual(hiddenErrorMessages.length); //Multiple validations dynamically displayed using one error message element expect(0).toEqual(visibleErrorMessages.length); expect(successSpy).toHaveBeenCalled(); }); }); describe('asynchronous validation', function(){ beforeEach(function (){ inject(function ($injector, $rootScope, $compile, $timeout, $q) { element = angular.element('<form name="form">' + '<input ng-model="user.password" type="text" name="password" id="password" ng-model="user.password" '+ 'validation-dynamically-defined="locallyDefinedValidations"/>'+ '</form>'); passwordInput = element.find('#password'); confirmPasswordInput = element.find('#confirmPassword'); scope = $rootScope; angular.extend(scope, { user: { password: null, confirmPassword: null }, locallyDefinedValidations: [ { errorMessage: 'Cannot contain the number one', validator: function (errorMessageElement, val){ var deferred = $q.defer(); $tim