Simon Priet e69a613a37 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.
2021-09-08 14:01:19 +02:00

286 lines
8.6 KiB
JavaScript

const _ = require('lodash'),
Ajv = require('ajv'),
sdk = require('postman-collection'),
PostmanCookieJar = require('./cookie-jar'),
VariableScope = sdk.VariableScope,
PostmanRequest = sdk.Request,
PostmanResponse = sdk.Response,
PostmanCookieList = sdk.CookieList,
chai = require('chai'),
/**
* Use this function to assign readonly properties to an object
*
* @private
*
* @param {Object} obj -
* @param {Object} properties -
*/
_assignDefinedReadonly = function (obj, properties) {
var config = {
writable: false
},
prop;
for (prop in properties) {
if (Object.hasOwnProperty.call(properties, prop) && (properties[prop] !== undefined)) {
config.value = properties[prop];
Object.defineProperty(obj, prop, config);
}
}
return obj; // chainable
},
setupTestRunner = require('./pmapi-setup-runner');
/**
* @constructor
*
* @param {Execution} execution -
* @param {Function} onRequest -
* @param {Function} onAssertion -
* @param {Object} cookieStore -
*/
function Postman (execution, onRequest, onAssertion, cookieStore) {
// @todo - ensure runtime passes data in a scope format
let iterationData = new VariableScope();
iterationData.syncVariablesFrom(execution.data);
// instead of creating new instance of variableScope,
// reuse one so that any changes made through pm.variables.set() is directly reflected
execution._variables.addLayer(iterationData.values);
execution._variables.addLayer(execution.environment.values);
execution._variables.addLayer(execution.collectionVariables.values);
execution._variables.addLayer(execution.globals.values);
execution.cookies && (execution.cookies.jar = function () {
return new PostmanCookieJar(cookieStore);
});
_assignDefinedReadonly(this, /** @lends Postman.prototype */ {
/**
* Contains information pertaining to the script execution
*
* @interface Info
*/
/**
* The pm.info object contains information pertaining to the script being executed.
* Useful information such as the request name, request Id, and iteration count are
* stored inside of this object.
*
* @type {Info}
*/
info: _assignDefinedReadonly({}, /** @lends Info */ {
/**
* Contains information whether the script being executed is a "prerequest" or a "test" script.
*
* @type {string}
* @instance
*/
eventName: execution.target,
/**
* Is the value of the current iteration being run.
*
* @type {number}
* @instance
*/
iteration: execution.cursor.iteration,
/**
* Is the total number of iterations that are scheduled to run.
*
* @type {number}
* @instance
*/
iterationCount: execution.cursor.cycles,
/**
* The saved name of the individual request being run.
*
* @type {string}
* @instance
*/
requestName: execution.legacy._itemName,
/**
* The unique guid that identifies the request being run.
*
* @type {string}
* @instance
*/
requestId: execution.legacy._itemId
}),
/**
* @type {VariableScope}
*/
globals: execution.globals,
/**
* @type {VariableScope}
*/
environment: execution.environment,
/**
* @type {VariableScope}
*/
collectionVariables: execution.collectionVariables,
/**
* @type {VariableScope}
*/
variables: execution._variables,
/**
* The iterationData object contains data from the data file provided during a collection run.
*
* @type {VariableScope}
*/
iterationData: iterationData,
/**
* The request object inside pm is a representation of the request for which this script is being run.
* For a pre-request script, this is the request that is about to be sent and when in a test script,
* this is the representation of the request that was sent.
*
* @type {Request}
*/
request: execution.request,
/**
* Inside the test scripts, the pm.response object contains all information pertaining
* to the response that was received.
*
* @type {Response}
* @customexclude true
*/
response: execution.response,
/**
* The cookies object contains a list of cookies that are associated with the domain
* to which the request was made.
*
* @type {CookieList}
*/
cookies: execution.cookies,
/**
* @interface Visualizer
*/
/**
* @type {Visualizer}
*/
visualizer: /** @lends Visualizer */ {
/**
* Set visualizer template and its options
*
* @instance
* @param {String} template - visualisation layout in form of template
* @param {Object} [data] - data object to be used in template
* @param {Object} [options] - options to use while processing the template
*/
set (template, data, options) {
if (typeof template !== 'string') {
throw new Error(`Invalid template. Template must be of type string, found ${typeof template}`);
}
if (data && typeof data !== 'object') {
throw new Error(`Invalid data. Data must be an object, found ${typeof data}`);
}
if (options && typeof options !== 'object') {
throw new Error(`Invalid options. Options must be an object, found ${typeof options}`);
}
/**
*
* @property {String} template - template string
* @property {Object} data - data to use while processing template
* @property {Object} options - options to use while processing template
*/
execution.return.visualizer = {
template,
data,
options
};
},
/**
* Clear all visualizer data
*
* @instance
*/
clear () {
execution.return.visualizer = undefined;
}
}
});
// extend pm api with test runner abilities
setupTestRunner(this, onAssertion);
// add response assertions
if (this.response) {
// these are removed before serializing see `purse.js`
Object.defineProperty(this.response, 'to', {
get () {
return chai.expect(this).to;
}
});
}
// add request assertions
if (this.request) {
// these are removed before serializing see `purse.js`
Object.defineProperty(this.request, 'to', {
get () {
return chai.expect(this).to;
}
});
}
/**
* Allows one to send request from script asynchronously.
*
* @param {Request|String} req -
* @param {Function} callback -
*/
this.sendRequest = function (req, callback) {
var self = this;
if (!req) {
return _.isFunction(callback) && callback.call(self, new Error('sendrequest: nothing to request'));
}
onRequest(PostmanRequest.isRequest(req) ? req : (new PostmanRequest(req)), function (err, resp, history) {
if (history && !PostmanCookieList.isCookieList(history.cookies)) {
history.cookies = new PostmanCookieList({}, history.cookies);
}
_.isFunction(callback) && callback.call(self, err,
PostmanResponse.isResponse(resp) ? resp : (new PostmanResponse(resp)),
history);
});
return self;
};
iterationData = null; // precautionary
}
// expose chai assertion library via prototype
/**
* @type {Chai.ExpectStatic}
*/
Postman.prototype.expect = chai.expect;
// make chai use postman extension
chai.use(require('chai-postman')(sdk, _, Ajv));
// export
module.exports = Postman;