var _ = require('../util').lodash, Property = require('./property').Property, PropertyList = require('./property-list').PropertyList, EventList = require('./event-list').EventList, Request = require('./request').Request, RequestAuth = require('./request-auth').RequestAuth, Response = require('./response').Response, Item, /** * @private * @type {String} */ OBJECT = 'object', /** * @private * @type {String} */ STRING = 'string', /** * Extracts `auth` from an entity. Checks if `auth` is present and it is not falsy type. * * @private * * @param {Object} [entity] - */ extractAuth = function (entity) { var auth; return (entity && (auth = entity.auth) && RequestAuth.isValidType(auth.type)) ? auth : undefined; }, /** * Extracts `protocolProfileBehavior` from an entity. * * @private * * @param {Item|ItemGroup} entity - * @returns {Object} */ extractProtocolProfileBehavior = function (entity) { var protocolProfileBehavior = entity && entity.protocolProfileBehavior; return typeof protocolProfileBehavior === OBJECT ? protocolProfileBehavior : {}; }; /** * The following defines the object (or JSON) structure that one can pass to the Item while creating a new Item * instance. This is also the object structure returned when `.toJSON()` is called on an Item instance. * * @typedef Item.definition * * @property {Request.definition=} [request] A request represents an HTTP request. If a string, the string is assumed to * be the request URL and the method is assumed to be 'GET'. * @property {Array=} [responses] Sample responses for this request can be stored along with the * item definition. * @property {Array=} [events] Postman allows you to configure scripts to run when specific events * occur. These scripts are stored here, and can be referenced in the collection by their id. * * @example * { * "name": "Get Headers from Echo", * "id": "my-request-1", * "description": "Makes a GET call to echo service and returns the client headers that were sent", * * "request": { * "url": "https://postman-echo.com/headers", * "method": "GET" * } * } * * @todo add response and event to example */ _.inherit(( /** * A Postman Collection Item that holds your request definition, responses and other stuff. An Item essentially is * a HTTP request definition along with the sample responses and test scripts clubbed together. One or more of these * items can be grouped together and placed in an {@link ItemGroup} and as such forms a {@link Collection} of * requests. * * @constructor * @extends {Property} * * @param {Item.definition=} [definition] While creating a new instance of Item, one can provide the initial * configuration of the item with the the request it sends, the expected sample responses, tests, etc * * @example Add a new Item to a folder in a collection instance * var Collection = require('postman-collection').Collection, * Item = require('postman-collection').Item, * myCollection; * * myCollection = new Collection({ * "item": [{ * "id": "my-folder-1", * "name": "The solo folder in this collection", * "item": [] // blank array indicates this is a folder * }] * }); // create a collection with an empty folder * // add a request to "my-folder-1" that sends a GET request * myCollection.items.one("my-folder-1").items.add(new Item({ * "name": "Send a GET request", * "id": "my-get-request", * "request": { * "url": "https://postman-echo.com/get", * "method": "GET" * } * })); */ Item = function PostmanItem (definition) { // this constructor is intended to inherit and as such the super constructor is required to be executed Item.super_.apply(this, arguments); _.mergeDefined(this, /** @lends Item.prototype */ { /** * The instance of the {@link Request} object inside an Item defines the HTTP request that is supposed to be * sent. It further contains the request method, url, request body, etc. * * @type {Request} */ request: definition && (new Request(definition.request)), /** * An Item also contains a list of sample responses that is expected when the request defined in the item is * executed. The sample responses are useful in elaborating API usage and is also useful for other * integrations that use the sample responses to do something - say a mock service. * * @type {PropertyList} */ responses: new PropertyList(Response, this, definition && definition.response), /** * Events are a set of of {@link Script}s that are executed when certain activities are triggered on an * Item. For example, on defining an event that listens to the "test" event, would cause the associated * script of the event to be executed when the test runs. * * @type {EventList} * * @example Add a script to be executed on "prerequest" event * var Collection = require('postman-collection').Collection, * Item = require('postman-collection').Item, * myCollection; * * myCollection = new Collection({ * "item": [{ * "name": "Send a GET request", * "id": "my-get-request", * "request": { * "url": "https://postman-echo.com/get", * "method": "GET" * } * }] * }); // create a collection with one request * * // add a pre-request script to the event list * myCollection.items.one('my-get-request').events.add({ * "listen": "prerequest", * "script": { * "type": "text/javascript", * "exec": "console.log(new Date())" * } * }); */ events: new EventList(this, definition && definition.event), /** * Set of configurations used to alter the usual behavior of sending the request. * * @type {Object} */ protocolProfileBehavior: definition && typeof definition.protocolProfileBehavior === OBJECT ? definition.protocolProfileBehavior : undefined }); }), Property); _.assign(Item.prototype, /** @lends Item.prototype */ { /** * Defines whether this property instances requires an id * * @private * @readOnly * @type {Boolean} */ _postman_propertyRequiresId: true, /** * Fetches applicable AuthType from the current item. * * @returns {RequestAuth} * * @note Since v3.0 release, this returns the entire auth RequestAuth, instead of just the parameters * * @todo Deprecate this and use getAuthResolved instead */ getAuth: function () { var requestAuth; // find auth on request, if not found or empty auth, lookup in the parents // eslint-disable-next-line no-cond-assign return (requestAuth = extractAuth(this.request)) ? requestAuth : this.findInParents('auth', extractAuth); }, /** * Fetches protocol profile behavior for the current Item * * @private * @returns {Object} * * @note This will not inherit protocol profile behaviors from parent, * use `getProtocolProfileBehaviorResolved` to achieve that behavior. */ getProtocolProfileBehavior: function () { return extractProtocolProfileBehavior(this); }, /** * Fetches protocol profile behavior applicable for the current Item, * inherited from parent ItemGroup(s). * * @private * @returns {Object} */ getProtocolProfileBehaviorResolved: function () { var protocolProfileBehavior = extractProtocolProfileBehavior(this); // inherit protocolProfileBehavior from ItemGroup(s) this.forEachParent({ withRoot: true }, function (entity) { protocolProfileBehavior = { ...extractProtocolProfileBehavior(entity), ...protocolProfileBehavior }; }); return protocolProfileBehavior; }, /** * Set or update protocol profile behavior for the current Item. * * @example Set or update protocol profile behavior * item.setProtocolProfileBehavior('strictSSL', false); * * @private * @param {String} key - protocol profile behavior name * @param {*} value - protocol profile behavior value * @returns {Item} */ setProtocolProfileBehavior: function (key, value) { // bail out if key is non-string if (typeof key !== STRING) { return this; } !this.protocolProfileBehavior && (this.protocolProfileBehavior = {}); this.protocolProfileBehavior[key] = value; return this; }, /** * Unset or delete protocol profile behavior for the current Item. * * @example Unset protocol profile behavior * item.unsetProtocolProfileBehavior('strictSSL'); * * @private * @param {String} key - protocol profile behavior name to unset * @returns {Item} */ unsetProtocolProfileBehavior: function (key) { // bail out if property protocolProfileBehavior is not set or key is non-string if (!(typeof this.protocolProfileBehavior === OBJECT && typeof key === STRING)) { return this; } if (_.has(this.protocolProfileBehavior, key)) { delete this.protocolProfileBehavior[key]; } return this; }, /** * Returns {@link Event}s corresponding to a particular event name. If no name is given, returns all events. This * is useful when you want to trigger all associated scripts for an event. * * @param {String} name - one of the available event types such as `test`, `prerequest`, `postrequest`, etc. * @returns {Array} * * @example Get all events for an item and evaluate their scripts * var fs = require('fs'), // needed to read JSON file from disk * Collection = require('postman-collection').Collection, * myCollection; * * // Load a collection to memory from a JSON file on disk (say, sample-collection.json) * myCollection = new Collection(JSON.stringify(fs.readFileSync('sample-collection.json').toString())); * * // assuming the collection has a request called "my-request-1" in root, we get it's test events * myCollection.items.one("my-request-1").getEvents("test").forEach(function (event) { * event.script && eval(event.script.toSource()); * }); * * @todo decide appropriate verb names based on the fact that it gets events for a specific listener name * @draft */ getEvents: function (name) { if (!name) { return this.events.all(); // return all events if name is not provided. } return this.events.filter(function (ev) { return ev.listen === name; }); }, /** * Sets authentication method for the request within this item * * @param {?String|RequestAuth.definition} type - * @param {VariableList=} [options] - * * @note This function was previously (in v2 of SDK) used to clone request and populate headers. Now it is used to * only set auth information to request */ authorizeRequestUsing: function (type, options) { if (!this.request) { this.request = new Request(); } // worst case return this.request.authorizeUsing(type, options); } }); _.assign(Item, /** @lends Item */ { /** * Defines the name of this property for internal use. * * @private * @readOnly * @type {String} */ _postman_propertyName: 'Item', /** * Check whether an object is an instance of PostmanItem. * * @param {*} obj - * @returns {Boolean} */ isItem: function (obj) { return Boolean(obj) && ((obj instanceof Item) || _.inSuperChain(obj.constructor, '_postman_propertyName', Item._postman_propertyName)); } }); module.exports = { Item };