UNPKG

validator-chain

Version:

Powerful tool for validate input parameters in the most stylish way. Could be use as simple test case in conditional statement or in standalone chain of validation

1,020 lines (970 loc) 36.2 kB
require('mocha'); const sinon = require('sinon'); const chai = require('chai'); const chaiAsPromised = require('chai-as-promised'); chai.use(chaiAsPromised); const { expect } = chai; chai.should(); const Bluebird = require('bluebird'); const { default: Errors, Eratum } = require('eratum'); Errors.isStackEnabled = true; const Validator = require('../sources'); function getIdentifier() { const letters = '0123456789azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN'; let identifier = ''; while (identifier.length < 16) { identifier += letters.charAt(Math.floor(letters.length * Math.random())); } return identifier; } function assertErrorIsEratum(error) { expect(error).instanceOf(Eratum); expect(error).property('parameters').a('object'); } function assertErrorIsProgramingFault(error, reason) { assertErrorIsEratum(error); expect(error).instanceOf(Errors.programingFault.class); if (reason !== undefined) { expect(error.parameters).property('reason').equal(reason); } } function assertErrorIsInvalidFormat(error, name, value, format) { assertErrorIsEratum(error); expect(error).instanceOf(Errors.invalidFormat.class); expect(error.parameters).property('name').equal(name); expect(error.parameters).property('value').equal(value); expect(error.parameters).property('format').equal(format); } function assertErrorIsInvalidType(error, name, actualType, expectedType) { assertErrorIsEratum(error); expect(error).instanceOf(Errors.invalidType.class); expect(error.parameters).property('name').equal(name); expect(error.parameters).property('actualType').equal(actualType); expect(error.parameters).property('expectedType').equal(expectedType); } function assertErrorIdInvalid(error, name) { assertErrorIsEratum(error); expect(error).instanceOf(Errors.invalid.class); expect(error.parameters).property('name').equal(name); } function assertErrorIsOutOfBound(error, clazz, name, value, limit) { assertErrorIsEratum(error); expect(error).instanceOf(clazz.class); expect(error.parameters).property('name').equal(name); expect(error.parameters).property('value').equal(value); expect(error.parameters).property('limit').equal(limit); } describe('instanceOf', () => { it('Validator.instanceOf() should return \'undefined\'', () => { expect(Validator.instanceOf()).equal('undefined'); }); it('Validator.instanceOf(null) should return \'undefined\'', () => { expect(Validator.instanceOf(null)).equal('undefined'); }); it('Validator.isInstance(null, \'undefined\') should return true', () => { expect(Validator.isInstance(null, 'undefined')).equal(true); }); it('Validator.isInstance(undefined, \'undefined\') should return true', () => { expect(Validator.isInstance(undefined, 'undefined')).equal(true); }); it('Validator.isInstance({}, \'Object\') should return true', () => { expect(Validator.isInstance({}, 'Object')).equal(true); }); it('Validator.isInstance(new Error(), \'Object\') should return true', () => { expect(Validator.isInstance(new Error(), 'Object')).equal(true); }); it('Validator.isInstance(14, \'Object\') should return false', () => { expect(Validator.isInstance(14, 'Object')).equal(false); }); it('Validator.isInstance({}, \'undefined\') should return false', () => { expect(Validator.isInstance({}, 'undefined')).equal(false); }); it('Validator.isInstance(8, Object) should return false', () => { expect(Validator.isInstance(8, Object)).equal(false); }); it('Validator.isInstance(8, \'Number\') should return true', () => { expect(Validator.isInstance(8, 'Number')).equal(true); }); it('Validator.isInstance({}, Number) should return false', () => { expect(Validator.isInstance({}, Number)).equal(false); }); it('Validator.isInstance({}, Object) should return true', () => { expect(Validator.isInstance({}, Object)).equal(true); }); }); describe('Chain', () => { it('Chain should return this', () => { const v = Validator(); const keys = [ 'must', 'have', 'has', 'been', 'be', 'is', 'are', 'a', 'an', 'and', 'of', 'not' ]; keys.forEach((key) => expect(v[key]).equal(v)); expect(v.setModifier(true)).equal(v); expect(v.invalidateOn(() => false)).equal(v); expect(v.try()).equal(v); }); }); describe('Try / Resolve', () => { it('Should continue on valid validator', () => { try { Validator().try(); } catch (error) { expect(error).equal(null); } }); it('Shoud throw error on invalidated validator', () => { const ERROR = Errors.internalError(); try { Validator().invalidate(ERROR).try(); expect.fail(undefined, undefined, 'Should throws'); } catch (error) { expect(error).equal(ERROR); } }); it('Should fulfill on valid validator', () => { return Validator().resolve().should.fulfilled; }); it('Should reject error on invalid validator', () => { const ERROR = Errors.internalError(); return Validator().invalidate(ERROR).resolve().should.rejectedWith(ERROR); }); it('Should throws programingFault on throwing test', () => { const ERROR = Errors.internalError(); try { Validator(42).invalidateOn(() => { throw ERROR; }).try(); expect.fail(undefined, undefined, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error, 'Validation was interupted by unhandeled throws error'); expect(error.cause).equal(ERROR); } }); }); describe('Apply', () => { it('Validator().apply(...) should pass this as parameter to applier', () => { const validator = Validator(42); validator.apply((v) => expect(v).equal(validator)).try(); }); it('Validator().apply(...) should handle throw inside applier', () => { const ERROR = Errors.internalError(); try { Validator(42).apply(() => { throw ERROR; }).try(); expect.fail(undefined, undefined, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error, 'Validation was interupted by unhandeled throws error'); expect(error.cause).equal(ERROR); } }); it('Validator().apply(...) should be validate by applier chain', () => { Validator(42).apply((v) => v.number()).try(); }); it('Validator().apply(...) should be invalidated by applier chain', () => { const identifier = getIdentifier(); try { Validator(42, identifier).apply((v) => v.string()).try(); expect.fail(undefined, undefined, 'Should throws'); } catch (error) { assertErrorIsInvalidType(error, identifier, 'Number', 'String'); } }); }); describe('Exist', () => { it('Validator().exist() should be invalid', () => { const identifier = getIdentifier(); try { Validator(undefined, identifier).exist().try(); expect.fail(undefined, undefined, 'Should throws'); } catch (error) { expect(error).instanceOf(Errors.doesntExist.class); expect(error).property('parameters').a('object'); expect(error.parameters).property('name').equal(identifier); } }); it('Validator(17).exist() should be valid', () => { Validator(17).exist().try(); }); it('Validator([]).exist() should be valid', () => { Validator([]).exist().try(); }); it('Validator(null).not.exist() should be valid', () => { Validator(null).not.exist().try(); }); it('Validator({}).not.exist() should be invalid', () => { const identifier = getIdentifier(); try { Validator({}, identifier).not.exist().try(); expect.fail(undefined, undefined, 'Should throws'); } catch (error) { expect(error).instanceOf(Errors.exist.class); expect(error).property('parameters').a('object'); expect(error.parameters).property('name').equal(identifier); } }); }); describe('Type', () => { it('Validator(42).type(\'number\') should be valid', () => { Validator(42).type('number').try(); }); it('Validator(true).type(\'string\') should be invalid', () => { const identifier = getIdentifier(); try { Validator(true, identifier).type('string').try(); } catch (error) { assertErrorIsInvalidType(error, identifier, 'boolean', 'string'); } }); it('Validator([]).not.type(\'function\') should be valid', () => { Validator([]).not.type('function').try(); }); it('Validator(new Error()).not.type(\'object\') should be invalid', () => { const identifier = getIdentifier(); try { Validator(new Error(), identifier).not.type('object').try(); } catch (error) { assertErrorIsInvalidType(error, identifier, 'object', '!object'); } }); }); describe('Instance', () => { it('Validator(42).number() should be valid', () => { Validator(42).number().try(); }); it('Validator(true).string() should be invalid', () => { const identifier = getIdentifier(); try { Validator(true, identifier).string().try(); } catch (error) { assertErrorIsInvalidType(error, identifier, 'Boolean', 'String'); } }); it('Validator([]).not.object() should be valid', () => { Validator([]).not.object().try(); }); it('Validator(false).not.boolean() should be invalid', () => { const identifier = getIdentifier(); try { Validator(false, identifier).not.boolean().try(); } catch (error) { assertErrorIsInvalidType(error, identifier, 'Boolean', '!Boolean'); } }); it('Validator(() => 12).function() should be valid', () => { Validator(() => 12).function().try(); }); it('Validator(new Error()).instance(Error) should be valid', () => { Validator(new Error()).instance('Error').try(); }); }); describe('Equal', () => { it('Validator(42).equal(42) should be valid', () => { Validator(42).equal(42).try(); }); it('Validator(true).equal(\'String\') should be invalid', () => { const identifier = getIdentifier(); try { Validator(true, identifier).equal('String').try(); } catch (error) { expect(error).instanceOf(Errors.notEqual.class); expect(error).property('parameters').a('object'); expect(error.parameters).property('name').equal(identifier); expect(error.parameters).property('actualValue').equal('true'); expect(error.parameters).property('expectedValue').equal('\'String\''); } }); it('Validator([]).not.equal(\'Object\') should be valid', () => { Validator([]).not.equal('Object').try(); }); it('Validator({ a: 12 }).not.equal({ a: 12 }) should be invalid', () => { const identifier = getIdentifier(); try { Validator({ a: 12 }, identifier).not.equal({ a: 12 }).try(); } catch (error) { expect(error).instanceOf(Errors.equal.class); expect(error).property('parameters').a('object'); expect(error.parameters).property('name').equal(identifier); expect(error.parameters).property('value').equal('{ a: 12 }'); } }); }); describe('Among', () => { it('Validator(42).among([ 42, 72 ]) should be valid', () => { Validator(42).among([ 42, 72 ]).try(); }); it('Validator(true).among([ false, { a: 12 } ]) should be invalid', () => { const identifier = getIdentifier(); try { Validator(true, identifier).among([ false, { a: 12 } ]).try(); } catch (error) { expect(error).instanceOf(Errors.notIncluded.class); expect(error).property('parameters').a('object'); expect(error.parameters).property('name').equal(identifier); expect(error.parameters).property('value').equal('true'); expect(error.parameters).property('possibleValues').equal('[ false, { a: 12 } ]'); } }); it('Validator(27).not.among([ false, { a: 12 } ]) should be valid', () => { Validator([]).not.among([ false, { a: 12 } ]).try(); }); it('Validator({ a: 12 }).not.among([ { a: 12 } ]) should be invalid', () => { const identifier = getIdentifier(); try { Validator({ a: 12 }, identifier).not.among([ { a: 12 } ]).try(); } catch (error) { expect(error).instanceOf(Errors.included.class); expect(error).property('parameters').a('object'); expect(error.parameters).property('name').equal(identifier); expect(error.parameters).property('value').equal('{ a: 12 }'); expect(error.parameters).property('forbiddenValues').equal('[ { a: 12 } ]'); } }); }); describe('GreaterThan', () => { it('Validator(42).greaterThan(28) should be valid', () => { Validator(42).greaterThan(28).try(); }); it('Validator(42).greaterThan(42) should be invalid', () => { const identifier = getIdentifier(); try { Validator(42, identifier).greaterThan(42).try(); } catch (error) { assertErrorIsOutOfBound(error, Errors.notGreaterThan, identifier, '42', '42'); } }); it('Validator(42).lowerOrEqualThan(42) should be valid', () => { Validator(42).lowerOrEqualThan(57).try(); }); it('Validator(42).lowerOrEqualThan(28) should be invalid', () => { const identifier = getIdentifier(); try { Validator(42, identifier).lowerOrEqualThan(28).try(); } catch (error) { assertErrorIsOutOfBound(error, Errors.greaterThan, identifier, '42', '28'); } }); }); describe('LowerThan', () => { it('Validator(42).lowerThan(57) should be valid', () => { Validator(42).lowerThan(57).try(); }); it('Validator(42).lowerThan(28) should be invalid', () => { const identifier = getIdentifier(); try { Validator(42, identifier).lowerThan(28).try(); } catch (error) { assertErrorIsOutOfBound(error, Errors.notLowerThan, identifier, '42', '28'); } }); it('Validator(42).greaterOrEqualThan(28) should be valid', () => { Validator(42).greaterOrEqualThan(28).try(); }); it('Validator(42).greaterOrEqualThan(57) should be invalid', () => { const identifier = getIdentifier(); try { Validator(42, identifier).greaterOrEqualThan(57).try(); } catch (error) { assertErrorIsOutOfBound(error, Errors.lowerThan, identifier, '42', '57'); } }); }); describe('Match', () => { it('Validator(\'Hello World\').match(/^[ \\w]{11}$/) should be valid', () => { return Validator('Hello World').match(/^[ \w]{11}$/).resolve() .should.fulfilled; }); it('Validator(\'Hello World\').match(/[0-9]\\+/) should be invalid', () => { const identifier = getIdentifier(); return Validator('Hello World', identifier).match(/[0-9]\+/).match(/^[ \w]{11}$/).resolve() .should.rejectedWith(Errors.invalidFormat.class); }); it('Validator(\'Hello World\').not.match(/[0-9]\\+/) should be valid', () => { return Validator('Hello World').not.match(/[0-9]\+/).resolve() .should.fulfilled; }); it('Validator(\'Hello World\').not.match(/^[ \\w]{11}$/) should be invalid', () => { const identifier = getIdentifier(); return Validator('Hello World', identifier).not.match(/^[ \w]{11}$/).resolve() .should.rejectedWith(Errors.invalidFormat.class); }); }); describe('startsWith', () => { it('Validator(\'john\').startsWith(\'j\') should be valid', () => { Validator('john').startsWith('j').try(); }); it('Validator(\'john\').startsWith(\'J\') should be invalid', () => { const identifier = getIdentifier(); try { Validator('john', identifier).startsWith('J').try(); } catch (error) { assertErrorIsInvalidFormat(error, identifier, '\'john\'', 'startsWith(\'J\')'); } }); it('Validator(\'john\').not.startsWith(\'k\') should be valid', () => { Validator('john').not.startsWith('k').try(); }); it('Validator(\'john\').not.startsWith(\'j\') should be invalid', () => { const identifier = getIdentifier(); try { Validator('john', identifier).not.startsWith('j').try(); } catch (error) { assertErrorIsInvalidFormat(error, identifier, '\'john\'', '!startsWith(\'j\')'); } }); }); describe('endsWith', () => { it('Validator(\'john\').endsWith(\'n\') should be valid', () => { Validator('john').endsWith('n').try(); }); it('Validator(\'john\').endsWith(\'J\') should be invalid', () => { const identifier = getIdentifier(); try { Validator('john', identifier).endsWith('J').try(); } catch (error) { assertErrorIsInvalidFormat(error, identifier, '\'john\'', 'endsWith(\'J\')'); } }); it('Validator(\'john\').not.endsWith(\'k\') should be valid', () => { Validator('john').not.endsWith('k').try(); }); it('Validator(\'john\').not.endsWith(\'j\') should be invalid', () => { const identifier = getIdentifier(); try { Validator('john', identifier).not.endsWith('n').try(); } catch (error) { assertErrorIsInvalidFormat(error, identifier, '\'john\'', '!endsWith(\'n\')'); } }); }); describe('Hexadecimal', () => { it('Validator(\'0123456789abcdefABCDEF\').hexadecimal() should be valid', () => { return Validator('0123456789abcdefABCDEF').hexadecimal().resolve() .should.fulfilled; }); it('Validator(\'0123456789 abcdef ABCDEF\').hexadecimal() should be invalid', () => { return Validator('0123456789 abcdef ABCDEF', 'ISKVRZLVNB').hexadecimal().resolve() .should.rejectedWith(Errors.invalidFormat.class); }); it('Validator(\'0123456789 abcdef ABCDEF\').not.hexadecimal() should be valid', () => { return Validator('0123456789 abcdef ABCDEF').not.hexadecimal().resolve() .should.fulfilled; }); it('Validator(\'0123456789abcdefABCDEF\').not.hexadecimal() should be invalid', () => { return Validator('0123456789abcdefABCDEF', 'ISKVRZLVNB').not.hexadecimal().resolve() .should.rejectedWith(Errors.invalidFormat.class); }); }); describe('Base64', () => { it('Validator(\'0123456789azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN=\').base64() should be valid', () => { return Validator('0123456789azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN=').base64().resolve() .should.fulfilled; }); it('Validator(\'132\').base64() should be invalid', () => { return Validator('132', 'ISKVRZLVNB').base64().resolve() .should.rejectedWith(Errors.invalidFormat.class); }); it('Validator(\'132\').not.base64() should be valid', () => { return Validator('0123456789 abcdef ABCDEF').not.base64().resolve() .should.fulfilled; }); it('Validator(\'0123456789azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN=\').not.base64() should be invalid', () => { return Validator('0123456789azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN=', 'ISKVRZLVNB').not.base64().resolve() .should.rejectedWith(Errors.invalidFormat.class); }); }); describe('URL', () => { it('Validator(\'www.google.com\').url() should be valid', () => { return Validator('www.google.com').url().resolve() .should.fulfilled; }); it('Validator(\'www.goog le.com\').url() should be invalid', () => { return Validator('www.goog le.com', 'ISKVRZLVNB').url().resolve() .should.rejectedWith(Errors.invalidFormat.class); }); it('Validator(\'www.go=ogle.com\').not.url() should be valid', () => { return Validator('www.go=ogle.com').not.url().resolve() .should.fulfilled; }); it('Validator(\'www.google.com\').not.url() should be invalid', () => { return Validator('www.google.com', 'ISKVRZLVNB').not.url().resolve() .should.rejectedWith(Errors.invalidFormat.class); }); }); describe('Integer', () => { it('Validator(1).integer() should be valid', () => { Validator(1).integer().try(); }); it('Validator(2.4).integer() should be invalid', () => { const identifier = getIdentifier(); try { Validator(2.4, identifier).integer().try(); expect.fail(null, null, 'Should throws'); } catch (error) { expect(error).instanceOf(Errors.invalidFormat.class); expect(error).property('parameters').a('object'); expect(error.parameters).property('name').equal(identifier); expect(error.parameters).property('value').equal('2.4'); expect(error.parameters).property('format').equal('Integer'); } }); it('Validator(3.14).not.integer() should be valid', () => { Validator(3.14).not.integer().try(); }); it('Validator(42).not.integer() should be invalid', () => { const identifier = getIdentifier(); try { Validator(42, identifier).not.integer().try(); expect.fail(null, null, 'Should throws'); } catch (error) { expect(error).instanceOf(Errors.invalidFormat.class); expect(error).property('parameters').a('object'); expect(error.parameters).property('name').equal(identifier); expect(error.parameters).property('value').equal('42'); expect(error.parameters).property('format').equal('!Integer'); } }); }); describe('Array', () => { it('Validator([ ]).array() should be valid', () => { Validator([]).array().try(); }); it('Validator({ }).array() should be invalid', () => { const identifier = getIdentifier(); try { Validator({}, identifier).array().try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsInvalidType(error, identifier, 'Object', 'Array'); } }); it('Validator({ }).not.array() should be valid', () => { Validator({}).not.array().try(); }); it('Validator([ ]).not.array() should be invalid', () => { const identifier = getIdentifier(); try { Validator([], identifier).not.array().try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsInvalidType(error, identifier, 'Array', '!Array'); } }); }); describe('Length', () => { it('Validator().length() should throws invalid type', () => { try { Validator().length(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsInvalidType(error, 'length.arg', 'undefined', '[ Number, Function ]'); } }); it('Validator([ ]).length(0) should be valid', () => { Validator([]).length(0).try(); }); it('Validator([ 1, 2, 3 ]).length(0) should be invalid', () => { const identifier = getIdentifier(); try { Validator([ 1, 2, 3 ], identifier).length(0).try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIdInvalid(error, identifier); expect(error.cause).instanceOf(Errors.notEqual.class); expect(error.cause).property('parameters').a('object'); expect(error.cause.parameters).property('name').equal(`${identifier}.length`); expect(error.cause.parameters).property('actualValue').equal('3'); expect(error.cause.parameters).property('expectedValue').equal('0'); } }); it('Validator([ ]).not.length(3) should be valid', () => { Validator([]).not.length(3).try(); }); it('Validator([ 1, 2, 3 ]).not.length(3) should be invalid', () => { const identifier = getIdentifier(); try { Validator([ 1, 2, 3 ], identifier).not.length(3).try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIdInvalid(error, identifier); expect(error.cause).instanceOf(Errors.equal.class); expect(error.cause).property('parameters').a('object'); expect(error.cause.parameters).property('name').equal(`${identifier}.length`); expect(error.cause.parameters).property('value').equal('3'); } }); it('Validator([ 1, 2, 3 ]).not.length(vLength => vLength) should throws invalid modifier use', () => { try { Validator([ 1, 2, 3 ]).not.length((vLength) => vLength); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error, '"keys" should not be use with not modifier'); } }); it('Validator([ 1, 2, 3 ]).length(vLength => vLength.greaterThan(0).lowerThan(10)) should be valid', () => { Validator([ 1, 2, 3 ]).length((vLength) => vLength.greaterThan(0).lowerThan(10)).try(); }); it('Validator([ 1, 2, 3 ]).length(vLength => vLength.string()) should be invalid', () => { const identifier = getIdentifier(); try { Validator([ 1, 2, 3 ], identifier).length((vLength) => vLength.string()).try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIdInvalid(error, identifier); assertErrorIsInvalidType(error.cause, `${identifier}.length`, 'Number', 'String'); } }); }); describe('Each', () => { it('Should throws error if using not modifier', () => { try { Validator([ true ]).not.each((vItem) => vItem.exist()); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error, '"each" should not be use with not modifier'); } }); it('Should allow chain on invalid validator', () => { const identifier = getIdentifier(); try { Validator(12, identifier).array().each((child) => child.number()).try(); } catch (error) { assertErrorIsInvalidType(error, identifier, 'Number', 'Array'); } }); it('Should validate on each array item', () => { Validator([ 1, 2, 3 ]).array().each((child) => child.instance('Number')).try(); }); it('Should not validate on each array item', () => { const identifier = getIdentifier(); try { Validator([ 1, false, 3 ], identifier).array().each((child) => child.instance('Number')).try(); } catch (error) { assertErrorIdInvalid(error, identifier); assertErrorIsInvalidType(error.cause, `${identifier}[1]`, 'Boolean', 'Number'); } }); // TODO throwing apply function }); describe('Keys', () => { it('Should throws error if using not modifier', () => { try { Validator({ key: true }).not.keys('key'); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error, '"keys" should not be use with not modifier'); } }); it('Should throws error if invalid parameters', () => { try { Validator({}).keys(47).try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error); assertErrorIsInvalidType(error.cause, 'appliers[0]', 'Number', 'String|Object'); } }); it('Should throws error if invalid parameters', () => { try { Validator({}).keys({ key: 3 }).try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error); assertErrorIsInvalidType(error.cause, 'appliers[0].key', 'Number', 'String'); } }); it('Should throws error if invalid parameters', () => { try { Validator({}).keys({ key: 'key', optional: 'false' }).try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error); assertErrorIsInvalidType(error.cause, 'appliers[0].optional', 'String', 'Boolean'); } }); it('Should throws error if invalid parameters', () => { try { Validator({}).keys({ key: 'key', chain: 'false' }).try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error); assertErrorIsInvalidType(error.cause, 'appliers[0].chain', 'String', 'Function'); } }); it('Should allow chain on invalid validator', () => { const identifier = getIdentifier(); try { Validator(null, identifier).object().keys('test').try(); } catch (error) { assertErrorIsInvalidType(error, identifier, 'undefined', 'Object'); } }); it('Should validate single key label', () => { try { Validator({ a: 12 }).keys('a').try(); } catch (error) { expect.fail(null, null, `Should not throws ${error}`); } }); it('Should not validate single key label', () => { const identifier = getIdentifier(); try { Validator({}, identifier).keys('a').try(); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIdInvalid(error, identifier); expect(error.cause).instanceOf(Errors.doesntExist.class); expect(error.cause).property('tag').equal('DOESNT_EXIST'); expect(error.cause).property('parameters').a('object').property('name').equal(`${identifier}.a`); } }); it('Should validate single key', () => { try { Validator({ age: 37 }).keys({ key: 'age', chain: (vAge) => vAge.number().integer().greaterThan(0).not.greaterThan(130) }).try(); } catch (error) { expect.fail(null, null, `Should not throws ${error}`); } }); it('Should validate optional key', () => { try { Validator({}).keys({ key: 'id', optional: true }).try(); } catch (error) { expect.fail(null, null, `Should not throws ${error}`); } }); it('Should invalidate optional key', () => { const identifier = getIdentifier(); try { Validator({ id: '87' }, identifier).keys({ key: 'id', optional: true, chain: (vId) => vId.number().integer().greaterThan(0) }).try(); expect.fail(null, null, 'Should throw'); } catch (error) { assertErrorIdInvalid(error, identifier); assertErrorIsInvalidType(error.cause, `${identifier}.id`, 'String', 'Number'); } }); it('Should validate multiple properties', () => { try { const obj = { id: 12, name: 'john', data: { amount: 27, enabled: true } }; Validator(obj).keys( { key: 'id', chain: (vId) => vId.number().not.equal(0) }, { key: 'name', chain: (vName) => vName.string().startsWith('j') }, { key: 'data', chain: (vData) => vData.object().keys( { key: 'amount', chain: (vAmount) => vAmount.number() }, { key: 'enabled', chain: (vEnabled) => vEnabled.boolean() }, ), }, ).try(); } catch (error) { expect.fail(null, null, `Should not throws ${error}`); } }); it('Should not validate multiple properties', () => { const identifier = getIdentifier(); try { const obj = { id: 12, name: 'john', data: { amount: '27', enabled: true } }; Validator(obj, identifier).keys( { key: 'id', chain: (vId) => vId.number().not.equal(0) }, { key: 'name', chain: (vName) => vName.string().startsWith('j') }, { key: 'data', chain: (vData) => vData.object().keys( { key: 'amount', chain: (vAmount) => vAmount.number() }, { key: 'enabled', chain: (vEnabled) => vEnabled.boolean() }, ), }, ).try(); expect.fail(null, null, 'Should throw'); } catch (error) { assertErrorIdInvalid(error, identifier); assertErrorIdInvalid(error.cause, `${identifier}.data`); assertErrorIsInvalidType(error.cause.cause, `${identifier}.data.amount`, 'String', 'Number'); } }); it('Should validate multiple properties with optional', () => { try { const obj = { id: 12, name: 'john', data: { amount: 27 } }; Validator(obj).keys( { key: 'id', chain: (vId) => vId.number().not.equal(0) }, { key: 'name', chain: (vName) => vName.string().startsWith('j') }, { key: 'data', chain: (vData) => vData.object().keys( { key: 'amount', chain: (vAmount) => vAmount.number() }, { key: 'enabled', optional: true, chain: (vEnabled) => vEnabled.boolean() }, ), }, ).try(); } catch (error) { expect.fail(null, null, `Should not throws ${error}`); } }); it('Should invalidate multiple properties with optional', () => { const identifier = getIdentifier(); try { const obj = { id: 12, name: 'john', data: { amount: 27, enabled: 'false' } }; Validator(obj, identifier).keys( { key: 'id', chain: (vId) => vId.number().not.equal(0) }, { key: 'name', chain: (vName) => vName.string().startsWith('j') }, { key: 'data', chain: (vData) => vData.object().keys( { key: 'amount', chain: (vAmount) => vAmount.number() }, { key: 'enabled', optional: true, chain: (vEnabled) => vEnabled.boolean() }, ), }, ).try(); expect.fail(null, null, 'Should throw'); } catch (error) { assertErrorIdInvalid(error, identifier); assertErrorIdInvalid(error.cause, `${identifier}.data`); assertErrorIsInvalidType(error.cause.cause, `${identifier}.data.enabled`, 'String', 'Boolean'); } }); it('Should invalidate multiple properties with optional', () => { const identifier = getIdentifier(); try { const obj = { id: '12', name: 'john', data: { amount: 27 } }; Validator(obj, identifier).keys( { key: 'id', chain: (vId) => vId.number().not.equal(0) }, { key: 'name', chain: (vName) => vName.string().startsWith('j') }, { key: 'data', chain: (vData) => vData.object().keys( { key: 'amount', chain: (vAmount) => vAmount.number() }, { key: 'enabled', chain: (vEnabled) => vEnabled.boolean() }, ), }, ).try(); expect.fail(null, null, 'Should throw'); } catch (error) { assertErrorIdInvalid(error, identifier); expect(error).property('cause').a('array'); expect(error.cause.length).equal(2); assertErrorIsInvalidType(error.cause[0], `${identifier}.id`, 'String', 'Number'); assertErrorIdInvalid(error.cause[1], `${identifier}.data`); assertErrorIsInvalidType(error.cause[1].cause, `${identifier}.data.enabled`, 'undefined', 'Boolean'); } }); it('Should ignore falsy args', () => { try { Validator({}).keys('', null, false).try(); } catch (error) { expect.fail(null, null, `Should not throws ${error}`); } }); // TODO throwing apply function // TODO invalid params inside Chain }); describe('Or switch', () => { it('Should throws error if parameters arn\'t functions', () => { try { Validator().or('coucou'); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIdInvalid(error, 'or.args'); assertErrorIsInvalidType(error.cause, 'or.args[0]', 'String', 'Function'); } }); it('Should throws error if using not modifier', () => { try { Validator(12).not.or((v) => v.number()); expect.fail(null, null, 'Should throws'); } catch (error) { assertErrorIsProgramingFault(error, '"or" should not be use with not modifier'); } }); it('Should allow chain on invalid validator', () => { const validator = Validator(null).array(); expect(validator.isValid).equal(false); expect(validator.or((v) => v.each((vItem) => vItem.number()), (v) => v.each((vItem) => vItem.string())).isValid).equal(false); }); it('Should not allow 12 being string or object ', () => { const parent = Validator(12).or( (v) => v.object(), (v) => v.string(), ); expect(parent.isValid).equal(false); }); it('Should allow 12 being string or number ', () => { const parent = Validator(12).or( (v) => v.type('number'), (v) => v.type('string'), ); expect(parent.isValid).equal(true); }); }); describe('Middlewares', () => { const req = { body: { } }; const res = { }; const keys = [ { key: 'label', chain: (vLabel) => vLabel.string() }, { key: 'enabled', optional: true, chain: (vEnabled) => vEnabled.boolean() }, { key: 'quantity', optional: true, chain: (vQuantity) => vQuantity.or((vQ) => vQ.equal(null), (vQ) => vQ.integer()) }, ]; describe('Express', () => { it('Should be proxy to validate body keys. Valid path', () => { const mw = Validator.mw.express.body(...keys); const keysStub = sinon.stub(Validator.class.prototype, 'keys').callsFake(function l(...args) { expect(this).property('value').equal(req.body); expect(this).property('name').equal('body'); expect(args).deep.equal(keys); return { resolve: () => Bluebird.resolve() }; }); return new Bluebird((resolve, reject) => { return mw(req, res, (error) => { try { expect(error).equal(undefined); return resolve(); } catch (err) { return reject(err); } }); }).finally(() => keysStub.restore()); }); it('Should be proxy to validate body keys. Invalid path', () => { const error = new Error(); const mw = Validator.mw.express.body(...keys); const keysStub = sinon.stub(Validator.class.prototype, 'keys').callsFake(function l(...args) { expect(this).property('value').equal(req.body); expect(this).property('name').equal('body'); expect(args).deep.equal(keys); return { resolve: () => Bluebird.reject(error) }; }); return new Bluebird((resolve, reject) => { return mw(req, res, (errorArg) => { try { expect(errorArg).equal(error); return resolve(); } catch (err) { return reject(err); } }); }).finally(() => keysStub.restore()); }); }); describe('Koa', () => { it('Should be proxy to validate body keys. Valid path', () => { const mw = Validator.mw.koa.body(...keys); const keysStub = sinon.stub(Validator.class.prototype, 'keys').callsFake(function l(...args) { expect(this).property('value').equal(req.body); expect(this).property('name').equal('body'); expect(args).deep.equal(keys); return { resolve: () => Bluebird.resolve() }; }); return mw({ req, res }, async (errorArg) => { expect(errorArg).equal(undefined); }).finally(() => keysStub.restore()); }); it('Should be proxy to validate body keys. Invalid path', () => { const error = new Error(); const mw = Validator.mw.koa.body(...keys); const keysStub = sinon.stub(Validator.class.prototype, 'keys').callsFake(function l(...args) { expect(this).property('value').equal(req.body); expect(this).property('name').equal('body'); expect(args).deep.equal(keys); return { resolve: () => Bluebird.reject(error) }; }); return mw({ req, res }, async () => null).should.rejectedWith(error).then(() => keysStub.restore()); }); }); });