UNPKG

rjon

Version:

route js object notation is a way to standardize route metadata for use and testing in universal route interpreter software

471 lines (450 loc) 16.7 kB
"use strict"; var __assign = (this && this.__assign) || Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); require("rxjs/add/operator/toPromise"); var pipes_class_1 = require("ack-angular/pipes.class"); var ack = require("ack-x/index-browser"); var icons = { check: '✓' }; function AssertionError(message) { this.name = this.constructor.name; this.message = message; } AssertionError.prototype = Object.create(Error.prototype); var ɵ0 = function (a, b, message) { if (a == b) return; throw message ? new AssertionError(message) : new AssertionError(a + ' == ' + b); }; exports0 = ɵ0; var assert = { equal: ɵ0 }; /*if (process.platform === 'win32') { icons.check = '\u221A'; }*/ var /*if (process.platform === 'win32') { icons.check = '\u221A'; }*/ Tester = (function () { function Tester() { } //public requestSampleRoute:any //public requestSampleRoute:any Tester.prototype.log = //public requestSampleRoute:any function (options) { options = options || {}; switch (options.type) { case 'success': options.message = '\x1b[32m' + options.message + '\x1b[0m'; break; case 'error': options.message = '\x1b[31m' + options.message + '\x1b[0m'; break; case 'info': options.message = '\x1b[36m' + options.message + '\x1b[0m'; break; } console.log.apply(console, options.message); }; /** @options{ port - what port to conduct test on method - limit tests to only matching methods host - server address } */ /** @options{ port - what port to conduct test on method - limit tests to only matching methods host - server address } */ Tester.prototype.testRoutes = /** @options{ port - what port to conduct test on method - limit tests to only matching methods host - server address } */ function (routes, options) { var _this = this; var passing = []; var failing = []; var errs = []; var successCount = 0; var processTestError = function (test, err) { var msg = errs.length + ') ' + test.name; errs.push({ msg: msg, error: err }); _this.log({ type: 'error', message: msg }); return err; }; var processTest = function (test, err) { if (err) { failing.push(test); return processTestError(test, err); } ++successCount; /*let msg = test.name if(test.time>75){ msg += ' ('+test.time+'ms)' }else if(test.time>37){ msg += ' ('+test.time+'ms)' }*/ /*let msg = test.name if(test.time>75){ msg += ' ('+test.time+'ms)' }else if(test.time>37){ msg += ' ('+test.time+'ms)' }*/ _this.log({ type: 'success', message: test.name, test: test }); passing.push(test); }; var tests = []; var onlyArray = []; routes.forEach(function (route) { if (!route.sample) return; var routeTests = pipes_class_1.array(route.sample).map(function (sample) { return _this.mapSample(sample, route, options); }); tests.push.apply(tests, routeTests); }); for (var x = tests.length - 1; x >= 0; --x) { var testMeta = tests[x]; if (!testMeta) { tests.splice(x, 1); continue; } if (testMeta.sample.test.only) { onlyArray.unshift(testMeta); } } var runs = onlyArray.length ? onlyArray : tests; return this.runTestCases(runs, processTest) .then(function () { return _this.processRanCases(passing, failing, errs); }); //.catch(e=>console.error(e)) }; Tester.prototype.processRanCases = function (passing, failing, errs) { var _this = this; this.log({ type: 'success', message: passing.length + ' passing' }); if (errs.length) { this.log({ type: 'error', message: errs.length + ' failing' }); errs.forEach(function (err) { return _this.logCaseError(err); }); } return { passing: passing, failing: failing }; }; Tester.prototype.logCaseError = function (err) { this.log({ type: 'error', message: err.msg, error: err }); var response = err.error || err; var data = response.data || response; //try parsed json ELSE error is response var resErr = data.error || data; //try response body for error ELSE error is body if (resErr.message) { this.log({ type: 'error', message: resErr.message }); if (resErr.stack && !resErr.isTimeoutError) { this.log({ type: 'error', message: resErr.stack }); } } }; Tester.prototype.runTestCase = function (test) { var startTime = Date.now(); return test.test() .then(function (x) { return (test.time = Date.now() - startTime) && x; }); }; Tester.prototype.promiseTestCase = function (test, processTest) { if (test.sample.test.skip) { this.log({ type: 'info', message: 'skipped ' + test.name, test: { time: 0 } }); return; } return Promise.resolve(this.runTestCase(test)) .catch(function (err) { return err; }) .then(function (err) { return processTest(test, err); }); }; Tester.prototype.runTestCases = function (tests, processTest) { var _this = this; var promise = Promise.resolve(); tests.forEach(function (test) { promise = promise.then(function () { return _this.promiseTestCase(test, processTest); }); }); return promise; }; //HOLD ONTO /*ackRequestSampleRoute(sample, route, options){ options = options || {} options.host = options.host || 'localhost' const simplePath = this.getRouteSamplePath(route, sample) const req = ack.req() if(sample.post){ req.postVar(sample.post) } if(route.method){ req.method(route.method) } if(sample.request){ req.json(result) } const urlPath = 'http://'+options.host+':'+options.port + simplePath //send request return req.send(urlPath,{spread:false}) .then(this.testRouteSampleResponse(route,sample)) }*/ //HOLD ONTO /*ackRequestSampleRoute(sample, route, options){ options = options || {} options.host = options.host || 'localhost' const simplePath = this.getRouteSamplePath(route, sample) const req = ack.req() if(sample.post){ req.postVar(sample.post) } if(route.method){ req.method(route.method) } if(sample.request){ req.json(result) } const urlPath = 'http://'+options.host+':'+options.port + simplePath //send request return req.send(urlPath,{spread:false}) .then(this.testRouteSampleResponse(route,sample)) }*/ Tester.prototype.requestSampleRoute = //HOLD ONTO /*ackRequestSampleRoute(sample, route, options){ options = options || {} options.host = options.host || 'localhost' const simplePath = this.getRouteSamplePath(route, sample) const req = ack.req() if(sample.post){ req.postVar(sample.post) } if(route.method){ req.method(route.method) } if(sample.request){ req.json(result) } const urlPath = 'http://'+options.host+':'+options.port + simplePath //send request return req.send(urlPath,{spread:false}) .then(this.testRouteSampleResponse(route,sample)) }*/ function (sample, route, options) { throw new Error('Expected requestSampleRoute override'); }; /** @options{ port - what port to conduct test on method - limit tests to only matching methods host - server address } */ /** @options{ port - what port to conduct test on method - limit tests to only matching methods host - server address } */ Tester.prototype.getTestBySampleRoute = /** @options{ port - what port to conduct test on method - limit tests to only matching methods host - server address } */ function (sample, route, options) { var _this = this; if (sample.response) { //foo request by sample.response return function () { return ({ fooResponse: true, statusCode: 200, headers: __assign({ "content-type": "application/json" }, options.headers), body: JSON.stringify(sample.response) }); }; } return function () { var timeout = sample.test.timeout || 2000; var promise = _this.requestSampleRoute(sample, route, options); //ignite var callback = _this.callbackTimeout(promise, timeout); //wrap in timeout return ack.promise().callback(callback) //will resolve or timeout or error .then(_this.testRouteSampleResponse(route, sample)); }; }; Tester.prototype.testRouteSampleResponse = function (route, sample) { var simplePath = Tester.getRouteSamplePath(route, sample); return function (res) { var body = res.body; var contentType = ''; var promises = []; //see if json for (var key in res.headers) { if (key.toLowerCase() == 'content-type') { contentType = res.headers[key]; break; } } var method = (route.method || 'GET').toUpperCase(); var isParseBody = !sample.request; if (sample.test.cases) { var cases = sample.test.cases.constructor == Array ? sample.test.cases : [sample.test.cases]; promises.push(this.testCases(cases, res)); } if (isParseBody && contentType.search(/application\/json/i) >= 0) { body = JSON.parse(body); } if (route.returnType) { var returnType = route.returnType.toLowerCase(); switch (returnType) { case 'array': assert.equal(body.constructor, Array, 'returnType mismatch. Expected:Array Received:' + body.constructor); break; case 'string': case 'number': case 'boolean': case 'object': assert.equal(typeof (body), returnType, 'returnType mismatch. Expected:' + returnType + ' Received:' + typeof (body)); break; default: var contentTypeMatch = contentType.search(returnType) >= 0; assert.equal(contentTypeMatch, true, 'returnType mismatch. Expected:' + returnType + ' Received:' + contentType); } } var statusCode = sample.test.statusCode || 200; var resStatus = res.status || res.statusCode; assert.equal(resStatus, statusCode); return Promise.all(promises).then(function () { }); }; }; Tester.prototype.testCases = function (cases, res) { var promises = []; for (var index = 0; index < cases.length; ++index) { promises.push(cases[index](res, assert)); } return Promise.all(promises); }; Tester.prototype.callbackTimeout = function (promise, timeout) { return function (callback) { var killCallback = function (err, x) { callback(err, x); callback = function () { }; //all future calls will become ignored }; setTimeout(function () { var err = new Error('Error: Timeout of ' + timeout + 'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.'); err['isTimeoutError'] = true; killCallback(err); }, timeout); Promise.resolve(promise) .then(function (x) { return killCallback(null, x); }) .catch(function (e) { return killCallback(e); }); }; }; Tester.prototype.mapSample = function (sample, route, options) { var test = this.getTestBySampleRoute(sample, route, options); var simplePath = Tester.getRouteSamplePath(route, sample); //const itsName = (route.method||'GET')+':'+options.port+simplePath var itsName = (route.method || 'GET') + ':' + simplePath; if (!sample.test) return; if (options.method && route.method != options.method) { return; } return { test: test, name: itsName, sample: sample }; }; Tester.getRouteSamplePath = function (route, sample) { if (sample === void 0) { sample = { path: null, params: null }; } var simplePath = sample.path || route.path; if (sample.params) { for (var key in sample.params) { var regX = new RegExp(':' + key, 'gi'); simplePath = simplePath.replace(regX, sample.params[key]); } } return simplePath; }; Tester.getRouteActualTests = function (routes) { var onlyMode = false; var tests = []; Tester.getRouteTests(routes).forEach(function (test) { if (test.only) { onlyMode = true; return tests.push(test); } if (onlyMode || test.skip) return; tests.push(test); }); return tests; }; Tester.getRouteTests = function (routes) { var tests = []; routes.forEach(function (route) { pipes_class_1.array(route.sample).forEach(function (sample) { if (sample.test) tests.push(sample.test); }); }); return tests; }; Tester.getTestGroups = function (routes) { var groups = []; routes.forEach(function (route) { if (route.groupNames) groups.push.apply(groups, route.groupNames); }); //remove duplicate groups var find = -1; var _loop_1 = function (x) { //remove duplicates that appear before current while ((function (find) { return find >= 0 && find < x; })(groups.indexOf(groups[x]))) { groups.splice(x, 1); } }; for (var x = groups.length - 1; x >= 0; --x) { _loop_1(x); } return groups; }; Tester.getRoutesWithTests = function (routes) { var tests = []; routes.forEach(function (route) { pipes_class_1.array(route.sample).forEach(function (sample) { if (sample.test) tests.push(route); }); }); return tests; }; Tester.getRoutesWithActualTests = function (routes) { var onlyMode = false; var tests = []; Tester.getRoutesWithTests(routes).forEach(function (route) { pipes_class_1.array(route.sample).forEach(function (sample) { if (!sample.test) return; if (sample.test.only) { onlyMode = true; return tests.push(route); } if (onlyMode || sample.test.skip) return; tests.push(route); }); }); return tests; }; return Tester; }()); exports.Tester = Tester; //# sourceMappingURL=rjonTester.js.map