New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

input-data-validator

Package Overview
Dependencies
Maintainers
2
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

input-data-validator - npm Package Compare versions

Comparing version
1.2.2
to
1.3.0
+256
test/integration/Test.spec.js
/* 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

@@ -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.`
}
}
{
"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",

@@ -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