UNPKG

playr-json-scenario

Version:

plays back request scenarios defined in a json file

243 lines (163 loc) 8.65 kB
(function() { 'use strict'; var Class = require('ee-class') , log = require('ee-log') , type = require('ee-types') , playr = require('playr') , ValidatorContext = require('./ValidatorContext') , ArrayValidator = require('./validators/ArrayValidator') , ObjectValidator = require('./validators/ObjectValidator') , ComparatorValidator = require('./validators/ComparatorValidator') , TypeValidator = require('./validators/TypeValidator') , RegexpValidator = require('./validators/RegexpValidator') , OptionalValidator = require('./validators/OptionalValidator') , NullableValidator = require('./validators/NullableValidator') ; module.exports = new Class({ inherits: playr.ResponseMiddleware // validator storage , validators: null /** * sets up the validators */ , init: function() { this.validators = new Map(); this.validators.set('array', new ArrayValidator(this)); this.validators.set('object', new ObjectValidator(this)); this.validators.set('comparator', new ComparatorValidator(this)); this.validators.set('type', new TypeValidator(this)); this.validators.set('regexp', new RegexpValidator(this)); this.validators.set('optional', new OptionalValidator(this)); this.validators.set('nullable', new NullableValidator(this)); } /** * this method is called for every respüonse * * @param {response} response * * @returns {promise} */ , applyTo: function(response) { let definition = response.getRequest().definition.response; // new validator context let context = new ValidatorContext(); if (definition) { return Promise.resolve().then(() => { // HTTP Status if (definition.status) return this.validateProperty('HTTP Response Status', definition.status, response.statusCode, context); else return Promise.resolve(); }).then(() => { // HTTP Headers if (definition.headers) { return Promise.all(Object.keys(definition.headers).map((headerName) => { return this.validateProperty(`HTTP Header ${headerName}`, definition.headers[headerName], (response.headers || {})[headerName.toLowerCase()], context); })); } else return Promise.resolve(); }).then(() => { // content if (definition.content) return this.validateContent(definition.content, response.data, context); else return Promise.resolve(); }).then(() => { // body string if (definition.body) return this.validateProperty('HTTP Response Body', definition.body, response.body, context); else return Promise.resolve(); }).then(() => { if (definition.responseTime) return this.validateProperty('HTTP Response Time', definition.responseTime, (response.endTime - response.getRequest().startTime), context); else return Promise.resolve(); }).then(() => { // we're done // check if the hook for getting messages instead of // printing the is set if (type.function(this.resultHook)) this.resultHook(context.messages); else { if (context.messages.length) return Promise.reject(new Error(`Validation failed:\n ${context.messages.join('\n')}`)); return Promise.resolve(); } }); } else return Promise.resolve(); } /** * validate the data. * */ , validateContent: function(validators, data, context) { // check if we got any validators if (validators && (type.object(validators) || type.array(validators))) { // pass this to the generic validator engine return this.validateProperty('HTTP Response Body', validators, data, context); } else return Promise.resolve(); } /** * valdiates one property */ , validateProperty: function(name, validators, data, context) { // multiple validators if (type.array(validators)) { // sort the validatory by their priority validators.sort((a, b) => { let validatorAPriority = this.validators.has(a.kind) ? this.validators.get(a.kind).priority : -10; let validatorBPriority = this.validators.has(b.kind) ? this.validators.get(b.kind).priority : -10; return validatorAPriority > validatorBPriority ? 1 : -1; }); // execute one validator after another, stop // when a validator tells us to do so let executor = (index) => { if (validators.length > index) { return this.validateProperty(name, validators[index], data, context).then((abort) => { if (abort) return Promise.resolve(); else return executor(index+1); }); } else return Promise.resolve(); }; return executor(0); } // one single validator else if (type.object(validators)) { // first apply the validator if (!this.validators.has(validators.kind)) return Promise.reject(new Error(`${name.cyan}: invalid valdiator. Validator kind ${validators.kind} unkown on object ${JSON.stringify(validators)}!`)); else { return this.validators.get(validators.kind).validate(name, data, validators, context).then((abort) => { if (abort) return Promise.resolve(true); else if (validators.kind === 'array') { // then check if there is content to check for // it is an array or null or undefined which is ok if (type.array(data)) { // check each item return Promise.all(data.map((item, index) => { return this.validateProperty(`${name}[${index}]`, validators.data, item, context); })).then((results) => { return Promise.resolve(results.some(a => !!a)); }); } else return Promise.resolve(); } else if (validators.kind === 'object') { // if the content is an object, its valiadatable if (type.object(data)) { // got an object, validate properties return Promise.all(Object.keys(validators.data).map((propertyName) => { return this.validateProperty(`${name}.${propertyName}`, validators.data[propertyName], data[propertyName], context); })).then((results) => { return Promise.resolve(results.some(a => !!a)); }); } else return Promise.resolve(); } // ok :) else return Promise.resolve(); }); } } // problem! the validator looks not too good else { return this.validators.get('comparator').validate(name, data, { kind: 'comparator' , comparator: '=' , type: type(validators) , value: validators }, context); } } }); })();