feat: Created a mini nodeJS server with NewMan for testing without PostMan GUI.

This will mimic a run in a CD/CI environment or docker container.
This commit is contained in:
Simon Priet
2021-09-08 14:01:19 +02:00
parent 5fbd7c88fa
commit e69a613a37
5610 changed files with 740417 additions and 3 deletions

150
node_modules/newman/bin/newman.js generated vendored Normal file
View File

@@ -0,0 +1,150 @@
#!/usr/bin/env node
require('../lib/node-version-check'); // @note that this should not respect CLI --silent
const _ = require('lodash'),
waterfall = require('async/waterfall'),
{ Command } = require('commander'),
program = new Command(),
version = require('../package.json').version,
newman = require('../'),
util = require('./util');
program
.name('newman')
.addHelpCommand(false)
.version(version, '-v, --version');
// The `run` command allows you to specify a collection to be run with the provided options.
program
.command('run <collection>')
.description('Initiate a Postman Collection run from a given URL or path')
.usage('<collection> [options]')
.option('-e, --environment <path>', 'Specify a URL or path to a Postman Environment')
.option('-g, --globals <path>', 'Specify a URL or path to a file containing Postman Globals')
.option('-r, --reporters [reporters]', 'Specify the reporters to use for this run', util.cast.csvParse, ['cli'])
.option('-n, --iteration-count <n>', 'Define the number of iterations to run', util.cast.integer)
.option('-d, --iteration-data <path>', 'Specify a data file to use for iterations (either JSON or CSV)')
.option('--folder <path>',
'Specify the folder to run from a collection. Can be specified multiple times to run multiple folders',
util.cast.memoize, [])
.option('--global-var <value>',
'Allows the specification of global variables via the command line, in a key=value format',
util.cast.memoizeKeyVal, [])
.option('--env-var <value>',
'Allows the specification of environment variables via the command line, in a key=value format',
util.cast.memoizeKeyVal, [])
.option('--export-environment <path>', 'Exports the final environment to a file after completing the run')
.option('--export-globals <path>', 'Exports the final globals to a file after completing the run')
.option('--export-collection <path>', 'Exports the executed collection to a file after completing the run')
.option('--postman-api-key <apiKey>', 'API Key used to load the resources from the Postman API')
.option('--bail [modifiers]',
'Specify whether or not to gracefully stop a collection run on encountering an error' +
' and whether to end the run with an error based on the optional modifier', util.cast.csvParse)
.option('--ignore-redirects', 'Prevents Newman from automatically following 3XX redirect responses')
.option('-x , --suppress-exit-code', 'Specify whether or not to override the default exit code for the current run')
.option('--silent', 'Prevents Newman from showing output to CLI')
.option('--disable-unicode', 'Forces Unicode compliant symbols to be replaced by their plain text equivalents')
.option('--color <value>', 'Enable/Disable colored output (auto|on|off)', util.cast.colorOptions, 'auto')
.option('--delay-request [n]', 'Specify the extent of delay between requests (milliseconds)', util.cast.integer, 0)
.option('--timeout [n]', 'Specify a timeout for collection run (milliseconds)', util.cast.integer, 0)
.option('--timeout-request [n]', 'Specify a timeout for requests (milliseconds)', util.cast.integer, 0)
.option('--timeout-script [n]', 'Specify a timeout for scripts (milliseconds)', util.cast.integer, 0)
.option('--working-dir <path>', 'Specify the path to the working directory')
.option('--no-insecure-file-read', 'Prevents reading the files situated outside of the working directory')
.option('-k, --insecure', 'Disables SSL validations')
.option('--ssl-client-cert-list <path>', 'Specify the path to a client certificates configurations (JSON)')
.option('--ssl-client-cert <path>', 'Specify the path to a client certificate (PEM)')
.option('--ssl-client-key <path>', 'Specify the path to a client certificate private key')
.option('--ssl-client-passphrase <passphrase>', 'Specify the client certificate passphrase (for protected key)')
.option('--ssl-extra-ca-certs <path>', 'Specify additionally trusted CA certificates (PEM)')
.option('--cookie-jar <path>', 'Specify the path to a custom cookie jar (serialized tough-cookie JSON) ')
.option('--export-cookie-jar <path>', 'Exports the cookie jar to a file after completing the run')
.option('--verbose', 'Show detailed information of collection run and each request sent')
.action((collection, command) => {
let options = util.commanderToObject(command),
// parse custom reporter options
reporterOptions = util.parseNestedOptions(program._originalArgs, '--reporter-', options.reporters);
// Inject additional properties into the options object
options.collection = collection;
options.reporterOptions = reporterOptions._generic;
options.reporter = _.transform(_.omit(reporterOptions, '_generic'), (acc, value, key) => {
acc[key] = _.assignIn(value, reporterOptions._generic); // overrides reporter options with _generic
}, {});
newman.run(options, function (err, summary) {
const runError = err || summary.run.error || summary.run.failures.length;
if (err) {
console.error(`error: ${err.message || err}\n`);
err.friendly && console.error(` ${err.friendly}\n`);
}
runError && !_.get(options, 'suppressExitCode') && process.exit(1);
});
});
program.addHelpText('after', `
To get available options for a command:
newman <command> -h`);
// Warn on invalid command and then exits.
program.on('command:*', (command) => {
console.error(`error: invalid command \`${command}\`\n`);
program.help();
});
/**
* Starts the script execution.
* callback is required when this is required as a module in tests.
*
* @param {String[]} argv - Argument vector.
* @param {?Function} callback - The callback function invoked on the completion of execution.
*/
function run (argv, callback) {
waterfall([
(next) => {
// cache original argv, required to parse nested options later.
program._originalArgs = argv;
// omit custom nested options, otherwise commander will throw unknown options error
next(null, util.omitNestedOptions(argv, '--reporter-'));
},
(args, next) => {
let error = null;
try {
program.parse(args);
}
catch (err) {
error = err;
}
next(error);
},
(next) => {
// throw error if no argument is provided.
next(program.args.length ? null : new Error('no arguments provided'));
}
], (error) => {
// invoke callback if this is required as module, used in tests.
if (callback) { return callback(error); }
// in case of an error, log error message and print help message.
if (error) {
console.error(`error: ${error.message || error}\n`);
program.help();
}
});
}
// This hack has been added from https://github.com/nodejs/node/issues/6456#issue-151760275
// @todo: remove when https://github.com/nodejs/node/issues/6456 has been fixed
(Number(process.version[1]) >= 6) && [process.stdout, process.stderr].forEach((s) => {
s && s.isTTY && s._handle && s._handle.setBlocking && s._handle.setBlocking(true);
});
// Run this script if this is a direct stdin.
!module.parent && run(process.argv);
// Export to allow debugging and testing.
module.exports = run;

203
node_modules/newman/bin/util.js generated vendored Normal file
View File

@@ -0,0 +1,203 @@
const _ = require('lodash');
module.exports = {
cast: {
/**
* Helper to coerce number like strings into integers.
* Perform safety checks, and return the result.
*
* @param {String} arg - The stringified number argument.
* @returns {Number} - The supplied argument, casted to an integer.
*/
integer: (arg) => {
const num = Number(arg);
if (!_.isSafeInteger(num) || num <= 0) {
throw new Error('The value must be a positive integer.');
}
return num.valueOf();
},
/**
* Helper for collecting argument passed multiple times.
*
* --folder f1 --folder f2
*
* @param {String} val - The argument value.
* @param {String[]} memo - The array that is populated by argument values.
* @returns {String[]} - The array of argument values collected.
*/
memoize: (val, memo) => {
memo.push(val);
return memo;
},
/**
* Helper for collecting argument passed multiple times as key=value.
*
* --global-var "foo=bar" --global-var "alpha=beta"
*
* @param {String} val - The argument value, passed as key=value.
* @param {Array} memo - The array that is populated by key value pairs.
* @returns {Array} - [{key, value}] - The object representation of the current CLI variable.
*/
memoizeKeyVal: (val, memo) => {
let arg,
eqIndex = val.indexOf('=');
// This is done instead of splitting by `=` to avoid chopping off `=` that could be present in the value
arg = eqIndex !== -1 ? {
key: val.slice(0, eqIndex),
value: val.slice(eqIndex + 1)
} : {
key: val,
value: undefined
};
memo.push(arg);
return memo;
},
/**
* Helper to coerce comma separated string to an array.
*
* eg. item1,item2
*
* @param {String} list - The comma separated string.
* @returns {String[]} - [item1, item2] - The array representation of the passed string.
*/
csvParse: (list) => {
return _.split(list, ',');
},
colorOptions: (value) => {
if (!(/^(auto|on|off)$/).test(value)) {
throw new Error(`invalid value \`${value}\` for --color. Expected: auto|on|off`);
}
return value;
}
},
/**
* Extract selected options in the provided command.
* Omits commander private variables and other objects.
*
* @param {Object} command - Commander.Command Instance
* @returns {Object} - Extracted options from command
*/
commanderToObject: (command) => {
return _.reduce(command, (result, value, key) => {
// Exclude command's private `_` variables and other objects
const validProp = !_.startsWith(key, '_') && !_.includes(['commands', 'options', 'parent'], key);
validProp && (result[key] = value);
return result;
}, {});
},
/**
* Remove nested options having the provided prefix from `process.argv`.
*
* @param {String[]} argv - Argument vector.
* @param {String} optionPrefix - Argument prefix to search for.
* @returns {String[]} - All arguments without prefixed options and their values
*/
omitNestedOptions: (argv, optionPrefix) => {
let args = [],
len,
i;
for (i = 0, len = argv.length; i < len; i++) {
if (!_.startsWith(argv[i], optionPrefix)) {
args.push(argv[i]);
continue;
}
// For prefixed args also omit its value, --prefix-arg value
if (argv[i + 1] && !_.startsWith(argv[i + 1], '-')) {
++i;
}
}
return args;
},
/**
* Parse nested options having the provided prefix from `process.argv`.
*
* @param {String[]} argv - Argument vector.
* @param {String} optionPrefix - Argument prefix to search for.
* @param {String[]} options - Selected options.
* @returns {Object} Parsed object with nested options.
*
* @example
* let argv = ['--reporters=json,html', '--reporter-html-template=template.hb', '--reporter-export=path'],
* options = ['json', 'html'];
* parseNestedOptions(argv, '--reporter-', options);
* //returns
* {
* _generic: { export: path },
* html: { template: template.hb },
* json: {}
* }
*
*/
parseNestedOptions: (argv, optionPrefix, options) => {
let args = [],
parsed = { _generic: {} },
name,
path,
len,
eqIndex,
i;
// Extract prefixed arguments from argv
for (i = 0, len = argv.length; i < len; i++) {
const arg = argv[i];
if (!_.startsWith(arg, optionPrefix)) { continue; } // skip non-prefixed args
eqIndex = arg.indexOf('=');
if (eqIndex !== -1) {
// Split the attribute if its like key=value
args.push(arg.slice(0, eqIndex), arg.slice(eqIndex + 1));
}
else if (argv[i + 1] && !_.startsWith(argv[i + 1], '-')) {
// Also push the next parameter if it's not an option.
args.push(arg, argv[++i]);
}
else {
args.push(arg);
}
}
// ensure that whatever option is provided a blank options object is forwarded
_.forEach(options, (option) => { parsed[option] = {}; });
// Parse nested options
for (i = 0, len = args.length; i < len; i++) {
const arg = args[i].replace(optionPrefix, '');
name = _.split(arg, '-', 1)[0]; // eg. `cli` in --reporter-cli-silent
// if we have a valid option, the path should be the <name>.camelCaseOfTheRest
// otherwise, we add it to the generic options.
path = _.includes(options, name) ?
[name, _.camelCase(arg.replace(name + '-', ''))].join('.') :
['_generic', _.camelCase(arg)].join('.');
// If the next arg is an option, set the current arg to true,
// otherwise set it to the next arg.
_.set(parsed, path, (!args[i + 1] || _.startsWith(args[i + 1], '-')) ? true : args[++i]);
}
return parsed;
}
};