');
$rootScope.$digest();
expect(helper.validationCounter.pattern).toBe(1);
});
});
describe('minlength', function() {
it('should invalidate values that are shorter than the given minlength', function() {
var inputElm = helper.compileInput('');
helper.changeInputValueTo('aa');
expect(inputElm).toBeInvalid();
helper.changeInputValueTo('aaa');
expect(inputElm).toBeValid();
});
it('should listen on ng-minlength when minlength is observed', function() {
var value = 0;
var inputElm = helper.compileInput('');
helper.attrs.$observe('minlength', function(v) {
value = toInt(helper.attrs.minlength);
});
$rootScope.$apply('min = 5');
expect(value).toBe(5);
});
it('should observe the standard minlength attribute and register it as a validator on the model', function() {
var inputElm = helper.compileInput('');
$rootScope.$apply('min = 10');
helper.changeInputValueTo('12345');
expect(inputElm).toBeInvalid();
expect($rootScope.form.input.$error.minlength).toBe(true);
$rootScope.$apply('min = 5');
expect(inputElm).toBeValid();
expect($rootScope.form.input.$error.minlength).not.toBe(true);
});
it('should validate when the model is initialized as a number', function() {
$rootScope.value = 12345;
var inputElm = helper.compileInput('');
expect($rootScope.value).toBe(12345);
expect($rootScope.form.input.$error.minlength).toBeUndefined();
});
it('should validate emptiness against the viewValue', function() {
var inputElm = helper.compileInput('');
var ctrl = inputElm.controller('ngModel');
spyOn(ctrl, '$isEmpty').and.callThrough();
ctrl.$parsers.push(function(value) {
return value + '678';
});
helper.changeInputValueTo('12345');
expect(ctrl.$isEmpty).toHaveBeenCalledWith('12345');
});
it('should validate on non-input elements', inject(function($compile) {
$rootScope.min = 3;
var elm = $compile('')($rootScope);
var elmNg = $compile('')($rootScope);
var ctrl = elm.controller('ngModel');
var ctrlNg = elmNg.controller('ngModel');
expect(ctrl.$error.minlength).not.toBe(true);
expect(ctrlNg.$error.minlength).not.toBe(true);
ctrl.$setViewValue('12');
ctrlNg.$setViewValue('12');
expect(ctrl.$error.minlength).toBe(true);
expect(ctrlNg.$error.minlength).toBe(true);
}));
it('should only validate once after compilation when inside ngRepeat', function() {
$rootScope.minlength = 5;
var element = helper.compileInput(
'
' +
'' +
'
');
$rootScope.$digest();
expect(helper.validationCounter.minlength).toBe(1);
element = helper.compileInput(
'
' +
'' +
'
');
$rootScope.$digest();
expect(helper.validationCounter.minlength).toBe(1);
});
});
describe('maxlength', function() {
it('should invalidate values that are longer than the given maxlength', function() {
var inputElm = helper.compileInput('');
helper.changeInputValueTo('aaaaaaaa');
expect(inputElm).toBeInvalid();
helper.changeInputValueTo('aaa');
expect(inputElm).toBeValid();
});
it('should only accept empty values when maxlength is 0', function() {
var inputElm = helper.compileInput('');
helper.changeInputValueTo('');
expect(inputElm).toBeValid();
helper.changeInputValueTo('a');
expect(inputElm).toBeInvalid();
});
it('should accept values of any length when maxlength is negative', function() {
var inputElm = helper.compileInput('');
helper.changeInputValueTo('');
expect(inputElm).toBeValid();
helper.changeInputValueTo('aaaaaaaaaa');
expect(inputElm).toBeValid();
});
it('should accept values of any length when maxlength is non-numeric', function() {
var inputElm = helper.compileInput('');
helper.changeInputValueTo('aaaaaaaaaa');
$rootScope.$apply('maxlength = "5"');
expect(inputElm).toBeInvalid();
$rootScope.$apply('maxlength = "abc"');
expect(inputElm).toBeValid();
$rootScope.$apply('maxlength = ""');
expect(inputElm).toBeValid();
$rootScope.$apply('maxlength = null');
expect(inputElm).toBeValid();
$rootScope.someObj = {};
$rootScope.$apply('maxlength = someObj');
expect(inputElm).toBeValid();
});
it('should listen on ng-maxlength when maxlength is observed', function() {
var value = 0;
var inputElm = helper.compileInput('');
helper.attrs.$observe('maxlength', function(v) {
value = toInt(helper.attrs.maxlength);
});
$rootScope.$apply('max = 10');
expect(value).toBe(10);
});
it('should observe the standard maxlength attribute and register it as a validator on the model', function() {
var inputElm = helper.compileInput('');
$rootScope.$apply('max = 1');
helper.changeInputValueTo('12345');
expect(inputElm).toBeInvalid();
expect($rootScope.form.input.$error.maxlength).toBe(true);
$rootScope.$apply('max = 6');
expect(inputElm).toBeValid();
expect($rootScope.form.input.$error.maxlength).not.toBe(true);
});
it('should assign the correct model after an observed validator became valid', function() {
var inputElm = helper.compileInput('');
$rootScope.$apply('max = 1');
helper.changeInputValueTo('12345');
expect($rootScope.value).toBeUndefined();
$rootScope.$apply('max = 6');
expect($rootScope.value).toBe('12345');
});
it('should assign the correct model after an observed validator became invalid', function() {
var inputElm = helper.compileInput('');
$rootScope.$apply('max = 6');
helper.changeInputValueTo('12345');
expect($rootScope.value).toBe('12345');
$rootScope.$apply('max = 1');
expect($rootScope.value).toBeUndefined();
});
it('should leave the value as invalid if observed maxlength changed, but is still invalid', function() {
var inputElm = helper.compileInput('');
$rootScope.$apply('max = 1');
helper.changeInputValueTo('12345');
expect(inputElm).toBeInvalid();
expect($rootScope.form.input.$error.maxlength).toBe(true);
expect($rootScope.value).toBeUndefined();
$rootScope.$apply('max = 3');
expect(inputElm).toBeInvalid();
expect($rootScope.form.input.$error.maxlength).toBe(true);
expect($rootScope.value).toBeUndefined();
});
it('should not notify if observed maxlength changed, but is still invalid', function() {
var inputElm = helper.compileInput('');
$rootScope.$apply('max = 1');
helper.changeInputValueTo('12345');
$rootScope.ngChangeSpy = jasmine.createSpy();
$rootScope.$apply('max = 3');
expect($rootScope.ngChangeSpy).not.toHaveBeenCalled();
});
it('should leave the model untouched when validating before model initialization', function() {
$rootScope.value = '12345';
var inputElm = helper.compileInput('');
expect($rootScope.value).toBe('12345');
});
it('should validate when the model is initialized as a number', function() {
$rootScope.value = 12345;
var inputElm = helper.compileInput('');
expect($rootScope.value).toBe(12345);
expect($rootScope.form.input.$error.maxlength).toBeUndefined();
});
it('should validate emptiness against the viewValue', function() {
var inputElm = helper.compileInput('');
var ctrl = inputElm.controller('ngModel');
spyOn(ctrl, '$isEmpty').and.callThrough();
ctrl.$parsers.push(function(value) {
return value + '678';
});
helper.changeInputValueTo('12345');
expect(ctrl.$isEmpty).toHaveBeenCalledWith('12345');
});
it('should validate on non-input elements', inject(function($compile) {
$rootScope.max = 3;
var elm = $compile('')($rootScope);
var elmNg = $compile('')($rootScope);
var ctrl = elm.controller('ngModel');
var ctrlNg = elmNg.controller('ngModel');
expect(ctrl.$error.maxlength).not.toBe(true);
expect(ctrlNg.$error.maxlength).not.toBe(true);
ctrl.$setViewValue('1234');
ctrlNg.$setViewValue('1234');
expect(ctrl.$error.maxlength).toBe(true);
expect(ctrlNg.$error.maxlength).toBe(true);
}));
it('should only validate once after compilation when inside ngRepeat', function() {
$rootScope.maxlength = 5;
var element = helper.compileInput(
'
' +
'' +
'
');
$rootScope.$digest();
expect(helper.validationCounter.maxlength).toBe(1);
element = helper.compileInput(
'
' +
'' +
'
');
$rootScope.$digest();
expect(helper.validationCounter.maxlength).toBe(1);
});
});
describe('required', function() {
it('should allow bindings via ngRequired', function() {
var inputElm = helper.compileInput('');
$rootScope.$apply('required = false');
helper.changeInputValueTo('');
expect(inputElm).toBeValid();
$rootScope.$apply('required = true');
expect(inputElm).toBeInvalid();
$rootScope.$apply('value = \'some\'');
expect(inputElm).toBeValid();
helper.changeInputValueTo('');
expect(inputElm).toBeInvalid();
$rootScope.$apply('required = false');
expect(inputElm).toBeValid();
});
it('should invalid initial value with bound required', function() {
var inputElm = helper.compileInput('');
$rootScope.$apply('required = true');
expect(inputElm).toBeInvalid();
});
it('should be $invalid but $pristine if not touched', function() {
var inputElm = helper.compileInput('');
$rootScope.$apply('name = null');
expect(inputElm).toBeInvalid();
expect(inputElm).toBePristine();
helper.changeInputValueTo('');
expect(inputElm).toBeInvalid();
expect(inputElm).toBeDirty();
});
it('should allow empty string if not required', function() {
var inputElm = helper.compileInput('');
helper.changeInputValueTo('a');
helper.changeInputValueTo('');
expect($rootScope.foo).toBe('');
});
it('should set $invalid when model undefined', function() {
var inputElm = helper.compileInput('');
expect(inputElm).toBeInvalid();
});
it('should consider bad input as an error before any other errors are considered', function() {
var inputElm = helper.compileInput('', { badInput: true });
var ctrl = inputElm.controller('ngModel');
ctrl.$parsers.push(function() {
return undefined;
});
helper.changeInputValueTo('abc123');
expect(ctrl.$error.parse).toBe(true);
expect(inputElm).toHaveClass('ng-invalid-parse');
expect(inputElm).toBeInvalid(); // invalid because of the number validator
});
it('should allow `false` as a valid value when the input type is not "checkbox"', function() {
var inputElm = helper.compileInput('' +
'');
$rootScope.$apply();
expect(inputElm).toBeInvalid();
$rootScope.$apply('answer = true');
expect(inputElm).toBeValid();
$rootScope.$apply('answer = false');
expect(inputElm).toBeValid();
});
it('should validate emptiness against the viewValue', function() {
var inputElm = helper.compileInput('');
var ctrl = inputElm.controller('ngModel');
spyOn(ctrl, '$isEmpty').and.callThrough();
ctrl.$parsers.push(function(value) {
return value + '678';
});
helper.changeInputValueTo('12345');
expect(ctrl.$isEmpty).toHaveBeenCalledWith('12345');
});
it('should validate on non-input elements', inject(function($compile) {
$rootScope.value = '12';
var elm = $compile('')($rootScope);
var elmNg = $compile('')($rootScope);
var ctrl = elm.controller('ngModel');
var ctrlNg = elmNg.controller('ngModel');
expect(ctrl.$error.required).not.toBe(true);
expect(ctrlNg.$error.required).not.toBe(true);
ctrl.$setViewValue('');
ctrlNg.$setViewValue('');
expect(ctrl.$error.required).toBe(true);
expect(ctrlNg.$error.required).toBe(true);
}));
it('should override "required" when ng-required="false" is set', function() {
var inputElm = helper.compileInput('');
expect(inputElm).toBeValid();
});
it('should validate only once after compilation when inside ngRepeat', function() {
helper.compileInput(
'
' +
'' +
'
');
$rootScope.$digest();
expect(helper.validationCounter.required).toBe(1);
});
it('should validate only once after compilation when inside ngRepeat and ngRequired is true', function() {
$rootScope.isRequired = true;
helper.compileInput(
'
' +
'' +
'
');
expect(helper.validationCounter.required).toBe(1);
});
it('should validate only once after compilation when inside ngRepeat and ngRequired is false', function() {
$rootScope.isRequired = false;
helper.compileInput(
'
' +
'' +
'
');
expect(helper.validationCounter.required).toBe(1);
});
it('should validate once when inside ngRepeat, and set the "required" error when ngRequired is false by default', function() {
$rootScope.isRequired = false;
$rootScope.refs = {};
var elm = helper.compileInput(
'
' +
'' +
'
');
expect(helper.validationCounter.required).toBe(1);
expect($rootScope.refs.input.$error.required).toBeUndefined();
});
it('should validate only once when inside ngIf with required on non-input elements', inject(function($compile) {
$rootScope.value = '12';
$rootScope.refs = {};
helper.compileInput('