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:
277
node_modules/postman-runtime/lib/runner/extensions/item.command.js
generated
vendored
Normal file
277
node_modules/postman-runtime/lib/runner/extensions/item.command.js
generated
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
var _ = require('lodash'),
|
||||
uuid = require('uuid'),
|
||||
Response = require('postman-collection').Response,
|
||||
visualizer = require('../../visualizer'),
|
||||
|
||||
/**
|
||||
* List of request properties which can be mutated via pre-request
|
||||
*
|
||||
* @private
|
||||
* @const
|
||||
* @type {String[]}
|
||||
*/
|
||||
ALLOWED_REQUEST_MUTATIONS = ['url', 'method', 'headers', 'body'],
|
||||
|
||||
extractVisualizerData,
|
||||
getResponseJSON;
|
||||
|
||||
/**
|
||||
* Returns visualizer data from the latest execution result.
|
||||
*
|
||||
* @param {Array} prereqExecutions - pre-script executions results
|
||||
* @param {Array} testExecutions - test-script executions results
|
||||
* @returns {Object|undefined} - visualizer data
|
||||
*/
|
||||
extractVisualizerData = function (prereqExecutions, testExecutions) {
|
||||
var visualizerData,
|
||||
i;
|
||||
|
||||
if (_.isArray(testExecutions)) {
|
||||
// loop through the test executions in reverse order to return data from latest execution
|
||||
for (i = testExecutions.length - 1; i >= 0; i--) {
|
||||
visualizerData = _.get(testExecutions[i], 'result.return.visualizer');
|
||||
|
||||
if (visualizerData) {
|
||||
return visualizerData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_.isArray(prereqExecutions)) {
|
||||
// extract visualizer data from pre-request script results if it is not found earlier
|
||||
for (i = prereqExecutions.length - 1; i >= 0; i--) {
|
||||
visualizerData = _.get(prereqExecutions[i], 'result.return.visualizer');
|
||||
|
||||
if (visualizerData) {
|
||||
return visualizerData;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert response into a JSON serializable object.
|
||||
* The stream property is converted to base64 string for performance reasons.
|
||||
*
|
||||
* @param {Object} response - SDK Response instance
|
||||
* @returns {Object}
|
||||
*/
|
||||
getResponseJSON = function (response) {
|
||||
if (!Response.isResponse(response)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
id: response.id,
|
||||
code: response.code,
|
||||
status: response.status,
|
||||
header: response.headers && response.headers.toJSON(),
|
||||
stream: response.stream && {
|
||||
type: 'Base64',
|
||||
data: response.stream.toString('base64')
|
||||
},
|
||||
responseTime: response.responseTime
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Add options
|
||||
* stopOnError:Boolean
|
||||
* @type {Object}
|
||||
*/
|
||||
module.exports = {
|
||||
init: function (done) {
|
||||
// @todo - code item global timeout and delay here
|
||||
done();
|
||||
},
|
||||
|
||||
triggers: ['beforeItem', 'item', 'beforePrerequest', 'prerequest', 'beforeTest', 'test'],
|
||||
|
||||
process: {
|
||||
/**
|
||||
* @param {Function=} callback
|
||||
* @param {Object} payload
|
||||
* @param {Function} next
|
||||
* @todo validate payload
|
||||
*/
|
||||
item: function (callback, payload, next) {
|
||||
// adjust for polymorphic instructions
|
||||
if (!next && _.isFunction(payload) && !_.isFunction(callback)) {
|
||||
next = payload;
|
||||
payload = callback;
|
||||
callback = null;
|
||||
}
|
||||
|
||||
var item = payload.item,
|
||||
originalRequest = item.request.clone(),
|
||||
coords = payload.coords,
|
||||
data = _.isObject(payload.data) ? payload.data : {},
|
||||
environment = _.isObject(payload.environment) ? payload.environment : {},
|
||||
globals = _.isObject(payload.globals) ? payload.globals : {},
|
||||
collectionVariables = _.isObject(payload.collectionVariables) ? payload.collectionVariables : {},
|
||||
_variables = _.isObject(payload._variables) ? payload._variables : {},
|
||||
stopOnError = _.has(payload, 'stopOnError') ? payload.stopOnError : this.options.stopOnError,
|
||||
|
||||
// @todo: this is mostly coded in event extension and we are
|
||||
// still not sure whether that is the right place for it to be.
|
||||
abortOnFailure = this.options.abortOnFailure,
|
||||
stopOnFailure = this.options.stopOnFailure,
|
||||
delay = _.get(this.options, 'delay.item'),
|
||||
|
||||
ctxTemplate;
|
||||
|
||||
// validate minimum parameters required for the command to work
|
||||
if (!(item && coords)) {
|
||||
return next(new Error('runtime: item execution is missing required parameters'));
|
||||
}
|
||||
|
||||
// store a common uuid in the coords
|
||||
coords.ref = uuid.v4();
|
||||
|
||||
// here we code to queue prerequest script, then make a request and then execute test script
|
||||
this.triggers.beforeItem(null, coords, item);
|
||||
|
||||
this.queueDelay(function () {
|
||||
// create the context object for scripts to run
|
||||
ctxTemplate = {
|
||||
collectionVariables: collectionVariables,
|
||||
_variables: _variables,
|
||||
globals: globals,
|
||||
environment: environment,
|
||||
data: data,
|
||||
request: item.request
|
||||
};
|
||||
|
||||
// @todo make it less nested by coding Instruction.thenQueue
|
||||
this.queue('event', {
|
||||
name: 'prerequest',
|
||||
item: item,
|
||||
coords: coords,
|
||||
context: ctxTemplate,
|
||||
trackContext: ['globals', 'environment', 'collectionVariables'],
|
||||
stopOnScriptError: stopOnError,
|
||||
stopOnFailure: stopOnFailure
|
||||
}).done(function (prereqExecutions, prereqExecutionError) {
|
||||
// if stop on error is marked and script executions had an error,
|
||||
// do not proceed with more commands, instead we bail out
|
||||
if ((stopOnError || stopOnFailure) && prereqExecutionError) {
|
||||
this.triggers.item(null, coords, item); // @todo - should this trigger receive error?
|
||||
|
||||
return callback && callback.call(this, prereqExecutionError, {
|
||||
prerequest: prereqExecutions
|
||||
});
|
||||
}
|
||||
|
||||
// update allowed request mutation properties with the mutated context
|
||||
// @note from this point forward, make sure this mutated
|
||||
// request instance is used for upcoming commands.
|
||||
ALLOWED_REQUEST_MUTATIONS.forEach(function (property) {
|
||||
if (_.has(ctxTemplate, ['request', property])) {
|
||||
item.request[property] = ctxTemplate.request[property];
|
||||
}
|
||||
|
||||
// update property's parent reference
|
||||
if (item.request[property] && typeof item.request[property].setParent === 'function') {
|
||||
item.request[property].setParent(item.request);
|
||||
}
|
||||
});
|
||||
|
||||
this.queue('request', {
|
||||
item: item,
|
||||
globals: ctxTemplate.globals,
|
||||
environment: ctxTemplate.environment,
|
||||
collectionVariables: ctxTemplate.collectionVariables,
|
||||
_variables: ctxTemplate._variables,
|
||||
data: ctxTemplate.data,
|
||||
coords: coords,
|
||||
source: 'collection'
|
||||
}).done(function (result, requestError) {
|
||||
!result && (result = {});
|
||||
|
||||
var request = result.request,
|
||||
response = result.response,
|
||||
cookies = result.cookies;
|
||||
|
||||
if ((stopOnError || stopOnFailure) && requestError) {
|
||||
this.triggers.item(null, coords, item); // @todo - should this trigger receive error?
|
||||
|
||||
return callback && callback.call(this, requestError, {
|
||||
request: request
|
||||
});
|
||||
}
|
||||
|
||||
// also the test object requires the updated request object (since auth helpers may modify it)
|
||||
request && (ctxTemplate.request = request);
|
||||
|
||||
// @note convert response instance to plain object.
|
||||
// we want to avoid calling Response.toJSON() which triggers toJSON on Response.stream buffer.
|
||||
// Because that increases the size of stringified object by 3 times.
|
||||
// Also, that increases the total number of tokens (buffer.data) whereas Buffer.toString
|
||||
// generates a single string that is easier to stringify and sent over the UVM bridge.
|
||||
response && (ctxTemplate.response = getResponseJSON(response));
|
||||
|
||||
// set cookies for this transaction
|
||||
cookies && (ctxTemplate.cookies = cookies);
|
||||
|
||||
// the context template also has a test object to store assertions
|
||||
ctxTemplate.tests = {}; // @todo remove
|
||||
|
||||
this.queue('event', {
|
||||
name: 'test',
|
||||
item: item,
|
||||
coords: coords,
|
||||
context: ctxTemplate,
|
||||
trackContext: ['tests', 'globals', 'environment', 'collectionVariables'],
|
||||
stopOnScriptError: stopOnError,
|
||||
abortOnFailure: abortOnFailure,
|
||||
stopOnFailure: stopOnFailure
|
||||
}).done(function (testExecutions, testExecutionError) {
|
||||
var visualizerData = extractVisualizerData(prereqExecutions, testExecutions),
|
||||
visualizerResult;
|
||||
|
||||
if (visualizerData) {
|
||||
visualizer.processTemplate(visualizerData.template,
|
||||
visualizerData.data,
|
||||
visualizerData.options,
|
||||
function (err, processedTemplate) {
|
||||
visualizerResult = {
|
||||
// bubble up the errors while processing template through visualizer result
|
||||
error: err,
|
||||
|
||||
// add processed template and data to visualizer result
|
||||
processedTemplate: processedTemplate,
|
||||
data: visualizerData.data
|
||||
};
|
||||
|
||||
// trigger an event saying that item has been processed
|
||||
this.triggers.item(null, coords, item, visualizerResult);
|
||||
}.bind(this));
|
||||
}
|
||||
else {
|
||||
// trigger an event saying that item has been processed
|
||||
// @todo - should this trigger receive error?
|
||||
this.triggers.item(null, coords, item, null);
|
||||
}
|
||||
|
||||
// reset mutated request with original request instance
|
||||
// @note request mutations are not persisted across iterations
|
||||
item.request = originalRequest;
|
||||
|
||||
callback && callback.call(this, ((stopOnError || stopOnFailure) && testExecutionError) ?
|
||||
testExecutionError : null, {
|
||||
prerequest: prereqExecutions,
|
||||
request: request,
|
||||
response: response,
|
||||
test: testExecutions
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}.bind(this), {
|
||||
time: delay,
|
||||
source: 'item',
|
||||
cursor: coords
|
||||
}, next);
|
||||
}
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user