validator.js
Version:
Powerful object and string validation in Javascript.
1,179 lines (963 loc) • 63.6 kB
JavaScript
( function ( exports ) {
var Suite = function ( validatorjs, expect, AssertExtra ) {
describe( 'validator.js', function () {
var Assert = validatorjs.Assert,
Constraint = validatorjs.Constraint,
Validator = validatorjs.Validator,
Violation = validatorjs.Violation;
var validator = new validatorjs.Validator();
describe( 'Assert', function () {
var assert = new Assert();
describe( 'constructor', function () {
it( 'should not require the new keyword', function () {
expect( Assert() ).to.be.an( Assert );
} )
} )
describe('static constructor', function() {
it( 'should create an instance of `Assert`', function () {
var assert = validatorjs.assert( 'foobar' );
expect( assert ).to.be.an( Assert );
expect( assert.groups ).to.eql( ['foobar'] );
} )
} )
describe( 'static methods', function () {
it( 'should create an instance of `Assert` ', function () {
var assert = Assert.Range( 5, 10 );
expect( assert ).to.be.an( Assert );
expect( assert.__class__ ).to.be( 'Range' );
expect( assert.min ).to.be( 5 );
expect( assert.max ).to.be( 10 );
} );
it( 'should have a camel case alias', function () {
expect( Assert.NotBlank().__class__ ).to.be( Assert.notBlank().__class__ );
} );
it( 'should create new instances', function () {
const assert = Assert.NotBlank();
expect( assert ).to.not.equal( Assert.notBlank() );
} );
it( 'should support `extend`', function () {
const assert = Assert.extend({
Foobar: function() {
this.__class__ = 'Foobar';
this.validate = function() {
return false;
}
return this;
}
} ).Foobar();
expect( assert ).to.be.an( Assert );
expect( assert.__class__ ).to.be( 'Foobar' );
} );
it( 'should support groups', function () {
const assert1 = Assert('bizGroup').NotBlank();
expect( assert1 ).to.be.an( Assert );
expect( assert1.__class__ ).to.be( 'NotBlank' );
expect( assert1.groups ).to.eql( ['bizGroup'] );
const assert2 = Assert('fooGroup').notBlank();
expect( assert2 ).to.be.an( Assert );
expect( assert2.__class__ ).to.be( 'NotBlank' );
expect( assert2.groups ).to.eql( ['fooGroup'] );
var fn = function() {
this.__class__ = 'Foobar';
this.validate = function() {
return false;
}
return this;
}
const assert3 = Assert.extend({ Foobar: fn } )('barGroup').Foobar();
expect( assert3 ).to.be.an( Assert );
expect( assert3.__class__ ).to.be( 'Foobar' );
expect( assert3.groups ).to.eql( ['barGroup'] );
const assert4 = Assert.extend({ Foobar: fn } )('quxGroup').foobar();
expect( assert4 ).to.be.an( Assert );
expect( assert4.__class__ ).to.be( 'Foobar' );
expect( assert4.groups ).to.eql( ['quxGroup'] );
} );
});
describe( 'extend', function() {
it( 'should throw an error if the extend parameter is missing', function () {
try {
Assert.extend();
expect().fails();
} catch (err) {
expect( err.message ).to.be( 'Invalid parameter: `asserts` should be an object' );
}
} )
it( 'should throw an error if the extend parameter is not a object', function () {
try {
Assert.extend('foobar');
expect().fails();
} catch (err) {
expect( err.message ).to.be( 'Invalid parameter: `asserts` should be an object' );
}
} )
it( 'should throw an error if the extend parameter is an empty object', function () {
try {
Assert.extend({});
expect().fails();
} catch (err) {
expect( err.message ).to.be( 'Invalid parameter: `asserts` should have at least one property' );
}
} )
it( 'should throw an error if the given assert is not a function', function () {
try {
Assert.extend({ Foobar: '' });
expect().fails();
} catch (err) {
expect( err.message ).to.be( 'The extension assert must be a function' );
}
} )
it( 'should not require the new keyword', function () {
var fn = function() {};
var Extended = Assert.extend({ Foobar: fn });
expect( Extended() ).to.be.an( Extended );
} )
it( 'should call the `Assert` constructor', function () {
var fn = function() {};
var Extended = Assert.extend({ Foobar: fn });
var extended = new Extended('foobar');
expect( extended.groups ).to.eql( ['foobar' ]);
} )
it( 'should inherit the `Assert` prototype', function () {
var fn = function() {};
var Extended = Assert.extend({ Foobar: fn });
for (var assert in Assert.prototype) {
expect(Extended.prototype[assert]).to.equal(Assert.prototype[assert]);
}
} )
it( 'should inherit `Assert` static methods', function () {
var fn = function() {};
var Extended = Assert.extend({ Foobar: fn });
expect( Extended ).to.have.keys( Object.keys( Assert ) );
} )
it( 'should return an Assert extended copy and keep the original `Assert.prototype` unchanged', function () {
var fn = function() {};
var Extended = Assert.extend({ Foobar: fn });
expect(Assert.prototype.Foobar).to.be(undefined);
expect(Extended.prototype.Foobar).to.eql(fn);
} )
it( 'should return an Assert overriding default asserts', function () {
var fn = function() {
this.validate = function() { return 'foobar'; };
return this;
};
var Extended = Assert.extend({ Email: fn });
expect(Extended.prototype.Email).to.eql(fn);
expect(Extended.prototype.email).to.eql(fn);
expect(Extended.Email().validate()).to.equal('foobar');
expect(Extended.email().validate()).to.equal('foobar');
} )
} )
it( 'should be an object', function () {
expect( assert ).to.be.an( 'object' );
} )
it( 'should have "Assert" __class__', function () {
expect( assert.__class__ ).to.be( 'Assert' );
} )
it( 'should have "Assert" __parentClass__', function () {
expect( assert.__parentClass__ ).to.be( 'Assert' );
} )
it( 'should instanciate an assertion', function () {
var Length = new Assert().Length( { min: 10 } );
expect( Length ).to.be.an( 'object' );
expect( Length.__class__ ).to.be( 'Length' );
expect( assert.__parentClass__ ).to.be( 'Assert' );
} )
it( 'should return true if validate success', function () {
var Length = new Assert().Length( { min: 10 } );
expect( Length.validate( 'foo bar baz' ) ).to.be( true );
} )
it( 'should throw a Violation exception if fails', function () {
var Length = new Assert().Length( { min: 10 } );
try {
Length.validate( 'foo' );
expect().fails();
} catch ( violation ) {
expect( violation ).to.be.a( Violation );
}
} )
it( 'should register a group through assertion construct ', function () {
var Length = new Assert( 'foo' ).Length( { min: 10, min: 15 } );
expect( Length.hasGroups() ).to.be( true );
expect( Length.hasGroup( 'foo' ) ).to.be( true );
} )
it( 'should register mulitple groups through assertion construct', function () {
var Length = new Assert( [ 'foo', 'bar'] ).Length( { min: 10, min: 15 } );
expect( Length.hasGroups() ).to.be( true );
expect( Length.hasGroup( 'foo' ) ).to.be( true );
expect( Length.hasGroup( 'bar' ) ).to.be( true );
} )
it( 'should register a group through addGroup ', function () {
var Length = new Assert().Length( { min: 10 } ).addGroup( 'foo' );
expect( Length.hasGroups() ).to.be( true );
expect( Length.hasGroup( 'foo' ) ).to.be( true );
} )
it( 'should register multiple groups through addGroup', function () {
var Length = new Assert().Length( { min: 10 } ).addGroup( [ 'foo', 'bar' ] );
expect( Length.hasGroups() ).to.be( true );
expect( Length.hasGroup( 'foo' ) ).to.be( true );
expect( Length.hasGroup( 'bar' ) ).to.be( true );
} )
it( 'should register mulitple groups through addGroups', function () {
var Length = new Assert().Length( { min: 10 } ).addGroups( [ 'foo', 'bar'] );
expect( Length.hasGroups() ).to.be( true );
expect( Length.hasGroup( 'foo' ) ).to.be( true );
expect( Length.hasGroup( 'bar' ) ).to.be( true );
} )
it( 'should register mulitple groups through chained addGroup', function () {
var Length = new Assert().Length( { min: 10 } ).addGroup( 'foo' ).addGroup( 'bar' );
expect( Length.hasGroups() ).to.be( true );
expect( Length.hasGroup( 'foo' ) ).to.be( true );
expect( Length.hasGroup( 'bar' ) ).to.be( true );
} )
it( 'should remove group', function () {
var Length = new Assert().Length( { min: 10 } ).addGroup( 'foo' ).addGroup( 'bar' ).removeGroup( 'bar' );
expect( Length.hasGroups() ).to.be( true );
expect( Length.hasGroup( 'foo' ) ).to.be( true );
expect( Length.hasGroup( 'bar' ) ).to.be( false );
} )
it( 'should test hasOneOf for groups', function () {
var Length = new Assert().Length( { min: 10 } ).addGroup( [ 'foo', 'bar' ] );
expect( Length.hasOneOf( [ 'foo', 'baz' ] ) ).to.be( true );
expect( Length.hasOneOf( [ 'bar', 'baz' ] ) ).to.be( true );
expect( Length.hasOneOf( [ 'foobar', 'baz', 'foobaz' ] ) ).to.be( false );
} )
} )
describe( 'Violation', function () {
var violation = new Violation( new Assert().NotBlank(), '' );
describe( 'constructor', function () {
it( 'should not require the new keyword', function () {
expect( Violation( new Assert().NotBlank(), '' ) ).to.be.an( Violation );
} )
} )
describe('static constructor', function() {
it( 'should create an instance of `Violation`', function () {
var notNullViolation = new Violation( new Assert().NotNull() );
var violation = validatorjs.violation( new Assert().NotBlank(), '', notNullViolation );
expect( notNullViolation ).to.be.an( Violation );
expect( violation.violation ).to.equal( notNullViolation );
} )
} )
it( 'should be an object', function () {
expect( violation ).to.be.an( 'object' );
} )
it( 'should have "Violation" __class__', function () {
expect( violation.__class__ ).to.be( 'Violation' );
} )
it( 'should fail if not instanciated with an Assert object having __class__', function () {
try {
var violation = new Violation( 'foo' );
expect().fail();
} catch ( err ) {
expect( err.message ).to.be( 'Should give an assertion implementing the Assert interface' );
}
} )
} )
describe( 'Asserts', function () {
var assert, validate;
before( function () {
validate = function ( value, assert ) {
try {
assert.validate( value );
} catch ( violation ) {
return violation;
}
return true;
};
} )
it( 'NotNull', function () {
assert = new Assert().NotNull();
expect( validate( null, assert ) ).not.to.be( true );
expect( validate( '', assert ) ).to.be( true );
expect( validate( false, assert ) ).to.be( true );
expect( validate( 'foo', assert ) ).to.be( true );
} )
it( 'Null', function () {
assert = new Assert().Null();
expect( validate( null, assert ) ).to.be( true );
expect( validate( '', assert ) ).not.to.be( true );
expect( validate( false, assert ) ).not.to.be( true );
expect( validate( 'foo', assert ) ).not.to.be( true );
} )
it( 'NotBlank', function () {
assert = new Assert().NotBlank();
expect( validate( null, assert ) ).not.to.be( true );
expect( validate( '', assert ) ).not.to.be( true );
expect( validate( false, assert ) ).not.to.be( true );
expect( validate( 'foo', assert ) ).to.be( true );
} )
it( 'Blank', function () {
assert = new Assert().Blank();
expect( validate( null, assert ) ).not.to.be( true );
expect( validate( '', assert ) ).to.be( true );
expect( validate( false, assert ) ).not.to.be( true );
expect( validate( 'foo', assert ) ).not.to.be( true );
} )
it( 'HaveProperty', function () {
assert = new Assert().HaveProperty( 'foo' );
expect( validate( null, assert ) ).not.to.be( true );
expect( validate( { foo: 'bar' }, assert ) ).to.be( true );
expect( validate( { bar: 'baz' }, assert ) ).not.to.be( true );
} )
it( 'HaveProperty alias PropertyDefined', function () {
expect( new Assert().HaveProperty( 'foo' ).__class__ ).to.eql( new Assert().PropertyDefined( 'foo' ).__class__ );
} )
it( 'Length', function () {
assert = new Assert().Length( { min: 3 } );
expect( validate( null, assert ) ).not.to.be( true );
expect( validate( '', assert ) ).not.to.be( true );
expect( validate( false, assert ) ).not.to.be( true );
expect( validate( false, assert ).show() ).to.eql( { assert: 'Length', value: false, violation: { value: 'must_be_a_string_or_array' } } );
expect( validate( false, assert ).__toString() ).to.eql( 'Length assert failed for "false", value expected was must_be_a_string_or_array' );
expect( validate( 'foo', assert ) ).to.be( true );
expect( validate( 'f', assert ).show() ).to.eql( { assert: 'Length', value: 'f', violation: { min: 3 } } );
expect( validate( 'f', assert ).__toString() ).to.eql( 'Length assert failed for "f", min expected was 3' );
expect( validate( 'f', assert ) ).not.to.be( true );
assert = new Assert().Length( { max: 10 } );
expect( validate( 'foo bar baz', assert ) ).not.to.be( true );
expect( validate( 'foo bar baz', assert ).show() ).to.eql( { assert: 'Length', value: 'foo bar baz', violation: { max: 10 } } );
expect( validate( 'foo bar baz', assert ).__toString() ).to.eql( 'Length assert failed for "foo bar baz", max expected was 10' );
/**
* The following assertion tests a case that occurs upstream in Parsley.js where parameters come in as strings
* when the HTML5 standard attributes 'minlength' and 'maxlength' are parsed.
*/
assert = new Assert().Length( { min: '3', max: '3' } );
expect( validate( 'foo', assert ) ).to.be( true );
} )
it( 'Length for arrays', function () {
assert = new Assert().Length( { min: 3, max: 5 } );
expect( validator.validate([], assert) ).not.to.be( true );
expect( validator.validate(['foo'], assert) ).not.to.be( true );
expect( validator.validate(['foo', 'bar', 'baz'], assert) ).to.be( true );
expect( validator.validate(['foo', 'bar', 'baz', 'qux', 'bux', 'pux'], assert) ).not.to.be( true );
} )
it( 'Length alias OfLength', function () {
expect( new Assert().Length( { min: 0, max: 1 } ).__class__ ).to.eql( new Assert().OfLength( { min: 0, max: 1 } ).__class__ );
} )
it( 'Email', function () {
assert = new Assert().Email();
expect( validate( 'foo', assert ) ).not.to.be( true );
expect( validate( 'foo@bar', assert ) ).not.to.be( true );
expect( validate( 'foo@bar', assert ).show() ).to.eql( { assert: 'Email', value: 'foo@bar' } );
expect( validate( 'foo@bar', assert ).__toString() ).to.eql( 'Email assert failed for "foo@bar"' );
expect( validate( 'foo@bar.baz', assert ) ).to.be( true );
} )
it( 'InstanceOf', function () {
assert = new Assert().InstanceOf( Date );
expect( validate( 'foo', assert ) ).not.to.be( true );
expect( validate( 'foo', assert ).show() ).to.eql( { assert: 'InstanceOf', value: 'foo', violation: { classRef: Date } } );
expect( validate( 'foo', assert ).__toString() ).to.eql( 'InstanceOf assert failed for "foo", classRef expected was function Date() { [native code] }' );
expect( validate( 4, assert ) ).not.to.be( true );
expect( validate( new Date(), assert ) ).to.be( true );
} )
it( 'IsString', function () {
assert = new Assert().IsString();
expect( validate( 'foo', assert ) ).to.be( true );
expect( validate( new String( 'foo' ), assert ) ).to.be( true );
expect( validate( 7, assert ) ).not.to.be( true );
expect( validate( 7, assert ).show() ).to.eql( { assert: 'IsString', value: 7, violation: { value: 'must_be_a_string' } } );
expect( validate( 7, assert ).__toString() ).to.eql( 'IsString assert failed for "7", value expected was must_be_a_string' );
var now = new Date();
expect( validate( now, assert ) ).not.to.be( true );
expect( validate( now, assert ).show() ).to.eql( { assert: 'IsString', value: now, violation: { value: 'must_be_a_string' } } );
expect( validate( now, assert ).__toString() ).to.eql( 'IsString assert failed for "'+now+'", value expected was must_be_a_string' );
expect( validate( [1, 2, 3], assert ) ).not.to.be( true );
expect( validate( [1, 2, 3], assert ).show() ).to.eql( { assert: 'IsString', value: [1, 2, 3], violation: { value: 'must_be_a_string' } } );
expect( validate( [1, 2, 3], assert ).__toString() ).to.eql( 'IsString assert failed for "1,2,3", value expected was must_be_a_string' );
} )
it( 'IsString alias String', function () {
expect( new Assert().IsString( 'foo' ).__class__ ).to.eql( new Assert().String( 'foo' ).__class__ );
} )
it( 'EqualTo', function () {
assert = new Assert().EqualTo( 42 );
expect( validate( 'foo', assert ) ).not.to.be( true );
expect( validate( 'foo', assert ).show() ).to.eql( { assert: 'EqualTo', value: 'foo', violation: { value: 42 } } );
expect( validate( 'foo', assert ).__toString() ).to.eql( 'EqualTo assert failed for "foo", value expected was 42' );
expect( validate( 4, assert ) ).not.to.be( true );
expect( validate( 42, assert ) ).to.be( true );
} )
it( 'EqualTo w/ function', function () {
assert = new Assert().EqualTo( function ( value ) {
return 42;
} );
expect( validate( 'foo', assert ) ).not.to.be( true );
expect( validate( 'foo', assert ).show() ).to.eql( { assert: 'EqualTo', value: 'foo', violation: { value: 42 } } );
expect( validate( 'foo', assert ).__toString() ).to.eql( 'EqualTo assert failed for "foo", value expected was 42' );
expect( validate( 4, assert ) ).not.to.be( true );
expect( validate( 42, assert ) ).to.be( true );
} )
it( 'NotEqualTo', function () {
assert = new Assert().NotEqualTo( 42 );
expect( validate( 'foo', assert ) ).to.be( true );
expect( validate( 42, assert ).show() ).to.eql( { assert: 'NotEqualTo', value: 42, violation: { value: 42 } } );
expect( validate( 42, assert ).__toString() ).to.eql( 'NotEqualTo assert failed for "42", value expected was 42' );
expect( validate( 4, assert ) ).to.be( true );
expect( validate( 42, assert ) ).not.to.be( true );
} )
it( 'NotEqualTo w/ function', function () {
assert = new Assert().NotEqualTo( function ( value ) {
return 42;
} );
expect( validate( 'foo', assert ) ).to.be( true );
expect( validate( 42, assert ).show() ).to.eql( { assert: 'NotEqualTo', value: 42, violation: { value: 42 } } );
expect( validate( 4, assert ) ).to.be( true );
expect( validate( 42, assert ) ).not.to.be( true );
} )
it( 'Callback', function () {
assert = new Assert().Callback( function ( value ) {
var calc = ( 42 / value ) % 2;
return calc ? true : calc;
} );
expect( validate( 3, assert ) ).not.to.be( true );
expect( validate( 3, assert ).show() ).to.eql( { assert: 'Callback', value: 3, violation: { result: 0 } } );
expect( validate( 42, assert ) ).to.be( true );
// improved Callback
assert = new Assert().Callback( function ( value, string1, string2 ) {
return value + string1 + string2 === 'foobarbaz';
}, 'bar', 'baz' );
expect( validate( 'foo', assert ) ).to.be( true );
} )
it( 'Callback with error in function', function () {
assert = new Assert().Callback( function ( value ) {
this_function_does_not_exist();
} );
var r = validate( 3, assert ).show();
expect(r.violation).not.to.be(undefined);
expect(r.violation.error).to.be.an(ReferenceError);
expect('' + r.violation.error).to.be( "ReferenceError: this_function_does_not_exist is not defined" );
expect(r).to.eql( { assert: 'Callback', value: 3, violation: { error: r.violation.error } } );
} )
it( 'Choice', function () {
assert = new Assert().Choice( [ 'foo', 'bar', 'baz' ] );
expect( validate( 'qux', assert ) ).not.to.be( true );
expect( validate( 'qux', assert ).show() ).to.eql( { assert: 'Choice', value: 'qux', violation: { choices: [ 'foo', 'bar', 'baz' ] } } );
expect( validate( 'foo', assert ) ).to.be( true );
} )
it( 'Choice w/ function', function () {
var val1 = 'foo', val2 = 'bar', val3 = 'baz', fn = function () {
return [ val1, val2, val3 ];
};
assert = new Assert().Choice( fn );
expect( validate( 'qux', assert ) ).not.to.be( true );
expect( validate( 'qux', assert ).show() ).to.eql( { assert: 'Choice', value: 'qux', violation: { choices: [ 'foo', 'bar', 'baz' ] } } );
expect( validate( 'foo', assert ) ).to.be( true );
} )
it( 'Count', function () {
assert = new Assert().Count( 3 );
expect( validate( 'foo', assert ) ).not.to.be( true );
expect( validate( 'foo', assert ).show() ).to.eql( { assert: 'Count', value: 'foo', violation: { value: 'must_be_an_array' } } );
expect( validate( [ 1, 2 ], assert ) ).not.to.be( true );
expect( validate( [ 1, 2 ], assert ).show() ).to.eql( { assert: 'Count', value: [ 1, 2 ], violation: { count: 3 } } );
expect( validate( [ 1, 2, 3 ], assert ) ).to.be( true );
} )
it( 'Count w/ function', function () {
assert = new Assert().Count( function () { return 3; } );
expect( validate( 'foo', assert ) ).not.to.be( true );
expect( validate( 'foo', assert ).show() ).to.eql( { assert: 'Count', value: 'foo', violation: { value: 'must_be_an_array' } } );
expect( validate( [ 1, 2 ], assert ) ).not.to.be( true );
expect( validate( [ 1, 2 ], assert ).show() ).to.eql( { assert: 'Count', value: [ 1, 2 ], violation: { count: 3 } } );
expect( validate( [ 1, 2, 3 ], assert ) ).to.be( true );
} )
it( 'Required', function () {
assert = new Assert().Required();
var result = validate( undefined, assert );
expect( result ).not.to.be( true );
expect( result.assert.__class__ ).to.be("Required");
expect( validate( '', assert ) ).to.be( true );
expect( validate( [], assert ) ).to.be( true );
} )
it( 'Collection', function () {
var itemConstraint = new Constraint( { foobar: new Assert().NotNull(), foobaz: new Assert().NotNull() } ),
object = {
foo: null,
items: [
{ foobar: null, foobaz: 'foo', fooqux: null },
{ foobar: 'bar', foobaz: 'baz' },
{ foobar: null, foobaz: null }
]
},
constraint = {
foo: new Assert().NotNull(),
items: [ new Assert().Collection( itemConstraint ), new Assert().Count( 2 ) ]
};
var result = validator.validate( object, constraint );
expect( result ).to.have.key( 'foo' );
expect( result ).to.have.key( 'items' );
expect( result.items[ 0 ] ).to.have.key( '0' );
expect( result.items[ 0 ] ).to.have.key( '2' );
expect( result.items[ 0 ][ 0 ] ).to.have.key( 'foobar' );
expect( result.items[ 0 ][ 0 ] ).not.to.have.key( 'foobaz' );
expect( result.items[ 0 ][ 2 ] ).to.have.key( 'foobar' );
expect( result.items[ 0 ][ 2 ] ).to.have.key( 'foobaz' );
expect( result.items[ 1 ] ).to.be.a( Violation );
expect( result.items[ 1 ].assert.__class__ ).to.be( 'Count' );
} )
it( 'Collection with assert', function () {
var object = {
foo: null,
items: [
'foo',
'bar@qux.com',
'baz'
],
strings: [ {} ]
},
constraint = {
foo: new Assert().NotNull(),
items: [ new Assert().Collection( new Assert().Email() ), new Assert().Count( 2 ) ],
strings: [ new Assert().Collection( new Assert().IsString() ) ]
};
var result = validator.validate( object, constraint );
expect( result ).to.have.key( 'foo' );
expect( result ).to.have.key( 'items' );
expect( result.items[ 0 ] ).to.have.key( '0' );
expect( result.items[ 0 ] ).not.to.have.key( '1' );
expect( result.items[ 0 ] ).to.have.key( '2' );
expect( result.items[ 0 ][ 0 ][ 0 ] ).to.be.a( Violation );
expect( result.items[ 0 ][ 0 ][ 0 ].assert.__class__ ).to.be( 'Email' );
expect( result.items[ 0 ][ 2 ][ 0 ] ).to.be.a( Violation );
expect( result.items[ 0 ][ 2 ][ 0 ].assert.__class__ ).to.be( 'Email' );
expect( result.items[ 1 ] ).to.be.a( Violation );
expect( result.items[ 1 ].assert.__class__ ).to.be( 'Count' );
expect( result.strings[ 0 ] ).to.have.key( '0' );
expect( result.strings[ 0 ][ 0 ] ).to.be.a( Violation );
expect( result.strings[ 0 ][ 0 ].assert.__class__ ).to.be( 'IsString' );
} )
it( 'Collection with assert array', function () {
var object = {
foo: null,
items: [
'foo',
'bar@qux.com',
'baz'
]
},
constraint = {
foo: new Assert().NotNull(),
items: new Assert().Collection( [ new Assert().NotEqualTo('foo'), new Assert().Email() ] )
};
var result = validator.validate( object, constraint );
expect( result ).to.have.key( 'foo' );
expect( result ).to.have.key( 'items' );
expect( result.items[ 0 ] ).to.have.key( '0' );
expect( result.items[ 0 ] ).not.to.have.key( '1' );
expect( result.items[ 0 ] ).to.have.key( '2' );
expect( result.items[ 0 ][ 0 ][ 0 ] ).to.be.a( Violation );
expect( result.items[ 0 ][ 0 ][ 0 ].assert.__class__ ).to.be( 'NotEqualTo' );
expect( result.items[ 0 ][ 0 ][ 1 ] ).to.be.a( Violation );
expect( result.items[ 0 ][ 0 ][ 1 ].assert.__class__ ).to.be( 'Email' );
expect( result.items[ 0 ][ 2 ][ 0 ] ).to.be.a( Violation );
expect( result.items[ 0 ][ 2 ][ 0 ].assert.__class__ ).to.be( 'Email' );
} )
it( 'Collection with binded objects', function () {
var itemConstraint = { foobar: new Assert().NotNull(), foobaz: new Assert().NotNull() },
object = {
foo: null,
items: [
{ foobar: null, foobaz: 'foo', fooqux: null },
{ foobar: 'bar', foobaz: 'baz' },
{ foobar: null, foobaz: null }
]
},
constraint = {
foo: new Assert().NotNull(),
items: [ new Assert().Collection(), new Assert().Count( 2 ) ]
};
for ( var i = 0; i < object.items.length; i++ )
validator.bind( object.items[ i ], itemConstraint );
var result = validator.validate( object, constraint );
expect( result ).to.have.key( 'foo' );
expect( result ).to.have.key( 'items' );
expect( result.items[ 0 ] ).to.have.key( '0' );
expect( result.items[ 0 ] ).to.have.key( '2' );
expect( result.items[ 0 ][ 0 ] ).to.have.key( 'foobar' );
expect( result.items[ 0 ][ 0 ] ).not.to.have.key( 'foobaz' );
expect( result.items[ 0 ][ 2 ] ).to.have.key( 'foobar' );
expect( result.items[ 0 ][ 2 ] ).to.have.key( 'foobaz' );
expect( result.items[ 1 ] ).to.be.a( Violation );
expect( result.items[ 1 ].assert.__class__ ).to.be( 'Count' );
} )
it( 'Unique', function () {
assert = new Assert().Unique();
expect( validate( [ 'foo', 'bar', 'baz', 'foo' ], assert ) ).not.to.be( true );
expect( validate( [ 'foo', 'bar', 'baz', 'foo' ], assert ).show() ).to.eql( { assert: 'Unique', value: [ 'foo', 'bar', 'baz', 'foo' ], violation: { value: 'foo' } } );
expect( validate( [ 'foo', 'bar', 'baz' ], assert ) ).to.be( true );
} )
it( 'Unique with objects', function () {
assert = new Assert().Unique( { key: 'foo' } );
var array = [ { foo: 'bar' }, { foo: 'baz' }, { foo: 'bar' } ];
expect( validate( array, assert ) ).not.to.be( true );
expect( validate( array, assert ).show() ).to.eql( { assert: 'Unique', value: array, violation: { value: 'bar' } } );
expect( validate( [ { foo: 'bar' }, { foo: 'baz' } ], assert ) ).to.be( true );
expect( validate( [ { bar: 'bar' }, { baz: 'baz' } ], assert ) ).to.be( true );
} )
it( 'Regexp', function () {
assert = new Assert().Regexp( '^[A-Z]' );
expect( validate( 'foo', assert ) ).not.to.be( true );
expect( validate( 'foo', assert ).show() ).to.eql( { assert: 'Regexp', value: 'foo', violation: { regexp: '^[A-Z]', flag: undefined } } );
expect( validate( 'FOO', assert ) ).to.be( true );
assert = new Assert().Regexp( '^[A-Z]', 'i' );
expect( validate( 'foo', assert ) ).to.be( true );
expect( validate( 'FOO', assert ) ).to.be( true );
assert = new Assert().Regexp( /^[A-Z]/i );
expect( validate( 'foo', assert ) ).to.be( true );
expect( validate( 'FOO', assert ) ).to.be( true );
} )
it( 'Range', function () {
assert = new Assert().Range( 5, 10 );
var assertZero = new Assert().Range( 0, 10 );
// with strings
expect( validate( 'foo', assert ) ).not.to.be( true );
expect( validate( 'foo', assert ).show() ).to.eql( { assert: 'Range', value: 'foo', violation: { min: 5 } } );
expect( validate( 'foo bar', assert ) ).to.be( true );
expect( validate( 'foo bar baz', assert ) ).not.to.be( true );
expect( validate( 'foo bar baz', assert ).show() ).to.eql( { assert: 'Range', value: 'foo bar baz', violation: { max: 10 } } );
// with arrays
expect( validate( ['foo'], assert ) ).not.to.be( true );
expect( validate( ['foo', 'bar', 'baz', 'qux', 'bux'], assert ) ).to.be( true );
// with numbers
expect( validate( 3, assert ) ).not.to.be( true );
expect( validate( 7, assert ) ).to.be( true );
expect( validate( 15, assert ) ).not.to.be( true );
expect( validate( -1, assertZero ) ).not.to.be( true );
expect( validate( 3, assertZero ) ).to.be( true );
expect( validate( 7, assertZero ) ).to.be( true );
expect( validate( 15, assertZero ) ).not.to.be( true );
// numbers typed strings are considered as number
expect( validate( '7', assert ) ).to.be( true );
} )
it( 'GreaterThan', function () {
assert = new Assert().GreaterThan( 5 );
expect( validate( 'foo', assert) ).not.to.be( true );
expect( validate( 3, assert ) ).not.to.be( true );
expect( validate( 5, assert ).show() ).to.eql( { assert: 'GreaterThan', value: 5, violation: { threshold: 5 } } );
expect( validate( 7, assert ) ).to.be( true );
} )
it( 'GreaterThanOrEqual', function () {
assert = new Assert().GreaterThanOrEqual( 5 );
expect( validate( 'foo', assert) ).not.to.be( true );
expect( validate( 3, assert ) ).not.to.be( true );
expect( validate( 3, assert ).show() ).to.eql( { assert: 'GreaterThanOrEqual', value: 3, violation: { threshold: 5 } } );
expect( validate( 5, assert ) ).to.be( true );
expect( validate( 7, assert ) ).to.be( true );
} )
it( 'LessThan', function () {
assert = new Assert().LessThan( 5 );
expect( validate( 'foo', assert) ).not.to.be( true );
expect( validate( 3, assert ) ).to.be( true );
expect( validate( 5, assert ).show() ).to.eql( { assert: 'LessThan', value: 5, violation: { threshold: 5 } } );
expect( validate( 7, assert ) ).not.to.be( true );
} )
it( 'LessThanOrEqual', function () {
assert = new Assert().LessThanOrEqual( 5 );
expect( validate( 'foo', assert) ).not.to.be( true );
expect( validate( 3, assert ) ).to.be( true );
expect( validate( 5, assert ) ).to.be( true );
expect( validate( 7, assert ) ).not.to.be( true );
expect( validate( 7, assert ).show() ).to.eql( { assert: 'LessThanOrEqual', value: 7, violation: { threshold: 5 } } );
} )
it( 'When', function () {
// Using `is` and `otherwise`.
assert = {
foo: new Assert().When( 'bar', {
is: new Assert().Length( { min: 4 } ),
otherwise: new Assert().Length( { min: 5 } )
} )
};
expect( validator.validate( { foo: 'foo' }, assert ) ).to.be( true );
expect( validator.validate( { foo: 'foo', bar: 'bar' }, assert ) ).to.not.be( true );
expect( validator.validate( { foo: 'foobar', bar: 'bar' }, assert ) ).to.be( true );
expect( validator.validate( { foo: 'foo', bar: 'foobar' }, assert ) ).to.be( true );
// Using `is` and `then`.
assert = {
foo: new Assert().When( 'bar', {
is: new Assert().Length( { min: 4 } ),
then: new Assert().Length( { min: 5 } )
} )
};
expect( validator.validate( { foo: 'foo' }, assert ) ).to.be( true );
expect( validator.validate( { foo: 'foo', bar: 'bar' }, assert ) ).to.not.be( true );
expect( validator.validate( { foo: 'foo', bar: 'foobar' }, assert ) ).to.not.be( true );
expect( validator.validate( { foo: 'foobar', bar: 'foobar' }, assert ) ).to.be( true );
// Using `is`, `then` and `otherwise`.
assert = {
foo: new Assert().When( 'bar', {
is: new Assert().Length( { min: 4 } ),
otherwise: new Assert().Length( { min: 4 } ),
then: new Assert().Length( { min: 5 } )
} )
};
expect( validator.validate( { foo: 'foo' }, assert ) ).to.be( true );
expect( validator.validate( { foo: 'foo', bar: 'bar' }, assert ) ).to.not.be( true );
expect( validator.validate( { foo: 'foobar', bar: 'bar' }, assert ) ).to.be( true );
expect( validator.validate( { foo: 'foo', bar: 'foobar' }, assert ) ).to.not.be( true );
expect( validator.validate( { foo: 'foobar', bar: 'foobar' }, assert ) ).to.be( true );
} )
if ( !AssertExtra )
return;
describe( 'Extras Asserts', function () {
it( 'Mac', function () {
assert = new AssertExtra().Mac();
expect( validate( '0G:42:AT:F5:OP:Z2', assert ) ).not.to.be( true );
expect( validate( 'AD:32:11:F7:3B', assert ) ).not.to.be( true );
expect( validate( 'AD:32:11:F7:3B:ZX', assert ).show() ).to.eql( { assert: 'Mac', value: 'AD:32:11:F7:3B:ZX' } );
expect( validate( 'AD:32:11:F7:3B:C9', assert ) ).to.be( true );
} )
it( 'IPv4', function () {
assert = new AssertExtra().IPv4();
expect( validate( 'foo.bar', assert ) ).not.to.be( true );
expect( validate( '192.168.1', assert ) ).not.to.be( true );
expect( validate( '292.168.1.201', assert ).show() ).to.eql( { assert: 'IPv4', value: '292.168.1.201' } );
expect( validate( '192.168.1.201', assert ) ).to.be( true );
} )
it( 'Eql', function () {
assert = new AssertExtra().Eql( { foo: 'foo', bar: 'bar' } );
expect( validate( 'foo', assert) ).not.to.be( true );
expect( validate( 'foo', assert ).show() ).to.eql( { assert: 'Eql', value: 'foo', violation: { eql: { foo: 'foo', bar: 'bar' } } } );
expect( validate( { foo: 'foo' }, assert ) ).not.to.be( true );
expect( validate( { foo: null, bar: null }, assert ) ).not.to.be( true );
expect( validate( { foo: 'foo', bar: 'bar' }, assert ) ).to.be( true );
} )
it( 'Eql w/ function', function () {
assert = new AssertExtra().Eql( function ( value ) { return { foo: 'foo', bar: 'bar' } } );
expect( validate( { foo: null, bar: null }, assert ) ).not.to.be( true );
expect( validate( { foo: 'foo', bar: 'bar' }, assert ) ).to.be( true );
} )
} )
} )
describe( 'Constraint', function () {
var constraint = new Constraint();
describe( 'constructor', function () {
it( 'should not require the new keyword', function () {
expect( Constraint() ).to.be.an( Constraint );
} )
} )
describe('static constructor', function() {
it( 'should create an instance of `Constraint`', function () {
var constraint = validatorjs.constraint( { foo: new Assert().NotBlank() }, { bar: 'biz' } );
expect( constraint ).to.be.an( Constraint );
expect( constraint.nodes ).to.have.key( 'foo' );
expect( constraint.options ).to.have.property( 'bar', 'biz' );
} )
} )
it( 'should be an object', function () {
expect( constraint ).to.be.an( 'object' );
} )
it( 'should have "Constraint" __class__', function () {
expect( constraint.__class__ ).to.be( 'Constraint' );
} )
it( 'should be instanciated without an assertion', function () {
var myConstraint = new Constraint();
expect( myConstraint.nodes ).to.eql( {} );
} )
it( 'should throw an error if not instanciated with an object', function () {
try {
new Constraint( new Assert().Length( { min: 10 } ) );
expect().fails();
} catch ( err ) {
expect( err.message ).to.be( 'Should give a valid mapping object to Constraint' );
}
} )
it( 'should be instanciated with a simple object', function () {
var myConstraint = new Constraint( { foo: new Assert().Length( { min: 10 } ) } );
expect( myConstraint.has( 'foo' ) ).to.be( true );
} )
it( 'should add a node: Assert', function () {
var myConstraint = new Constraint();
myConstraint.add( 'foo', new Assert().Length( { min: 10 } ) );
expect( myConstraint.has( 'foo' ) ).to.be( true );
} )
it( 'should add a node: Constraint', function () {
var myConstraint = new Constraint();
myConstraint.add( 'foo', new Constraint( { bar: new Assert().Length( { min: 10 } ) } ) );
expect( myConstraint.has( 'foo' ) ).to.be( true );
expect( myConstraint.get( 'foo' ).has( 'bar' ) ).to.be( true );
} )
it( 'should be instanciated with a nested object', function () {
var object = {
foo: null,
bar: {
baz: null,
qux: {
bux: null
}
}
},
constraint = new Constraint({
foo: [ new Assert().NotNull(), new Assert().NotNull() ],
bar: {
baz: new Assert().NotNull(),
qux: {
bux: new Assert().NotNull()
}
}
});
expect( constraint ).to.be.a( Constraint );
expect( constraint.get( 'foo' ) ).to.be.an( Array );
expect( constraint.get( 'foo' )[0] ).to.be.an( Assert );
expect( constraint.get( 'foo' )[0].__class__ ).to.be( 'NotNull' );
expect( constraint.get( 'foo' )[1] ).to.be.an( Assert );
expect( constraint.get( 'foo' )[1].__class__ ).to.be( 'NotNull' );
expect( constraint.get( 'bar' ) ).to.be.a( Constraint );
expect( constraint.get( 'bar' ).get( 'baz' ) ).to.be.an( Assert );
expect( constraint.get( 'bar' ).get( 'baz' ).__class__ ).to.be( 'NotNull' );
expect( constraint.get( 'bar' ).get( 'qux' ) ).to.be.a( Constraint );
expect( constraint.get( 'bar' ).get( 'qux' ).get( 'bux' ) ).to.be.an( Assert );
expect( constraint.get( 'bar' ).get( 'qux' ).get( 'bux' ).__class__ ).to.be( 'NotNull' );
} )
it( 'should be instanciated with a constraint', function () {
var constraint = new Constraint( { foo: new Assert().NotNull(), bar: [ new Assert().NotNull(), new Assert().NotBlank() ] } );
constraint = new Constraint( constraint );
expect( constraint ).to.be.a( Constraint );
expect( constraint.has( 'foo' ) ).to.be( true );
expect( constraint.has( 'bar' ) ).to.be( true );
} )
} )
describe( 'Validator', function () {
describe( 'constructor', function () {
it( 'should not require the new keyword', function () {
expect( Validator() ).to.be.an( Validator );
} )
} )
describe('static constructor', function() {
it( 'should create an instance of `Validator`', function () {
var validator = validatorjs.validator( { foo: 'bar' } );
expect( validator ).to.be.an( Validator );
expect( validator.options ).to.have.property('foo', 'bar');
} )
} )
it( 'should be an object', function () {
expect( validator ).to.be.an( 'object' );
} )
it( 'should have "Validator" __class__', function () {
expect( validator.__class__ ).to.be( 'Validator' );
} )
describe( 'String validation', function () {
it( 'sould throw Error if not trying to validate a string against Assert or Asserts array', function () {
try {
validator.validate( 'foo', 'bar' );
expect().fail();
} catch ( err ) {
expect( err.message ).to.be( 'You must give an Assert or an Asserts array to validate a string' );
}
} )
it( 'should validate a string', function () {
expect( validator.validate( 'foo', [ new Assert().Length( { min: 5, max: 10 } ), new Assert().NotBlank() ] ) ).not.to.be( true );
expect( validator.validate( 'foobar', [ new Assert().Length( { min: 5, max: 10 } ), new Assert().NotBlank() ] ) ).to.be( true );
} )
it( 'should return violations for a string', function () {
var asserts = [ new Assert().Length( { min: 5, max: 10 } ), new Assert().NotBlank() ];
var violations = validator.validate( '', asserts );
expect( violations ).to.have.length( 2 );
expect( violations[ 0 ] ).to.be.a( validatorjs.Violation );
expect( violations[ 0 ].assert.__class__ ).to.be( 'Length' );
expect( violations[ 1 ].assert.__class__ ).to.be( 'NotBlank' );
violations = validator.validate( 'foo', asserts );
expect( violations ).to.have.length( 1 );
expect( violations[ 0 ].assert.__class__).to.be( 'Length' );
} )
it( 'should use groups for validation', function() {
var asserts = [ new Assert().Length( { min: 4 } ).addGroup( 'bar' ), new Assert().Length( { min: 8 } ).addGroup( 'baz' ), new Assert().Length( { min: 2 } ) ];
expect( validator.validate( 'foo', asserts ) ).to.be( true );
expect( validator.validate( 'foo', asserts, 'bar' ) ).not.to.be( true );
expect( validator.validate( 'foofoo', asserts, 'bar' ) ).to.be( true );
expect( validator.validate( 'foofoo', asserts, 'baz' ) ).not.to.be( true );
expect( validator.validate( 'foofoofoo', asserts, 'baz' ) ).to.be( true );
} )
it( 'should use numbers as groups for validation', function () {
var asserts = [ new Assert().Length( { min: 4 } ).addGroup( 512 ), new Assert().Length( { min: 8 } ).addGroup( 1024 ), new Assert().Length( { min: 2 } ) ];
expect( validator.validate( 'foo', asserts ) ).to.be( true );
expect( validator.validate( 'foo', asserts, 512 ) ).not.to.be( true );
expect( validator.validate( 'foofoo', asserts, 512 ) ).to.be( true );
expect( validator.validate( 'foofoo', asserts, 1024 ) ).not.to.be( true );
expect( validator.validate( 'foofoofoo', asserts, 1024 ) ).to.be( true );
} )
})
describe( 'Array validation', function () {
it( 'should validate an array of strings', function () {
var assert = new Assert().Collection( new Assert().Email() );
expect( validator.validate( ['foo@bar.baz', 'bar@baz.qux'], assert ) ).to.be( true );
expect( validator.validate( ['foo@bar.baz', 'not an email'], assert ) ).not.to.be( true );
expect( validator.validate( ['foo@bar.baz', 'not an email'], assert )[ 0 ][ '1' ][ 0 ].__class__ ).to.be( 'Violation' );
} )
} )
describe( 'Object validation', function () {
it( 'should validate an object with a simple constraint', function () {
var constraint = {
foo: new Assert().Required(),
bar: new Assert().Required(),
baz: new Assert().Required()
};
expect( validator.validate( {
foo: 42,
bar: 'bar'
}, constraint ) ).not.to.be( true );
expect( validator.validate( {
foo: 42,
bar: 'bar',
baz: 'baz'
}, constraint ) ).to.be( true );
} )
it( 'should validate required properties', function () {
var constraint = {
foo: new Assert().Required(),
bar: [ new Assert().Required(), new Assert().Length( { min: 4 } ) ],
};
var result = validator.validate( {
foo: 'foo',
}, constraint );
expect( result ).not.to.be( true );
expect( result.bar ).to.be.a( Violation );
expect( result.bar.assert.__class__ ).to.be( 'HaveProperty' );
expect( result.bar.violation.value ).to.be( 'bar' );
var result = validator.validate( {
foo: 'foo',
bar: '123'
}, constraint );
expect( result ).not.to.be( true );
expect( result.bar[0] ).to.be.a( Violation );
expect( result.bar[0].assert.__class__ ).to.be( 'Length' );
expect( result.bar[0].violation ).to.eql( { min: 4 } );
var result = validator.validate( {
foo: 'foo',
bar: '1234'
}, constraint );
expect( result ).to.be( true );
} )
it( 'should validate required properties in deepRequired mode', function () {
var constraint = new Constraint({
foo: {
bar: new Assert().Required()
}
}, { deepRequired: true });
var result = validator.validate( { }, constraint );
expect( result ).not.to.be( true );
expect( result.foo ).to.be.a( Violation );
expect( result.foo.assert.__class__ ).to.be( 'HaveProperty' );
expect( result.foo.violation.value ).to.be( 'foo' );
} )
it( 'should validate empty array in deepRequired mode', function () {
var constraint = new Constraint({
foo: new Assert().Collection({
bar: new Assert().Required()
})
}, { deepRequired: true });
var result = validator.validate( { foo: [ ] }, constraint );
expect( result ).to.be( true );
} )
it( 'should validate array of strings in deepRequired mode', function () {
var constraint = new Constraint({
foo: new Assert().Collection(new Assert().NotBlank())
}, { deepRequired: true });
var result = validator.validate( { foo: [ '' ] }, constraint );
expect( result ).not.to.be( true );
expect( result.foo ).to.be.an( Array );
expect( result.foo[0]['0'][0] ).to.be.a( Violation );
expect( result.foo[0]['0'][0].assert.__class__ ).to.be( 'NotBlank' );
} )
it( 'should validate array of objects in deepRequired mode', function () {
var constraint = new Constraint({
foo: new Assert().Collection({
bar: new Assert().Required()
})
}, { deepRequired: