input-data-validator
Advanced tools
| /* global describe it expect */ | ||
| const Validator = require('../../lib/class/Validator') | ||
| const { Field } = require('field-creator') | ||
| const express = require('express') | ||
| const request = require('request') | ||
| const bodyParser = require('body-parser') | ||
| const PORT = 9001 | ||
| describe('\n - Validaciones con objetos de tipo FieldGroup\n', () => { | ||
| describe(` Valores requeridos (AllowNull).`, () => { | ||
| let input, body | ||
| it('Objeto con campos de tipo FIELD', async () => { | ||
| input = { | ||
| a: { | ||
| titulo : Field.STRING(), | ||
| precio : Field.FLOAT() | ||
| }, | ||
| b: { | ||
| titulo : Field.STRING({ allowNull: false }), | ||
| precio : Field.FLOAT() | ||
| } | ||
| } | ||
| // Fallas por el tipo de dato | ||
| body = await _request(input.a, []) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.b, []) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, {}) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, {}) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, { titulo: 'ABC' }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { titulo: 'ABC' }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| }) | ||
| it('Array de objetos con campos de tipo FIELD', async () => { | ||
| input = { | ||
| a: [{ | ||
| titulo : Field.STRING(), | ||
| precio : Field.FLOAT() | ||
| }], | ||
| b: [{ | ||
| titulo : Field.STRING({ allowNull: false }), | ||
| precio : Field.FLOAT() | ||
| }] | ||
| } | ||
| // Fallas por el tipo de dato | ||
| body = await _request(input.a, {}) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.b, {}) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, []) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, []) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.a, [{}]) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, [{}]) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, [{ titulo: 'ABC' }]) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, [{ titulo: 'ABC' }]) | ||
| expect(body).to.have.property('status', 'OK') | ||
| }) | ||
| it('Objeto con campos de tipo OBJECT Nivel 1', async () => { | ||
| input = { | ||
| a: { | ||
| autor : { nombre: Field.STRING() }, | ||
| premio : { titulo: Field.STRING() } | ||
| }, | ||
| b: { | ||
| autor : { nombre: Field.STRING({ allowNull: false }) }, | ||
| premio : { titulo: Field.STRING() } | ||
| } | ||
| } | ||
| body = await _request(input.a, {}) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, {}) | ||
| expect(body).to.have.property('status', 'OK') | ||
| // Fallas por el tipo de dato | ||
| body = await _request(input.a, { autor: [] }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.b, { autor: [] }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, { autor: {} }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: {} }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, { autor: { nombre: 'John' } }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: { nombre: 'John' } }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| }) | ||
| it('Objeto con campos de tipo ARRAY Nivel 1', async () => { | ||
| input = { | ||
| a: { | ||
| autor : [{ nombre: Field.STRING() }], | ||
| premio : [{ titulo: Field.STRING() }] | ||
| }, | ||
| b: { | ||
| autor : [{ nombre: Field.STRING({ allowNull: false }) }], | ||
| premio : [{ titulo: Field.STRING() }] | ||
| } | ||
| } | ||
| body = await _request(input.a, {}) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, {}) | ||
| expect(body).to.have.property('status', 'OK') | ||
| // Fallas por el tipo de dato | ||
| body = await _request(input.a, { autor: {} }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.b, { autor: {} }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, { autor: [] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: [] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.a, { autor: [{}] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: [{}] }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, { autor: [{ nombre: 'John' }] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: [{ nombre: 'John' }] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| }) | ||
| it('Objeto con campos de tipo OBJECT Nivel 2', async () => { | ||
| input = { | ||
| a: { | ||
| autor : { persona: { nombre: Field.STRING() } }, | ||
| ilustrador : { persona: { nombre: Field.STRING() } } | ||
| }, | ||
| b: { | ||
| autor : { persona: { nombre: Field.STRING({ allowNull: false }) } }, | ||
| ilustrador : { persona: { nombre: Field.STRING() } } | ||
| } | ||
| } | ||
| body = await _request(input.a, {}) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, {}) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.a, { autor: {} }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: {} }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.a, { autor: { persona: {} } }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: { persona: {} } }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, { autor: { persona: { nombre: 'John' } } }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: { persona: { nombre: 'John' } } }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| }) | ||
| it('Objeto con campos de tipo ARRAY Nivel 2', async () => { | ||
| input = { | ||
| a: { | ||
| autor : [{ persona: { nombre: Field.STRING() } }], | ||
| ilustrador : [{ persona: { nombre: Field.STRING() } }] | ||
| }, | ||
| b: { | ||
| autor : [{ persona: { nombre: Field.STRING({ allowNull: false }) } }], | ||
| ilustrador : [{ persona: { nombre: Field.STRING() } }] | ||
| } | ||
| } | ||
| body = await _request(input.a, {}) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, {}) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.a, { autor: [] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: [] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.a, { autor: [{}] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: [{}] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| // Fallas por el tipo de dato | ||
| body = await _request(input.a, { autor: [{ persona: [] }] }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.b, { autor: [{ persona: [] }] }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, { autor: [{ persona: {} }] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: [{ persona: {} }] }) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| body = await _request(input.a, { autor: [{ persona: { nombre: 'John' } }] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| body = await _request(input.b, { autor: [{ persona: { nombre: 'John' } }] }) | ||
| expect(body).to.have.property('status', 'OK') | ||
| }) | ||
| }) | ||
| }) | ||
| function _request (inputBody, data) { | ||
| let options = { | ||
| uri : `http://localhost:${PORT}/api`, | ||
| method : 'POST', | ||
| json : data | ||
| } | ||
| const server = _createServer({ body: inputBody }) | ||
| return new Promise((resolve, reject) => { | ||
| return request(options, (error, response, body) => { | ||
| if (error) { console.log(error); return reject(error) } | ||
| if (response.statusCode === 500) return reject(body) | ||
| server.close() | ||
| return resolve(body) | ||
| }) | ||
| }) | ||
| } | ||
| function _createServer (input) { | ||
| const app = express() | ||
| app.use(bodyParser.json()) | ||
| app.post('/api', Validator.validate(input), (req, res, next) => { | ||
| res.status(201).json({ status: 'OK', data: req.body }) | ||
| }) | ||
| app.use((err, req, res, next) => { | ||
| if (err.name === 'InputDataValidationError') { | ||
| return res.status(400).json({ status: 'FAIL', error: err }) | ||
| } | ||
| console.log(err) | ||
| return res.status(500).json({ status: 'FAIL', error: err.toString() }) | ||
| }) | ||
| return app.listen(PORT) | ||
| } |
| /* global describe it expect */ | ||
| const Validator = require('../../lib/class/Validator') | ||
| const { Field, THIS } = require('field-creator') | ||
| const Sequelize = require('sequelize') | ||
| const express = require('express') | ||
| const request = require('request') | ||
| const PARAMS = { | ||
| dialect : 'postgres', | ||
| lang : 'es', | ||
| logging : false, | ||
| define : { | ||
| underscored : true, | ||
| freezeTableName : true, | ||
| timestamps : false | ||
| }, | ||
| operatorsAliases: false | ||
| } | ||
| const PORT = 4005 | ||
| describe('\n - Clase: Validator\n', () => { | ||
| describe(' Método: constructor', () => { | ||
| it('Probando el envío de datos por demás', async () => { | ||
| let input, result | ||
| input = { | ||
| headers : { a: Field.STRING() }, | ||
| params : { a: Field.STRING() }, | ||
| query : { a: Field.STRING() }, | ||
| body : { a: Field.STRING() } | ||
| } | ||
| result = await _validarInput(input, ['headers', 'params', 'query', 'body'], { | ||
| body : { a: '1', b: '2' }, | ||
| headers : { a: '1', b: '2' }, | ||
| params : { a: '1', b: '2' }, | ||
| query : { a: '1', b: '2' } | ||
| }) | ||
| expect(result.headers).to.be.an('object') | ||
| expect(Object.keys(result.headers).length).to.equal(1) | ||
| expect(result.headers).to.have.property('a', '1') | ||
| expect(result.headers).to.not.have.property('b') | ||
| expect(result.params).to.be.an('object') | ||
| expect(Object.keys(result.params).length).to.equal(1) | ||
| expect(result.params).to.have.property('a', ':a') | ||
| expect(result.params).to.not.have.property('b') | ||
| expect(result.query).to.be.an('object') | ||
| expect(Object.keys(result.query).length).to.equal(1) | ||
| expect(result.query).to.have.property('a', '1') | ||
| expect(result.query).to.not.have.property('b') | ||
| expect(result.body).to.be.an('object') | ||
| expect(Object.keys(result.body).length).to.equal(1) | ||
| expect(result.body).to.have.property('a', '1') | ||
| expect(result.body).to.not.have.property('b') | ||
| result = await _validarInput(input, [], { | ||
| body : { a: '1', b: '2' }, | ||
| headers : { a: '1', b: '2' }, | ||
| params : { a: '1', b: '2' }, | ||
| query : { a: '1', b: '2' } | ||
| }) | ||
| expect(result.body).to.be.an('object') | ||
| expect(Object.keys(result.body).length).to.equal(2) | ||
| expect(result.body).to.have.property('a', '1') | ||
| expect(result.body).to.have.property('b', '2') | ||
| expect(result.headers).to.be.an('object') | ||
| expect(result.headers).to.have.property('a', '1') | ||
| expect(result.headers).to.have.property('b', '2') | ||
| expect(result.params).to.be.an('object') | ||
| expect(result.params).to.have.property('a', ':a') | ||
| expect(result.params).to.not.have.property('b') // Caso especial, porque al definir la url, no se tomo en cuenta este campo. | ||
| expect(result.query).to.be.an('object') | ||
| expect(result.query).to.have.property('a', '1') | ||
| expect(result.query).to.have.property('b', '2') | ||
| }) | ||
| }) | ||
| describe(' Método: isRequired', () => { | ||
| let input | ||
| it('Campos de tipo FIELD', () => { | ||
| input = { | ||
| a : Field.STRING(), | ||
| b : Field.STRING({ allowNullObj: false }) | ||
| } | ||
| expect(Validator.isRequired(input.a)).to.equal(false) | ||
| expect(Validator.isRequired(input.b)).to.equal(true) | ||
| }) | ||
| it('Campos de tipo OBJECT Nivel 1', () => { | ||
| input = { | ||
| a : { nombre: Field.STRING() }, | ||
| b : { nombre: Field.STRING({ allowNullObj: false }) } | ||
| } | ||
| expect(Validator.isRequired(input.a)).to.equal(false) | ||
| expect(Validator.isRequired(input.b)).to.equal(true) | ||
| }) | ||
| it('Campos de tipo ARRAY Nivel 1', () => { | ||
| input = { | ||
| a : [{ nombre: Field.STRING() }], | ||
| b : [{ nombre: Field.STRING({ allowNullObj: false }) }] | ||
| } | ||
| expect(Validator.isRequired(input.a)).to.equal(false) | ||
| expect(Validator.isRequired(input.b)).to.equal(true) | ||
| }) | ||
| it('Campos de tipo OBJECT Nivel 2', () => { | ||
| input = { | ||
| a : { aa: { nombre: Field.STRING() } }, | ||
| b : { bb: { nombre: Field.STRING({ allowNullObj: false }) } } | ||
| } | ||
| expect(Validator.isRequired(input.a)).to.equal(false) | ||
| expect(Validator.isRequired(input.b)).to.equal(false) | ||
| }) | ||
| it('Campos de tipo ARRAY Nivel 2', () => { | ||
| input = { | ||
| a : [{ aa: { nombre: Field.STRING() } }], | ||
| b : [{ bb: { nombre: Field.STRING({ allowNullObj: false }) } }] | ||
| } | ||
| expect(Validator.isRequired(input.a)).to.equal(false) | ||
| expect(Validator.isRequired(input.b)).to.equal(false) | ||
| }) | ||
| it('Campos de tipo OBJECT Nivel 3', () => { | ||
| input = { | ||
| a : { aa: { aaa: { nombre: Field.STRING() } } }, | ||
| b : { bb: { bbb: { nombre: Field.STRING({ allowNullObj: false }) } } } | ||
| } | ||
| expect(Validator.isRequired(input.a)).to.equal(false) | ||
| expect(Validator.isRequired(input.b)).to.equal(false) | ||
| }) | ||
| // Nota.- Al verificar se toma en cuenta los campos de de tipo FIELD de primer nivel, | ||
| // ignorando los campos de tipo OBJECT y ARRAY. | ||
| it('Campos de tipo ARRAY Nivel 3', () => { | ||
| input = { | ||
| a : [{ aa: { aaa: { nombre: Field.STRING() } } }], | ||
| b : [{ bb: { bbb: { nombre: Field.STRING({ allowNullObj: false }) } } }] | ||
| } | ||
| expect(Validator.isRequired(input.a)).to.equal(false) | ||
| expect(Validator.isRequired(input.b)).to.equal(false) | ||
| }) | ||
| }) | ||
| describe(` Método: validate con el tipo de dato STRING.`, () => { | ||
| it('Validate con un modelo Sequelize', async () => { | ||
| const sequelize = new Sequelize(null, null, null, PARAMS) | ||
| const LIBRO = sequelize.define('libro', { | ||
| id : Field.ID(), | ||
| titulo : Field.STRING({ allowNull: false, allowNullMsg: `Se requiere el título.` }), | ||
| precio : Field.FLOAT({ validate: { min: { args: [0], msg: `El precio debe ser mayor o igual a 0.` } } }) | ||
| }) | ||
| const INPUT = { body: Field.group(LIBRO, { titulo: THIS(), precio: THIS() }) } | ||
| const server = await _createServer(INPUT) | ||
| let options = { | ||
| uri : `http://localhost:${PORT}/api`, | ||
| method : 'POST', | ||
| json : { id: 123, titulo: 'El cuervo', precio: 11.99 } | ||
| } | ||
| let body = await _request(options) | ||
| expect(body).to.have.property('status', 'OK') | ||
| expect(body).to.have.property('data') | ||
| expect(Object.keys(body.data).length).to.equal(2) | ||
| expect(body.data).to.have.property('titulo', options.json.titulo) | ||
| expect(body.data).to.have.property('precio', options.json.precio) | ||
| options.json = { precio: -124 } | ||
| body = await _request(options) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| expect(body).to.have.property('error') | ||
| expect(body.error).to.be.an('object') | ||
| expect(body.error.name).to.equal('InputDataValidationError') | ||
| expect(body.error.errors).to.be.an('array') | ||
| const errors = body.error.errors | ||
| expect(errors).to.have.lengthOf(2) | ||
| expect(errors[0]).to.have.property('path') | ||
| expect(errors[0]).to.have.property('value') | ||
| expect(errors[0]).to.have.property('msg') | ||
| server.close() | ||
| }) | ||
| it('Validate STRING [is] 1ra Forma', async () => { | ||
| const CH1 = 'abcABC' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('is', ['^[a-z]+$', 'i'], [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [is] 2da Forma', async () => { | ||
| const CH1 = 'abcABC' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('is', /^[a-z]+$/i, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [not]', async () => { | ||
| const CH1 = '_#-*@?' | ||
| const CH2 = 'abcABC' | ||
| await _validar('not', ['[a-z]', 'i'], [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isEmail]', async () => { | ||
| await _validar('isEmail', true, ['administrador@gmail.com', 'gmailuse6charactersmin@gmail.com', 'other@example.com'], ['min6@gmail.com', 's4*-sd.cdsc']) | ||
| }) | ||
| it('Validate STRING [isUrl]', async () => { | ||
| await _validar('isUrl', true, ['http://foo.com'], ['other-value']) | ||
| }) | ||
| it('Validate STRING [isIP]', async () => { | ||
| await _validar('isIP', true, ['129.89.23.1', 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329'], ['other-value']) | ||
| }) | ||
| it('Validate STRING [isIPv4]', async () => { | ||
| await _validar('isIPv4', true, ['129.89.23.1'], ['other-value', 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329']) | ||
| }) | ||
| it('Validate STRING [isIPv6]', async () => { | ||
| await _validar('isIPv6', true, ['FE80:0000:0000:0000:0202:B3FF:FE1E:8329'], ['other-value', '129.89.23.1']) | ||
| }) | ||
| it('Validate STRING [isAlpha]', async () => { | ||
| const CH1 = 'abcABC' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('isAlpha', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isAlphanumeric]', async () => { | ||
| const CH1 = 'abcABC1234567890' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('isAlphanumeric', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isNumeric]', async () => { | ||
| const CH1 = '1234567890' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('isNumeric', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isInt]', async () => { | ||
| await _validar('isInt', true, [2147483647], [21474836483423423234234234234523423449]) | ||
| }) | ||
| it('Validate STRING [isFloat]', async () => { | ||
| await _validar('isFloat', true, [1.4, '1.4'], ['1.4.5']) | ||
| }) | ||
| it('Validate STRING [isDecimal]', async () => { | ||
| await _validar('isDecimal', true, [10, 2.0, 3.2342342], ['10.5.3']) | ||
| }) | ||
| it('Validate STRING [isLowercase]', async () => { | ||
| const CH1 = 'abc' | ||
| const CH2 = 'ABC' | ||
| await _validar('isLowercase', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isUppercase]', async () => { | ||
| const CH1 = 'ABC' | ||
| const CH2 = 'abc' | ||
| await _validar('isUppercase', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isNull]', async () => { | ||
| await _validar('isNull', true, [null], ['not-null', 'null']) | ||
| }) | ||
| it('Validate STRING [notEmpty]', async () => { | ||
| await _validar('notEmpty', true, ['not-empty'], ['']) | ||
| }) | ||
| it('Validate STRING [equals]', async () => { | ||
| await _validar('equals', 'ABC', ['ABC'], ['otro-valor']) | ||
| }) | ||
| it('Validate STRING [contains]', async () => { | ||
| await _validar('contains', 'word', ['contiene la palabra word'], ['no contiene la palabra']) | ||
| }) | ||
| it('Validate STRING [notIn]', async () => { | ||
| await _validar('notIn', [['foo', 'bar']], ['other', 'word'], ['foo', 'bar']) | ||
| }) | ||
| it('Validate STRING [isIn]', async () => { | ||
| await _validar('isIn', [['foo', 'bar']], ['foo', 'bar'], ['other', 'word']) | ||
| }) | ||
| it('Validate STRING [len]', async () => { | ||
| await _validar('len', [10, 100], [randStr(10), randStr(100)], [randStr(9), randStr(101)]) | ||
| }) | ||
| it('Validate STRING [isUUID]', async () => { | ||
| await _validar('isUUID', 4, ['15dab328-07dc-4400-a5ea-55f836c40f31'], ['other-value']) | ||
| }) | ||
| it('Validate STRING [isDate]', async () => { | ||
| await _validar('isDate', true, ['2018-07-30', '2018-07-30 08:10:30'], ['other-value', '30/07/2018']) | ||
| }) | ||
| it('Validate STRING [isAfter]', async () => { | ||
| await _validar('isAfter', '2010-05-30', ['2010-06-30'], ['2010-04-30']) | ||
| }) | ||
| it('Validate STRING [isBefore]', async () => { | ||
| await _validar('isBefore', '2010-05-30', ['2010-04-30'], ['2010-06-30']) | ||
| }) | ||
| it('Validate STRING [min]', async () => { | ||
| await _validar('min', 10, [10, 20, 30], [0, 1, 2, 9]) | ||
| }) | ||
| it('Validate STRING [max]', async () => { | ||
| await _validar('max', 10, [0, 1, 2, 10], [11, 20, 30]) | ||
| }) | ||
| it('Validate STRING [isCreditCard]', async () => { | ||
| await _validar('isCreditCard', true, ['4539029473077866'], ['other-value', '0000000000000000']) | ||
| }) | ||
| it('Validate STRING [custom]', async () => { | ||
| await _validar('esPar', (value) => { if (parseInt(value) % 2 !== 0) { throw new Error(`Debe ser un número par.`) } }, [2, 4, 6], [1, 3, 5]) | ||
| }) | ||
| }) | ||
| describe(` Método: validate con diferentes tipos de datos.`, () => { | ||
| it('Validate STRING', async () => { | ||
| await _validar('_custom', () => {}, [randStr(0), randStr(255)], [randStr(256)], Field.STRING()) | ||
| await _validar('_custom', () => {}, [randStr(0), randStr(100)], [randStr(101)], Field.STRING(100)) | ||
| await _validar('_custom', () => {}, [randStr(10), randStr(100)], [randStr(9), randStr(101)], Field.STRING(100, { validate: { len: [10, 100] } })) | ||
| }) | ||
| it('Validate TEXT', async () => { | ||
| await _validar('_custom', () => {}, [randStr(0), randStr(900)], [], Field.TEXT()) | ||
| await _validar('_custom', () => {}, [randStr(10), randStr(100)], [randStr(9), randStr(101)], Field.TEXT({ validate: { len: [10, 100] } })) | ||
| }) | ||
| it('Validate INTEGER', async () => { | ||
| await _validar('_custom', () => {}, [0, 2147483647], [-1, 2147483648], Field.INTEGER()) | ||
| await _validar('_custom', () => {}, [-10, 0, 2147483647], [-11, 2147483648], Field.INTEGER({ validate: { min: -10 } })) | ||
| await _validar('_custom', () => {}, [0, 100], [-1, 101], Field.INTEGER({ validate: { max: 100 } })) | ||
| }) | ||
| it('Validate FLOAT', async () => { | ||
| await _validar('_custom', () => {}, [0.0], [-1.5], Field.FLOAT()) | ||
| await _validar('_custom', () => {}, [-10.49], [-10.51], Field.FLOAT({ validate: { min: -10.5 } })) | ||
| await _validar('_custom', () => {}, [100.5], [100.51], Field.FLOAT({ validate: { max: 100.5 } })) | ||
| }) | ||
| it('Validate BOOLEAN', async () => { | ||
| await _validar('_custom', () => {}, [true, false, 1, 0, 'true', 'false', '1', '0'], ['other', 'TRUE', 'FALSE'], Field.BOOLEAN()) | ||
| }) | ||
| it('Validate DATE', async () => { | ||
| await _validar('_custom', () => {}, ['2018-07-30'], ['30/07/2018'], Field.DATE()) | ||
| }) | ||
| it('Validate DATEONLY', async () => { | ||
| await _validar('_custom', () => {}, ['2018-07-30'], ['30/07/2018'], Field.DATEONLY()) | ||
| }) | ||
| it('Validate TIME', async () => { | ||
| await _validar('_custom', () => {}, ['08:12:00'], ['other', '05', '05:30'], Field.TIME()) | ||
| }) | ||
| it('Validate JSON', async () => { | ||
| await _validar('_custom', () => {}, [{ msg: 'Hola' }, {}, ['a', 'b'], []], ['other'], Field.JSON()) | ||
| }) | ||
| it('Validate JSONB', async () => { | ||
| await _validar('_custom', () => {}, [{ msg: 'Hola' }, {}, ['a', 'b'], []], ['other'], Field.JSONB()) | ||
| }) | ||
| it('Validate UUID', async () => { | ||
| await _validar('_custom', () => {}, ['15dab328-07dc-4400-a5ea-55f836c40f31'], ['other'], Field.UUID()) | ||
| }) | ||
| it('Validate ENUM', async () => { | ||
| await _validar('_custom', () => {}, ['A', 'B'], ['C', 'D'], Field.ENUM(['A', 'B'])) | ||
| }) | ||
| }) | ||
| }) | ||
| async function _validar (validatorName, validatorValue, validData = [], invalidData = [], FIELD) { | ||
| const VALIDATE = {} | ||
| VALIDATE[validatorName] = validatorValue | ||
| const INPUT = { | ||
| body: { | ||
| single : FIELD || Field.STRING({ validate: VALIDATE }), | ||
| array : Field.ARRAY(FIELD || Field.STRING({ validate: VALIDATE })) | ||
| } | ||
| } | ||
| // console.log(require('util').inspect(INPUT.body.single.validate, { depth: null }), 'VALID =', validData) | ||
| // console.log(require('util').inspect(INPUT.body.single.validate, { depth: null }), 'INVALID =', invalidData) | ||
| const server = await _createServer(INPUT) | ||
| let options = { | ||
| uri : `http://localhost:${PORT}/api`, | ||
| method : 'POST' | ||
| } | ||
| for (let i in validData) { | ||
| options.json = { single: validData[i], array: [validData[i]] } | ||
| // console.log(' data [OK]: ', options.json) | ||
| const body = await _request(options) | ||
| // console.log(body); | ||
| expect(body).to.have.property('status', 'OK') | ||
| } | ||
| for (let i in invalidData) { | ||
| options.json = { single: invalidData[i], array: [invalidData[i]] } | ||
| // console.log(' data [FAIL]: ', options.json) | ||
| const body = await _request(options) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| expect(body.error).to.have.property('name', 'InputDataValidationError') | ||
| } | ||
| await server.close() | ||
| } | ||
| async function _validarInput (input, inputOptions = ['body'], data) { | ||
| const server = await _createServer(input, { remove: inputOptions }) | ||
| let options = { | ||
| uri : `http://localhost:${PORT}/api`, | ||
| method : 'POST', | ||
| headers : data.headers, | ||
| json : data.body, | ||
| qs : data.query | ||
| } | ||
| if (input.params) { Object.keys(input.params).forEach(key => { options.uri += `/:${key}` }) } | ||
| if (data.params) { Object.keys(data.params).forEach(key => { options.uri.replace(`:${key}`, data.params[key]) }) } | ||
| const body = await _request(options) | ||
| await server.close() | ||
| return body.req | ||
| } | ||
| async function _createServer (INPUT, inputOptions = { remove: ['body'] }) { | ||
| const app = express() | ||
| let uri = '/api' | ||
| if (INPUT.params) { Object.keys(INPUT.params).forEach(key => { uri += `/:${key}` }) } | ||
| app.post(uri, Validator.validate(INPUT, inputOptions), (req, res, next) => { | ||
| const REQ = { headers: req.headers, params: req.params, query: req.query, body: req.body } | ||
| res.status(201).json({ status: 'OK', data: req.body, req: REQ }) | ||
| }) | ||
| app.post('/api', Validator.validate(INPUT, inputOptions), (req, res, next) => { | ||
| const REQ = { headers: req.headers, params: req.params, query: req.query, body: req.body } | ||
| res.status(201).json({ status: 'OK', data: req.body, req: REQ }) | ||
| }) | ||
| app.use((req, res, next) => { | ||
| return res.status(404).json({ status: 'FAIL' }) | ||
| }) | ||
| app.use((err, req, res, next) => { | ||
| if (err.name === 'InputDataValidationError') { | ||
| return res.status(400).json({ status: 'FAIL', error: err }) | ||
| } | ||
| console.log(err) | ||
| return res.status(500).json({ status: 'FAIL', error: err.toString() }) | ||
| }) | ||
| return app.listen(PORT) | ||
| } | ||
| function _request (options) { | ||
| return new Promise((resolve, reject) => { | ||
| return request(options, (error, response, body) => { | ||
| if (error) { console.log(error); return reject(error) } | ||
| if (typeof body === 'string') body = JSON.parse(body) | ||
| if (response.statusCode === 500) return reject(body) | ||
| return resolve(body) | ||
| }) | ||
| }) | ||
| } | ||
| function randStr (min, max, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') { | ||
| let str = '' | ||
| for (let i = 1; i <= randInt(min, max); i++) { | ||
| const index = randInt(0, chars.length - 1) | ||
| str += chars.charAt(index) | ||
| } | ||
| return str | ||
| } | ||
| function randInt (min, max) { | ||
| if (!max) max = min | ||
| return Math.floor(Math.random() * (max - min + 1)) + min | ||
| } |
+130
-56
@@ -14,6 +14,9 @@ /** @ignore */ const handlebars = require('handlebars') | ||
| * Devuelve un middleware para Validar los datos de entrada. | ||
| * @param {Object} input - Objeto input. | ||
| * @param {Object} input - Objeto input. | ||
| * @param {Object} options - Opciones de configuración. | ||
| * @param {String[]} options.remove - Contiene los campos que serán removidos si no han sdo especificados en el input. | ||
| * @return {Function} | ||
| */ | ||
| static validate (input) { | ||
| static validate (input, options = {}) { | ||
| options.remove = options.remove || ['body'] | ||
| Validator.ERROR_MSG = require(path.resolve(__dirname, `./../lang/${Validator.LANGUAJE}.js`)).errors | ||
@@ -37,3 +40,7 @@ if (!input) { | ||
| if (result.query) Object.keys(result.query).forEach(key => { req.query[key] = result.query[key] }) | ||
| req.body = result.body | ||
| if (result.body) Object.keys(result.body).forEach(key => { req.body[key] = result.body[key] }) | ||
| if (options.remove.includes('headers')) req.headers = result.headers | ||
| if (options.remove.includes('params')) req.params = result.params | ||
| if (options.remove.includes('query')) req.query = result.query | ||
| if (options.remove.includes('body')) req.body = result.body | ||
| next() | ||
@@ -44,2 +51,20 @@ } catch (err) { next(err) } | ||
| } | ||
| /** | ||
| * Indica si un objeto es requerido o no. | ||
| * Si alguno de sus campos contiene la propiedad allowNullObj igual a false, el objeto será requerido. | ||
| * @param {Object} obj - Objeto de tipo FieldGroup. | ||
| * @return {Boolean} | ||
| */ | ||
| static isRequired (obj) { | ||
| if (_isField(obj)) { return (typeof obj.allowNullObj !== 'undefined') && (obj.allowNullObj === false) } | ||
| if (Array.isArray(obj)) { obj = obj[0] } | ||
| for (let prop in obj) { | ||
| const FIELD = obj[prop] | ||
| if (_isField(FIELD) && (typeof FIELD.allowNullObj !== 'undefined') && (FIELD.allowNullObj === false)) { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } | ||
| } | ||
@@ -86,6 +111,7 @@ | ||
| /** | ||
| * Valida un objeto de tipo FieldGrouṕ. | ||
| * Devuelve un objeto que contiene el resultado de la validación. | ||
| * - errors contiene todos los errores encontrados y | ||
| * - errors contiene todos los errores encontrados. | ||
| * - result contiene un objeto con los datos validos según el formato de entrada. | ||
| * @param {Object} field - Atributo. | ||
| * @param {Object} field - Objeto de referencia (FieldGroup Array u Object) | ||
| * @param {String|Boolean|Number} value - Dato a validar. | ||
@@ -97,59 +123,98 @@ * @param {String} path - Ruta del campo. | ||
| async function _validate (field, value, path = '', fieldName = '') { | ||
| let errors = [] | ||
| let result = {} | ||
| // El campo es de tpo FIELD | ||
| if (_isField(field)) { | ||
| try { | ||
| const MODEL = field.validator.build() | ||
| MODEL.dataValues[fieldName] = value | ||
| await MODEL.validate({ fields: [fieldName] }) | ||
| value = (typeof value !== 'undefined') ? _parseValue(field, value) : undefined | ||
| } catch (err) { | ||
| if (!err.name || (err.name !== 'SequelizeValidationError')) { throw err } | ||
| for (let i in err.errors) { | ||
| const ERROR = err.errors[i] | ||
| const FIELD = field.validator.attributes[fieldName] | ||
| const VALIDATE = FIELD.validate ? FIELD.validate[ERROR.validatorKey] : undefined | ||
| let msg = VALIDATE ? VALIDATE.msg : ERROR.message | ||
| if (typeof VALIDATE === 'function') { msg += ` ${ERROR.message}` } | ||
| errors.push({ | ||
| path : path, | ||
| value : value || null, | ||
| msg : (ERROR.validatorKey === 'is_null') ? FIELD.allowNullMsg : msg | ||
| }) | ||
| } | ||
| return _validateField(field, value, path, fieldName) | ||
| } | ||
| // El campo es de tpo ARRAY | ||
| if (Array.isArray(field)) { | ||
| if (typeof value === 'undefined') { | ||
| return { errors: [], result: undefined } | ||
| } | ||
| return { errors, result: value } | ||
| } else { | ||
| if (Array.isArray(field)) { | ||
| result = [] | ||
| for (let i in value) { | ||
| result[i] = {} | ||
| if (typeof value[i] === 'undefined') { | ||
| errors.push({ path: path, value: null, msg: handlebars.compile(Validator.ERROR_MSG.allowNullObj)({ objName: fieldName }) }) | ||
| } else { | ||
| for (let prop in field) { | ||
| const path2 = (path === '') ? prop : `${path}.${prop}` | ||
| const RESULT_VALIDATION = await _validate(field[0][prop], value[i][prop], path2, prop) | ||
| errors = errors.concat(RESULT_VALIDATION.errors) | ||
| if (typeof RESULT_VALIDATION.result !== 'undefined') { result[i][prop] = RESULT_VALIDATION.result } | ||
| } | ||
| } | ||
| } | ||
| } else { | ||
| if (typeof value === 'undefined') { | ||
| errors.push({ path: path, value: null, msg: handlebars.compile(Validator.ERROR_MSG.allowNullObj)({ objName: fieldName }) }) | ||
| } else { | ||
| for (let prop in field) { | ||
| const path2 = (path === '') ? prop : `${path}.${prop}` | ||
| const RESULT_VALIDATION = await _validate(field[prop], value[prop], path2, prop) | ||
| errors = errors.concat(RESULT_VALIDATION.errors) | ||
| if (typeof RESULT_VALIDATION.result !== 'undefined') { result[prop] = RESULT_VALIDATION.result } | ||
| } | ||
| } | ||
| let err = [] | ||
| if (!Array.isArray(value)) { | ||
| err.push({ path: path, value: value, msg: handlebars.compile(Validator.ERROR_MSG.isArray)({ fieldName: _toWords(fieldName) }) }) | ||
| return { errors: err, result: [] } | ||
| } | ||
| let res = [] | ||
| for (let i in value) { | ||
| const { errors, result } = await _validate(field[0], value[i], path, fieldName) | ||
| err = err.concat(errors) | ||
| if (typeof result !== 'undefined') { res.push(result) } | ||
| } | ||
| return { errors: err, result: res } | ||
| } | ||
| return { errors, result } | ||
| // El campo es de tpo OBJECT | ||
| return _validateObject(field, value, path, fieldName) | ||
| } | ||
| /** | ||
| * Valida un objeto de tipo Field. | ||
| * Devuelve un objeto que contiene el resultado de la validación. | ||
| * - errors contiene todos los errores encontrados. | ||
| * - result contiene un objeto con los datos validos según el formato de entrada. | ||
| * @param {Object} field - Objeto de referencia (Field) | ||
| * @param {String|Boolean|Number} value - Dato a validar. | ||
| * @param {String} path - Ruta del campo. | ||
| * @param {String} fieldName - Nombre del campo. | ||
| * @return {Object} | ||
| */ | ||
| async function _validateField (field, value, path, fieldName) { | ||
| let errors = [] | ||
| try { | ||
| const MODEL = field.validator.build() | ||
| MODEL.dataValues[fieldName] = value | ||
| await MODEL.validate({ fields: [fieldName] }) | ||
| value = (typeof value !== 'undefined') ? _parseValue(field, value) : undefined | ||
| } catch (err) { | ||
| if (!err.name || (err.name !== 'SequelizeValidationError')) { throw err } | ||
| for (let i in err.errors) { | ||
| const ERROR = err.errors[i] | ||
| const FIELD = field.validator.attributes[fieldName] | ||
| const VALIDATE = FIELD.validate ? FIELD.validate[ERROR.validatorKey] : undefined | ||
| let msg = VALIDATE ? VALIDATE.msg : ERROR.message | ||
| if (typeof VALIDATE === 'function') { msg += ` ${ERROR.message}` } | ||
| errors.push({ | ||
| path : path, | ||
| value : value || null, | ||
| msg : (ERROR.validatorKey === 'is_null') ? FIELD.allowNullMsg : msg | ||
| }) | ||
| } | ||
| } | ||
| return { errors, result: value } | ||
| } | ||
| /** | ||
| * Valida un objeto. | ||
| * Devuelve un objeto que contiene el resultado de la validación. | ||
| * - errors contiene todos los errores encontrados. | ||
| * - result contiene un objeto con los datos validos según el formato de entrada. | ||
| * @param {Object} field - Objeto de referencia (FieldGroup Object). | ||
| * @param {String|Boolean|Number} value - Dato a validar. | ||
| * @param {String} path - Ruta del campo. | ||
| * @param {String} fieldName - Nombre del campo. | ||
| * @return {Object} | ||
| */ | ||
| async function _validateObject (field, value, path, fieldName) { | ||
| let err = [] | ||
| if (typeof value === 'undefined') { | ||
| if (Validator.isRequired(field)) { | ||
| err.push({ path: path, value: value, msg: handlebars.compile(Validator.ERROR_MSG.allowNullObj)({ fieldName: _toWords(fieldName) }) }) | ||
| } | ||
| return { errors: err, result: null } | ||
| } | ||
| if (typeof value !== 'object' || Array.isArray(value)) { | ||
| err.push({ path: path, value: value, msg: handlebars.compile(Validator.ERROR_MSG.isObject)({ fieldName: _toWords(fieldName) }) }) | ||
| return { errors: err, result: {} } | ||
| } | ||
| let res = {} | ||
| for (let prop in field) { | ||
| const path2 = (path === '') ? prop : `${path}.${prop}` | ||
| const { errors, result } = await _validate(field[prop], value[prop], path2, prop) | ||
| err = err.concat(errors) | ||
| if (typeof result !== 'undefined') { res[prop] = result } | ||
| } | ||
| return { errors: err, result: res } | ||
| } | ||
| /** | ||
| * Función que indica si un objeto es un campo o no. | ||
@@ -206,3 +271,3 @@ * @param {Object} obj Objeto. | ||
| _normalizeValidate(field) | ||
| const data = { fieldName: field.fieldName || fieldName } | ||
| const data = { fieldName: _toWords(field.fieldName || fieldName) } | ||
| if (field.validate) { | ||
@@ -256,4 +321,13 @@ Object.keys(field.validate).forEach(valKey => { | ||
| /** | ||
| * Converte una palabra compuesta (frase sin espacios) en palabras separadas. | ||
| * @param {String} str - Palabra compuesta. | ||
| * @return {String} | ||
| */ | ||
| function _toWords (str) { | ||
| return _.words(str).toString().replace(/,/g, ' ') | ||
| } | ||
| Validator.LANGUAJE = 'es' | ||
| module.exports = Validator |
+3
-2
@@ -5,3 +5,3 @@ module.exports = { | ||
| allowNull : `Se requiere el campo {{fieldName}}`, | ||
| allowNullObj : `Se requiere el objeto {{objName}}.`, | ||
| allowNullObj : `Se requiere el objeto {{fieldName}}.`, | ||
| len : `El campo {{fieldName}} debe tener entre {{args0}} y {{args1}} caracteres.`, | ||
@@ -18,4 +18,5 @@ min : `El campo {{fieldName}} debe ser mayor o igual a {{args}}`, | ||
| isUUID : `El campo {{fieldName}} debe ser un código UUID válido.`, | ||
| isArray : `El campo {{fieldName}} debe ser una lista.` | ||
| isArray : `El campo {{fieldName}} debe ser una lista.`, | ||
| isObject : `El campo {{fieldName}} debe ser un objeto.` | ||
| } | ||
| } |
+6
-4
| { | ||
| "name": "input-data-validator", | ||
| "version": "1.2.2", | ||
| "version": "1.3.0", | ||
| "description": "Valida los datos de entrada de una ruta de un servicio web creado con express.", | ||
| "main": "index.js", | ||
| "scripts": { | ||
| "test": "./node_modules/.bin/mocha --recursive test", | ||
| "doc": "./node_modules/.bin/esdoc", | ||
| "lint": "./node_modules/.bin/eslint ./lib" | ||
| "lint": "./node_modules/.bin/eslint ./lib", | ||
| "test": "npm run test-unit && npm run test-integration", | ||
| "test-unit": "NODE_ENV=test \"node_modules/.bin/mocha\" --recursive \"./test/unit/{,/**/}*.spec.js\"", | ||
| "test-integration": "NODE_ENV=test \"node_modules/.bin/mocha\" --recursive \"./test/integration/{,/**/}*.spec.js\"" | ||
| }, | ||
@@ -45,3 +47,3 @@ "repository": { | ||
| "express": "^4.16.2", | ||
| "field-creator": "^1.1.2", | ||
| "field-creator": "^1.2.1", | ||
| "mocha": "^5.0.0", | ||
@@ -48,0 +50,0 @@ "pg": "^7.4.1", |
+3
-1
@@ -42,3 +42,5 @@ # Input Data validator | ||
| app.post('/libros', Validator.validate(INPUT), (req, res, next) => { | ||
| const inputOptions = { remove: ['body'] } | ||
| app.post('/libros', Validator.validate(INPUT, inputOptions), (req, res, next) => { | ||
| return res.status(201).json({ status: 'OK', data: req.body }) | ||
@@ -45,0 +47,0 @@ }) |
| /* global describe it expect */ | ||
| const Validator = require('../../lib/class/Validator') | ||
| const { Field, THIS } = require('field-creator') | ||
| const Sequelize = require('sequelize') | ||
| const express = require('express') | ||
| const request = require('request') | ||
| const PARAMS = { | ||
| dialect : 'postgres', | ||
| lang : 'es', | ||
| logging : false, | ||
| define : { | ||
| underscored : true, | ||
| freezeTableName : true, | ||
| timestamps : false | ||
| }, | ||
| operatorsAliases: false | ||
| } | ||
| const PORT = 4005 | ||
| describe('\n - Clase: Validator\n', () => { | ||
| describe(` Método: validate con el tipo de dato STRING.`, () => { | ||
| it('Validate con un modelo Sequelize', async () => { | ||
| const sequelize = new Sequelize(null, null, null, PARAMS) | ||
| const LIBRO = sequelize.define('libro', { | ||
| id : Field.ID(), | ||
| titulo : Field.STRING({ allowNull: false, allowNullMsg: `Se requiere el título.` }), | ||
| precio : Field.FLOAT({ validate: { min: { args: [0], msg: `El precio debe ser mayor o igual a 0.` } } }) | ||
| }) | ||
| const INPUT = { body: Field.group(LIBRO, { titulo: THIS(), precio: THIS() }) } | ||
| const server = await _createServer(INPUT) | ||
| let options = { | ||
| uri : `http://localhost:${PORT}/libros`, | ||
| method : 'POST', | ||
| json : { id: 123, titulo: 'El cuervo', precio: 11.99 } | ||
| } | ||
| let body = await _request(options) | ||
| expect(body).to.have.property('status', 'OK') | ||
| expect(body).to.have.property('data') | ||
| expect(Object.keys(body.data).length).to.equal(2) | ||
| expect(body.data).to.have.property('titulo', options.json.titulo) | ||
| expect(body.data).to.have.property('precio', options.json.precio) | ||
| options.json = { precio: -124 } | ||
| body = await _request(options) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| expect(body).to.have.property('error') | ||
| expect(body.error).to.be.an('object') | ||
| expect(body.error.name).to.equal('InputDataValidationError') | ||
| expect(body.error.errors).to.be.an('array') | ||
| const errors = body.error.errors | ||
| expect(errors).to.have.lengthOf(2) | ||
| expect(errors[0]).to.have.property('path') | ||
| expect(errors[0]).to.have.property('value') | ||
| expect(errors[0]).to.have.property('msg') | ||
| server.close() | ||
| }) | ||
| it('Validate STRING [is] 1ra Forma', async () => { | ||
| const CH1 = 'abcABC' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('is', ['^[a-z]+$', 'i'], [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [is] 2da Forma', async () => { | ||
| const CH1 = 'abcABC' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('is', /^[a-z]+$/i, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [not]', async () => { | ||
| const CH1 = '_#-*@?' | ||
| const CH2 = 'abcABC' | ||
| await _validar('not', ['[a-z]', 'i'], [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isEmail]', async () => { | ||
| await _validar('isEmail', true, ['administrador@gmail.com', 'gmailuse6charactersmin@gmail.com', 'other@example.com'], ['min6@gmail.com', 's4*-sd.cdsc']) | ||
| }) | ||
| it('Validate STRING [isUrl]', async () => { | ||
| await _validar('isUrl', true, ['http://foo.com'], ['other-value']) | ||
| }) | ||
| it('Validate STRING [isIP]', async () => { | ||
| await _validar('isIP', true, ['129.89.23.1', 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329'], ['other-value']) | ||
| }) | ||
| it('Validate STRING [isIPv4]', async () => { | ||
| await _validar('isIPv4', true, ['129.89.23.1'], ['other-value', 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329']) | ||
| }) | ||
| it('Validate STRING [isIPv6]', async () => { | ||
| await _validar('isIPv6', true, ['FE80:0000:0000:0000:0202:B3FF:FE1E:8329'], ['other-value', '129.89.23.1']) | ||
| }) | ||
| it('Validate STRING [isAlpha]', async () => { | ||
| const CH1 = 'abcABC' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('isAlpha', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isAlphanumeric]', async () => { | ||
| const CH1 = 'abcABC1234567890' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('isAlphanumeric', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isNumeric]', async () => { | ||
| const CH1 = '1234567890' | ||
| const CH2 = '_#-*@?' | ||
| await _validar('isNumeric', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isInt]', async () => { | ||
| await _validar('isInt', true, [2147483647], [21474836483423423234234234234523423449]) | ||
| }) | ||
| it('Validate STRING [isFloat]', async () => { | ||
| await _validar('isFloat', true, [1.4, '1.4'], ['1.4.5']) | ||
| }) | ||
| it('Validate STRING [isDecimal]', async () => { | ||
| await _validar('isDecimal', true, [10, 2.0, 3.2342342], ['10.5.3']) | ||
| }) | ||
| it('Validate STRING [isLowercase]', async () => { | ||
| const CH1 = 'abc' | ||
| const CH2 = 'ABC' | ||
| await _validar('isLowercase', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isUppercase]', async () => { | ||
| const CH1 = 'ABC' | ||
| const CH2 = 'abc' | ||
| await _validar('isUppercase', true, [randStr(100, 100, CH1)], [randStr(1, 100, CH2)]) | ||
| }) | ||
| it('Validate STRING [isNull]', async () => { | ||
| await _validar('isNull', true, [null], ['not-null', 'null']) | ||
| }) | ||
| it('Validate STRING [notEmpty]', async () => { | ||
| await _validar('notEmpty', true, ['not-empty'], ['']) | ||
| }) | ||
| it('Validate STRING [equals]', async () => { | ||
| await _validar('equals', 'ABC', ['ABC'], ['otro-valor']) | ||
| }) | ||
| it('Validate STRING [contains]', async () => { | ||
| await _validar('contains', 'word', ['contiene la palabra word'], ['no contiene la palabra']) | ||
| }) | ||
| it('Validate STRING [notIn]', async () => { | ||
| await _validar('notIn', [['foo', 'bar']], ['other', 'word'], ['foo', 'bar']) | ||
| }) | ||
| it('Validate STRING [isIn]', async () => { | ||
| await _validar('isIn', [['foo', 'bar']], ['foo', 'bar'], ['other', 'word']) | ||
| }) | ||
| it('Validate STRING [len]', async () => { | ||
| await _validar('len', [10, 100], [randStr(10), randStr(100)], [randStr(9), randStr(101)]) | ||
| }) | ||
| it('Validate STRING [isUUID]', async () => { | ||
| await _validar('isUUID', 4, ['15dab328-07dc-4400-a5ea-55f836c40f31'], ['other-value']) | ||
| }) | ||
| it('Validate STRING [isDate]', async () => { | ||
| await _validar('isDate', true, ['2018-07-30', '2018-07-30 08:10:30'], ['other-value', '30/07/2018']) | ||
| }) | ||
| it('Validate STRING [isAfter]', async () => { | ||
| await _validar('isAfter', '2010-05-30', ['2010-06-30'], ['2010-04-30']) | ||
| }) | ||
| it('Validate STRING [isBefore]', async () => { | ||
| await _validar('isBefore', '2010-05-30', ['2010-04-30'], ['2010-06-30']) | ||
| }) | ||
| it('Validate STRING [min]', async () => { | ||
| await _validar('min', 10, [10, 20, 30], [0, 1, 2, 9]) | ||
| }) | ||
| it('Validate STRING [max]', async () => { | ||
| await _validar('max', 10, [0, 1, 2, 10], [11, 20, 30]) | ||
| }) | ||
| it('Validate STRING [isCreditCard]', async () => { | ||
| await _validar('isCreditCard', true, ['4539029473077866'], ['other-value', '0000000000000000']) | ||
| }) | ||
| it('Validate STRING [custom]', async () => { | ||
| await _validar('esPar', (value) => { if (parseInt(value) % 2 !== 0) { throw new Error(`Debe ser un número par.`) } }, [2, 4, 6], [1, 3, 5]) | ||
| }) | ||
| }) | ||
| describe(` Método: validate con diferentes tipos de datos.`, () => { | ||
| it('Validate STRING', async () => { | ||
| await _validar('_custom', () => {}, [randStr(0), randStr(255)], [randStr(256)], Field.STRING()) | ||
| await _validar('_custom', () => {}, [randStr(0), randStr(100)], [randStr(101)], Field.STRING(100)) | ||
| await _validar('_custom', () => {}, [randStr(10), randStr(100)], [randStr(9), randStr(101)], Field.STRING(100, { validate: { len: [10, 100] } })) | ||
| }) | ||
| it('Validate TEXT', async () => { | ||
| await _validar('_custom', () => {}, [randStr(0), randStr(900)], [], Field.TEXT()) | ||
| await _validar('_custom', () => {}, [randStr(10), randStr(100)], [randStr(9), randStr(101)], Field.TEXT({ validate: { len: [10, 100] } })) | ||
| }) | ||
| it('Validate INTEGER', async () => { | ||
| await _validar('_custom', () => {}, [0, 2147483647], [-1, 2147483648], Field.INTEGER()) | ||
| await _validar('_custom', () => {}, [-10, 0, 2147483647], [-11, 2147483648], Field.INTEGER({ validate: { min: -10 } })) | ||
| await _validar('_custom', () => {}, [0, 100], [-1, 101], Field.INTEGER({ validate: { max: 100 } })) | ||
| }) | ||
| it('Validate FLOAT', async () => { | ||
| await _validar('_custom', () => {}, [0.0], [-1.5], Field.FLOAT()) | ||
| await _validar('_custom', () => {}, [-10.49], [-10.51], Field.FLOAT({ validate: { min: -10.5 } })) | ||
| await _validar('_custom', () => {}, [100.5], [100.51], Field.FLOAT({ validate: { max: 100.5 } })) | ||
| }) | ||
| it('Validate BOOLEAN', async () => { | ||
| await _validar('_custom', () => {}, [true, false, 1, 0, 'true', 'false', '1', '0'], ['other', 'TRUE', 'FALSE'], Field.BOOLEAN()) | ||
| }) | ||
| it('Validate DATE', async () => { | ||
| await _validar('_custom', () => {}, ['2018-07-30'], ['30/07/2018'], Field.DATE()) | ||
| }) | ||
| it('Validate DATEONLY', async () => { | ||
| await _validar('_custom', () => {}, ['2018-07-30'], ['30/07/2018'], Field.DATEONLY()) | ||
| }) | ||
| it('Validate TIME', async () => { | ||
| await _validar('_custom', () => {}, ['08:12:00'], ['other', '05', '05:30'], Field.TIME()) | ||
| }) | ||
| it('Validate JSON', async () => { | ||
| await _validar('_custom', () => {}, [{ msg: 'Hola' }, {}, ['a', 'b'], []], ['other'], Field.JSON()) | ||
| }) | ||
| it('Validate JSONB', async () => { | ||
| await _validar('_custom', () => {}, [{ msg: 'Hola' }, {}, ['a', 'b'], []], ['other'], Field.JSONB()) | ||
| }) | ||
| it('Validate UUID', async () => { | ||
| await _validar('_custom', () => {}, ['15dab328-07dc-4400-a5ea-55f836c40f31'], ['other'], Field.UUID()) | ||
| }) | ||
| it('Validate ENUM', async () => { | ||
| await _validar('_custom', () => {}, ['A', 'B'], ['C', 'D'], Field.ENUM(['A', 'B'])) | ||
| }) | ||
| }) | ||
| }) | ||
| async function _validar (validatorName, validatorValue, validData = [], invalidData = [], FIELD) { | ||
| const VALIDATE = {} | ||
| VALIDATE[validatorName] = validatorValue | ||
| const INPUT = { | ||
| body: { | ||
| single : FIELD || Field.STRING({ validate: VALIDATE }), | ||
| array : Field.ARRAY(FIELD || Field.STRING({ validate: VALIDATE })) | ||
| } | ||
| } | ||
| // console.log(require('util').inspect(INPUT.body.single.validate, { depth: null }), 'VALID =', validData) | ||
| // console.log(require('util').inspect(INPUT.body.single.validate, { depth: null }), 'INVALID =', invalidData) | ||
| const server = await _createServer(INPUT) | ||
| let options = { | ||
| uri : `http://localhost:${PORT}/libros`, | ||
| method : 'POST' | ||
| } | ||
| for (let i in validData) { | ||
| options.json = { single: validData[i], array: [validData[i]] } | ||
| // console.log(' data [OK]: ', options.json) | ||
| const body = await _request(options) | ||
| // console.log(body); | ||
| expect(body).to.have.property('status', 'OK') | ||
| } | ||
| for (let i in invalidData) { | ||
| options.json = { single: invalidData[i], array: [invalidData[i]] } | ||
| // console.log(' data [FAIL]: ', options.json) | ||
| const body = await _request(options) | ||
| expect(body).to.have.property('status', 'FAIL') | ||
| expect(body.error).to.have.property('name', 'InputDataValidationError') | ||
| } | ||
| await server.close() | ||
| } | ||
| async function _createServer (INPUT) { | ||
| const app = express() | ||
| app.post('/libros', Validator.validate(INPUT), (req, res, next) => { | ||
| res.status(201).json({ status: 'OK', data: req.body }) | ||
| }) | ||
| app.use((err, req, res, next) => { | ||
| if (err.name === 'InputDataValidationError') { | ||
| return res.status(400).json({ status: 'FAIL', error: err }) | ||
| } | ||
| console.log(err) | ||
| return res.status(500).json({ status: 'FAIL', error: err.toString() }) | ||
| }) | ||
| return app.listen(PORT) | ||
| } | ||
| function _request (options) { | ||
| return new Promise((resolve, reject) => { | ||
| return request(options, (error, response, body) => { | ||
| if (error) { console.log(error); return reject(error) } | ||
| if (response.statusCode === 500) return reject(body) | ||
| return resolve(body) | ||
| }) | ||
| }) | ||
| } | ||
| function randStr (min, max, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') { | ||
| let str = '' | ||
| for (let i = 1; i <= randInt(min, max); i++) { | ||
| const index = randInt(0, chars.length - 1) | ||
| str += chars.charAt(index) | ||
| } | ||
| return str | ||
| } | ||
| function randInt (min, max) { | ||
| if (!max) max = min | ||
| return Math.floor(Math.random() * (max - min + 1)) + min | ||
| } |
Sorry, the diff of this file is too big to display
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
141236
15.29%15
7.14%1050
70.45%144
1.41%1
Infinity%