rest-api-starter
Version:
Rest API starter kit.
562 lines (542 loc) • 20.7 kB
JavaScript
/**
* Created by svinci on 1/13/17.
*/
;
const mocha = require('mocha');
const chai = require('chai');
const describe = mocha.describe;
const it = mocha.it;
const expect = chai.expect;
const validator = require('../app/validator');
const ComboSchema = {
'type': 'object',
'description': 'combo',
'additionalProperties': false,
'properties': {
'pizzaFlavorIds': {
'type': 'array',
'required': false
},
'description': {
'type': 'string',
'required': false
},
'name': {
'type': 'string',
'required': true
},
'feeds': {
'type': 'number',
'required': true
},
'price': {
'type': 'number',
'required': true
}
}
};
const OrderSchema = {
'type': 'object',
'description': 'pizza.delivery.order',
'properties': {
'order': {
'type': 'object',
'properties': {
'combos': {
'type': 'array',
'required': true,
'minItems': 0,
'items': {
'type': 'object',
'properties': {
'quantity': {
'type': 'number',
'required': true
},
'comboId': {
'type': 'string',
'required': true
}
}
}
},
'pizzas': {
'type': 'array',
'required': true,
'minItems': 0,
'items': {
'type': 'object',
'properties': {
'size': {
'enum': ['giant', 'classic', 'small'],
'required': true
},
'flavors': {
'type': 'array',
'minItems': 1,
'maxItems': 4,
'items': {
'type': 'object',
'properties': {
'portion': {
'enum': ['FULL', 'HALF', 'QUARTER'],
'required': true
},
'flavorId': {
'type': 'string',
'required': true
}
}
},
'required': true
}
}
}
},
'patties': {
'type': 'array',
'required': true,
'minItems': 0,
'items': {
'type': 'object',
'properties': {
'flavorId': {
'type': 'string',
'required': true
},
'quantity': {
'type': 'number',
'required': true
}
}
}
},
'fainaQuantity': {
'type': 'number',
'required': true
}
},
'required': true
},
'delivery': {
'type': 'object',
'properties': {
'pickUp': {
'type': 'boolean',
'required': true
},
'phone': {
'type': 'string',
'required': true
},
'name': {
'type': 'string',
'required': true
},
'address': {
'type': 'string',
'required': false
}
},
'required': true
}
}
};
describe('Validator', () => {
const comboValidator = validator(ComboSchema);
const orderValidator = validator(OrderSchema, (schema, object, id, errors, endValidation) => {
if (object.order.pizzas && object.order.pizzas.length > 0) {
object.order.pizzas.forEach((pizza) => {
if (pizza.flavors && pizza.flavors.length > 0) {
let portions = 0;
pizza.flavors.forEach((flavor) => {
switch (flavor.portion) {
case 'FULL':
portions += 4;
break;
case 'HALF':
portions += 2;
break;
case 'QUARTER':
portions += 1;
break;
}
});
if (portions !== 4) {
errors.push(`validation.error.${schema.description}.flavor.qty`);
}
}
});
}
if (object.delivery && !object.delivery.pickUp && !object.delivery.address) {
errors.push(`validation.error.${schema.description}.delivery.address`);
}
endValidation();
});
it('no errors should be raised if object is valid', (done) => {
const caseObject = {
'order': {
'combos': [
{'quantity': 1, 'comboId': '5828d73f59250039ffeeec6a'},
{'quantity': 2, 'comboId': '5828d76959250039ffeeec71'}
],
'pizzas': [
{
'size': 'giant',
'flavors': [
{
'portion': 'FULL',
'flavorId': '5828cb9059250039ffeeebf5'
}
]
},
{
'size': 'classic',
'flavors': [
{
'portion': 'HALF',
'flavorId': '5828cb9059250039ffeeebf5'
},
{
'portion': 'QUARTER',
'flavorId': '5828cff459250039ffeeec19'
},
{
'portion': 'QUARTER',
'flavorId': '5828cb7959250039ffeeebf2'
}
]
}
],
'patties': [
{'flavorId': '5828ddb059250039ffeeecd3', 'quantity': 6},
{'flavorId': '5828dcbe59250039ffeeeca6', 'quantity': 4},
{'flavorId': '5828dd4e59250039ffeeecc1', 'quantity': 2},
{'flavorId': '5828dd9959250039ffeeeccd', 'quantity': 12}
],
'fainaQuantity': 5
},
'delivery': {
'pickUp': true,
'phone': '1132287295',
'name': 'Seba'
}
};
orderValidator.validate(caseObject)
.then(() => done())
.catch((err) => done(err));
});
it('custom errors should be raised if object does not complies with custom validation', (done) => {
const caseObject = {
'order': {
'combos': [
{'quantity': 1, 'comboId': '5828d73f59250039ffeeec6a'},
{'quantity': 2, 'comboId': '5828d76959250039ffeeec71'}
],
'pizzas': [
{
'size': 'giant',
'flavors': [
{
'portion': 'FULL',
'flavorId': '5828cb9059250039ffeeebf5'
}
]
},
{
'size': 'classic',
'flavors': [
{
'portion': 'HALF',
'flavorId': '5828cb9059250039ffeeebf5'
},
{
'portion': 'HALF',
'flavorId': '5828cff459250039ffeeec19'
},
{
'portion': 'QUARTER',
'flavorId': '5828cb7959250039ffeeebf2'
}
]
}
],
'patties': [
{'flavorId': '5828ddb059250039ffeeecd3', 'quantity': 6},
{'flavorId': '5828dcbe59250039ffeeeca6', 'quantity': 4},
{'flavorId': '5828dd4e59250039ffeeecc1', 'quantity': 2},
{'flavorId': '5828dd9959250039ffeeeccd', 'quantity': 12}
],
'fainaQuantity': 5
},
'delivery': {
'pickUp': true,
'phone': '1132287295',
'name': 'Seba'
}
};
orderValidator.validate(caseObject)
.then(() => done('expected validation errors'))
.catch((err) => {
expect(err.errors).to.contain(`validation.error.${OrderSchema.description}.flavor.qty`);
})
.then(() => done())
.catch((err) => done(err));
});
it('id errors should be raised if object\'s id doesn\'t match provided id', (done) => {
const caseObject = {
'id': '123',
'order': {
'combos': [
{'quantity': 1, 'comboId': '5828d73f59250039ffeeec6a'},
{'quantity': 2, 'comboId': '5828d76959250039ffeeec71'}
],
'pizzas': [
{
'size': 'giant',
'flavors': [
{
'portion': 'FULL',
'flavorId': '5828cb9059250039ffeeebf5'
}
]
},
{
'size': 'classic',
'flavors': [
{
'portion': 'HALF',
'flavorId': '5828cb9059250039ffeeebf5'
},
{
'portion': 'QUARTER',
'flavorId': '5828cff459250039ffeeec19'
},
{
'portion': 'QUARTER',
'flavorId': '5828cb7959250039ffeeebf2'
}
]
}
],
'patties': [
{'flavorId': '5828ddb059250039ffeeecd3', 'quantity': 6},
{'flavorId': '5828dcbe59250039ffeeeca6', 'quantity': 4},
{'flavorId': '5828dd4e59250039ffeeecc1', 'quantity': 2},
{'flavorId': '5828dd9959250039ffeeeccd', 'quantity': 12}
],
'fainaQuantity': 5
},
'delivery': {
'pickUp': true,
'phone': '1132287295',
'name': 'Seba'
}
};
orderValidator.validate(caseObject, '234')
.then(() => done('expected validation errors'))
.catch((err) => {
expect(err.errors).to.contain(`validation.error.${OrderSchema.description}.id.match`);
})
.then(() => done())
.catch((err) => done(err));
});
it('id errors should be raised if an id is provided but object has none', (done) => {
const caseObject = {
'order': {
'combos': [
{'quantity': 1, 'comboId': '5828d73f59250039ffeeec6a'},
{'quantity': 2, 'comboId': '5828d76959250039ffeeec71'}
],
'pizzas': [
{
'size': 'giant',
'flavors': [
{
'portion': 'FULL',
'flavorId': '5828cb9059250039ffeeebf5'
}
]
},
{
'size': 'classic',
'flavors': [
{
'portion': 'HALF',
'flavorId': '5828cb9059250039ffeeebf5'
},
{
'portion': 'QUARTER',
'flavorId': '5828cff459250039ffeeec19'
},
{
'portion': 'QUARTER',
'flavorId': '5828cb7959250039ffeeebf2'
}
]
}
],
'patties': [
{'flavorId': '5828ddb059250039ffeeecd3', 'quantity': 6},
{'flavorId': '5828dcbe59250039ffeeeca6', 'quantity': 4},
{'flavorId': '5828dd4e59250039ffeeecc1', 'quantity': 2},
{'flavorId': '5828dd9959250039ffeeeccd', 'quantity': 12}
],
'fainaQuantity': 5
},
'delivery': {
'pickUp': true,
'phone': '1132287295',
'name': 'Seba'
}
};
orderValidator.validate(caseObject, '234')
.then(() => done('expected validation errors'))
.catch((err) => {
expect(err.errors).to.contain(`validation.error.${OrderSchema.description}.schema.instance.id`);
})
.then(() => done())
.catch((err) => done(err));
});
it('schema errors should be raised if object doesn\'t comply with provided schema.', (done) => {
const caseObject = {
'order': {
'combos': [
{'quantity': 1, 'comboId': '5828d73f59250039ffeeec6a'},
{'quantity': 2}
],
'pizzas': [
{
'size': 'giant',
'flavors': [
{
'portion': 'FULL',
'flavorId': '5828cb9059250039ffeeebf5'
}
]
},
{
'size': 'classic',
'flavors': [
{
'portion': 'HALF',
'flavorId': '5828cb9059250039ffeeebf5'
},
{
'portion': 'QUARTER',
'flavorId': '5828cff459250039ffeeec19'
},
{
'portion': 'QUARTER',
'flavorId': '5828cb7959250039ffeeebf2'
}
]
}
],
'patties': [
{'flavorId': '5828ddb059250039ffeeecd3', 'quantity': 6},
{'flavorId': '5828dcbe59250039ffeeeca6', 'quantity': 4},
{'flavorId': '5828dd4e59250039ffeeecc1', 'quantity': 2},
{'flavorId': '5828dd9959250039ffeeeccd', 'quantity': 12}
],
'fainaQuantity': 5
},
'delivery': {
'pickUp': true,
'phone': '1132287295',
'name': 'Seba'
}
};
orderValidator.validate(caseObject)
.then(() => done('expected validation errors'))
.catch((err) => {
expect(err.errors).to.contain(`validation.error.${OrderSchema.description}.schema.instance.order.combos[1].comboId`);
})
.then(() => done())
.catch((err) => done(err));
});
it('validator should be capable of validating even when no custom validations are provided', (done) => {
const caseObject = {
'pizzaFlavorIds': [1, 2, 3],
'name': 'COMBO 1',
'feeds': 4,
'price': 125.30
};
comboValidator.validate(caseObject)
.then(() => done())
.catch((err) => done(err));
});
it('validator should fail on unknown properties (only one) when configured to do so', (done) => {
const caseObject = {
'pizzaFlavorIds': [1, 2, 3],
'name': 'COMBO 1',
'feeds': 4,
'price': 125.30,
'someUnknownProp': 1,
'anotherUnknownProp': 2
};
comboValidator.validate(caseObject)
.then(() => done('expected validation error'))
.catch((err) => {
expect(err.name).to.equal('validation.error');
expect(err.errors.length).to.equal(1);
expect(err.errors).to.contain('validation.error.combo.schema.unknown.property');
done();
})
.catch((err) => done(err));
});
it('validator should not fail on unknown properties when not configured to do so', (done) => {
const caseObject = {
'someUnknownProperty': 1,
'order': {
'combos': [
{'quantity': 1, 'comboId': '5828d73f59250039ffeeec6a'},
{'quantity': 2, 'comboId': '5828d76959250039ffeeec71'}
],
'pizzas': [
{
'size': 'giant',
'flavors': [
{
'portion': 'FULL',
'flavorId': '5828cb9059250039ffeeebf5'
}
]
},
{
'size': 'classic',
'flavors': [
{
'portion': 'HALF',
'flavorId': '5828cb9059250039ffeeebf5'
},
{
'portion': 'QUARTER',
'flavorId': '5828cff459250039ffeeec19'
},
{
'portion': 'QUARTER',
'flavorId': '5828cb7959250039ffeeebf2'
}
]
}
],
'patties': [
{'flavorId': '5828ddb059250039ffeeecd3', 'quantity': 6},
{'flavorId': '5828dcbe59250039ffeeeca6', 'quantity': 4},
{'flavorId': '5828dd4e59250039ffeeecc1', 'quantity': 2},
{'flavorId': '5828dd9959250039ffeeeccd', 'quantity': 12}
],
'fainaQuantity': 5
},
'delivery': {
'pickUp': true,
'phone': '1132287295',
'name': 'Seba'
}
};
orderValidator.validate(caseObject)
.then(() => done())
.catch((err) => done(err));
});
});