From d3460b8add5dd2463f09e56352c321e805c2dd1a Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Wed, 1 Apr 2020 20:08:26 +0530 Subject: [PATCH 01/14] Boilerplate Code for nodejs-superagent codegen --- codegens/nodejs-superagent/.gitignore | 69 + codegens/nodejs-superagent/.jsdoc-config.json | 34 + codegens/nodejs-superagent/.npmignore | 74 + codegens/nodejs-superagent/README.md | 68 + codegens/nodejs-superagent/index.js | 1 + codegens/nodejs-superagent/lib/index.js | 4 + codegens/nodejs-superagent/lib/lodash.js | 456 ++++++ .../nodejs-superagent/lib/parseRequest.js | 180 +++ codegens/nodejs-superagent/lib/superagent.js | 190 +++ codegens/nodejs-superagent/lib/util.js | 88 ++ .../nodejs-superagent/npm-shrinkwrap.json | 440 ++++++ codegens/nodejs-superagent/npm/test-lint.js | 58 + codegens/nodejs-superagent/npm/test-newman.js | 59 + codegens/nodejs-superagent/npm/test-unit.js | 59 + codegens/nodejs-superagent/npm/test.js | 18 + codegens/nodejs-superagent/package.json | 36 + codegens/nodejs-superagent/test/.eslintrc | 30 + .../test/newman/newman.test.js | 27 + codegens/nodejs-superagent/test/unit/.gitkeep | 0 .../fixtures/testcollection/collection.json | 1349 +++++++++++++++++ .../test/unit/snippet.test.js | 416 +++++ .../test/unit/validation.test.js | 30 + 22 files changed, 3686 insertions(+) create mode 100644 codegens/nodejs-superagent/.gitignore create mode 100644 codegens/nodejs-superagent/.jsdoc-config.json create mode 100644 codegens/nodejs-superagent/.npmignore create mode 100644 codegens/nodejs-superagent/README.md create mode 100644 codegens/nodejs-superagent/index.js create mode 100644 codegens/nodejs-superagent/lib/index.js create mode 100644 codegens/nodejs-superagent/lib/lodash.js create mode 100644 codegens/nodejs-superagent/lib/parseRequest.js create mode 100644 codegens/nodejs-superagent/lib/superagent.js create mode 100644 codegens/nodejs-superagent/lib/util.js create mode 100644 codegens/nodejs-superagent/npm-shrinkwrap.json create mode 100644 codegens/nodejs-superagent/npm/test-lint.js create mode 100644 codegens/nodejs-superagent/npm/test-newman.js create mode 100755 codegens/nodejs-superagent/npm/test-unit.js create mode 100755 codegens/nodejs-superagent/npm/test.js create mode 100644 codegens/nodejs-superagent/package.json create mode 100644 codegens/nodejs-superagent/test/.eslintrc create mode 100644 codegens/nodejs-superagent/test/newman/newman.test.js create mode 100644 codegens/nodejs-superagent/test/unit/.gitkeep create mode 100644 codegens/nodejs-superagent/test/unit/fixtures/testcollection/collection.json create mode 100644 codegens/nodejs-superagent/test/unit/snippet.test.js create mode 100644 codegens/nodejs-superagent/test/unit/validation.test.js diff --git a/codegens/nodejs-superagent/.gitignore b/codegens/nodejs-superagent/.gitignore new file mode 100644 index 000000000..dd41cd99b --- /dev/null +++ b/codegens/nodejs-superagent/.gitignore @@ -0,0 +1,69 @@ +.DS_Store +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# temporarily generated file +run.js + +# Prevent IDE stuff +.idea +.vscode +*.sublime-* + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +.coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +out/ diff --git a/codegens/nodejs-superagent/.jsdoc-config.json b/codegens/nodejs-superagent/.jsdoc-config.json new file mode 100644 index 000000000..085a7be65 --- /dev/null +++ b/codegens/nodejs-superagent/.jsdoc-config.json @@ -0,0 +1,34 @@ +{ + "tags": { + "allowUnknownTags": true, + "dictionaries": ["jsdoc", "closure"] + }, + "source": { + "include": ["lib"], + "includePattern": ".+\\.js(doc)?$", + "excludePattern": "(^|\\/|\\\\)_" + }, + + "plugins": [ + "plugins/markdown" + ], + + "templates": { + "cleverLinks": false, + "monospaceLinks": false, + "highlightTutorialCode" : true + }, + + "opts": { + "template": "./node_modules/postman-jsdoc-theme", + "encoding": "utf8", + "destination": "./out/docs", + "recurse": true, + "readme": "README.md" + }, + + "markdown": { + "parser": "gfm", + "hardwrap": false + } +} diff --git a/codegens/nodejs-superagent/.npmignore b/codegens/nodejs-superagent/.npmignore new file mode 100644 index 000000000..17156c3bc --- /dev/null +++ b/codegens/nodejs-superagent/.npmignore @@ -0,0 +1,74 @@ +### NPM Specific: Disregard recursive project files +### =============================================== +/.editorconfig +/.gitmodules +/test + +### Borrowed from .gitignore +### ======================== + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Prevent IDE stuff +.idea +.vscode +*.sublime-* + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +.coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +out/ diff --git a/codegens/nodejs-superagent/README.md b/codegens/nodejs-superagent/README.md new file mode 100644 index 000000000..435d36da5 --- /dev/null +++ b/codegens/nodejs-superagent/README.md @@ -0,0 +1,68 @@ +# codegen-nodejs-superagent + +> Converts Postman-SDK SuperAgent into code snippet for NodeJS-SuperAgent. + +#### Prerequisites +To run the module, ensure that you have NodeJS >= v6. A copy of the NodeJS installable can be downloaded from https://nodejs.org/en/download/package-manager. + +## Using the Module +The module will expose an object which will have property `convert` which is the function for converting the Postman-SDK request to nodejs-superagent code snippet and `getOptions` function which returns an array of supported options. + +### convert function +Convert function will take three parameters +* `request`- Postman-SDK Request object + +* `options`- options is an object which can have following properties + * `indentType`- String denoting type of indentation for code snippet. eg: 'Space', 'Tab' + * `indentCount`- positiveInteger representing count of indentation required. + * `requestTimeout` : Integer denoting time after which the request will bail out in milliseconds + * `trimRequestBody` : Trim request body fields + * `followRedirect` : Boolean denoting whether to redirect a request + * `ES6_enabled` : Boolean denoting whether to generate snippet with ES6 features + +* `callback`- callback function with first parameter as error and second parameter as string for code snippet + +##### Example: +```js +var request = new sdk.Request('www.google.com'), //using postman sdk to create request + options = { + indentType: 'Space', + indentCount: 2, + ES6_enabled: true + }; +convert(request, options, function(error, snippet) { + if (error) { + // handle error + } + // handle snippet +}); +``` + +### getOptions function + +This function returns a list of options supported by this codegen. + +#### Example +```js +var options = getOptions(); + +console.log(options); +// output +// [ +// { +// name: 'Set indentation count', +// id: 'indentCount', +// type: 'positiveInteger', +// default: 2, +// description: 'Set the number of indentation characters to add per code level' +// }, +// ... +// ] +``` + +### Guideline for using generated snippet +* Generated snippet requires `superagent` and `fs` modules. + +* Since Postman-SDK Request object doesn't provide complete path of the file, it needs to be manually inserted in case of uploading a file. + +* This module doesn't support cookies. diff --git a/codegens/nodejs-superagent/index.js b/codegens/nodejs-superagent/index.js new file mode 100644 index 000000000..bb0a047c4 --- /dev/null +++ b/codegens/nodejs-superagent/index.js @@ -0,0 +1 @@ +module.exports = require('./lib'); diff --git a/codegens/nodejs-superagent/lib/index.js b/codegens/nodejs-superagent/lib/index.js new file mode 100644 index 000000000..d9a9054fc --- /dev/null +++ b/codegens/nodejs-superagent/lib/index.js @@ -0,0 +1,4 @@ +module.exports = { + convert: require('./superagent').convert, + getOptions: require('./superagent').getOptions +}; diff --git a/codegens/nodejs-superagent/lib/lodash.js b/codegens/nodejs-superagent/lib/lodash.js new file mode 100644 index 000000000..55ea6666d --- /dev/null +++ b/codegens/nodejs-superagent/lib/lodash.js @@ -0,0 +1,456 @@ +/* istanbul ignore next */ +module.exports = { + + /** + * Checks if `value` is an empty object, array or string. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Values such as strings, arrays are considered empty if they have a `length` of `0`. + * + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * isEmpty(null) + * // => true + * + * isEmpty(true) + * // => true + * + * isEmpty(1) + * // => true + * + * isEmpty([1, 2, 3]) + * // => false + * + * isEmpty('abc') + * // => false + * + * isEmpty({ 'a': 1 }) + * // => false + */ + isEmpty: function (value) { + // eslint-disable-next-line lodash/prefer-is-nil + if (value === null || value === undefined) { + return true; + } + if (Array.isArray(value) || typeof value === 'string' || typeof value.splice === 'function') { + return !value.length; + } + + for (const key in value) { + if (Object.prototype.hasOwnProperty.call(value, key)) { + return false; + } + } + + return true; + }, + + /** + * Checks if `value` is `undefined`. + * + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * isUndefined(void 0) + * // => true + * + * isUndefined(null) + * // => false + */ + isUndefined: function (value) { + return value === undefined; + }, + + /** + * Checks if `func` is classified as a `Function` object. + * + * @param {*} func The value to check. + * @returns {boolean} Returns `true` if `func` is a function, else `false`. + * @example + * + * isFunction(self.isEmpty) + * // => true + * + * isFunction(/abc/) + * // => false + */ + isFunction: function (func) { + return typeof func === 'function'; + }, + + /** + * Converts the first character of `string` to upper case and the remaining + * to lower case. + * + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * capitalize('FRED') + * // => 'Fred' + * + * capitalize('john') + * // => 'John' + */ + + capitalize: function (string) { + return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); + }, + + /** + * Reduces `array` to a value which is the accumulated result of running + * each element in `array` thru `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not given, the first element of `array` is used as the initial + * value. The iteratee is invoked with four arguments: + * (accumulator, value, index|key, array). + * + * @param {Array} array The Array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @example + * + * reduce([1, 2], (sum, n) => sum + n, 0) + * // => 3 + * + */ + reduce: function (array, iteratee, accumulator) { + return array.reduce(iteratee, accumulator); + }, + + /** + * Iterates over elements of `array`, returning an array of all elements + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index, array). + * + * @param {Array} array The array to iterate over. + * @param {Function|object} predicate The function/object invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @example + * + * const users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ] + * + * filter(users, ({ active }) => active) + * // => object for ['barney'] + */ + filter: function (array, predicate) { + if (typeof predicate === 'function') { + return array.filter(predicate); + } + var key = Object.keys(predicate), + val = predicate[key], + res = []; + array.forEach(function (item) { + if (item[key] && item[key] === val) { + res.push(item); + } + }); + return res; + }, + + /** + * The opposite of `filter` this method returns the elements of `array` + * that `predicate` does **not** return truthy for. + * + * @param {Array} array collection to iterate over. + * @param {String} predicate The String that needs to have truthy value, invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @example + * + * const users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ] + * + * reject(users, 'active') + * // => object for ['fred'] + */ + reject: function (array, predicate) { + var res = []; + array.forEach((object) => { + if (!object[predicate]) { + res.push(object); + } + }); + return res; + }, + + /** + * Creates an array of values by running each element of `array` thru `iteratee`. + * The iteratee is invoked with three arguments: (value, index, array). + * + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + * @example + * + * function square(n) { + * return n * n + * } + * + * map([4, 8], square) + * // => [16, 64] + */ + map: function (array, iteratee) { + return array.map(iteratee); + }, + + /** + * Iterates over elements of `collection` and invokes `iteratee` for each element. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @example + * + * forEach([1, 2], value => console.log(value)) + * // => Logs `1` then `2`. + * + * forEach({ 'a': 1, 'b': 2 }, (value, key) => console.log(key)) + * // => Logs 'a' then 'b' + */ + + forEach: function (collection, iteratee) { + if (collection === null) { + return null; + } + + if (Array.isArray(collection)) { + return collection.forEach(iteratee); + } + const iterable = Object(collection), + props = Object.keys(collection); + var index = -1, + key, i; + + for (i = 0; i < props.length; i++) { + key = props[++index]; + iteratee(iterable[key], key, iterable); + } + return collection; + }, + + /** + * Checks if `value` is in `collection`. If `collection` is a string, it's + * checked for a substring of `value`, otherwise it checks if the `value` is present + * as a key in a `collection` object. + * + * @param {Array|Object|string} collection The collection to inspect. + * @param {*} value The value to search for. + * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes({ 'a': 1, 'b': 2 }, 1); + * // => true + * + * _.includes('abcd', 'bc'); + * // => true + */ + includes: function (collection, value) { + if (Array.isArray(collection) || typeof collection === 'string') { + return collection.includes(value); + } + for (var key in collection) { + if (collection.hasOwnProperty(key)) { + if (collection[key] === value) { + return true; + } + } + } + return false; + }, + + /** + * Gets the size of `collection` by returning its length for array and strings. + * For objects it returns the number of enumerable string keyed + * properties. + * + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * size([1, 2, 3]) + * // => 3 + * + * size({ 'a': 1, 'b': 2 }) + * // => 2 + * + * size('pebbles') + * // => 7 + */ + size: function (collection) { + // eslint-disable-next-line lodash/prefer-is-nil + if (collection === null || collection === undefined) { + return 0; + } + if (Array.isArray(collection) || typeof collection === 'string') { + return collection.length; + } + + return Object.keys(collection).length; + }, + + /** + * Converts all elements in `array` into a string separated by `separator`. + * + * @param {Array} array The array to convert. + * @param {string} [separator=','] The element separator. + * @returns {string} Returns the joined string. + * @example + * + * _.join(['a', 'b', 'c'], '~'); + * // => 'a~b~c' + */ + join: function (array, separator) { + if (array === null) { + return ''; + } + return array.join(separator); + }, + + /** + * Removes trailing whitespace or specified characters from `string`. + * + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @returns {string} Returns the trimmed string. + * @example + * + * trimEnd(' abc ') + * // => ' abc' + * + * trimEnd('-_-abc-_-', '_-') + * // => '-_-abc' + */ + trimEnd: function (string, chars) { + if (!string) { + return ''; + } + if (string && !chars) { + return string.replace(/\s*$/, ''); + } + chars += '$'; + return string.replace(new RegExp(chars, 'g'), ''); + }, + + /** + * Returns the index of the first + * element `predicate` returns truthy for. + * + * @param {Array} array The array to inspect. + * @param {Object} predicate The exact object to be searched for in the array. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * _.findIndex(users, {'active' : false}); + * // => 0 + * + */ + findIndex: function (array, predicate) { + var length = array === null ? 0 : array.length, + index = -1, + keys = Object.keys(predicate), + found, i; + if (!length) { + return -1; + } + for (i = 0; i < array.length; i++) { + found = true; + // eslint-disable-next-line no-loop-func + keys.forEach((key) => { + if (!(array[i][key] && array[i][key] === predicate[key])) { + found = false; + } + }); + if (found) { + index = i; + break; + } + } + return index; + }, + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @param {Object} object The object to query. + * @param {string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * const object = { a: {b : 'c'} } + * + * + * get(object, 'a.b.c', 'default') + * // => 'default' + * + * get(object, 'a.b', 'default') + * // => 'c' + */ + get: function (object, path, defaultValue) { + if (object === null) { + return undefined; + } + var arr = path.split('.'), + res = object, + i; + for (i = 0; i < arr.length; i++) { + res = res[arr[i]]; + if (res === undefined) { + return defaultValue; + } + } + return res; + }, + + /** + * Checks if `predicate` returns truthy for **all** elements of `array`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * every([true, 1, null, 'yes'], Boolean) + * // => false + */ + every: function (array, predicate) { + var index = -1, + length = array === null ? 0 : array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + +}; diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js new file mode 100644 index 000000000..650c315b5 --- /dev/null +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -0,0 +1,180 @@ +var _ = require('./lodash'), + + sanitize = require('./util').sanitize, + path = require('path'); + +/** + * parses body of request when type of the request body is formdata or urlencoded and + * returns code snippet for nodejs to add body + * + * @param {Array} dataArray - array containing body elements of request + * @param {String} indentString - string required for indentation + * @param {Boolean} trimBody - indicates whether to trim body or not + */ +function extractFormData (dataArray, indentString, trimBody) { + if (!dataArray) { + return ''; + } + var snippetString = _.reduce(dataArray, (accumalator, item) => { + if (item.disabled) { + return accumalator; + } + /* istanbul ignore next */ + if (item.type === 'file') { + /** + * creating snippet to send file in nodejs request + * for example: + * 'fieldname': { + * 'value': fs.createStream('filename.ext'), + * 'options': { + * 'filename': 'filename.ext', + * 'contentType: null + * } + * } + * } + */ + if (Array.isArray(item.src) && item.src.length) { + let fileSnippet = '', + fileArray = []; + _.forEach(item.src, (filePath) => { + fileArray.push(`${indentString.repeat(3)}fs.createReadStream('${sanitize(filePath, trimBody)}')`); + }); + if (fileArray.length) { + fileSnippet += `${indentString.repeat(2)}'${sanitize(item.key, trimBody)}': ` + + `[\n${fileArray.join(',\n')}\n${indentString.repeat(2)}]`; + accumalator.push(fileSnippet); + } + else { + return accumalator; + } + } + else if (typeof item.src !== 'string') { + accumalator.push([ + indentString.repeat(2) + `'${sanitize(item.key, trimBody)}': {`, + indentString.repeat(3) + '\'value\': fs.createReadStream(\'/path/to/file\'),', + indentString.repeat(3) + '\'options\': {', + indentString.repeat(4) + '\'filename\': \'filename\'', + indentString.repeat(4) + '\'contentType\': null', + indentString.repeat(3) + '}', + indentString.repeat(2) + '}' + ].join('\n')); + } + else { + var pathArray = item.src.split(path.sep), + fileName = pathArray[pathArray.length - 1]; + accumalator.push([ + indentString.repeat(2) + `'${sanitize(item.key, trimBody)}': {`, + indentString.repeat(3) + `'value': fs.createReadStream('${sanitize(item.src, trimBody)}'),`, + indentString.repeat(3) + '\'options\': {', + indentString.repeat(4) + `'filename': '${sanitize(fileName, trimBody)}',`, + indentString.repeat(4) + '\'contentType\': null', + indentString.repeat(3) + '}', + indentString.repeat(2) + '}' + ].join('\n')); + } + } + else { + accumalator.push( + indentString.repeat(2) + + `'${sanitize(item.key, trimBody)}': '${sanitize(item.value, trimBody)}'` + ); + } + return accumalator; + }, []); + return snippetString.join(',\n') + '\n'; +} + +/** + * Parses body object based on mode of body and returns code snippet + * + * @param {Object} requestbody - json object for body of request + * @param {String} indentString - string for indentation + * @param {Boolean} trimBody - indicates whether to trim body fields or not + * @param {String} contentType Content type of the body being sent + */ +function parseBody (requestbody, indentString, trimBody, contentType) { + if (requestbody) { + switch (requestbody.mode) { + case 'raw': + if (contentType === 'application/json') { + try { + let jsonBody = JSON.parse(requestbody[requestbody.mode]); + return `body: JSON.stringify(${JSON.stringify(jsonBody)})\n`; + } + catch (error) { + return `body: ${JSON.stringify(requestbody[requestbody.mode])}\n`; + } + } + return `body: ${JSON.stringify(requestbody[requestbody.mode])}\n`; + // eslint-disable-next-line no-case-declarations + case 'graphql': + let query = requestbody[requestbody.mode].query, + graphqlVariables; + try { + graphqlVariables = JSON.parse(requestbody[requestbody.mode].variables); + } + catch (e) { + graphqlVariables = {}; + } + return 'body: JSON.stringify({\n' + + `${indentString.repeat(2)}query: '${sanitize(query, trimBody)}',\n` + + `${indentString.repeat(2)}variables: ${JSON.stringify(graphqlVariables)}\n` + + `${indentString}})`; + case 'formdata': + return `formData: {\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + + indentString + '}'; + case 'urlencoded': + return `form: {\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + + indentString + '}'; + /* istanbul ignore next */ + case 'file': + // return 'formData: {\n' + + // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + + // indentString + '}'; + return 'body: ""\n'; + default: + return ''; + } + } + return ''; +} + +/** + * parses header of request object and returns code snippet of nodejs superagent to add header + * + * @param {Object} request - Postman SDK request object + * @param {String} indentString - indentation required in code snippet + * @returns {String} - code snippet of nodejs superagent to add header + */ +function parseHeader (request, indentString) { + var headerObject = request.getHeaders({enabled: true}), + headerSnippet = indentString + '\'headers\': {\n'; + + if (!_.isEmpty(headerObject)) { + headerSnippet += _.reduce(Object.keys(headerObject), function (accumalator, key) { + if (Array.isArray(headerObject[key])) { + var headerValues = []; + _.forEach(headerObject[key], (value) => { + headerValues.push(`'${sanitize(value)}'`); + }); + accumalator.push( + indentString.repeat(2) + `'${sanitize(key, true)}': [${headerValues.join(', ')}]` + ); + } + else { + accumalator.push( + indentString.repeat(2) + `'${sanitize(key, true)}': '${sanitize(headerObject[key])}'` + ); + } + return accumalator; + }, []).join(',\n') + '\n'; + } + + headerSnippet += indentString + '}'; + return headerSnippet; +} + +module.exports = { + parseBody: parseBody, + parseHeader: parseHeader +}; diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js new file mode 100644 index 000000000..c1a0a84c8 --- /dev/null +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -0,0 +1,190 @@ +var _ = require('./lodash'), + + parseRequest = require('./parseRequest'), + sanitize = require('./util').sanitize, + sanitizeOptions = require('./util').sanitizeOptions; + +/** + * returns snippet of nodejs(superagent) by parsing data from Postman-SDK request object + * + * @param {Object} request - Postman SDK request object + * @param {String} indentString - indentation required for code snippet + * @param {Object} options + * @returns {String} - nodejs(superagent) code snippet for given request object + */ +function makeSnippet (request, indentString, options) { + var snippet, + optionsArray = [], + isFormDataFile = false; + if (options.ES6_enabled) { + snippet = 'const '; + } + else { + snippet = 'var '; + } + snippet += 'superagent = require(\'superagent\');\n'; + if (request.body && request.body.mode === 'formdata') { + _.forEach(request.body.toJSON().formdata, function (data) { + if (!data.disabled && data.type === 'file') { + isFormDataFile = true; + } + }); + } + if (isFormDataFile) { + if (options.ES6_enabled) { + snippet += 'const '; + } + else { + snippet += 'var '; + } + snippet += 'fs = require(\'fs\');\n'; + } + if (options.ES6_enabled) { + snippet += 'let '; + } + else { + snippet += 'var '; + } + snippet += 'options = {\n'; + + /** + * creating string to represent options object using optionArray.join() + * example: + * options: { + * method: 'GET', + * url: 'www.google.com', + * timeout: 1000 + * } + */ + optionsArray.push(indentString + `'method': '${request.method}'`); + optionsArray.push(indentString + `'url': '${sanitize(request.url.toString())}'`); + if (request.body && !request.headers.has('Content-Type')) { + if (request.body.mode === 'file') { + request.addHeader({ + key: 'Content-Type', + value: 'text/plain' + }); + } + else if (request.body.mode === 'graphql') { + request.addHeader({ + key: 'Content-Type', + value: 'application/json' + }); + } + } + optionsArray.push(parseRequest.parseHeader(request, indentString)); + + if (request.body && request.body[request.body.mode]) { + optionsArray.push( + indentString + parseRequest.parseBody(request.body.toJSON(), indentString, options.trimRequestBody, + request.headers.get('Content-Type')) + ); + } + if (options.requestTimeout) { + optionsArray.push(indentString + `timeout: ${options.requestTimeout}`); + } + if (options.followRedirect === false) { + optionsArray.push(indentString + 'followRedirect: false'); + } + snippet += optionsArray.join(',\n') + '\n'; + snippet += '};\n'; + + snippet += 'superagent(options, '; + if (options.ES6_enabled) { + snippet += '(error, response) => {\n'; + } + else { + snippet += 'function (error, response) {\n'; + } + snippet += indentString + 'if (error) throw new Error(error);\n'; + snippet += indentString + 'console.log(response.body);\n'; + snippet += '});\n'; + return snippet; +} + +/** + * Used to get the options specific to this codegen + * + * @returns {Array} - Returns an array of option objects + */ +function getOptions () { + return [ + { + name: 'Set indentation count', + id: 'indentCount', + type: 'positiveInteger', + default: 2, + description: 'Set the number of indentation characters to add per code level' + }, + { + name: 'Set indentation type', + id: 'indentType', + type: 'enum', + availableOptions: ['Tab', 'Space'], + default: 'Space', + description: 'Select the character used to indent lines of code' + }, + { + name: 'Set request timeout', + id: 'requestTimeout', + type: 'positiveInteger', + default: 0, + description: 'Set number of milliseconds the request should wait for a response' + + ' before timing out (use 0 for infinity)' + }, + { + name: 'Follow redirects', + id: 'followRedirect', + type: 'boolean', + default: true, + description: 'Automatically follow HTTP redirects' + }, + { + name: 'Trim request body fields', + id: 'trimRequestBody', + type: 'boolean', + default: false, + description: 'Remove white space and additional lines that may affect the server\'s response' + }, + { + name: 'Enable ES6 features', + id: 'ES6_enabled', + type: 'boolean', + default: false, + description: 'Modifies code snippet to incorporate ES6 (EcmaScript) features' + } + ]; +} + +/** + * Converts Postman sdk request object to nodejs request code snippet + * + * @param {Object} request - postman-SDK request object + * @param {Object} options + * @param {String} options.indentType - type for indentation eg: Space, Tab + * @param {String} options.indentCount - number of spaces or tabs for indentation. + * @param {Boolean} options.followRedirect - whether to enable followredirect + * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not + * @param {Boolean} options.ES6_enabled - whether to generate snippet with ES6 features + * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out + * @param {Function} callback - callback function with parameters (error, snippet) + */ +function convert (request, options, callback) { + if (!_.isFunction(callback)) { + throw new Error('NodeJS-Request-Converter: callback is not valid function'); + } + options = sanitizeOptions(options, getOptions()); + + // String representing value of indentation required + var indentString; + + indentString = options.indentType === 'Tab' ? '\t' : ' '; + indentString = indentString.repeat(options.indentCount); + + return callback(null, makeSnippet(request, indentString, options)); +} + +module.exports = { + convert: convert, + getOptions: getOptions +}; diff --git a/codegens/nodejs-superagent/lib/util.js b/codegens/nodejs-superagent/lib/util.js new file mode 100644 index 000000000..e5e8b2a4b --- /dev/null +++ b/codegens/nodejs-superagent/lib/util.js @@ -0,0 +1,88 @@ + +/** + * sanitizes input string by handling escape characters eg: converts '''' to '\'\'' + * and trim input if required + * + * @param {String} inputString + * @param {Boolean} [trim] - indicates whether to trim string or not + * @returns {String} + */ +function sanitize (inputString, trim) { + if (typeof inputString !== 'string') { + return ''; + } + (trim) && (inputString = inputString.trim()); + return inputString.replace(/\\/g, '\\\\').replace(/'/g, '\\\'').replace(/\n/g, '\\n'); +} + +/** + * sanitizes input options + * + * @param {Object} options - Options provided by the user + * @param {Array} optionsArray - options array received from getOptions function + * + * @returns {Object} - Sanitized options object + */ +function sanitizeOptions (options, optionsArray) { + var result = {}, + defaultOptions = {}, + id; + optionsArray.forEach((option) => { + defaultOptions[option.id] = { + default: option.default, + type: option.type + }; + if (option.type === 'enum') { + defaultOptions[option.id].availableOptions = option.availableOptions; + } + }); + + for (id in options) { + if (options.hasOwnProperty(id)) { + if (defaultOptions[id] === undefined) { + continue; + } + switch (defaultOptions[id].type) { + case 'boolean': + if (typeof options[id] !== 'boolean') { + result[id] = defaultOptions[id].default; + } + else { + result[id] = options[id]; + } + break; + case 'positiveInteger': + if (typeof options[id] !== 'number' || options[id] < 0) { + result[id] = defaultOptions[id].default; + } + else { + result[id] = options[id]; + } + break; + case 'enum': + if (!defaultOptions[id].availableOptions.includes(options[id])) { + result[id] = defaultOptions[id].default; + } + else { + result[id] = options[id]; + } + break; + default: + result[id] = options[id]; + } + } + } + + for (id in defaultOptions) { + if (defaultOptions.hasOwnProperty(id)) { + if (result[id] === undefined) { + result[id] = defaultOptions[id].default; + } + } + } + return result; +} +module.exports = { + sanitize: sanitize, + sanitizeOptions: sanitizeOptions +}; diff --git a/codegens/nodejs-superagent/npm-shrinkwrap.json b/codegens/nodejs-superagent/npm-shrinkwrap.json new file mode 100644 index 000000000..366e33607 --- /dev/null +++ b/codegens/nodejs-superagent/npm-shrinkwrap.json @@ -0,0 +1,440 @@ +{ + "name": "@postman/codegen-nodejs-superagent", + "version": "0.1.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.x.x" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cryptiles": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.4.tgz", + "integrity": "sha512-8I1sgZHfVwcSOY6mSGpVU3lw/GSIZvusg8dD2+OGehCJpOhQRLNcH0qb9upQnOH4XhgxxFJSg6E2kx95deb1Tw==", + "dev": true, + "requires": { + "boom": "5.x.x" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.x.x" + } + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "^5.1.0", + "har-schema": "^2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.x.x", + "cryptiles": "3.x.x", + "hoek": "4.x.x", + "sntp": "2.x.x" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "hawk": "~6.0.2", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "stringstream": "~0.0.5", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, + "requires": { + "hoek": "4.x.x" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "dev": true + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + } + } +} diff --git a/codegens/nodejs-superagent/npm/test-lint.js b/codegens/nodejs-superagent/npm/test-lint.js new file mode 100644 index 000000000..b113b8bfd --- /dev/null +++ b/codegens/nodejs-superagent/npm/test-lint.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node +var shell = require('shelljs'), + chalk = require('chalk'), + async = require('async'), + ESLintCLIEngine = require('eslint').CLIEngine, + + /** + * The list of source code files / directories to be linted. + * + * @type {Array} + */ + LINT_SOURCE_DIRS = [ + './lib', + './bin', + './test', + './examples/*.js', + './npm/*.js', + './index.js' + ]; + +module.exports = function (exit) { + // banner line + console.info(chalk.yellow.bold('\nLinting files using eslint...')); + + async.waterfall([ + + /** + * Instantiates an ESLint CLI engine and runs it in the scope defined within LINT_SOURCE_DIRS. + * + * @param {Function} next - The callback function whose invocation marks the end of the lint test run. + * @returns {*} + */ + function (next) { + next(null, (new ESLintCLIEngine()).executeOnFiles(LINT_SOURCE_DIRS)); + }, + + /** + * Processes a test report from the Lint test runner, and displays meaningful results. + * + * @param {Object} report - The overall test report for the current lint test. + * @param {Object} report.results - The set of test results for the current lint run. + * @param {Function} next - The callback whose invocation marks the completion of the post run tasks. + * @returns {*} + */ + function (report, next) { + var errorReport = ESLintCLIEngine.getErrorResults(report.results); + // log the result to CLI + console.info(ESLintCLIEngine.getFormatter()(report.results)); + // log the success of the parser if it has no errors + (errorReport && !errorReport.length) && console.info(chalk.green('eslint ok!')); + // ensure that the exit code is non zero in case there was an error + next(Number(errorReport && errorReport.length) || 0); + } + ], exit); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(shell.exit); diff --git a/codegens/nodejs-superagent/npm/test-newman.js b/codegens/nodejs-superagent/npm/test-newman.js new file mode 100644 index 000000000..ae7d2afe1 --- /dev/null +++ b/codegens/nodejs-superagent/npm/test-newman.js @@ -0,0 +1,59 @@ +#!/usr/bin/env node +/* eslint-env node, es6 */ +// --------------------------------------------------------------------------------------------------------------------- +// This script is intended to execute all newman tests. +// --------------------------------------------------------------------------------------------------------------------- + +var shell = require('shelljs'), + + // set directories and files for test and coverage report + path = require('path'), + + NYC = require('nyc'), + chalk = require('chalk'), + recursive = require('recursive-readdir'), + + COV_REPORT_PATH = '.coverage', + SPEC_SOURCE_DIR = path.join(__dirname, '..', 'test', 'newman'); + +module.exports = function (exit) { + // banner line + console.info(chalk.yellow.bold('Running newman tests using mocha on node...')); + + shell.test('-d', COV_REPORT_PATH) && shell.rm('-rf', COV_REPORT_PATH); + shell.mkdir('-p', COV_REPORT_PATH); + + var Mocha = require('mocha'), + nyc = new NYC({ + reportDir: COV_REPORT_PATH, + tempDirectory: COV_REPORT_PATH, + reporter: ['text', 'lcov', 'text-summary'], + exclude: ['config', 'test'], + hookRunInContext: true, + hookRunInThisContext: true + }); + + nyc.wrap(); + // add all spec files to mocha + recursive(SPEC_SOURCE_DIR, function (err, files) { + if (err) { console.error(err); return exit(1); } + + var mocha = new Mocha({ timeout: 1000 * 60 }); + + files.filter(function (file) { // extract all test files + return (file.substr(-8) === '.test.js'); + }).forEach(mocha.addFile.bind(mocha)); + + mocha.run(function (runError) { + runError && console.error(runError.stack || runError); + + nyc.reset(); + nyc.writeCoverageFile(); + nyc.report(); + exit(runError ? 1 : 0); + }); + }); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(shell.exit); diff --git a/codegens/nodejs-superagent/npm/test-unit.js b/codegens/nodejs-superagent/npm/test-unit.js new file mode 100755 index 000000000..0de7fd529 --- /dev/null +++ b/codegens/nodejs-superagent/npm/test-unit.js @@ -0,0 +1,59 @@ +#!/usr/bin/env node +/* eslint-env node, es6 */ +// --------------------------------------------------------------------------------------------------------------------- +// This script is intended to execute all unit tests. +// --------------------------------------------------------------------------------------------------------------------- + +var shell = require('shelljs'), + + // set directories and files for test and coverage report + path = require('path'), + + NYC = require('nyc'), + chalk = require('chalk'), + recursive = require('recursive-readdir'), + + COV_REPORT_PATH = '.coverage', + SPEC_SOURCE_DIR = path.join(__dirname, '..', 'test', 'unit'); + +module.exports = function (exit) { + // banner line + console.info(chalk.yellow.bold('Running unit tests using mocha on node...')); + + shell.test('-d', COV_REPORT_PATH) && shell.rm('-rf', COV_REPORT_PATH); + shell.mkdir('-p', COV_REPORT_PATH); + + var Mocha = require('mocha'), + nyc = new NYC({ + reportDir: COV_REPORT_PATH, + tempDirectory: COV_REPORT_PATH, + reporter: ['text', 'lcov', 'text-summary'], + exclude: ['config', 'test'], + hookRunInContext: true, + hookRunInThisContext: true + }); + + nyc.wrap(); + // add all spec files to mocha + recursive(SPEC_SOURCE_DIR, function (err, files) { + if (err) { console.error(err); return exit(1); } + + var mocha = new Mocha({ timeout: 1000 * 60 }); + + files.filter(function (file) { // extract all test files + return (file.substr(-8) === '.test.js'); + }).forEach(mocha.addFile.bind(mocha)); + + mocha.run(function (runError) { + runError && console.error(runError.stack || runError); + + nyc.reset(); + nyc.writeCoverageFile(); + nyc.report(); + exit(runError ? 1 : 0); + }); + }); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(shell.exit); diff --git a/codegens/nodejs-superagent/npm/test.js b/codegens/nodejs-superagent/npm/test.js new file mode 100755 index 000000000..da2816f09 --- /dev/null +++ b/codegens/nodejs-superagent/npm/test.js @@ -0,0 +1,18 @@ +#!/usr/bin/env node +var chalk = require('chalk'), + exit = require('shelljs').exit, + prettyms = require('pretty-ms'), + startedAt = Date.now(), + name = require('../package.json').name; + +require('async').series([ + require('./test-lint'), + require('./test-newman'), + require('./test-unit') + // require('./test-browser') + // require('./test-integration') +], function (code) { + // eslint-disable-next-line max-len + console.info(chalk[code ? 'red' : 'green'](`\n${name}: duration ${prettyms(Date.now() - startedAt)}\n${name}: ${code ? 'not ok' : 'ok'}!`)); + exit(code && (typeof code === 'number' ? code : 1) || 0); +}); diff --git a/codegens/nodejs-superagent/package.json b/codegens/nodejs-superagent/package.json new file mode 100644 index 000000000..8f4e314a7 --- /dev/null +++ b/codegens/nodejs-superagent/package.json @@ -0,0 +1,36 @@ +{ + "name": "@postman/codegen-nodejs-superagent", + "version": "0.1.2", + "description": "Converts Postman-SDK Request into code snippet for NodeJS(SuperAgent)", + "com_postman_plugin": { + "type": "code_generator", + "lang": "nodejs", + "variant": "SuperAgent", + "syntax_mode": "javascript" + }, + "main": "index.js", + "directories": { + "lib": "lib", + "test": "test" + }, + "scripts": { + "test": "node npm/test.js", + "test-lint": "node npm/test-lint.js", + "test-newman": "node npm/test-newman.js", + "test-unit": "node npm/test-unit.js" + }, + "repository": { + "type": "git", + "url": "" + }, + "author": "Postman Labs ", + "license": "Apache-2.0", + "homepage": "https://github.com/postmanlabs/code-generators/tree/master/codegens/nodejs-superagent", + "dependencies": {}, + "devDependencies": { + "superagent": "5.2.2" + }, + "engines": { + "node": ">=8" + } +} diff --git a/codegens/nodejs-superagent/test/.eslintrc b/codegens/nodejs-superagent/test/.eslintrc new file mode 100644 index 000000000..9d477e31e --- /dev/null +++ b/codegens/nodejs-superagent/test/.eslintrc @@ -0,0 +1,30 @@ +{ + "plugins": [ + "mocha" + ], + "env": { + "mocha": true, + "node": true, + "es6": true + }, + "rules": { + // Mocha + "mocha/handle-done-callback": "error", + "mocha/max-top-level-suites": "error", + "mocha/no-exclusive-tests": "error", + "mocha/no-global-tests": "error", + "mocha/no-hooks-for-single-case": "off", + "mocha/no-hooks": "off", + "mocha/no-identical-title": "error", + "mocha/no-mocha-arrows": "error", + "mocha/no-nested-tests": "error", + "mocha/no-pending-tests": "error", + "mocha/no-return-and-callback": "error", + "mocha/no-sibling-hooks": "error", + "mocha/no-skipped-tests": "warn", + "mocha/no-synchronous-tests": "off", + "mocha/no-top-level-hooks": "warn", + "mocha/valid-test-description": "off", + "mocha/valid-suite-description": "off" + } +} diff --git a/codegens/nodejs-superagent/test/newman/newman.test.js b/codegens/nodejs-superagent/test/newman/newman.test.js new file mode 100644 index 000000000..faa8cac1a --- /dev/null +++ b/codegens/nodejs-superagent/test/newman/newman.test.js @@ -0,0 +1,27 @@ +var runNewmanTest = require('../../../../test/codegen/newman/newmanTestUtil').runNewmanTest, + convert = require('../../lib/index').convert; + +describe('Convert for different types of request', function () { + var options = {indentCount: 2, indentType: 'Space'}, + testConfig = { + compileScript: null, + runScript: 'node run.js', + fileName: 'run.js', + headerSnippet: '/* eslint-disable */\n' + }; + + runNewmanTest(convert, options, testConfig); + + describe('Convert for request incorporating ES6 features', function () { + var options = {indentCount: 2, indentType: 'Space', ES6_enabled: true}, + testConfig = { + compileScript: null, + runScript: 'node run.js', + fileName: 'run.js', + headerSnippet: '/* eslint-disable */\n' + }; + + runNewmanTest(convert, options, testConfig); + }); + +}); diff --git a/codegens/nodejs-superagent/test/unit/.gitkeep b/codegens/nodejs-superagent/test/unit/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/codegens/nodejs-superagent/test/unit/fixtures/testcollection/collection.json b/codegens/nodejs-superagent/test/unit/fixtures/testcollection/collection.json new file mode 100644 index 000000000..186aa9ce5 --- /dev/null +++ b/codegens/nodejs-superagent/test/unit/fixtures/testcollection/collection.json @@ -0,0 +1,1349 @@ +{ + "info": { + "name": "Code-Gen Test Cases", + "_postman_id": "41182fad-912e-6bc9-d6b9-dfb6f5bf5ffb", + "description": "This collection contains requests that will be used to test validity of plugin created to convert postman request into code snippet of particular language.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Request Headers with disabled headers", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "try {", + " tests[\"Body contains headers\"] = responseBody.has(\"headers\");", + " responseJSON = JSON.parse(responseBody);", + " tests[\"Header contains host\"] = \"host\" in responseJSON.headers;", + " tests[\"Header contains test parameter sent as part of request header\"] = \"my-sample-header\" in responseJSON.headers;", + "}", + "catch (e) { }", + "", + "", + "", + "" + ] + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "my-sample-header", + "value": "Lorem ipsum dolor sit amet" + }, + { + "key": "not-disabled-header", + "value": "ENABLED" + }, + { + "key": "disabled header", + "value": "DISABLED", + "disabled": true + } + ], + "body": {}, + "url": { + "raw": "https://postman-echo.com/headers", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "headers" + ] + }, + "description": "A `GET` request to this endpoint returns the list of all request headers as part of the response JSON.\nIn Postman, sending your own set of headers through the [Headers tab](https://www.getpostman.com/docs/requests#headers?source=echo-collection-app-onboarding) will reveal the headers as part of the response." + }, + "response": [] + }, + { + "name": "GET Request with disabled query", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "tests['response json contains headers'] = _.has(responseJSON, 'headers');", + "tests['response json contains args'] = _.has(responseJSON, 'args');", + "tests['response json contains url'] = _.has(responseJSON, 'url');", + "", + "tests['args key contains argument passed as url parameter'] = ('test' in responseJSON.args);", + "tests['args passed via request url params has value \"123\"'] = (_.get(responseJSON, 'args.test') === \"123\");" + ] + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": {}, + "url": { + "raw": "https://postman-echo.com/get?test=123&anotherone=232", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "get" + ], + "query": [ + { + "key": "test", + "value": "123", + "equals": true + }, + { + "key": "anotherone", + "value": "232", + "equals": true + }, + { + "key": "anotheroneone", + "value": "sdfsdf", + "equals": true, + "disabled": true + } + ] + }, + "description": "The HTTP `GET` request method is meant to retrieve data from a server. The data\nis identified by a unique URI (Uniform Resource Identifier). \n\nA `GET` request can pass parameters to the server using \"Query String \nParameters\". For example, in the following request,\n\n> http://example.com/hi/there?hand=wave\n\nThe parameter \"hand\" has the value \"wave\".\n\nThis endpoint echoes the HTTP headers, request parameters and the complete\nURI requested." + }, + "response": [] + }, + { + "name": "POST Raw Text", + "event": [ + { + "listen": "test", + "script": { + "id": "753f8a33-adb6-402f-8d19-386c1981ecb6", + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "\"'Duis posuere augue vel cursus pharetra. In luctus a ex nec pretium. Praesent neque quam, tincidunt nec leo eget, rutrum vehicula magna.\nMaecenas consequat elementum elit, \"id\" \"se\\\"mper\" sem tristique et. Integer pulvinar enim quis consectetur interdum volutpat.'\"" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST form data with file", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "disabled": true + }, + { + "key": "content-type", + "value": "application/json", + "disabled": true + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "fdjks", + "value": "dsf", + "type": "text" + }, + { + "key": "sdf", + "value": "helo", + "type": "text" + }, + { + "key": "12", + "value": "\"23\"", + "description": "", + "type": "text" + }, + { + "key": "'123'", + "value": "'\"23\\\"4\\\"\"'", + "description": "", + "type": "text" + }, + { + "key": "", + "value": "", + "description": "", + "type": "text", + "disabled": true + } + ] + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST urlencoded data with disabled entries", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded" + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "1", + "value": "a", + "description": "", + "type": "text" + }, + { + "key": "2", + "value": "b", + "description": "", + "type": "text" + }, + { + "key": "\"\"12\"\"", + "value": "\"23\"", + "description": "", + "type": "text" + }, + { + "key": "'1\"2\\\"\"3'", + "value": "'1\"23\"4'", + "description": "", + "type": "text" + } + ] + }, + "url": { + "raw": "https://postman-echo.com/post/?hardik=\"me\"", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post", + "" + ], + "query": [ + { + "key": "hardik", + "value": "\"me\"", + "equals": true + } + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST json with raw", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"json\": \"Test-Test\"\n}" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [ + { + "id": "a331f873-b13f-459f-82f4-506d65e41bef", + "name": "POST json with raw", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"json\": \"Test-Test\"\n}" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "", + "name": "Access-Control-Allow-Credentials", + "description": "Indicates whether or not the response to the request can be exposed when the credentials flag is true. When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials." + }, + { + "key": "Access-Control-Allow-Headers", + "value": "", + "name": "Access-Control-Allow-Headers", + "description": "Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request." + }, + { + "key": "Access-Control-Allow-Methods", + "value": "", + "name": "Access-Control-Allow-Methods", + "description": "Specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request." + }, + { + "key": "Access-Control-Allow-Origin", + "value": "", + "name": "Access-Control-Allow-Origin", + "description": "Specifies a URI that may access the resource. For requests without credentials, the server may specify '*' as a wildcard, thereby allowing any origin to access the resource." + }, + { + "key": "Access-Control-Expose-Headers", + "value": "", + "name": "Access-Control-Expose-Headers", + "description": "Lets a server whitelist headers that browsers are allowed to access." + }, + { + "key": "Connection", + "value": "keep-alive", + "name": "Connection", + "description": "Options that are desired for the connection" + }, + { + "key": "Content-Encoding", + "value": "gzip", + "name": "Content-Encoding", + "description": "The type of encoding used on the data." + }, + { + "key": "Content-Length", + "value": "385", + "name": "Content-Length", + "description": "The length of the response body in octets (8-bit bytes)" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8", + "name": "Content-Type", + "description": "The mime type of this content" + }, + { + "key": "Date", + "value": "Wed, 07 Feb 2018 10:06:15 GMT", + "name": "Date", + "description": "The date and time that the message was sent" + }, + { + "key": "ETag", + "value": "W/\"215-u7EU1nFtauIn0/aVifjuXA\"", + "name": "ETag", + "description": "An identifier for a specific version of a resource, often a message digest" + }, + { + "key": "Server", + "value": "nginx", + "name": "Server", + "description": "A name for the server" + }, + { + "key": "Vary", + "value": "X-HTTP-Method-Override, Accept-Encoding", + "name": "Vary", + "description": "Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather than requesting a fresh one from the origin server." + }, + { + "key": "set-cookie", + "value": "sails.sid=s%3AxRBxgrc9M-jKK_l1mX3y3rM_ry8wYLz4.Of4qpOzd9hi6uO0sAQIj%2Bxs2VeppWxYjJa4OpIW3PKg; Path=/; HttpOnly", + "name": "set-cookie", + "description": "an HTTP cookie" + } + ], + "cookie": [ + { + "expires": "Tue Jan 19 2038 08:44:07 GMT+0530 (IST)", + "httpOnly": true, + "domain": "postman-echo.com", + "path": "/", + "secure": false, + "value": "s%3AxRBxgrc9M-jKK_l1mX3y3rM_ry8wYLz4.Of4qpOzd9hi6uO0sAQIj%2Bxs2VeppWxYjJa4OpIW3PKg", + "key": "sails.sid" + } + ], + "body": "{\"args\":{},\"data\":\"{\\n \\\"json\\\": \\\"Test-Test\\\"\\n}\",\"files\":{},\"form\":{},\"headers\":{\"host\":\"postman-echo.com\",\"content-length\":\"25\",\"accept\":\"*/*\",\"accept-encoding\":\"gzip, deflate\",\"cache-control\":\"no-cache\",\"content-type\":\"text/plain\",\"cookie\":\"sails.sid=s%3AkOgtF1XmXtVFx-Eg3S7-37BKKaMqMDPe.hnwldNwyvsaASUiRR0Y0vcowadkMXO4HMegTeVIPgqo\",\"postman-token\":\"2ced782f-a141-428e-8af6-04ce954a77d5\",\"user-agent\":\"PostmanRuntime/7.1.1\",\"x-forwarded-port\":\"443\",\"x-forwarded-proto\":\"https\"},\"json\":null,\"url\":\"https://postman-echo.com/post\"}" + } + ] + }, + { + "name": "POST javascript with raw", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/javascript" + } + ], + "body": { + "mode": "raw", + "raw": "var val = 6;\nconsole.log(val);" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST text/xml with raw", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "text/xml" + } + ], + "body": { + "mode": "raw", + "raw": "\n Test Test\n" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST text/html with raw", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "text/html" + } + ], + "body": { + "mode": "raw", + "raw": "\n Test Test\n" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "Resolve URL", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded" + } + ], + "body": { + "mode": "raw", + "raw": "Duis posuere augue vel cursus pharetra. In luctus a ex nec pretium. Praesent neque quam, tincidunt nec leo eget, rutrum vehicula magna.\nMaecenas consequat elementum elit, id semper sem tristique et. Integer pulvinar enim quis consectetur interdum volutpat." + }, + "url": { + "raw": "https://postman-echo.com/:action", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":action" + ], + "variable": [ + { + "key": "action", + "value": "post" + } + ] + }, + "description": null + }, + "response": [] + }, + { + "name": "PUT Request", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has PUT data'] = _.has(responseJSON, 'data');", + "tests['response matches the data sent in request'] = (responseJSON.data && responseJSON.data.length === 256);" + ] + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "Etiam mi lacus, cursus vitae felis et, blandit pellentesque neque. Vestibulum eget nisi a tortor commodo dignissim.\nQuisque ipsum ligula, faucibus a felis a, commodo elementum nisl. Mauris vulputate sapien et tincidunt viverra. Donec vitae velit nec metus." + }, + "url": { + "raw": "https://postman-echo.com/put", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "put" + ] + }, + "description": "The HTTP `PUT` request method is similar to HTTP `POST`. It too is meant to \ntransfer data to a server (and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `PUT` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following \nraw HTTP request,\n\n> PUT /hi/there?hand=wave\n>\n> \n\n\n" + }, + "response": [] + }, + { + "name": "PATCH Request", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has PUT data'] = _.has(responseJSON, 'data');", + "tests['response matches the data sent in request'] = (responseJSON.data && responseJSON.data.length === 256);" + ] + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "Curabitur auctor, elit nec pulvinar porttitor, ex augue condimentum enim, eget suscipit urna felis quis neque.\nSuspendisse sit amet luctus massa, nec venenatis mi. Suspendisse tincidunt massa at nibh efficitur fringilla. Nam quis congue mi. Etiam volutpat." + }, + "url": { + "raw": "https://postman-echo.com/patch", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "patch" + ] + }, + "description": "The HTTP `PATCH` method is used to update resources on a server. The exact\nuse of `PATCH` requests depends on the server in question. There are a number\nof server implementations which handle `PATCH` differently. Technically, \n`PATCH` supports both Query String parameters and a Request Body.\n\nThis endpoint accepts an HTTP `PATCH` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body." + }, + "response": [] + }, + { + "name": "DELETE Request", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has PUT data'] = _.has(responseJSON, 'data');", + "tests['response matches the data sent in request'] = (responseJSON.data && responseJSON.data.length === 256);" + ] + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded" + }, + { + "key": "Content-Length", + "value": "1000", + "disabled": true + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "dsfs", + "value": "sfdds", + "description": "", + "type": "text" + }, + { + "key": "sfdsdf", + "value": "sdf", + "description": "", + "type": "text" + } + ] + }, + "url": { + "raw": "https://postman-echo.com/delete", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "delete" + ] + }, + "description": "The HTTP `DELETE` method is used to delete resources on a server. The exact\nuse of `DELETE` requests depends on the server implementation. In general, \n`DELETE` requests support both, Query String parameters as well as a Request \nBody.\n\nThis endpoint accepts an HTTP `DELETE` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body." + }, + "response": [] + }, + { + "name": "OPTIONS to postman echo", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "OPTIONS", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded" + } + ], + "body": {}, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "HEAD request", + "request": { + "method": "HEAD", + "header": [ + { + "key": "hello", + "value": "helloagain", + "disabled": true + } + ], + "body": {}, + "url": { + "raw": "https://bf1621bb-f962-46b8-bf28-459e03b513ff.mock.pstmn.io/head", + "protocol": "https", + "host": [ + "bf1621bb-f962-46b8-bf28-459e03b513ff", + "mock", + "pstmn", + "io" + ], + "path": [ + "head" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "LINK request", + "request": { + "method": "LINK", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "UNLINK request", + "request": { + "method": "UNLINK", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "LOCK request", + "request": { + "method": "LOCK", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "UNLOCK request", + "request": { + "method": "UNLOCK", + "header": [], + "body": {}, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "PROPFIND request", + "request": { + "method": "PROPFIND", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "VIEW request", + "request": { + "method": "VIEW", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "PURGE Request", + "request": { + "method": "PURGE", + "header": [], + "body": {}, + "url": { + "raw": "https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io", + "protocol": "https", + "host": [ + "9c76407d-5b8d-4b22-99fb-8c47a85d9848", + "mock", + "pstmn", + "io" + ] + }, + "description": null + }, + "response": [ + { + "id": "95c11e09-9abe-4b26-a6b0-bc7f40dded08", + "name": "PURGE Request", + "originalRequest": { + "method": "PURGE", + "header": [], + "body": {}, + "url": { + "raw": "https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io", + "protocol": "https", + "host": [ + "9c76407d-5b8d-4b22-99fb-8c47a85d9848", + "mock", + "pstmn", + "io" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "", + "name": "Access-Control-Allow-Credentials", + "description": "" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "", + "name": "Access-Control-Allow-Headers", + "description": "" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "", + "name": "Access-Control-Allow-Methods", + "description": "" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*", + "name": "Access-Control-Allow-Origin", + "description": "" + }, + { + "key": "Access-Control-Expose-Headers", + "value": "", + "name": "Access-Control-Expose-Headers", + "description": "" + }, + { + "key": "Connection", + "value": "keep-alive", + "name": "Connection", + "description": "" + }, + { + "key": "Content-Encoding", + "value": "gzip", + "name": "Content-Encoding", + "description": "" + }, + { + "key": "Content-Length", + "value": "152", + "name": "Content-Length", + "description": "" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8", + "name": "Content-Type", + "description": "" + }, + { + "key": "Date", + "value": "Tue, 13 Feb 2018 13:58:56 GMT", + "name": "Date", + "description": "" + }, + { + "key": "ETag", + "value": "W/\"a7-kIxN5L9H0YwilUQPUUio9A\"", + "name": "ETag", + "description": "" + }, + { + "key": "Server", + "value": "nginx", + "name": "Server", + "description": "" + }, + { + "key": "Vary", + "value": "Accept-Encoding", + "name": "Vary", + "description": "" + } + ], + "cookie": [], + "responseTime": "375", + "body": "{\n \"args\": {},\n \"data\": \"Curabitur auctor, elit nec pulvinar porttitor, ex augue condimentum enim, eget suscipit urna felis quis neque.\\nSuspendisse sit amet luctus massa, nec venenatis mi. Suspendisse tincidunt massa at nibh efficitur fringilla. Nam quis congue mi. Etiam volutpat.\",\n \"files\": {},\n \"form\": {},\n \"headers\": {\n \"host\": \"postman-echo.com\",\n \"content-length\": \"256\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate\",\n \"content-type\": \"text/plain\",\n \"cookie\": \"sails.sid=s%3A1wOi4AdoZEbqBjGi6oSUC5Vlfje8wJvs.DHQfRLXfIBvZ%2Bv0KhLAThMDz%2FXvxh9gyxWYa0u1EZOU\",\n \"user-agent\": \"PostmanRuntime/7.1.1\",\n \"x-forwarded-port\": \"443\",\n \"x-forwarded-proto\": \"https\"\n },\n \"json\": null,\n \"url\": \"https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io\"\n}" + } + ] + }, + { + "name": "COPY Request", + "request": { + "method": "COPY", + "header": [], + "body": {}, + "url": { + "raw": "https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io", + "protocol": "https", + "host": [ + "9c76407d-5b8d-4b22-99fb-8c47a85d9848", + "mock", + "pstmn", + "io" + ] + } + }, + "response": [ + { + "id": "b8517e1f-3aad-4c0e-bc2d-fb8d834adba7", + "name": "COPY Request", + "originalRequest": { + "method": "COPY", + "header": [], + "body": {}, + "url": { + "raw": "https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io", + "protocol": "https", + "host": [ + "9c76407d-5b8d-4b22-99fb-8c47a85d9848", + "mock", + "pstmn", + "io" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [], + "cookie": [], + "responseTime": "0", + "body": "{\n \"args\": {},\n \"data\": \"Curabitur auctor, elit nec pulvinar porttitor, ex augue condimentum enim, eget suscipit urna felis quis neque.\\nSuspendisse sit amet luctus massa, nec venenatis mi. Suspendisse tincidunt massa at nibh efficitur fringilla. Nam quis congue mi. Etiam volutpat.\",\n \"files\": {},\n \"form\": {},\n \"headers\": {\n \"host\": \"postman-echo.com\",\n \"content-length\": \"256\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate\",\n \"content-type\": \"text/plain\",\n \"cookie\": \"sails.sid=s%3A1wOi4AdoZEbqBjGi6oSUC5Vlfje8wJvs.DHQfRLXfIBvZ%2Bv0KhLAThMDz%2FXvxh9gyxWYa0u1EZOU\",\n \"user-agent\": \"PostmanRuntime/7.1.1\",\n \"x-forwarded-port\": \"443\",\n \"x-forwarded-proto\": \"https\"\n },\n \"json\": null,\n \"url\": \"https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io\"\n}" + } + ] + } + ] +} \ No newline at end of file diff --git a/codegens/nodejs-superagent/test/unit/snippet.test.js b/codegens/nodejs-superagent/test/unit/snippet.test.js new file mode 100644 index 000000000..e1a228684 --- /dev/null +++ b/codegens/nodejs-superagent/test/unit/snippet.test.js @@ -0,0 +1,416 @@ +// TODO +var expect = require('chai').expect, + sdk = require('postman-collection'), + sanitize = require('../../lib/util').sanitize, + parseBody = require('../../lib/parseRequest').parseBody, + getOptions = require('../../lib/index').getOptions, + convert = require('../../lib/index').convert, + mainCollection = require('./fixtures/testcollection/collection.json'); + +describe('nodejs-superagent convert function', function () { + describe('Convert function', function () { + var request, + reqObject, + options = {}, + snippetArray, + line_no; + + it('should return a Tab indented snippet ', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + indentType: 'Tab', + indentCount: 1 + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + snippetArray = snippet.split('\n'); + for (var i = 0; i < snippetArray.length; i++) { + if (snippetArray[i] === 'var options = {') { line_no = i + 1; } + } + expect(snippetArray[line_no].charAt(0)).to.equal('\t'); + }); + }); + + it('should return snippet with timeout property when timeout is set to non zero', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + requestTimeout: 1000 + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + expect(snippet).to.include('timeout: 1000'); + }); + }); + + it('should return snippet with ES6 features when ES6_enabled is set to true', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + ES6_enabled: true + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + snippetArray = snippet.split('\n'); + expect(snippetArray[0]).to.equal('const request = require(\'request\');'); + expect(snippetArray).to.include('let options = {'); + expect(snippetArray).to.include('request(options, (error, response) => {'); + }); + }); + + it('should return snippet with followRedirect property set to ' + + 'false for no follow redirect', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + followRedirect: false + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + expect(snippet).to.include('followRedirect: false'); + }); + }); + + it('should return valid code snippet for no headers and no body', function () { + reqObject = { + 'description': 'This is a sample POST request without headers and body', + 'url': 'https://echo.getpostman.com/post', + 'method': 'POST' + }; + request = new sdk.Request(reqObject); + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('\'headers\': {\n }'); + }); + }); + + it('should not fail for a random body mode', function () { + request = new sdk.Request(mainCollection.item[2].request); + request.body.mode = 'random'; + request.body[request.body.mode] = {}; + + convert(request, options, function (error, snippet) { + + if (error) { + expect.fail(null, null, error); + return; + } + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('body:'); + }); + }); + + it('should generate snippet for file body mode', function () { + request = new sdk.Request({ + 'url': 'https://echo.getpostman.com/post', + 'method': 'POST', + 'body': { + 'mode': 'file', + 'file': [ + { + 'key': 'fileName', + 'src': 'file', + 'type': 'file' + } + ] + } + }); + options = { indentType: 'Space', indentCount: 2 }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.not.equal(''); + }); + }); + + it('should return snippet with proper semicolon placed where required', function () { + // testing for the below snippet + /* + var request = require('request'); + var fs = require('fs'); + var options = { + 'method': 'GET', + 'url': 'https://postman-echo.com/headers', + 'headers': { + 'my-sample-header': 'Lorem ipsum dolor sit amet', + 'not-disabled-header': 'ENABLED' + } + }; + request(options, function (error, response) { + if (error) throw new Error(error); + console.log(response.body); + }); */ + request = new sdk.Request(mainCollection.item[0].request); + options = {}; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + var snippetArray = snippet.split('\n'); + snippetArray.forEach(function (line, index) { + if (line.charAt(line.length - 2) === ')') { + expect(line.charAt(line.length - 1)).to.equal(';'); + } + expect(line.charAt(line.length - 1)).to.not.equal(')'); + // check for the closing curly bracket of options object + if (line.startsWith('request')) { + var previousLine = snippetArray[index - 1]; + expect(previousLine.charAt(previousLine.length - 1)).to.equal(';'); + } + }); + }); + }); + + it('should return snippet with no trailing comma when requestTimeout ' + + 'is set to non zero and followRedirect as true', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + requestTimeout: 1000 + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('timeout: 1000,'); + expect(snippet).to.include('timeout: 1000'); + }); + }); + + it('should return snippet with just a single comma when requestTimeout ' + + 'is set to non zero and followRedirect as false', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + requestTimeout: 1000, + followRedirect: false, + indentCount: 1, + indentType: 'space' + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('timeout: 1000,,'); + expect(snippet).to.include('timeout: 1000,\n followRedirect: false'); + }); + }); + + it('should not require unused fs', function () { + request = new sdk.Request({ + 'url': 'https://postman-echo.com/get', + 'method': 'GET', + 'body': { + 'mode': 'raw', + 'raw': '' + } + }); + convert(request, {}, (error, snippet) => { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('var fs = require(\'fs\')'); + }); + }); + + it('should add fs for form-data file upload', function () { + request = new sdk.Request({ + 'url': 'https://postman-echo.com/post', + 'method': 'POST', + 'body': { + 'mode': 'formdata', + 'formdata': [ + { + 'key': 'fileName', + 'src': '/some/path/file.txt', + 'type': 'file' + } + ] + } + }); + convert(request, {}, (error, snippet) => { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('var fs = require(\'fs\')'); + }); + }); + + it('should trim header keys and not trim header values', function () { + var request = new sdk.Request({ + 'method': 'GET', + 'header': [ + { + 'key': ' key_containing_whitespaces ', + 'value': ' value_containing_whitespaces ' + } + ], + 'url': { + 'raw': 'https://google.com', + 'protocol': 'https', + 'host': [ + 'google', + 'com' + ] + } + }); + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('\'key_containing_whitespaces\': \' value_containing_whitespaces \''); + }); + }); + + it('should include JSON.stringify in the snippet for raw json bodies', function () { + var request = new sdk.Request({ + 'method': 'POST', + 'header': [ + { + 'key': 'Content-Type', + 'value': 'application/json' + } + ], + 'body': { + 'mode': 'raw', + 'raw': '{\n "json": "Test-Test"\n}' + }, + 'url': { + 'raw': 'https://postman-echo.com/post', + 'protocol': 'https', + 'host': [ + 'postman-echo', + 'com' + ], + 'path': [ + 'post' + ] + } + }); + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('body: JSON.stringify({"json":"Test-Test"})'); + }); + }); + + it('should generate snippets for no files in form data', function () { + var request = new sdk.Request({ + 'method': 'POST', + 'header': [], + 'body': { + 'mode': 'formdata', + 'formdata': [ + { + 'key': 'no file', + 'value': '', + 'type': 'file', + 'src': [] + }, + { + 'key': 'no src', + 'value': '', + 'type': 'file' + }, + { + 'key': 'invalid src', + 'value': '', + 'type': 'file', + 'src': {} + } + ] + }, + 'url': { + 'raw': 'https://postman-echo.com/post', + 'protocol': 'https', + 'host': [ + 'postman-echo', + 'com' + ], + 'path': [ + 'post' + ] + } + }); + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('\'no file\': {'); + expect(snippet).to.include('\'no src\': {'); + expect(snippet).to.include('\'invalid src\': {'); + expect(snippet).to.include('\'value\': fs.createReadStream(\'/path/to/file\')'); + }); + }); + + describe('getOptions function', function () { + + it('should return an array of specific options', function () { + expect(getOptions()).to.be.an('array'); + }); + + it('should return all the valid options', function () { + expect(getOptions()[0]).to.have.property('id', 'indentCount'); + expect(getOptions()[1]).to.have.property('id', 'indentType'); + expect(getOptions()[2]).to.have.property('id', 'requestTimeout'); + expect(getOptions()[3]).to.have.property('id', 'followRedirect'); + expect(getOptions()[4]).to.have.property('id', 'trimRequestBody'); + }); + }); + + describe('Sanitize function', function () { + + it('should return empty string when input is not a string type', function () { + expect(sanitize(123, false)).to.equal(''); + expect(sanitize(null, false)).to.equal(''); + expect(sanitize({}, false)).to.equal(''); + expect(sanitize([], false)).to.equal(''); + }); + + it('should trim input string when needed', function () { + expect(sanitize('inputString ', true)).to.equal('inputString'); + }); + }); + + describe('parseRequest function', function () { + + it('should return empty string for empty body', function () { + expect(parseBody(null, ' ', false)).to.equal(''); + }); + }); + }); +}); diff --git a/codegens/nodejs-superagent/test/unit/validation.test.js b/codegens/nodejs-superagent/test/unit/validation.test.js new file mode 100644 index 000000000..f1083b153 --- /dev/null +++ b/codegens/nodejs-superagent/test/unit/validation.test.js @@ -0,0 +1,30 @@ +var expect = require('chai').expect, + path = require('path'), + + package = require(path.resolve('.', 'package.json')); + + +describe('package.json', function () { + it('should have com_postman_plugin object with valid properties', function () { + expect(package).to.have.property('com_postman_plugin'); + + expect(package.com_postman_plugin.type).to.equal('code_generator'); + expect(package.com_postman_plugin.lang).to.be.a('string'); + expect(package.com_postman_plugin.variant).to.be.a('string'); + expect(package.com_postman_plugin.syntax_mode).to.be.equal('javascript'); + }); + it('should have main property with relative path to object with convert property', function () { + var languageModule; + + expect(package.main).to.be.a('string'); + + try { + languageModule = require(path.resolve('.', package.main)); + } + catch (error) { + console.error(error); + } + expect(languageModule).to.be.a('object'); + expect(languageModule.convert).to.be.a('function'); + }); +}); From 86075f52a13c904db55b979684bb114bd371ceef Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Wed, 1 Apr 2020 22:26:08 +0530 Subject: [PATCH 02/14] superagent code generator converter --- .../nodejs-superagent/lib/parseRequest.js | 16 +++--- codegens/nodejs-superagent/lib/superagent.js | 53 +++++++------------ 2 files changed, 26 insertions(+), 43 deletions(-) diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index 650c315b5..9e6367632 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -99,13 +99,13 @@ function parseBody (requestbody, indentString, trimBody, contentType) { if (contentType === 'application/json') { try { let jsonBody = JSON.parse(requestbody[requestbody.mode]); - return `body: JSON.stringify(${JSON.stringify(jsonBody)})\n`; + return `JSON.stringify(${JSON.stringify(jsonBody)})\n`; } catch (error) { - return `body: ${JSON.stringify(requestbody[requestbody.mode])}\n`; + return `${JSON.stringify(requestbody[requestbody.mode])}\n`; } } - return `body: ${JSON.stringify(requestbody[requestbody.mode])}\n`; + return `${JSON.stringify(requestbody[requestbody.mode])}\n`; // eslint-disable-next-line no-case-declarations case 'graphql': let query = requestbody[requestbody.mode].query, @@ -116,22 +116,22 @@ function parseBody (requestbody, indentString, trimBody, contentType) { catch (e) { graphqlVariables = {}; } - return 'body: JSON.stringify({\n' + + return 'JSON.stringify({\n' + `${indentString.repeat(2)}query: '${sanitize(query, trimBody)}',\n` + `${indentString.repeat(2)}variables: ${JSON.stringify(graphqlVariables)}\n` + `${indentString}})`; case 'formdata': - return `formData: {\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + + return `{\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + indentString + '}'; case 'urlencoded': - return `form: {\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + + return `{\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + indentString + '}'; /* istanbul ignore next */ case 'file': // return 'formData: {\n' + // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + // indentString + '}'; - return 'body: ""\n'; + return '""\n'; default: return ''; } @@ -148,7 +148,7 @@ function parseBody (requestbody, indentString, trimBody, contentType) { */ function parseHeader (request, indentString) { var headerObject = request.getHeaders({enabled: true}), - headerSnippet = indentString + '\'headers\': {\n'; + headerSnippet = '{\n'; if (!_.isEmpty(headerObject)) { headerSnippet += _.reduce(Object.keys(headerObject), function (accumalator, key) { diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js index c1a0a84c8..c4891797b 100644 --- a/codegens/nodejs-superagent/lib/superagent.js +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -14,7 +14,6 @@ var _ = require('./lodash'), */ function makeSnippet (request, indentString, options) { var snippet, - optionsArray = [], isFormDataFile = false; if (options.ES6_enabled) { snippet = 'const '; @@ -39,25 +38,7 @@ function makeSnippet (request, indentString, options) { } snippet += 'fs = require(\'fs\');\n'; } - if (options.ES6_enabled) { - snippet += 'let '; - } - else { - snippet += 'var '; - } - snippet += 'options = {\n'; - /** - * creating string to represent options object using optionArray.join() - * example: - * options: { - * method: 'GET', - * url: 'www.google.com', - * timeout: 1000 - * } - */ - optionsArray.push(indentString + `'method': '${request.method}'`); - optionsArray.push(indentString + `'url': '${sanitize(request.url.toString())}'`); if (request.body && !request.headers.has('Content-Type')) { if (request.body.mode === 'file') { request.addHeader({ @@ -72,33 +53,35 @@ function makeSnippet (request, indentString, options) { }); } } - optionsArray.push(parseRequest.parseHeader(request, indentString)); + + snippet += 'superagent\n'; + snippet += indentString + `.${request.method.toLowerCase()}('${sanitize(request.url.toString())}')\n`; + snippet += indentString + `.send(${parseRequest.parseHeader(request, indentString)})\n`; if (request.body && request.body[request.body.mode]) { - optionsArray.push( - indentString + parseRequest.parseBody(request.body.toJSON(), indentString, options.trimRequestBody, - request.headers.get('Content-Type')) - ); + snippet += indentString + `.set(${parseRequest.parseBody(request.body.toJSON(), + indentString, options.trimRequestBody, request.headers.get('Content-Type'))})\n`; } + if (options.requestTimeout) { - optionsArray.push(indentString + `timeout: ${options.requestTimeout}`); + snippet += indentString + `.timeout(${options.requestTimeout})\n`; } + if (options.followRedirect === false) { - optionsArray.push(indentString + 'followRedirect: false'); + snippet += indentString + '.redirects(0)\n'; } - snippet += optionsArray.join(',\n') + '\n'; - snippet += '};\n'; - snippet += 'superagent(options, '; + snippet += indentString + '.end('; if (options.ES6_enabled) { snippet += '(error, response) => {\n'; } else { snippet += 'function (error, response) {\n'; } - snippet += indentString + 'if (error) throw new Error(error);\n'; - snippet += indentString + 'console.log(response.body);\n'; - snippet += '});\n'; + snippet += indentString.repeat(2) + 'if (error) throw new Error(error);\n'; + snippet += indentString.repeat(2) + 'console.log(response.body);\n'; + snippet += indentString + '});'; + return snippet; } @@ -157,7 +140,7 @@ function getOptions () { } /** - * Converts Postman sdk request object to nodejs request code snippet + * Converts Postman sdk request object to nodejs superagent code snippet * * @param {Object} request - postman-SDK request object * @param {Object} options @@ -166,12 +149,12 @@ function getOptions () { * @param {Boolean} options.followRedirect - whether to enable followredirect * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not * @param {Boolean} options.ES6_enabled - whether to generate snippet with ES6 features - * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out + * @param {Number} options.requestTimeout : time in milliseconds after which request will bail out * @param {Function} callback - callback function with parameters (error, snippet) */ function convert (request, options, callback) { if (!_.isFunction(callback)) { - throw new Error('NodeJS-Request-Converter: callback is not valid function'); + throw new Error('NodeJS-SuperAgent-Converter: callback is not valid function'); } options = sanitizeOptions(options, getOptions()); From 839bd8f8ec5623a568e3ac60a6acae16c6363e01 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Wed, 1 Apr 2020 23:59:20 +0530 Subject: [PATCH 03/14] snippet test added --- .../test/unit/snippet.test.js | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/codegens/nodejs-superagent/test/unit/snippet.test.js b/codegens/nodejs-superagent/test/unit/snippet.test.js index e1a228684..3d750ca98 100644 --- a/codegens/nodejs-superagent/test/unit/snippet.test.js +++ b/codegens/nodejs-superagent/test/unit/snippet.test.js @@ -1,4 +1,3 @@ -// TODO var expect = require('chai').expect, sdk = require('postman-collection'), sanitize = require('../../lib/util').sanitize, @@ -30,7 +29,7 @@ describe('nodejs-superagent convert function', function () { expect(snippet).to.be.a('string'); snippetArray = snippet.split('\n'); for (var i = 0; i < snippetArray.length; i++) { - if (snippetArray[i] === 'var options = {') { line_no = i + 1; } + if (snippetArray[i] === 'superagent') { line_no = i + 1; } } expect(snippetArray[line_no].charAt(0)).to.equal('\t'); }); @@ -48,7 +47,7 @@ describe('nodejs-superagent convert function', function () { } expect(snippet).to.be.a('string'); - expect(snippet).to.include('timeout: 1000'); + expect(snippet).to.include('.timeout(1000)'); }); }); @@ -65,9 +64,8 @@ describe('nodejs-superagent convert function', function () { expect(snippet).to.be.a('string'); snippetArray = snippet.split('\n'); - expect(snippetArray[0]).to.equal('const request = require(\'request\');'); - expect(snippetArray).to.include('let options = {'); - expect(snippetArray).to.include('request(options, (error, response) => {'); + expect(snippetArray[0]).to.equal('const superagent = require(\'superagent\');'); + expect(snippetArray).to.include('.end((error, response) => {'); }); }); @@ -84,7 +82,7 @@ describe('nodejs-superagent convert function', function () { } expect(snippet).to.be.a('string'); - expect(snippet).to.include('followRedirect: false'); + expect(snippet).to.include('.redirects(0)'); }); }); @@ -101,7 +99,7 @@ describe('nodejs-superagent convert function', function () { return; } expect(snippet).to.be.a('string'); - expect(snippet).to.include('\'headers\': {\n }'); + expect(snippet).to.include('.set({})'); }); }); @@ -117,7 +115,7 @@ describe('nodejs-superagent convert function', function () { return; } expect(snippet).to.be.a('string'); - expect(snippet).to.not.include('body:'); + expect(snippet).to.include('.set({})'); }); }); @@ -146,6 +144,7 @@ describe('nodejs-superagent convert function', function () { }); }); + // TODO it('should return snippet with proper semicolon placed where required', function () { // testing for the below snippet /* @@ -172,7 +171,7 @@ describe('nodejs-superagent convert function', function () { expect(snippet).to.be.a('string'); var snippetArray = snippet.split('\n'); snippetArray.forEach(function (line, index) { - if (line.charAt(line.length - 2) === ')') { + if (line.contains('.') === ')') { expect(line.charAt(line.length - 1)).to.equal(';'); } expect(line.charAt(line.length - 1)).to.not.equal(')'); @@ -185,6 +184,7 @@ describe('nodejs-superagent convert function', function () { }); }); + // TODO it('should return snippet with no trailing comma when requestTimeout ' + 'is set to non zero and followRedirect as true', function () { request = new sdk.Request(mainCollection.item[0].request); @@ -203,6 +203,7 @@ describe('nodejs-superagent convert function', function () { }); }); + // TODO: it('should return snippet with just a single comma when requestTimeout ' + 'is set to non zero and followRedirect as false', function () { request = new sdk.Request(mainCollection.item[0].request); @@ -238,7 +239,7 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.not.include('var fs = require(\'fs\')'); + expect(snippet).to.not.include('var fs = require(\'fs\');'); }); }); @@ -262,7 +263,7 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.include('var fs = require(\'fs\')'); + expect(snippet).to.include('var fs = require(\'fs\');'); }); }); @@ -323,7 +324,7 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.include('body: JSON.stringify({"json":"Test-Test"})'); + expect(snippet).to.include('JSON.stringify({"json":"Test-Test"})'); }); }); From fb0c5f4833b35a312de758f31907c55126156972 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Thu, 2 Apr 2020 18:02:14 +0530 Subject: [PATCH 04/14] update parsing functions for superagent --- .../nodejs-superagent/lib/parseRequest.js | 71 ++++++++----------- codegens/nodejs-superagent/lib/superagent.js | 9 +-- 2 files changed, 33 insertions(+), 47 deletions(-) diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index 9e6367632..f5d57e7e9 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -10,8 +10,9 @@ var _ = require('./lodash'), * @param {Array} dataArray - array containing body elements of request * @param {String} indentString - string required for indentation * @param {Boolean} trimBody - indicates whether to trim body or not + * @param {String} requestType - indicates whether the requestBody is to be parsed as urlencoded or formdata */ -function extractFormData (dataArray, indentString, trimBody) { +function extractFormData (dataArray, indentString, trimBody, requestType) { if (!dataArray) { return ''; } @@ -34,14 +35,12 @@ function extractFormData (dataArray, indentString, trimBody) { * } */ if (Array.isArray(item.src) && item.src.length) { - let fileSnippet = '', - fileArray = []; + let fileSnippet = ''; _.forEach(item.src, (filePath) => { - fileArray.push(`${indentString.repeat(3)}fs.createReadStream('${sanitize(filePath, trimBody)}')`); + fileSnippet += indentString + `.attach('${sanitize(item.key, trimBody)}', + '${sanitize(filePath, trimBody)}')\n`; }); - if (fileArray.length) { - fileSnippet += `${indentString.repeat(2)}'${sanitize(item.key, trimBody)}': ` + - `[\n${fileArray.join(',\n')}\n${indentString.repeat(2)}]`; + if (fileSnippet !== '') { accumalator.push(fileSnippet); } else { @@ -49,39 +48,26 @@ function extractFormData (dataArray, indentString, trimBody) { } } else if (typeof item.src !== 'string') { - accumalator.push([ - indentString.repeat(2) + `'${sanitize(item.key, trimBody)}': {`, - indentString.repeat(3) + '\'value\': fs.createReadStream(\'/path/to/file\'),', - indentString.repeat(3) + '\'options\': {', - indentString.repeat(4) + '\'filename\': \'filename\'', - indentString.repeat(4) + '\'contentType\': null', - indentString.repeat(3) + '}', - indentString.repeat(2) + '}' - ].join('\n')); + accumalator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', '/path/to/file')`); } else { var pathArray = item.src.split(path.sep), fileName = pathArray[pathArray.length - 1]; - accumalator.push([ - indentString.repeat(2) + `'${sanitize(item.key, trimBody)}': {`, - indentString.repeat(3) + `'value': fs.createReadStream('${sanitize(item.src, trimBody)}'),`, - indentString.repeat(3) + '\'options\': {', - indentString.repeat(4) + `'filename': '${sanitize(fileName, trimBody)}',`, - indentString.repeat(4) + '\'contentType\': null', - indentString.repeat(3) + '}', - indentString.repeat(2) + '}' - ].join('\n')); + accumalator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', + '${sanitize(item.src, trimBody)}', '${sanitize(fileName, trimBody)}')`); } } - else { - accumalator.push( - indentString.repeat(2) + - `'${sanitize(item.key, trimBody)}': '${sanitize(item.value, trimBody)}'` - ); + else if (requestType === 'urlencoded') { + accumalator.push(indentString + + `.send({'${sanitize(item.key, trimBody)}':'${sanitize(item.value, trimBody)}'})`); + } + else if (requestType === 'formdata') { + accumalator.push(indentString + + `.field('${sanitize(item.key, trimBody)}', '${sanitize(item.value, trimBody)}')`); } return accumalator; }, []); - return snippetString.join(',\n') + '\n'; + return snippetString.join('\n') + '\n'; } /** @@ -99,13 +85,13 @@ function parseBody (requestbody, indentString, trimBody, contentType) { if (contentType === 'application/json') { try { let jsonBody = JSON.parse(requestbody[requestbody.mode]); - return `JSON.stringify(${JSON.stringify(jsonBody)})\n`; + return `.send(JSON.stringify(${JSON.stringify(jsonBody)}))\n`; } catch (error) { - return `${JSON.stringify(requestbody[requestbody.mode])}\n`; + return `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; } } - return `${JSON.stringify(requestbody[requestbody.mode])}\n`; + return `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; // eslint-disable-next-line no-case-declarations case 'graphql': let query = requestbody[requestbody.mode].query, @@ -116,22 +102,21 @@ function parseBody (requestbody, indentString, trimBody, contentType) { catch (e) { graphqlVariables = {}; } - return 'JSON.stringify({\n' + + return '.send(JSON.stringify({\n' + `${indentString.repeat(2)}query: '${sanitize(query, trimBody)}',\n` + `${indentString.repeat(2)}variables: ${JSON.stringify(graphqlVariables)}\n` + - `${indentString}})`; + `${indentString}}))\n`; case 'formdata': - return `{\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + - indentString + '}'; + return `${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}`; case 'urlencoded': - return `{\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + - indentString + '}'; + return `.type('form')\n${extractFormData(requestbody[requestbody.mode], + indentString, trimBody, requestbody.mode)}\n`; /* istanbul ignore next */ case 'file': // return 'formData: {\n' + // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + // indentString + '}'; - return '""\n'; + return '.send("")\n'; default: return ''; } @@ -140,11 +125,11 @@ function parseBody (requestbody, indentString, trimBody, contentType) { } /** - * parses header of request object and returns code snippet of nodejs superagent to add header + * parses header of request object and returns code snippet of nodejs request to add header * * @param {Object} request - Postman SDK request object * @param {String} indentString - indentation required in code snippet - * @returns {String} - code snippet of nodejs superagent to add header + * @returns {String} - code snippet of nodejs request to add header */ function parseHeader (request, indentString) { var headerObject = request.getHeaders({enabled: true}), diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js index c4891797b..9a5e70964 100644 --- a/codegens/nodejs-superagent/lib/superagent.js +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -38,6 +38,7 @@ function makeSnippet (request, indentString, options) { } snippet += 'fs = require(\'fs\');\n'; } + snippet += '\n'; if (request.body && !request.headers.has('Content-Type')) { if (request.body.mode === 'file') { @@ -56,11 +57,11 @@ function makeSnippet (request, indentString, options) { snippet += 'superagent\n'; snippet += indentString + `.${request.method.toLowerCase()}('${sanitize(request.url.toString())}')\n`; - snippet += indentString + `.send(${parseRequest.parseHeader(request, indentString)})\n`; + snippet += indentString + `.set(${parseRequest.parseHeader(request, indentString)})\n`; if (request.body && request.body[request.body.mode]) { - snippet += indentString + `.set(${parseRequest.parseBody(request.body.toJSON(), - indentString, options.trimRequestBody, request.headers.get('Content-Type'))})\n`; + snippet += indentString + parseRequest.parseBody(request.body.toJSON(), + indentString, options.trimRequestBody, request.headers.get('Content-Type')); } if (options.requestTimeout) { @@ -79,7 +80,7 @@ function makeSnippet (request, indentString, options) { snippet += 'function (error, response) {\n'; } snippet += indentString.repeat(2) + 'if (error) throw new Error(error);\n'; - snippet += indentString.repeat(2) + 'console.log(response.body);\n'; + snippet += indentString.repeat(2) + 'console.log(JSON.stringify(response.body));\n'; snippet += indentString + '});'; return snippet; From 858c926eeb0735eae5c2b58aa5bb4ede9ec2521c Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Thu, 2 Apr 2020 20:20:33 +0530 Subject: [PATCH 05/14] updated codegen level tests --- .../nodejs-superagent/lib/parseRequest.js | 34 ++++--- codegens/nodejs-superagent/lib/superagent.js | 4 +- .../test/unit/snippet.test.js | 94 ++----------------- 3 files changed, 31 insertions(+), 101 deletions(-) diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index f5d57e7e9..f6f9af97e 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -67,7 +67,7 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { } return accumalator; }, []); - return snippetString.join('\n') + '\n'; + return snippetString.join('\n'); } /** @@ -80,18 +80,22 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { */ function parseBody (requestbody, indentString, trimBody, contentType) { if (requestbody) { + var bodySnippet = indentString; switch (requestbody.mode) { case 'raw': if (contentType === 'application/json') { try { let jsonBody = JSON.parse(requestbody[requestbody.mode]); - return `.send(JSON.stringify(${JSON.stringify(jsonBody)}))\n`; + bodySnippet += `.send(JSON.stringify(${JSON.stringify(jsonBody)}))\n`; + break; } catch (error) { - return `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + bodySnippet += `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + break; } } - return `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + bodySnippet += `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + break; // eslint-disable-next-line no-case-declarations case 'graphql': let query = requestbody[requestbody.mode].query, @@ -102,24 +106,29 @@ function parseBody (requestbody, indentString, trimBody, contentType) { catch (e) { graphqlVariables = {}; } - return '.send(JSON.stringify({\n' + + bodySnippet += '.send(JSON.stringify({\n' + `${indentString.repeat(2)}query: '${sanitize(query, trimBody)}',\n` + `${indentString.repeat(2)}variables: ${JSON.stringify(graphqlVariables)}\n` + `${indentString}}))\n`; + break; case 'formdata': - return `${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}`; + bodySnippet = `${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}`; + break; case 'urlencoded': - return `.type('form')\n${extractFormData(requestbody[requestbody.mode], + bodySnippet += `.type('form')\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}\n`; + break; /* istanbul ignore next */ case 'file': // return 'formData: {\n' + // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + // indentString + '}'; - return '.send("")\n'; + bodySnippet += '.send("")\n'; + break; default: - return ''; + bodySnippet = ''; } + return bodySnippet; } return ''; } @@ -133,7 +142,7 @@ function parseBody (requestbody, indentString, trimBody, contentType) { */ function parseHeader (request, indentString) { var headerObject = request.getHeaders({enabled: true}), - headerSnippet = '{\n'; + headerSnippet = `${indentString}.set({\n`; if (!_.isEmpty(headerObject)) { headerSnippet += _.reduce(Object.keys(headerObject), function (accumalator, key) { @@ -154,8 +163,11 @@ function parseHeader (request, indentString) { return accumalator; }, []).join(',\n') + '\n'; } + else { + return ''; + } - headerSnippet += indentString + '}'; + headerSnippet += indentString + '})\n'; return headerSnippet; } diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js index 9a5e70964..7f59de422 100644 --- a/codegens/nodejs-superagent/lib/superagent.js +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -57,10 +57,10 @@ function makeSnippet (request, indentString, options) { snippet += 'superagent\n'; snippet += indentString + `.${request.method.toLowerCase()}('${sanitize(request.url.toString())}')\n`; - snippet += indentString + `.set(${parseRequest.parseHeader(request, indentString)})\n`; + snippet += parseRequest.parseHeader(request, indentString); if (request.body && request.body[request.body.mode]) { - snippet += indentString + parseRequest.parseBody(request.body.toJSON(), + snippet += parseRequest.parseBody(request.body.toJSON(), indentString, options.trimRequestBody, request.headers.get('Content-Type')); } diff --git a/codegens/nodejs-superagent/test/unit/snippet.test.js b/codegens/nodejs-superagent/test/unit/snippet.test.js index 3d750ca98..cc5bcfe9f 100644 --- a/codegens/nodejs-superagent/test/unit/snippet.test.js +++ b/codegens/nodejs-superagent/test/unit/snippet.test.js @@ -65,7 +65,7 @@ describe('nodejs-superagent convert function', function () { expect(snippet).to.be.a('string'); snippetArray = snippet.split('\n'); expect(snippetArray[0]).to.equal('const superagent = require(\'superagent\');'); - expect(snippetArray).to.include('.end((error, response) => {'); + expect(snippet).to.include('.end((error, response) => {'); }); }); @@ -99,7 +99,7 @@ describe('nodejs-superagent convert function', function () { return; } expect(snippet).to.be.a('string'); - expect(snippet).to.include('.set({})'); + expect(snippet).to.not.include('.set('); }); }); @@ -115,7 +115,6 @@ describe('nodejs-superagent convert function', function () { return; } expect(snippet).to.be.a('string'); - expect(snippet).to.include('.set({})'); }); }); @@ -144,87 +143,6 @@ describe('nodejs-superagent convert function', function () { }); }); - // TODO - it('should return snippet with proper semicolon placed where required', function () { - // testing for the below snippet - /* - var request = require('request'); - var fs = require('fs'); - var options = { - 'method': 'GET', - 'url': 'https://postman-echo.com/headers', - 'headers': { - 'my-sample-header': 'Lorem ipsum dolor sit amet', - 'not-disabled-header': 'ENABLED' - } - }; - request(options, function (error, response) { - if (error) throw new Error(error); - console.log(response.body); - }); */ - request = new sdk.Request(mainCollection.item[0].request); - options = {}; - convert(request, options, function (error, snippet) { - if (error) { - expect.fail(null, null, error); - } - expect(snippet).to.be.a('string'); - var snippetArray = snippet.split('\n'); - snippetArray.forEach(function (line, index) { - if (line.contains('.') === ')') { - expect(line.charAt(line.length - 1)).to.equal(';'); - } - expect(line.charAt(line.length - 1)).to.not.equal(')'); - // check for the closing curly bracket of options object - if (line.startsWith('request')) { - var previousLine = snippetArray[index - 1]; - expect(previousLine.charAt(previousLine.length - 1)).to.equal(';'); - } - }); - }); - }); - - // TODO - it('should return snippet with no trailing comma when requestTimeout ' + - 'is set to non zero and followRedirect as true', function () { - request = new sdk.Request(mainCollection.item[0].request); - options = { - requestTimeout: 1000 - }; - convert(request, options, function (error, snippet) { - if (error) { - expect.fail(null, null, error); - return; - } - - expect(snippet).to.be.a('string'); - expect(snippet).to.not.include('timeout: 1000,'); - expect(snippet).to.include('timeout: 1000'); - }); - }); - - // TODO: - it('should return snippet with just a single comma when requestTimeout ' + - 'is set to non zero and followRedirect as false', function () { - request = new sdk.Request(mainCollection.item[0].request); - options = { - requestTimeout: 1000, - followRedirect: false, - indentCount: 1, - indentType: 'space' - }; - convert(request, options, function (error, snippet) { - if (error) { - expect.fail(null, null, error); - return; - } - - expect(snippet).to.be.a('string'); - expect(snippet).to.not.include('timeout: 1000,,'); - expect(snippet).to.include('timeout: 1000,\n followRedirect: false'); - }); - }); - it('should not require unused fs', function () { request = new sdk.Request({ 'url': 'https://postman-echo.com/get', @@ -371,10 +289,10 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.include('\'no file\': {'); - expect(snippet).to.include('\'no src\': {'); - expect(snippet).to.include('\'invalid src\': {'); - expect(snippet).to.include('\'value\': fs.createReadStream(\'/path/to/file\')'); + expect(snippet).to.include('\'no file\','); + expect(snippet).to.include('\'no src\','); + expect(snippet).to.include('\'invalid src\','); + expect(snippet).to.include(', \'/path/to/file\')'); }); }); From b1162a5dbf93aca19eaef470c1776e841082db04 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Thu, 2 Apr 2020 20:29:56 +0530 Subject: [PATCH 06/14] README update and fix typos --- README.md | 1 + .../nodejs-superagent/lib/parseRequest.js | 68 ++++++++----------- codegens/nodejs-superagent/lib/superagent.js | 2 +- .../test/unit/snippet.test.js | 6 +- 4 files changed, 33 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 12b163170..9c8ff3b68 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ List of supported code generators: | JavaScript | XHR | | NodeJs | Native | | NodeJs | Request | +| NodeJs | SuperAgent | | NodeJs | Unirest | | Objective-C| NSURLSession| | OCaml | Cohttp | diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index f6f9af97e..2463c1047 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -16,24 +16,12 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { if (!dataArray) { return ''; } - var snippetString = _.reduce(dataArray, (accumalator, item) => { + var snippetString = _.reduce(dataArray, (accumulator, item) => { if (item.disabled) { - return accumalator; + return accumulator; } /* istanbul ignore next */ if (item.type === 'file') { - /** - * creating snippet to send file in nodejs request - * for example: - * 'fieldname': { - * 'value': fs.createStream('filename.ext'), - * 'options': { - * 'filename': 'filename.ext', - * 'contentType: null - * } - * } - * } - */ if (Array.isArray(item.src) && item.src.length) { let fileSnippet = ''; _.forEach(item.src, (filePath) => { @@ -41,31 +29,31 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { '${sanitize(filePath, trimBody)}')\n`; }); if (fileSnippet !== '') { - accumalator.push(fileSnippet); + accumulator.push(fileSnippet); } else { - return accumalator; + return accumulator; } } else if (typeof item.src !== 'string') { - accumalator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', '/path/to/file')`); + accumulator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', '/path/to/file')`); } else { var pathArray = item.src.split(path.sep), fileName = pathArray[pathArray.length - 1]; - accumalator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', + accumulator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', '${sanitize(item.src, trimBody)}', '${sanitize(fileName, trimBody)}')`); } } else if (requestType === 'urlencoded') { - accumalator.push(indentString + + accumulator.push(indentString + `.send({'${sanitize(item.key, trimBody)}':'${sanitize(item.value, trimBody)}'})`); } else if (requestType === 'formdata') { - accumalator.push(indentString + + accumulator.push(indentString + `.field('${sanitize(item.key, trimBody)}', '${sanitize(item.value, trimBody)}')`); } - return accumalator; + return accumulator; }, []); return snippetString.join('\n'); } @@ -73,35 +61,35 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { /** * Parses body object based on mode of body and returns code snippet * - * @param {Object} requestbody - json object for body of request + * @param {Object} requestBody - json object for body of request * @param {String} indentString - string for indentation * @param {Boolean} trimBody - indicates whether to trim body fields or not * @param {String} contentType Content type of the body being sent */ -function parseBody (requestbody, indentString, trimBody, contentType) { - if (requestbody) { +function parseBody (requestBody, indentString, trimBody, contentType) { + if (requestBody) { var bodySnippet = indentString; - switch (requestbody.mode) { + switch (requestBody.mode) { case 'raw': if (contentType === 'application/json') { try { - let jsonBody = JSON.parse(requestbody[requestbody.mode]); + let jsonBody = JSON.parse(requestBody[requestBody.mode]); bodySnippet += `.send(JSON.stringify(${JSON.stringify(jsonBody)}))\n`; break; } catch (error) { - bodySnippet += `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + bodySnippet += `.send(${JSON.stringify(requestBody[requestBody.mode])})\n`; break; } } - bodySnippet += `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + bodySnippet += `.send(${JSON.stringify(requestBody[requestBody.mode])})\n`; break; // eslint-disable-next-line no-case-declarations case 'graphql': - let query = requestbody[requestbody.mode].query, + let query = requestBody[requestBody.mode].query, graphqlVariables; try { - graphqlVariables = JSON.parse(requestbody[requestbody.mode].variables); + graphqlVariables = JSON.parse(requestBody[requestBody.mode].variables); } catch (e) { graphqlVariables = {}; @@ -112,16 +100,16 @@ function parseBody (requestbody, indentString, trimBody, contentType) { `${indentString}}))\n`; break; case 'formdata': - bodySnippet = `${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}`; + bodySnippet = `${extractFormData(requestBody[requestBody.mode], indentString, trimBody, requestBody.mode)}`; break; case 'urlencoded': - bodySnippet += `.type('form')\n${extractFormData(requestbody[requestbody.mode], - indentString, trimBody, requestbody.mode)}\n`; + bodySnippet += `.type('form')\n${extractFormData(requestBody[requestBody.mode], + indentString, trimBody, requestBody.mode)}\n`; break; /* istanbul ignore next */ case 'file': // return 'formData: {\n' + - // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + + // extractFormData(requestBody[requestBody.mode], indentString, trimBody) + // indentString + '}'; bodySnippet += '.send("")\n'; break; @@ -134,33 +122,33 @@ function parseBody (requestbody, indentString, trimBody, contentType) { } /** - * parses header of request object and returns code snippet of nodejs request to add header + * parses header of request object and returns code snippet of nodejs superagent to add header * * @param {Object} request - Postman SDK request object * @param {String} indentString - indentation required in code snippet - * @returns {String} - code snippet of nodejs request to add header + * @returns {String} - code snippet of nodejs superagent to add header */ function parseHeader (request, indentString) { var headerObject = request.getHeaders({enabled: true}), headerSnippet = `${indentString}.set({\n`; if (!_.isEmpty(headerObject)) { - headerSnippet += _.reduce(Object.keys(headerObject), function (accumalator, key) { + headerSnippet += _.reduce(Object.keys(headerObject), function (accumulator, key) { if (Array.isArray(headerObject[key])) { var headerValues = []; _.forEach(headerObject[key], (value) => { headerValues.push(`'${sanitize(value)}'`); }); - accumalator.push( + accumulator.push( indentString.repeat(2) + `'${sanitize(key, true)}': [${headerValues.join(', ')}]` ); } else { - accumalator.push( + accumulator.push( indentString.repeat(2) + `'${sanitize(key, true)}': '${sanitize(headerObject[key])}'` ); } - return accumalator; + return accumulator; }, []).join(',\n') + '\n'; } else { diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js index 7f59de422..76d7b0eff 100644 --- a/codegens/nodejs-superagent/lib/superagent.js +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -147,7 +147,7 @@ function getOptions () { * @param {Object} options * @param {String} options.indentType - type for indentation eg: Space, Tab * @param {String} options.indentCount - number of spaces or tabs for indentation. - * @param {Boolean} options.followRedirect - whether to enable followredirect + * @param {Boolean} options.followRedirect - whether to enable follow redirect * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not * @param {Boolean} options.ES6_enabled - whether to generate snippet with ES6 features * @param {Number} options.requestTimeout : time in milliseconds after which request will bail out diff --git a/codegens/nodejs-superagent/test/unit/snippet.test.js b/codegens/nodejs-superagent/test/unit/snippet.test.js index cc5bcfe9f..bc2339826 100644 --- a/codegens/nodejs-superagent/test/unit/snippet.test.js +++ b/codegens/nodejs-superagent/test/unit/snippet.test.js @@ -190,8 +190,8 @@ describe('nodejs-superagent convert function', function () { 'method': 'GET', 'header': [ { - 'key': ' key_containing_whitespaces ', - 'value': ' value_containing_whitespaces ' + 'key': ' key_containing_whitespace ', + 'value': ' value_containing_whitespace ' } ], 'url': { @@ -208,7 +208,7 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.include('\'key_containing_whitespaces\': \' value_containing_whitespaces \''); + expect(snippet).to.include('\'key_containing_whitespace\': \' value_containing_whitespace \''); }); }); From 306dee922098913553fdc047ed9cb978bcc64be8 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Tue, 12 May 2020 11:39:44 +0530 Subject: [PATCH 07/14] Added missing newline character --- codegens/nodejs-superagent/lib/parseRequest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index 2463c1047..cb6ca8861 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -100,7 +100,7 @@ function parseBody (requestBody, indentString, trimBody, contentType) { `${indentString}}))\n`; break; case 'formdata': - bodySnippet = `${extractFormData(requestBody[requestBody.mode], indentString, trimBody, requestBody.mode)}`; + bodySnippet = `${extractFormData(requestBody[requestBody.mode], indentString, trimBody, requestBody.mode)}\n`; break; case 'urlencoded': bodySnippet += `.type('form')\n${extractFormData(requestBody[requestBody.mode], From bb674f90d12e006ae904171676381ba9b2bff2fe Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Wed, 1 Apr 2020 20:08:26 +0530 Subject: [PATCH 08/14] Boilerplate Code for nodejs-superagent codegen --- codegens/nodejs-superagent/.gitignore | 69 + codegens/nodejs-superagent/.jsdoc-config.json | 34 + codegens/nodejs-superagent/.npmignore | 74 + codegens/nodejs-superagent/README.md | 68 + codegens/nodejs-superagent/index.js | 1 + codegens/nodejs-superagent/lib/index.js | 4 + codegens/nodejs-superagent/lib/lodash.js | 456 ++++++ .../nodejs-superagent/lib/parseRequest.js | 180 +++ codegens/nodejs-superagent/lib/superagent.js | 190 +++ codegens/nodejs-superagent/lib/util.js | 88 ++ .../nodejs-superagent/npm-shrinkwrap.json | 440 ++++++ codegens/nodejs-superagent/npm/test-lint.js | 58 + codegens/nodejs-superagent/npm/test-newman.js | 59 + codegens/nodejs-superagent/npm/test-unit.js | 59 + codegens/nodejs-superagent/npm/test.js | 18 + codegens/nodejs-superagent/package.json | 36 + codegens/nodejs-superagent/test/.eslintrc | 30 + .../test/newman/newman.test.js | 27 + codegens/nodejs-superagent/test/unit/.gitkeep | 0 .../fixtures/testcollection/collection.json | 1349 +++++++++++++++++ .../test/unit/snippet.test.js | 416 +++++ .../test/unit/validation.test.js | 30 + 22 files changed, 3686 insertions(+) create mode 100644 codegens/nodejs-superagent/.gitignore create mode 100644 codegens/nodejs-superagent/.jsdoc-config.json create mode 100644 codegens/nodejs-superagent/.npmignore create mode 100644 codegens/nodejs-superagent/README.md create mode 100644 codegens/nodejs-superagent/index.js create mode 100644 codegens/nodejs-superagent/lib/index.js create mode 100644 codegens/nodejs-superagent/lib/lodash.js create mode 100644 codegens/nodejs-superagent/lib/parseRequest.js create mode 100644 codegens/nodejs-superagent/lib/superagent.js create mode 100644 codegens/nodejs-superagent/lib/util.js create mode 100644 codegens/nodejs-superagent/npm-shrinkwrap.json create mode 100644 codegens/nodejs-superagent/npm/test-lint.js create mode 100644 codegens/nodejs-superagent/npm/test-newman.js create mode 100755 codegens/nodejs-superagent/npm/test-unit.js create mode 100755 codegens/nodejs-superagent/npm/test.js create mode 100644 codegens/nodejs-superagent/package.json create mode 100644 codegens/nodejs-superagent/test/.eslintrc create mode 100644 codegens/nodejs-superagent/test/newman/newman.test.js create mode 100644 codegens/nodejs-superagent/test/unit/.gitkeep create mode 100644 codegens/nodejs-superagent/test/unit/fixtures/testcollection/collection.json create mode 100644 codegens/nodejs-superagent/test/unit/snippet.test.js create mode 100644 codegens/nodejs-superagent/test/unit/validation.test.js diff --git a/codegens/nodejs-superagent/.gitignore b/codegens/nodejs-superagent/.gitignore new file mode 100644 index 000000000..dd41cd99b --- /dev/null +++ b/codegens/nodejs-superagent/.gitignore @@ -0,0 +1,69 @@ +.DS_Store +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# temporarily generated file +run.js + +# Prevent IDE stuff +.idea +.vscode +*.sublime-* + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +.coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +out/ diff --git a/codegens/nodejs-superagent/.jsdoc-config.json b/codegens/nodejs-superagent/.jsdoc-config.json new file mode 100644 index 000000000..085a7be65 --- /dev/null +++ b/codegens/nodejs-superagent/.jsdoc-config.json @@ -0,0 +1,34 @@ +{ + "tags": { + "allowUnknownTags": true, + "dictionaries": ["jsdoc", "closure"] + }, + "source": { + "include": ["lib"], + "includePattern": ".+\\.js(doc)?$", + "excludePattern": "(^|\\/|\\\\)_" + }, + + "plugins": [ + "plugins/markdown" + ], + + "templates": { + "cleverLinks": false, + "monospaceLinks": false, + "highlightTutorialCode" : true + }, + + "opts": { + "template": "./node_modules/postman-jsdoc-theme", + "encoding": "utf8", + "destination": "./out/docs", + "recurse": true, + "readme": "README.md" + }, + + "markdown": { + "parser": "gfm", + "hardwrap": false + } +} diff --git a/codegens/nodejs-superagent/.npmignore b/codegens/nodejs-superagent/.npmignore new file mode 100644 index 000000000..17156c3bc --- /dev/null +++ b/codegens/nodejs-superagent/.npmignore @@ -0,0 +1,74 @@ +### NPM Specific: Disregard recursive project files +### =============================================== +/.editorconfig +/.gitmodules +/test + +### Borrowed from .gitignore +### ======================== + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Prevent IDE stuff +.idea +.vscode +*.sublime-* + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +.coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +out/ diff --git a/codegens/nodejs-superagent/README.md b/codegens/nodejs-superagent/README.md new file mode 100644 index 000000000..435d36da5 --- /dev/null +++ b/codegens/nodejs-superagent/README.md @@ -0,0 +1,68 @@ +# codegen-nodejs-superagent + +> Converts Postman-SDK SuperAgent into code snippet for NodeJS-SuperAgent. + +#### Prerequisites +To run the module, ensure that you have NodeJS >= v6. A copy of the NodeJS installable can be downloaded from https://nodejs.org/en/download/package-manager. + +## Using the Module +The module will expose an object which will have property `convert` which is the function for converting the Postman-SDK request to nodejs-superagent code snippet and `getOptions` function which returns an array of supported options. + +### convert function +Convert function will take three parameters +* `request`- Postman-SDK Request object + +* `options`- options is an object which can have following properties + * `indentType`- String denoting type of indentation for code snippet. eg: 'Space', 'Tab' + * `indentCount`- positiveInteger representing count of indentation required. + * `requestTimeout` : Integer denoting time after which the request will bail out in milliseconds + * `trimRequestBody` : Trim request body fields + * `followRedirect` : Boolean denoting whether to redirect a request + * `ES6_enabled` : Boolean denoting whether to generate snippet with ES6 features + +* `callback`- callback function with first parameter as error and second parameter as string for code snippet + +##### Example: +```js +var request = new sdk.Request('www.google.com'), //using postman sdk to create request + options = { + indentType: 'Space', + indentCount: 2, + ES6_enabled: true + }; +convert(request, options, function(error, snippet) { + if (error) { + // handle error + } + // handle snippet +}); +``` + +### getOptions function + +This function returns a list of options supported by this codegen. + +#### Example +```js +var options = getOptions(); + +console.log(options); +// output +// [ +// { +// name: 'Set indentation count', +// id: 'indentCount', +// type: 'positiveInteger', +// default: 2, +// description: 'Set the number of indentation characters to add per code level' +// }, +// ... +// ] +``` + +### Guideline for using generated snippet +* Generated snippet requires `superagent` and `fs` modules. + +* Since Postman-SDK Request object doesn't provide complete path of the file, it needs to be manually inserted in case of uploading a file. + +* This module doesn't support cookies. diff --git a/codegens/nodejs-superagent/index.js b/codegens/nodejs-superagent/index.js new file mode 100644 index 000000000..bb0a047c4 --- /dev/null +++ b/codegens/nodejs-superagent/index.js @@ -0,0 +1 @@ +module.exports = require('./lib'); diff --git a/codegens/nodejs-superagent/lib/index.js b/codegens/nodejs-superagent/lib/index.js new file mode 100644 index 000000000..d9a9054fc --- /dev/null +++ b/codegens/nodejs-superagent/lib/index.js @@ -0,0 +1,4 @@ +module.exports = { + convert: require('./superagent').convert, + getOptions: require('./superagent').getOptions +}; diff --git a/codegens/nodejs-superagent/lib/lodash.js b/codegens/nodejs-superagent/lib/lodash.js new file mode 100644 index 000000000..55ea6666d --- /dev/null +++ b/codegens/nodejs-superagent/lib/lodash.js @@ -0,0 +1,456 @@ +/* istanbul ignore next */ +module.exports = { + + /** + * Checks if `value` is an empty object, array or string. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Values such as strings, arrays are considered empty if they have a `length` of `0`. + * + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * isEmpty(null) + * // => true + * + * isEmpty(true) + * // => true + * + * isEmpty(1) + * // => true + * + * isEmpty([1, 2, 3]) + * // => false + * + * isEmpty('abc') + * // => false + * + * isEmpty({ 'a': 1 }) + * // => false + */ + isEmpty: function (value) { + // eslint-disable-next-line lodash/prefer-is-nil + if (value === null || value === undefined) { + return true; + } + if (Array.isArray(value) || typeof value === 'string' || typeof value.splice === 'function') { + return !value.length; + } + + for (const key in value) { + if (Object.prototype.hasOwnProperty.call(value, key)) { + return false; + } + } + + return true; + }, + + /** + * Checks if `value` is `undefined`. + * + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * isUndefined(void 0) + * // => true + * + * isUndefined(null) + * // => false + */ + isUndefined: function (value) { + return value === undefined; + }, + + /** + * Checks if `func` is classified as a `Function` object. + * + * @param {*} func The value to check. + * @returns {boolean} Returns `true` if `func` is a function, else `false`. + * @example + * + * isFunction(self.isEmpty) + * // => true + * + * isFunction(/abc/) + * // => false + */ + isFunction: function (func) { + return typeof func === 'function'; + }, + + /** + * Converts the first character of `string` to upper case and the remaining + * to lower case. + * + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * capitalize('FRED') + * // => 'Fred' + * + * capitalize('john') + * // => 'John' + */ + + capitalize: function (string) { + return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); + }, + + /** + * Reduces `array` to a value which is the accumulated result of running + * each element in `array` thru `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not given, the first element of `array` is used as the initial + * value. The iteratee is invoked with four arguments: + * (accumulator, value, index|key, array). + * + * @param {Array} array The Array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @example + * + * reduce([1, 2], (sum, n) => sum + n, 0) + * // => 3 + * + */ + reduce: function (array, iteratee, accumulator) { + return array.reduce(iteratee, accumulator); + }, + + /** + * Iterates over elements of `array`, returning an array of all elements + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index, array). + * + * @param {Array} array The array to iterate over. + * @param {Function|object} predicate The function/object invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @example + * + * const users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ] + * + * filter(users, ({ active }) => active) + * // => object for ['barney'] + */ + filter: function (array, predicate) { + if (typeof predicate === 'function') { + return array.filter(predicate); + } + var key = Object.keys(predicate), + val = predicate[key], + res = []; + array.forEach(function (item) { + if (item[key] && item[key] === val) { + res.push(item); + } + }); + return res; + }, + + /** + * The opposite of `filter` this method returns the elements of `array` + * that `predicate` does **not** return truthy for. + * + * @param {Array} array collection to iterate over. + * @param {String} predicate The String that needs to have truthy value, invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @example + * + * const users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ] + * + * reject(users, 'active') + * // => object for ['fred'] + */ + reject: function (array, predicate) { + var res = []; + array.forEach((object) => { + if (!object[predicate]) { + res.push(object); + } + }); + return res; + }, + + /** + * Creates an array of values by running each element of `array` thru `iteratee`. + * The iteratee is invoked with three arguments: (value, index, array). + * + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + * @example + * + * function square(n) { + * return n * n + * } + * + * map([4, 8], square) + * // => [16, 64] + */ + map: function (array, iteratee) { + return array.map(iteratee); + }, + + /** + * Iterates over elements of `collection` and invokes `iteratee` for each element. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @example + * + * forEach([1, 2], value => console.log(value)) + * // => Logs `1` then `2`. + * + * forEach({ 'a': 1, 'b': 2 }, (value, key) => console.log(key)) + * // => Logs 'a' then 'b' + */ + + forEach: function (collection, iteratee) { + if (collection === null) { + return null; + } + + if (Array.isArray(collection)) { + return collection.forEach(iteratee); + } + const iterable = Object(collection), + props = Object.keys(collection); + var index = -1, + key, i; + + for (i = 0; i < props.length; i++) { + key = props[++index]; + iteratee(iterable[key], key, iterable); + } + return collection; + }, + + /** + * Checks if `value` is in `collection`. If `collection` is a string, it's + * checked for a substring of `value`, otherwise it checks if the `value` is present + * as a key in a `collection` object. + * + * @param {Array|Object|string} collection The collection to inspect. + * @param {*} value The value to search for. + * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes({ 'a': 1, 'b': 2 }, 1); + * // => true + * + * _.includes('abcd', 'bc'); + * // => true + */ + includes: function (collection, value) { + if (Array.isArray(collection) || typeof collection === 'string') { + return collection.includes(value); + } + for (var key in collection) { + if (collection.hasOwnProperty(key)) { + if (collection[key] === value) { + return true; + } + } + } + return false; + }, + + /** + * Gets the size of `collection` by returning its length for array and strings. + * For objects it returns the number of enumerable string keyed + * properties. + * + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * size([1, 2, 3]) + * // => 3 + * + * size({ 'a': 1, 'b': 2 }) + * // => 2 + * + * size('pebbles') + * // => 7 + */ + size: function (collection) { + // eslint-disable-next-line lodash/prefer-is-nil + if (collection === null || collection === undefined) { + return 0; + } + if (Array.isArray(collection) || typeof collection === 'string') { + return collection.length; + } + + return Object.keys(collection).length; + }, + + /** + * Converts all elements in `array` into a string separated by `separator`. + * + * @param {Array} array The array to convert. + * @param {string} [separator=','] The element separator. + * @returns {string} Returns the joined string. + * @example + * + * _.join(['a', 'b', 'c'], '~'); + * // => 'a~b~c' + */ + join: function (array, separator) { + if (array === null) { + return ''; + } + return array.join(separator); + }, + + /** + * Removes trailing whitespace or specified characters from `string`. + * + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @returns {string} Returns the trimmed string. + * @example + * + * trimEnd(' abc ') + * // => ' abc' + * + * trimEnd('-_-abc-_-', '_-') + * // => '-_-abc' + */ + trimEnd: function (string, chars) { + if (!string) { + return ''; + } + if (string && !chars) { + return string.replace(/\s*$/, ''); + } + chars += '$'; + return string.replace(new RegExp(chars, 'g'), ''); + }, + + /** + * Returns the index of the first + * element `predicate` returns truthy for. + * + * @param {Array} array The array to inspect. + * @param {Object} predicate The exact object to be searched for in the array. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * _.findIndex(users, {'active' : false}); + * // => 0 + * + */ + findIndex: function (array, predicate) { + var length = array === null ? 0 : array.length, + index = -1, + keys = Object.keys(predicate), + found, i; + if (!length) { + return -1; + } + for (i = 0; i < array.length; i++) { + found = true; + // eslint-disable-next-line no-loop-func + keys.forEach((key) => { + if (!(array[i][key] && array[i][key] === predicate[key])) { + found = false; + } + }); + if (found) { + index = i; + break; + } + } + return index; + }, + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @param {Object} object The object to query. + * @param {string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * const object = { a: {b : 'c'} } + * + * + * get(object, 'a.b.c', 'default') + * // => 'default' + * + * get(object, 'a.b', 'default') + * // => 'c' + */ + get: function (object, path, defaultValue) { + if (object === null) { + return undefined; + } + var arr = path.split('.'), + res = object, + i; + for (i = 0; i < arr.length; i++) { + res = res[arr[i]]; + if (res === undefined) { + return defaultValue; + } + } + return res; + }, + + /** + * Checks if `predicate` returns truthy for **all** elements of `array`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * every([true, 1, null, 'yes'], Boolean) + * // => false + */ + every: function (array, predicate) { + var index = -1, + length = array === null ? 0 : array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + +}; diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js new file mode 100644 index 000000000..650c315b5 --- /dev/null +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -0,0 +1,180 @@ +var _ = require('./lodash'), + + sanitize = require('./util').sanitize, + path = require('path'); + +/** + * parses body of request when type of the request body is formdata or urlencoded and + * returns code snippet for nodejs to add body + * + * @param {Array} dataArray - array containing body elements of request + * @param {String} indentString - string required for indentation + * @param {Boolean} trimBody - indicates whether to trim body or not + */ +function extractFormData (dataArray, indentString, trimBody) { + if (!dataArray) { + return ''; + } + var snippetString = _.reduce(dataArray, (accumalator, item) => { + if (item.disabled) { + return accumalator; + } + /* istanbul ignore next */ + if (item.type === 'file') { + /** + * creating snippet to send file in nodejs request + * for example: + * 'fieldname': { + * 'value': fs.createStream('filename.ext'), + * 'options': { + * 'filename': 'filename.ext', + * 'contentType: null + * } + * } + * } + */ + if (Array.isArray(item.src) && item.src.length) { + let fileSnippet = '', + fileArray = []; + _.forEach(item.src, (filePath) => { + fileArray.push(`${indentString.repeat(3)}fs.createReadStream('${sanitize(filePath, trimBody)}')`); + }); + if (fileArray.length) { + fileSnippet += `${indentString.repeat(2)}'${sanitize(item.key, trimBody)}': ` + + `[\n${fileArray.join(',\n')}\n${indentString.repeat(2)}]`; + accumalator.push(fileSnippet); + } + else { + return accumalator; + } + } + else if (typeof item.src !== 'string') { + accumalator.push([ + indentString.repeat(2) + `'${sanitize(item.key, trimBody)}': {`, + indentString.repeat(3) + '\'value\': fs.createReadStream(\'/path/to/file\'),', + indentString.repeat(3) + '\'options\': {', + indentString.repeat(4) + '\'filename\': \'filename\'', + indentString.repeat(4) + '\'contentType\': null', + indentString.repeat(3) + '}', + indentString.repeat(2) + '}' + ].join('\n')); + } + else { + var pathArray = item.src.split(path.sep), + fileName = pathArray[pathArray.length - 1]; + accumalator.push([ + indentString.repeat(2) + `'${sanitize(item.key, trimBody)}': {`, + indentString.repeat(3) + `'value': fs.createReadStream('${sanitize(item.src, trimBody)}'),`, + indentString.repeat(3) + '\'options\': {', + indentString.repeat(4) + `'filename': '${sanitize(fileName, trimBody)}',`, + indentString.repeat(4) + '\'contentType\': null', + indentString.repeat(3) + '}', + indentString.repeat(2) + '}' + ].join('\n')); + } + } + else { + accumalator.push( + indentString.repeat(2) + + `'${sanitize(item.key, trimBody)}': '${sanitize(item.value, trimBody)}'` + ); + } + return accumalator; + }, []); + return snippetString.join(',\n') + '\n'; +} + +/** + * Parses body object based on mode of body and returns code snippet + * + * @param {Object} requestbody - json object for body of request + * @param {String} indentString - string for indentation + * @param {Boolean} trimBody - indicates whether to trim body fields or not + * @param {String} contentType Content type of the body being sent + */ +function parseBody (requestbody, indentString, trimBody, contentType) { + if (requestbody) { + switch (requestbody.mode) { + case 'raw': + if (contentType === 'application/json') { + try { + let jsonBody = JSON.parse(requestbody[requestbody.mode]); + return `body: JSON.stringify(${JSON.stringify(jsonBody)})\n`; + } + catch (error) { + return `body: ${JSON.stringify(requestbody[requestbody.mode])}\n`; + } + } + return `body: ${JSON.stringify(requestbody[requestbody.mode])}\n`; + // eslint-disable-next-line no-case-declarations + case 'graphql': + let query = requestbody[requestbody.mode].query, + graphqlVariables; + try { + graphqlVariables = JSON.parse(requestbody[requestbody.mode].variables); + } + catch (e) { + graphqlVariables = {}; + } + return 'body: JSON.stringify({\n' + + `${indentString.repeat(2)}query: '${sanitize(query, trimBody)}',\n` + + `${indentString.repeat(2)}variables: ${JSON.stringify(graphqlVariables)}\n` + + `${indentString}})`; + case 'formdata': + return `formData: {\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + + indentString + '}'; + case 'urlencoded': + return `form: {\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + + indentString + '}'; + /* istanbul ignore next */ + case 'file': + // return 'formData: {\n' + + // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + + // indentString + '}'; + return 'body: ""\n'; + default: + return ''; + } + } + return ''; +} + +/** + * parses header of request object and returns code snippet of nodejs superagent to add header + * + * @param {Object} request - Postman SDK request object + * @param {String} indentString - indentation required in code snippet + * @returns {String} - code snippet of nodejs superagent to add header + */ +function parseHeader (request, indentString) { + var headerObject = request.getHeaders({enabled: true}), + headerSnippet = indentString + '\'headers\': {\n'; + + if (!_.isEmpty(headerObject)) { + headerSnippet += _.reduce(Object.keys(headerObject), function (accumalator, key) { + if (Array.isArray(headerObject[key])) { + var headerValues = []; + _.forEach(headerObject[key], (value) => { + headerValues.push(`'${sanitize(value)}'`); + }); + accumalator.push( + indentString.repeat(2) + `'${sanitize(key, true)}': [${headerValues.join(', ')}]` + ); + } + else { + accumalator.push( + indentString.repeat(2) + `'${sanitize(key, true)}': '${sanitize(headerObject[key])}'` + ); + } + return accumalator; + }, []).join(',\n') + '\n'; + } + + headerSnippet += indentString + '}'; + return headerSnippet; +} + +module.exports = { + parseBody: parseBody, + parseHeader: parseHeader +}; diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js new file mode 100644 index 000000000..c1a0a84c8 --- /dev/null +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -0,0 +1,190 @@ +var _ = require('./lodash'), + + parseRequest = require('./parseRequest'), + sanitize = require('./util').sanitize, + sanitizeOptions = require('./util').sanitizeOptions; + +/** + * returns snippet of nodejs(superagent) by parsing data from Postman-SDK request object + * + * @param {Object} request - Postman SDK request object + * @param {String} indentString - indentation required for code snippet + * @param {Object} options + * @returns {String} - nodejs(superagent) code snippet for given request object + */ +function makeSnippet (request, indentString, options) { + var snippet, + optionsArray = [], + isFormDataFile = false; + if (options.ES6_enabled) { + snippet = 'const '; + } + else { + snippet = 'var '; + } + snippet += 'superagent = require(\'superagent\');\n'; + if (request.body && request.body.mode === 'formdata') { + _.forEach(request.body.toJSON().formdata, function (data) { + if (!data.disabled && data.type === 'file') { + isFormDataFile = true; + } + }); + } + if (isFormDataFile) { + if (options.ES6_enabled) { + snippet += 'const '; + } + else { + snippet += 'var '; + } + snippet += 'fs = require(\'fs\');\n'; + } + if (options.ES6_enabled) { + snippet += 'let '; + } + else { + snippet += 'var '; + } + snippet += 'options = {\n'; + + /** + * creating string to represent options object using optionArray.join() + * example: + * options: { + * method: 'GET', + * url: 'www.google.com', + * timeout: 1000 + * } + */ + optionsArray.push(indentString + `'method': '${request.method}'`); + optionsArray.push(indentString + `'url': '${sanitize(request.url.toString())}'`); + if (request.body && !request.headers.has('Content-Type')) { + if (request.body.mode === 'file') { + request.addHeader({ + key: 'Content-Type', + value: 'text/plain' + }); + } + else if (request.body.mode === 'graphql') { + request.addHeader({ + key: 'Content-Type', + value: 'application/json' + }); + } + } + optionsArray.push(parseRequest.parseHeader(request, indentString)); + + if (request.body && request.body[request.body.mode]) { + optionsArray.push( + indentString + parseRequest.parseBody(request.body.toJSON(), indentString, options.trimRequestBody, + request.headers.get('Content-Type')) + ); + } + if (options.requestTimeout) { + optionsArray.push(indentString + `timeout: ${options.requestTimeout}`); + } + if (options.followRedirect === false) { + optionsArray.push(indentString + 'followRedirect: false'); + } + snippet += optionsArray.join(',\n') + '\n'; + snippet += '};\n'; + + snippet += 'superagent(options, '; + if (options.ES6_enabled) { + snippet += '(error, response) => {\n'; + } + else { + snippet += 'function (error, response) {\n'; + } + snippet += indentString + 'if (error) throw new Error(error);\n'; + snippet += indentString + 'console.log(response.body);\n'; + snippet += '});\n'; + return snippet; +} + +/** + * Used to get the options specific to this codegen + * + * @returns {Array} - Returns an array of option objects + */ +function getOptions () { + return [ + { + name: 'Set indentation count', + id: 'indentCount', + type: 'positiveInteger', + default: 2, + description: 'Set the number of indentation characters to add per code level' + }, + { + name: 'Set indentation type', + id: 'indentType', + type: 'enum', + availableOptions: ['Tab', 'Space'], + default: 'Space', + description: 'Select the character used to indent lines of code' + }, + { + name: 'Set request timeout', + id: 'requestTimeout', + type: 'positiveInteger', + default: 0, + description: 'Set number of milliseconds the request should wait for a response' + + ' before timing out (use 0 for infinity)' + }, + { + name: 'Follow redirects', + id: 'followRedirect', + type: 'boolean', + default: true, + description: 'Automatically follow HTTP redirects' + }, + { + name: 'Trim request body fields', + id: 'trimRequestBody', + type: 'boolean', + default: false, + description: 'Remove white space and additional lines that may affect the server\'s response' + }, + { + name: 'Enable ES6 features', + id: 'ES6_enabled', + type: 'boolean', + default: false, + description: 'Modifies code snippet to incorporate ES6 (EcmaScript) features' + } + ]; +} + +/** + * Converts Postman sdk request object to nodejs request code snippet + * + * @param {Object} request - postman-SDK request object + * @param {Object} options + * @param {String} options.indentType - type for indentation eg: Space, Tab + * @param {String} options.indentCount - number of spaces or tabs for indentation. + * @param {Boolean} options.followRedirect - whether to enable followredirect + * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not + * @param {Boolean} options.ES6_enabled - whether to generate snippet with ES6 features + * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out + * @param {Function} callback - callback function with parameters (error, snippet) + */ +function convert (request, options, callback) { + if (!_.isFunction(callback)) { + throw new Error('NodeJS-Request-Converter: callback is not valid function'); + } + options = sanitizeOptions(options, getOptions()); + + // String representing value of indentation required + var indentString; + + indentString = options.indentType === 'Tab' ? '\t' : ' '; + indentString = indentString.repeat(options.indentCount); + + return callback(null, makeSnippet(request, indentString, options)); +} + +module.exports = { + convert: convert, + getOptions: getOptions +}; diff --git a/codegens/nodejs-superagent/lib/util.js b/codegens/nodejs-superagent/lib/util.js new file mode 100644 index 000000000..e5e8b2a4b --- /dev/null +++ b/codegens/nodejs-superagent/lib/util.js @@ -0,0 +1,88 @@ + +/** + * sanitizes input string by handling escape characters eg: converts '''' to '\'\'' + * and trim input if required + * + * @param {String} inputString + * @param {Boolean} [trim] - indicates whether to trim string or not + * @returns {String} + */ +function sanitize (inputString, trim) { + if (typeof inputString !== 'string') { + return ''; + } + (trim) && (inputString = inputString.trim()); + return inputString.replace(/\\/g, '\\\\').replace(/'/g, '\\\'').replace(/\n/g, '\\n'); +} + +/** + * sanitizes input options + * + * @param {Object} options - Options provided by the user + * @param {Array} optionsArray - options array received from getOptions function + * + * @returns {Object} - Sanitized options object + */ +function sanitizeOptions (options, optionsArray) { + var result = {}, + defaultOptions = {}, + id; + optionsArray.forEach((option) => { + defaultOptions[option.id] = { + default: option.default, + type: option.type + }; + if (option.type === 'enum') { + defaultOptions[option.id].availableOptions = option.availableOptions; + } + }); + + for (id in options) { + if (options.hasOwnProperty(id)) { + if (defaultOptions[id] === undefined) { + continue; + } + switch (defaultOptions[id].type) { + case 'boolean': + if (typeof options[id] !== 'boolean') { + result[id] = defaultOptions[id].default; + } + else { + result[id] = options[id]; + } + break; + case 'positiveInteger': + if (typeof options[id] !== 'number' || options[id] < 0) { + result[id] = defaultOptions[id].default; + } + else { + result[id] = options[id]; + } + break; + case 'enum': + if (!defaultOptions[id].availableOptions.includes(options[id])) { + result[id] = defaultOptions[id].default; + } + else { + result[id] = options[id]; + } + break; + default: + result[id] = options[id]; + } + } + } + + for (id in defaultOptions) { + if (defaultOptions.hasOwnProperty(id)) { + if (result[id] === undefined) { + result[id] = defaultOptions[id].default; + } + } + } + return result; +} +module.exports = { + sanitize: sanitize, + sanitizeOptions: sanitizeOptions +}; diff --git a/codegens/nodejs-superagent/npm-shrinkwrap.json b/codegens/nodejs-superagent/npm-shrinkwrap.json new file mode 100644 index 000000000..366e33607 --- /dev/null +++ b/codegens/nodejs-superagent/npm-shrinkwrap.json @@ -0,0 +1,440 @@ +{ + "name": "@postman/codegen-nodejs-superagent", + "version": "0.1.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.x.x" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cryptiles": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.4.tgz", + "integrity": "sha512-8I1sgZHfVwcSOY6mSGpVU3lw/GSIZvusg8dD2+OGehCJpOhQRLNcH0qb9upQnOH4XhgxxFJSg6E2kx95deb1Tw==", + "dev": true, + "requires": { + "boom": "5.x.x" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.x.x" + } + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "^5.1.0", + "har-schema": "^2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.x.x", + "cryptiles": "3.x.x", + "hoek": "4.x.x", + "sntp": "2.x.x" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "hawk": "~6.0.2", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "stringstream": "~0.0.5", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, + "requires": { + "hoek": "4.x.x" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "dev": true + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + } + } +} diff --git a/codegens/nodejs-superagent/npm/test-lint.js b/codegens/nodejs-superagent/npm/test-lint.js new file mode 100644 index 000000000..b113b8bfd --- /dev/null +++ b/codegens/nodejs-superagent/npm/test-lint.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node +var shell = require('shelljs'), + chalk = require('chalk'), + async = require('async'), + ESLintCLIEngine = require('eslint').CLIEngine, + + /** + * The list of source code files / directories to be linted. + * + * @type {Array} + */ + LINT_SOURCE_DIRS = [ + './lib', + './bin', + './test', + './examples/*.js', + './npm/*.js', + './index.js' + ]; + +module.exports = function (exit) { + // banner line + console.info(chalk.yellow.bold('\nLinting files using eslint...')); + + async.waterfall([ + + /** + * Instantiates an ESLint CLI engine and runs it in the scope defined within LINT_SOURCE_DIRS. + * + * @param {Function} next - The callback function whose invocation marks the end of the lint test run. + * @returns {*} + */ + function (next) { + next(null, (new ESLintCLIEngine()).executeOnFiles(LINT_SOURCE_DIRS)); + }, + + /** + * Processes a test report from the Lint test runner, and displays meaningful results. + * + * @param {Object} report - The overall test report for the current lint test. + * @param {Object} report.results - The set of test results for the current lint run. + * @param {Function} next - The callback whose invocation marks the completion of the post run tasks. + * @returns {*} + */ + function (report, next) { + var errorReport = ESLintCLIEngine.getErrorResults(report.results); + // log the result to CLI + console.info(ESLintCLIEngine.getFormatter()(report.results)); + // log the success of the parser if it has no errors + (errorReport && !errorReport.length) && console.info(chalk.green('eslint ok!')); + // ensure that the exit code is non zero in case there was an error + next(Number(errorReport && errorReport.length) || 0); + } + ], exit); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(shell.exit); diff --git a/codegens/nodejs-superagent/npm/test-newman.js b/codegens/nodejs-superagent/npm/test-newman.js new file mode 100644 index 000000000..ae7d2afe1 --- /dev/null +++ b/codegens/nodejs-superagent/npm/test-newman.js @@ -0,0 +1,59 @@ +#!/usr/bin/env node +/* eslint-env node, es6 */ +// --------------------------------------------------------------------------------------------------------------------- +// This script is intended to execute all newman tests. +// --------------------------------------------------------------------------------------------------------------------- + +var shell = require('shelljs'), + + // set directories and files for test and coverage report + path = require('path'), + + NYC = require('nyc'), + chalk = require('chalk'), + recursive = require('recursive-readdir'), + + COV_REPORT_PATH = '.coverage', + SPEC_SOURCE_DIR = path.join(__dirname, '..', 'test', 'newman'); + +module.exports = function (exit) { + // banner line + console.info(chalk.yellow.bold('Running newman tests using mocha on node...')); + + shell.test('-d', COV_REPORT_PATH) && shell.rm('-rf', COV_REPORT_PATH); + shell.mkdir('-p', COV_REPORT_PATH); + + var Mocha = require('mocha'), + nyc = new NYC({ + reportDir: COV_REPORT_PATH, + tempDirectory: COV_REPORT_PATH, + reporter: ['text', 'lcov', 'text-summary'], + exclude: ['config', 'test'], + hookRunInContext: true, + hookRunInThisContext: true + }); + + nyc.wrap(); + // add all spec files to mocha + recursive(SPEC_SOURCE_DIR, function (err, files) { + if (err) { console.error(err); return exit(1); } + + var mocha = new Mocha({ timeout: 1000 * 60 }); + + files.filter(function (file) { // extract all test files + return (file.substr(-8) === '.test.js'); + }).forEach(mocha.addFile.bind(mocha)); + + mocha.run(function (runError) { + runError && console.error(runError.stack || runError); + + nyc.reset(); + nyc.writeCoverageFile(); + nyc.report(); + exit(runError ? 1 : 0); + }); + }); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(shell.exit); diff --git a/codegens/nodejs-superagent/npm/test-unit.js b/codegens/nodejs-superagent/npm/test-unit.js new file mode 100755 index 000000000..0de7fd529 --- /dev/null +++ b/codegens/nodejs-superagent/npm/test-unit.js @@ -0,0 +1,59 @@ +#!/usr/bin/env node +/* eslint-env node, es6 */ +// --------------------------------------------------------------------------------------------------------------------- +// This script is intended to execute all unit tests. +// --------------------------------------------------------------------------------------------------------------------- + +var shell = require('shelljs'), + + // set directories and files for test and coverage report + path = require('path'), + + NYC = require('nyc'), + chalk = require('chalk'), + recursive = require('recursive-readdir'), + + COV_REPORT_PATH = '.coverage', + SPEC_SOURCE_DIR = path.join(__dirname, '..', 'test', 'unit'); + +module.exports = function (exit) { + // banner line + console.info(chalk.yellow.bold('Running unit tests using mocha on node...')); + + shell.test('-d', COV_REPORT_PATH) && shell.rm('-rf', COV_REPORT_PATH); + shell.mkdir('-p', COV_REPORT_PATH); + + var Mocha = require('mocha'), + nyc = new NYC({ + reportDir: COV_REPORT_PATH, + tempDirectory: COV_REPORT_PATH, + reporter: ['text', 'lcov', 'text-summary'], + exclude: ['config', 'test'], + hookRunInContext: true, + hookRunInThisContext: true + }); + + nyc.wrap(); + // add all spec files to mocha + recursive(SPEC_SOURCE_DIR, function (err, files) { + if (err) { console.error(err); return exit(1); } + + var mocha = new Mocha({ timeout: 1000 * 60 }); + + files.filter(function (file) { // extract all test files + return (file.substr(-8) === '.test.js'); + }).forEach(mocha.addFile.bind(mocha)); + + mocha.run(function (runError) { + runError && console.error(runError.stack || runError); + + nyc.reset(); + nyc.writeCoverageFile(); + nyc.report(); + exit(runError ? 1 : 0); + }); + }); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(shell.exit); diff --git a/codegens/nodejs-superagent/npm/test.js b/codegens/nodejs-superagent/npm/test.js new file mode 100755 index 000000000..da2816f09 --- /dev/null +++ b/codegens/nodejs-superagent/npm/test.js @@ -0,0 +1,18 @@ +#!/usr/bin/env node +var chalk = require('chalk'), + exit = require('shelljs').exit, + prettyms = require('pretty-ms'), + startedAt = Date.now(), + name = require('../package.json').name; + +require('async').series([ + require('./test-lint'), + require('./test-newman'), + require('./test-unit') + // require('./test-browser') + // require('./test-integration') +], function (code) { + // eslint-disable-next-line max-len + console.info(chalk[code ? 'red' : 'green'](`\n${name}: duration ${prettyms(Date.now() - startedAt)}\n${name}: ${code ? 'not ok' : 'ok'}!`)); + exit(code && (typeof code === 'number' ? code : 1) || 0); +}); diff --git a/codegens/nodejs-superagent/package.json b/codegens/nodejs-superagent/package.json new file mode 100644 index 000000000..8f4e314a7 --- /dev/null +++ b/codegens/nodejs-superagent/package.json @@ -0,0 +1,36 @@ +{ + "name": "@postman/codegen-nodejs-superagent", + "version": "0.1.2", + "description": "Converts Postman-SDK Request into code snippet for NodeJS(SuperAgent)", + "com_postman_plugin": { + "type": "code_generator", + "lang": "nodejs", + "variant": "SuperAgent", + "syntax_mode": "javascript" + }, + "main": "index.js", + "directories": { + "lib": "lib", + "test": "test" + }, + "scripts": { + "test": "node npm/test.js", + "test-lint": "node npm/test-lint.js", + "test-newman": "node npm/test-newman.js", + "test-unit": "node npm/test-unit.js" + }, + "repository": { + "type": "git", + "url": "" + }, + "author": "Postman Labs ", + "license": "Apache-2.0", + "homepage": "https://github.com/postmanlabs/code-generators/tree/master/codegens/nodejs-superagent", + "dependencies": {}, + "devDependencies": { + "superagent": "5.2.2" + }, + "engines": { + "node": ">=8" + } +} diff --git a/codegens/nodejs-superagent/test/.eslintrc b/codegens/nodejs-superagent/test/.eslintrc new file mode 100644 index 000000000..9d477e31e --- /dev/null +++ b/codegens/nodejs-superagent/test/.eslintrc @@ -0,0 +1,30 @@ +{ + "plugins": [ + "mocha" + ], + "env": { + "mocha": true, + "node": true, + "es6": true + }, + "rules": { + // Mocha + "mocha/handle-done-callback": "error", + "mocha/max-top-level-suites": "error", + "mocha/no-exclusive-tests": "error", + "mocha/no-global-tests": "error", + "mocha/no-hooks-for-single-case": "off", + "mocha/no-hooks": "off", + "mocha/no-identical-title": "error", + "mocha/no-mocha-arrows": "error", + "mocha/no-nested-tests": "error", + "mocha/no-pending-tests": "error", + "mocha/no-return-and-callback": "error", + "mocha/no-sibling-hooks": "error", + "mocha/no-skipped-tests": "warn", + "mocha/no-synchronous-tests": "off", + "mocha/no-top-level-hooks": "warn", + "mocha/valid-test-description": "off", + "mocha/valid-suite-description": "off" + } +} diff --git a/codegens/nodejs-superagent/test/newman/newman.test.js b/codegens/nodejs-superagent/test/newman/newman.test.js new file mode 100644 index 000000000..faa8cac1a --- /dev/null +++ b/codegens/nodejs-superagent/test/newman/newman.test.js @@ -0,0 +1,27 @@ +var runNewmanTest = require('../../../../test/codegen/newman/newmanTestUtil').runNewmanTest, + convert = require('../../lib/index').convert; + +describe('Convert for different types of request', function () { + var options = {indentCount: 2, indentType: 'Space'}, + testConfig = { + compileScript: null, + runScript: 'node run.js', + fileName: 'run.js', + headerSnippet: '/* eslint-disable */\n' + }; + + runNewmanTest(convert, options, testConfig); + + describe('Convert for request incorporating ES6 features', function () { + var options = {indentCount: 2, indentType: 'Space', ES6_enabled: true}, + testConfig = { + compileScript: null, + runScript: 'node run.js', + fileName: 'run.js', + headerSnippet: '/* eslint-disable */\n' + }; + + runNewmanTest(convert, options, testConfig); + }); + +}); diff --git a/codegens/nodejs-superagent/test/unit/.gitkeep b/codegens/nodejs-superagent/test/unit/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/codegens/nodejs-superagent/test/unit/fixtures/testcollection/collection.json b/codegens/nodejs-superagent/test/unit/fixtures/testcollection/collection.json new file mode 100644 index 000000000..186aa9ce5 --- /dev/null +++ b/codegens/nodejs-superagent/test/unit/fixtures/testcollection/collection.json @@ -0,0 +1,1349 @@ +{ + "info": { + "name": "Code-Gen Test Cases", + "_postman_id": "41182fad-912e-6bc9-d6b9-dfb6f5bf5ffb", + "description": "This collection contains requests that will be used to test validity of plugin created to convert postman request into code snippet of particular language.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Request Headers with disabled headers", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "try {", + " tests[\"Body contains headers\"] = responseBody.has(\"headers\");", + " responseJSON = JSON.parse(responseBody);", + " tests[\"Header contains host\"] = \"host\" in responseJSON.headers;", + " tests[\"Header contains test parameter sent as part of request header\"] = \"my-sample-header\" in responseJSON.headers;", + "}", + "catch (e) { }", + "", + "", + "", + "" + ] + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "my-sample-header", + "value": "Lorem ipsum dolor sit amet" + }, + { + "key": "not-disabled-header", + "value": "ENABLED" + }, + { + "key": "disabled header", + "value": "DISABLED", + "disabled": true + } + ], + "body": {}, + "url": { + "raw": "https://postman-echo.com/headers", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "headers" + ] + }, + "description": "A `GET` request to this endpoint returns the list of all request headers as part of the response JSON.\nIn Postman, sending your own set of headers through the [Headers tab](https://www.getpostman.com/docs/requests#headers?source=echo-collection-app-onboarding) will reveal the headers as part of the response." + }, + "response": [] + }, + { + "name": "GET Request with disabled query", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "tests['response json contains headers'] = _.has(responseJSON, 'headers');", + "tests['response json contains args'] = _.has(responseJSON, 'args');", + "tests['response json contains url'] = _.has(responseJSON, 'url');", + "", + "tests['args key contains argument passed as url parameter'] = ('test' in responseJSON.args);", + "tests['args passed via request url params has value \"123\"'] = (_.get(responseJSON, 'args.test') === \"123\");" + ] + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": {}, + "url": { + "raw": "https://postman-echo.com/get?test=123&anotherone=232", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "get" + ], + "query": [ + { + "key": "test", + "value": "123", + "equals": true + }, + { + "key": "anotherone", + "value": "232", + "equals": true + }, + { + "key": "anotheroneone", + "value": "sdfsdf", + "equals": true, + "disabled": true + } + ] + }, + "description": "The HTTP `GET` request method is meant to retrieve data from a server. The data\nis identified by a unique URI (Uniform Resource Identifier). \n\nA `GET` request can pass parameters to the server using \"Query String \nParameters\". For example, in the following request,\n\n> http://example.com/hi/there?hand=wave\n\nThe parameter \"hand\" has the value \"wave\".\n\nThis endpoint echoes the HTTP headers, request parameters and the complete\nURI requested." + }, + "response": [] + }, + { + "name": "POST Raw Text", + "event": [ + { + "listen": "test", + "script": { + "id": "753f8a33-adb6-402f-8d19-386c1981ecb6", + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "\"'Duis posuere augue vel cursus pharetra. In luctus a ex nec pretium. Praesent neque quam, tincidunt nec leo eget, rutrum vehicula magna.\nMaecenas consequat elementum elit, \"id\" \"se\\\"mper\" sem tristique et. Integer pulvinar enim quis consectetur interdum volutpat.'\"" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST form data with file", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "disabled": true + }, + { + "key": "content-type", + "value": "application/json", + "disabled": true + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "fdjks", + "value": "dsf", + "type": "text" + }, + { + "key": "sdf", + "value": "helo", + "type": "text" + }, + { + "key": "12", + "value": "\"23\"", + "description": "", + "type": "text" + }, + { + "key": "'123'", + "value": "'\"23\\\"4\\\"\"'", + "description": "", + "type": "text" + }, + { + "key": "", + "value": "", + "description": "", + "type": "text", + "disabled": true + } + ] + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST urlencoded data with disabled entries", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded" + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "1", + "value": "a", + "description": "", + "type": "text" + }, + { + "key": "2", + "value": "b", + "description": "", + "type": "text" + }, + { + "key": "\"\"12\"\"", + "value": "\"23\"", + "description": "", + "type": "text" + }, + { + "key": "'1\"2\\\"\"3'", + "value": "'1\"23\"4'", + "description": "", + "type": "text" + } + ] + }, + "url": { + "raw": "https://postman-echo.com/post/?hardik=\"me\"", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post", + "" + ], + "query": [ + { + "key": "hardik", + "value": "\"me\"", + "equals": true + } + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST json with raw", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"json\": \"Test-Test\"\n}" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [ + { + "id": "a331f873-b13f-459f-82f4-506d65e41bef", + "name": "POST json with raw", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"json\": \"Test-Test\"\n}" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "", + "name": "Access-Control-Allow-Credentials", + "description": "Indicates whether or not the response to the request can be exposed when the credentials flag is true. When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials." + }, + { + "key": "Access-Control-Allow-Headers", + "value": "", + "name": "Access-Control-Allow-Headers", + "description": "Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request." + }, + { + "key": "Access-Control-Allow-Methods", + "value": "", + "name": "Access-Control-Allow-Methods", + "description": "Specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request." + }, + { + "key": "Access-Control-Allow-Origin", + "value": "", + "name": "Access-Control-Allow-Origin", + "description": "Specifies a URI that may access the resource. For requests without credentials, the server may specify '*' as a wildcard, thereby allowing any origin to access the resource." + }, + { + "key": "Access-Control-Expose-Headers", + "value": "", + "name": "Access-Control-Expose-Headers", + "description": "Lets a server whitelist headers that browsers are allowed to access." + }, + { + "key": "Connection", + "value": "keep-alive", + "name": "Connection", + "description": "Options that are desired for the connection" + }, + { + "key": "Content-Encoding", + "value": "gzip", + "name": "Content-Encoding", + "description": "The type of encoding used on the data." + }, + { + "key": "Content-Length", + "value": "385", + "name": "Content-Length", + "description": "The length of the response body in octets (8-bit bytes)" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8", + "name": "Content-Type", + "description": "The mime type of this content" + }, + { + "key": "Date", + "value": "Wed, 07 Feb 2018 10:06:15 GMT", + "name": "Date", + "description": "The date and time that the message was sent" + }, + { + "key": "ETag", + "value": "W/\"215-u7EU1nFtauIn0/aVifjuXA\"", + "name": "ETag", + "description": "An identifier for a specific version of a resource, often a message digest" + }, + { + "key": "Server", + "value": "nginx", + "name": "Server", + "description": "A name for the server" + }, + { + "key": "Vary", + "value": "X-HTTP-Method-Override, Accept-Encoding", + "name": "Vary", + "description": "Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather than requesting a fresh one from the origin server." + }, + { + "key": "set-cookie", + "value": "sails.sid=s%3AxRBxgrc9M-jKK_l1mX3y3rM_ry8wYLz4.Of4qpOzd9hi6uO0sAQIj%2Bxs2VeppWxYjJa4OpIW3PKg; Path=/; HttpOnly", + "name": "set-cookie", + "description": "an HTTP cookie" + } + ], + "cookie": [ + { + "expires": "Tue Jan 19 2038 08:44:07 GMT+0530 (IST)", + "httpOnly": true, + "domain": "postman-echo.com", + "path": "/", + "secure": false, + "value": "s%3AxRBxgrc9M-jKK_l1mX3y3rM_ry8wYLz4.Of4qpOzd9hi6uO0sAQIj%2Bxs2VeppWxYjJa4OpIW3PKg", + "key": "sails.sid" + } + ], + "body": "{\"args\":{},\"data\":\"{\\n \\\"json\\\": \\\"Test-Test\\\"\\n}\",\"files\":{},\"form\":{},\"headers\":{\"host\":\"postman-echo.com\",\"content-length\":\"25\",\"accept\":\"*/*\",\"accept-encoding\":\"gzip, deflate\",\"cache-control\":\"no-cache\",\"content-type\":\"text/plain\",\"cookie\":\"sails.sid=s%3AkOgtF1XmXtVFx-Eg3S7-37BKKaMqMDPe.hnwldNwyvsaASUiRR0Y0vcowadkMXO4HMegTeVIPgqo\",\"postman-token\":\"2ced782f-a141-428e-8af6-04ce954a77d5\",\"user-agent\":\"PostmanRuntime/7.1.1\",\"x-forwarded-port\":\"443\",\"x-forwarded-proto\":\"https\"},\"json\":null,\"url\":\"https://postman-echo.com/post\"}" + } + ] + }, + { + "name": "POST javascript with raw", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/javascript" + } + ], + "body": { + "mode": "raw", + "raw": "var val = 6;\nconsole.log(val);" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST text/xml with raw", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "text/xml" + } + ], + "body": { + "mode": "raw", + "raw": "\n Test Test\n" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "POST text/html with raw", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "text/html" + } + ], + "body": { + "mode": "raw", + "raw": "\n Test Test\n" + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "Resolve URL", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded" + } + ], + "body": { + "mode": "raw", + "raw": "Duis posuere augue vel cursus pharetra. In luctus a ex nec pretium. Praesent neque quam, tincidunt nec leo eget, rutrum vehicula magna.\nMaecenas consequat elementum elit, id semper sem tristique et. Integer pulvinar enim quis consectetur interdum volutpat." + }, + "url": { + "raw": "https://postman-echo.com/:action", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":action" + ], + "variable": [ + { + "key": "action", + "value": "post" + } + ] + }, + "description": null + }, + "response": [] + }, + { + "name": "PUT Request", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has PUT data'] = _.has(responseJSON, 'data');", + "tests['response matches the data sent in request'] = (responseJSON.data && responseJSON.data.length === 256);" + ] + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "Etiam mi lacus, cursus vitae felis et, blandit pellentesque neque. Vestibulum eget nisi a tortor commodo dignissim.\nQuisque ipsum ligula, faucibus a felis a, commodo elementum nisl. Mauris vulputate sapien et tincidunt viverra. Donec vitae velit nec metus." + }, + "url": { + "raw": "https://postman-echo.com/put", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "put" + ] + }, + "description": "The HTTP `PUT` request method is similar to HTTP `POST`. It too is meant to \ntransfer data to a server (and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `PUT` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following \nraw HTTP request,\n\n> PUT /hi/there?hand=wave\n>\n> \n\n\n" + }, + "response": [] + }, + { + "name": "PATCH Request", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has PUT data'] = _.has(responseJSON, 'data');", + "tests['response matches the data sent in request'] = (responseJSON.data && responseJSON.data.length === 256);" + ] + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "Curabitur auctor, elit nec pulvinar porttitor, ex augue condimentum enim, eget suscipit urna felis quis neque.\nSuspendisse sit amet luctus massa, nec venenatis mi. Suspendisse tincidunt massa at nibh efficitur fringilla. Nam quis congue mi. Etiam volutpat." + }, + "url": { + "raw": "https://postman-echo.com/patch", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "patch" + ] + }, + "description": "The HTTP `PATCH` method is used to update resources on a server. The exact\nuse of `PATCH` requests depends on the server in question. There are a number\nof server implementations which handle `PATCH` differently. Technically, \n`PATCH` supports both Query String parameters and a Request Body.\n\nThis endpoint accepts an HTTP `PATCH` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body." + }, + "response": [] + }, + { + "name": "DELETE Request", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has PUT data'] = _.has(responseJSON, 'data');", + "tests['response matches the data sent in request'] = (responseJSON.data && responseJSON.data.length === 256);" + ] + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded" + }, + { + "key": "Content-Length", + "value": "1000", + "disabled": true + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "dsfs", + "value": "sfdds", + "description": "", + "type": "text" + }, + { + "key": "sfdsdf", + "value": "sdf", + "description": "", + "type": "text" + } + ] + }, + "url": { + "raw": "https://postman-echo.com/delete", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "delete" + ] + }, + "description": "The HTTP `DELETE` method is used to delete resources on a server. The exact\nuse of `DELETE` requests depends on the server implementation. In general, \n`DELETE` requests support both, Query String parameters as well as a Request \nBody.\n\nThis endpoint accepts an HTTP `DELETE` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body." + }, + "response": [] + }, + { + "name": "OPTIONS to postman echo", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON;", + "", + "try { ", + " responseJSON = JSON.parse(responseBody); ", + " tests['response is valid JSON'] = true;", + "}", + "catch (e) { ", + " responseJSON = {}; ", + " tests['response is valid JSON'] = false;", + "}", + "", + "", + "tests['response has post data'] = _.has(responseJSON, 'data');", + "tests['response matches the data posted'] = (responseJSON.data && responseJSON.data.length === 256);", + "", + "tests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');" + ] + } + } + ], + "request": { + "method": "OPTIONS", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded" + } + ], + "body": {}, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + }, + "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." + }, + "response": [] + }, + { + "name": "HEAD request", + "request": { + "method": "HEAD", + "header": [ + { + "key": "hello", + "value": "helloagain", + "disabled": true + } + ], + "body": {}, + "url": { + "raw": "https://bf1621bb-f962-46b8-bf28-459e03b513ff.mock.pstmn.io/head", + "protocol": "https", + "host": [ + "bf1621bb-f962-46b8-bf28-459e03b513ff", + "mock", + "pstmn", + "io" + ], + "path": [ + "head" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "LINK request", + "request": { + "method": "LINK", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "UNLINK request", + "request": { + "method": "UNLINK", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "LOCK request", + "request": { + "method": "LOCK", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "UNLOCK request", + "request": { + "method": "UNLOCK", + "header": [], + "body": {}, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "PROPFIND request", + "request": { + "method": "PROPFIND", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "VIEW request", + "request": { + "method": "VIEW", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "https://mockbin.org/request", + "protocol": "https", + "host": [ + "mockbin", + "org" + ], + "path": [ + "request" + ] + }, + "description": "" + }, + "response": [] + }, + { + "name": "PURGE Request", + "request": { + "method": "PURGE", + "header": [], + "body": {}, + "url": { + "raw": "https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io", + "protocol": "https", + "host": [ + "9c76407d-5b8d-4b22-99fb-8c47a85d9848", + "mock", + "pstmn", + "io" + ] + }, + "description": null + }, + "response": [ + { + "id": "95c11e09-9abe-4b26-a6b0-bc7f40dded08", + "name": "PURGE Request", + "originalRequest": { + "method": "PURGE", + "header": [], + "body": {}, + "url": { + "raw": "https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io", + "protocol": "https", + "host": [ + "9c76407d-5b8d-4b22-99fb-8c47a85d9848", + "mock", + "pstmn", + "io" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "", + "name": "Access-Control-Allow-Credentials", + "description": "" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "", + "name": "Access-Control-Allow-Headers", + "description": "" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "", + "name": "Access-Control-Allow-Methods", + "description": "" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*", + "name": "Access-Control-Allow-Origin", + "description": "" + }, + { + "key": "Access-Control-Expose-Headers", + "value": "", + "name": "Access-Control-Expose-Headers", + "description": "" + }, + { + "key": "Connection", + "value": "keep-alive", + "name": "Connection", + "description": "" + }, + { + "key": "Content-Encoding", + "value": "gzip", + "name": "Content-Encoding", + "description": "" + }, + { + "key": "Content-Length", + "value": "152", + "name": "Content-Length", + "description": "" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8", + "name": "Content-Type", + "description": "" + }, + { + "key": "Date", + "value": "Tue, 13 Feb 2018 13:58:56 GMT", + "name": "Date", + "description": "" + }, + { + "key": "ETag", + "value": "W/\"a7-kIxN5L9H0YwilUQPUUio9A\"", + "name": "ETag", + "description": "" + }, + { + "key": "Server", + "value": "nginx", + "name": "Server", + "description": "" + }, + { + "key": "Vary", + "value": "Accept-Encoding", + "name": "Vary", + "description": "" + } + ], + "cookie": [], + "responseTime": "375", + "body": "{\n \"args\": {},\n \"data\": \"Curabitur auctor, elit nec pulvinar porttitor, ex augue condimentum enim, eget suscipit urna felis quis neque.\\nSuspendisse sit amet luctus massa, nec venenatis mi. Suspendisse tincidunt massa at nibh efficitur fringilla. Nam quis congue mi. Etiam volutpat.\",\n \"files\": {},\n \"form\": {},\n \"headers\": {\n \"host\": \"postman-echo.com\",\n \"content-length\": \"256\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate\",\n \"content-type\": \"text/plain\",\n \"cookie\": \"sails.sid=s%3A1wOi4AdoZEbqBjGi6oSUC5Vlfje8wJvs.DHQfRLXfIBvZ%2Bv0KhLAThMDz%2FXvxh9gyxWYa0u1EZOU\",\n \"user-agent\": \"PostmanRuntime/7.1.1\",\n \"x-forwarded-port\": \"443\",\n \"x-forwarded-proto\": \"https\"\n },\n \"json\": null,\n \"url\": \"https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io\"\n}" + } + ] + }, + { + "name": "COPY Request", + "request": { + "method": "COPY", + "header": [], + "body": {}, + "url": { + "raw": "https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io", + "protocol": "https", + "host": [ + "9c76407d-5b8d-4b22-99fb-8c47a85d9848", + "mock", + "pstmn", + "io" + ] + } + }, + "response": [ + { + "id": "b8517e1f-3aad-4c0e-bc2d-fb8d834adba7", + "name": "COPY Request", + "originalRequest": { + "method": "COPY", + "header": [], + "body": {}, + "url": { + "raw": "https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io", + "protocol": "https", + "host": [ + "9c76407d-5b8d-4b22-99fb-8c47a85d9848", + "mock", + "pstmn", + "io" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [], + "cookie": [], + "responseTime": "0", + "body": "{\n \"args\": {},\n \"data\": \"Curabitur auctor, elit nec pulvinar porttitor, ex augue condimentum enim, eget suscipit urna felis quis neque.\\nSuspendisse sit amet luctus massa, nec venenatis mi. Suspendisse tincidunt massa at nibh efficitur fringilla. Nam quis congue mi. Etiam volutpat.\",\n \"files\": {},\n \"form\": {},\n \"headers\": {\n \"host\": \"postman-echo.com\",\n \"content-length\": \"256\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate\",\n \"content-type\": \"text/plain\",\n \"cookie\": \"sails.sid=s%3A1wOi4AdoZEbqBjGi6oSUC5Vlfje8wJvs.DHQfRLXfIBvZ%2Bv0KhLAThMDz%2FXvxh9gyxWYa0u1EZOU\",\n \"user-agent\": \"PostmanRuntime/7.1.1\",\n \"x-forwarded-port\": \"443\",\n \"x-forwarded-proto\": \"https\"\n },\n \"json\": null,\n \"url\": \"https://9c76407d-5b8d-4b22-99fb-8c47a85d9848.mock.pstmn.io\"\n}" + } + ] + } + ] +} \ No newline at end of file diff --git a/codegens/nodejs-superagent/test/unit/snippet.test.js b/codegens/nodejs-superagent/test/unit/snippet.test.js new file mode 100644 index 000000000..e1a228684 --- /dev/null +++ b/codegens/nodejs-superagent/test/unit/snippet.test.js @@ -0,0 +1,416 @@ +// TODO +var expect = require('chai').expect, + sdk = require('postman-collection'), + sanitize = require('../../lib/util').sanitize, + parseBody = require('../../lib/parseRequest').parseBody, + getOptions = require('../../lib/index').getOptions, + convert = require('../../lib/index').convert, + mainCollection = require('./fixtures/testcollection/collection.json'); + +describe('nodejs-superagent convert function', function () { + describe('Convert function', function () { + var request, + reqObject, + options = {}, + snippetArray, + line_no; + + it('should return a Tab indented snippet ', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + indentType: 'Tab', + indentCount: 1 + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + snippetArray = snippet.split('\n'); + for (var i = 0; i < snippetArray.length; i++) { + if (snippetArray[i] === 'var options = {') { line_no = i + 1; } + } + expect(snippetArray[line_no].charAt(0)).to.equal('\t'); + }); + }); + + it('should return snippet with timeout property when timeout is set to non zero', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + requestTimeout: 1000 + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + expect(snippet).to.include('timeout: 1000'); + }); + }); + + it('should return snippet with ES6 features when ES6_enabled is set to true', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + ES6_enabled: true + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + snippetArray = snippet.split('\n'); + expect(snippetArray[0]).to.equal('const request = require(\'request\');'); + expect(snippetArray).to.include('let options = {'); + expect(snippetArray).to.include('request(options, (error, response) => {'); + }); + }); + + it('should return snippet with followRedirect property set to ' + + 'false for no follow redirect', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + followRedirect: false + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + expect(snippet).to.include('followRedirect: false'); + }); + }); + + it('should return valid code snippet for no headers and no body', function () { + reqObject = { + 'description': 'This is a sample POST request without headers and body', + 'url': 'https://echo.getpostman.com/post', + 'method': 'POST' + }; + request = new sdk.Request(reqObject); + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('\'headers\': {\n }'); + }); + }); + + it('should not fail for a random body mode', function () { + request = new sdk.Request(mainCollection.item[2].request); + request.body.mode = 'random'; + request.body[request.body.mode] = {}; + + convert(request, options, function (error, snippet) { + + if (error) { + expect.fail(null, null, error); + return; + } + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('body:'); + }); + }); + + it('should generate snippet for file body mode', function () { + request = new sdk.Request({ + 'url': 'https://echo.getpostman.com/post', + 'method': 'POST', + 'body': { + 'mode': 'file', + 'file': [ + { + 'key': 'fileName', + 'src': 'file', + 'type': 'file' + } + ] + } + }); + options = { indentType: 'Space', indentCount: 2 }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.not.equal(''); + }); + }); + + it('should return snippet with proper semicolon placed where required', function () { + // testing for the below snippet + /* + var request = require('request'); + var fs = require('fs'); + var options = { + 'method': 'GET', + 'url': 'https://postman-echo.com/headers', + 'headers': { + 'my-sample-header': 'Lorem ipsum dolor sit amet', + 'not-disabled-header': 'ENABLED' + } + }; + request(options, function (error, response) { + if (error) throw new Error(error); + console.log(response.body); + }); */ + request = new sdk.Request(mainCollection.item[0].request); + options = {}; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + var snippetArray = snippet.split('\n'); + snippetArray.forEach(function (line, index) { + if (line.charAt(line.length - 2) === ')') { + expect(line.charAt(line.length - 1)).to.equal(';'); + } + expect(line.charAt(line.length - 1)).to.not.equal(')'); + // check for the closing curly bracket of options object + if (line.startsWith('request')) { + var previousLine = snippetArray[index - 1]; + expect(previousLine.charAt(previousLine.length - 1)).to.equal(';'); + } + }); + }); + }); + + it('should return snippet with no trailing comma when requestTimeout ' + + 'is set to non zero and followRedirect as true', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + requestTimeout: 1000 + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('timeout: 1000,'); + expect(snippet).to.include('timeout: 1000'); + }); + }); + + it('should return snippet with just a single comma when requestTimeout ' + + 'is set to non zero and followRedirect as false', function () { + request = new sdk.Request(mainCollection.item[0].request); + options = { + requestTimeout: 1000, + followRedirect: false, + indentCount: 1, + indentType: 'space' + }; + convert(request, options, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + return; + } + + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('timeout: 1000,,'); + expect(snippet).to.include('timeout: 1000,\n followRedirect: false'); + }); + }); + + it('should not require unused fs', function () { + request = new sdk.Request({ + 'url': 'https://postman-echo.com/get', + 'method': 'GET', + 'body': { + 'mode': 'raw', + 'raw': '' + } + }); + convert(request, {}, (error, snippet) => { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('var fs = require(\'fs\')'); + }); + }); + + it('should add fs for form-data file upload', function () { + request = new sdk.Request({ + 'url': 'https://postman-echo.com/post', + 'method': 'POST', + 'body': { + 'mode': 'formdata', + 'formdata': [ + { + 'key': 'fileName', + 'src': '/some/path/file.txt', + 'type': 'file' + } + ] + } + }); + convert(request, {}, (error, snippet) => { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('var fs = require(\'fs\')'); + }); + }); + + it('should trim header keys and not trim header values', function () { + var request = new sdk.Request({ + 'method': 'GET', + 'header': [ + { + 'key': ' key_containing_whitespaces ', + 'value': ' value_containing_whitespaces ' + } + ], + 'url': { + 'raw': 'https://google.com', + 'protocol': 'https', + 'host': [ + 'google', + 'com' + ] + } + }); + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('\'key_containing_whitespaces\': \' value_containing_whitespaces \''); + }); + }); + + it('should include JSON.stringify in the snippet for raw json bodies', function () { + var request = new sdk.Request({ + 'method': 'POST', + 'header': [ + { + 'key': 'Content-Type', + 'value': 'application/json' + } + ], + 'body': { + 'mode': 'raw', + 'raw': '{\n "json": "Test-Test"\n}' + }, + 'url': { + 'raw': 'https://postman-echo.com/post', + 'protocol': 'https', + 'host': [ + 'postman-echo', + 'com' + ], + 'path': [ + 'post' + ] + } + }); + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('body: JSON.stringify({"json":"Test-Test"})'); + }); + }); + + it('should generate snippets for no files in form data', function () { + var request = new sdk.Request({ + 'method': 'POST', + 'header': [], + 'body': { + 'mode': 'formdata', + 'formdata': [ + { + 'key': 'no file', + 'value': '', + 'type': 'file', + 'src': [] + }, + { + 'key': 'no src', + 'value': '', + 'type': 'file' + }, + { + 'key': 'invalid src', + 'value': '', + 'type': 'file', + 'src': {} + } + ] + }, + 'url': { + 'raw': 'https://postman-echo.com/post', + 'protocol': 'https', + 'host': [ + 'postman-echo', + 'com' + ], + 'path': [ + 'post' + ] + } + }); + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.include('\'no file\': {'); + expect(snippet).to.include('\'no src\': {'); + expect(snippet).to.include('\'invalid src\': {'); + expect(snippet).to.include('\'value\': fs.createReadStream(\'/path/to/file\')'); + }); + }); + + describe('getOptions function', function () { + + it('should return an array of specific options', function () { + expect(getOptions()).to.be.an('array'); + }); + + it('should return all the valid options', function () { + expect(getOptions()[0]).to.have.property('id', 'indentCount'); + expect(getOptions()[1]).to.have.property('id', 'indentType'); + expect(getOptions()[2]).to.have.property('id', 'requestTimeout'); + expect(getOptions()[3]).to.have.property('id', 'followRedirect'); + expect(getOptions()[4]).to.have.property('id', 'trimRequestBody'); + }); + }); + + describe('Sanitize function', function () { + + it('should return empty string when input is not a string type', function () { + expect(sanitize(123, false)).to.equal(''); + expect(sanitize(null, false)).to.equal(''); + expect(sanitize({}, false)).to.equal(''); + expect(sanitize([], false)).to.equal(''); + }); + + it('should trim input string when needed', function () { + expect(sanitize('inputString ', true)).to.equal('inputString'); + }); + }); + + describe('parseRequest function', function () { + + it('should return empty string for empty body', function () { + expect(parseBody(null, ' ', false)).to.equal(''); + }); + }); + }); +}); diff --git a/codegens/nodejs-superagent/test/unit/validation.test.js b/codegens/nodejs-superagent/test/unit/validation.test.js new file mode 100644 index 000000000..f1083b153 --- /dev/null +++ b/codegens/nodejs-superagent/test/unit/validation.test.js @@ -0,0 +1,30 @@ +var expect = require('chai').expect, + path = require('path'), + + package = require(path.resolve('.', 'package.json')); + + +describe('package.json', function () { + it('should have com_postman_plugin object with valid properties', function () { + expect(package).to.have.property('com_postman_plugin'); + + expect(package.com_postman_plugin.type).to.equal('code_generator'); + expect(package.com_postman_plugin.lang).to.be.a('string'); + expect(package.com_postman_plugin.variant).to.be.a('string'); + expect(package.com_postman_plugin.syntax_mode).to.be.equal('javascript'); + }); + it('should have main property with relative path to object with convert property', function () { + var languageModule; + + expect(package.main).to.be.a('string'); + + try { + languageModule = require(path.resolve('.', package.main)); + } + catch (error) { + console.error(error); + } + expect(languageModule).to.be.a('object'); + expect(languageModule.convert).to.be.a('function'); + }); +}); From c33d40635eb1bb754b2fa982081071123f432fdb Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Wed, 1 Apr 2020 22:26:08 +0530 Subject: [PATCH 09/14] superagent code generator converter --- .../nodejs-superagent/lib/parseRequest.js | 16 +++--- codegens/nodejs-superagent/lib/superagent.js | 53 +++++++------------ 2 files changed, 26 insertions(+), 43 deletions(-) diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index 650c315b5..9e6367632 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -99,13 +99,13 @@ function parseBody (requestbody, indentString, trimBody, contentType) { if (contentType === 'application/json') { try { let jsonBody = JSON.parse(requestbody[requestbody.mode]); - return `body: JSON.stringify(${JSON.stringify(jsonBody)})\n`; + return `JSON.stringify(${JSON.stringify(jsonBody)})\n`; } catch (error) { - return `body: ${JSON.stringify(requestbody[requestbody.mode])}\n`; + return `${JSON.stringify(requestbody[requestbody.mode])}\n`; } } - return `body: ${JSON.stringify(requestbody[requestbody.mode])}\n`; + return `${JSON.stringify(requestbody[requestbody.mode])}\n`; // eslint-disable-next-line no-case-declarations case 'graphql': let query = requestbody[requestbody.mode].query, @@ -116,22 +116,22 @@ function parseBody (requestbody, indentString, trimBody, contentType) { catch (e) { graphqlVariables = {}; } - return 'body: JSON.stringify({\n' + + return 'JSON.stringify({\n' + `${indentString.repeat(2)}query: '${sanitize(query, trimBody)}',\n` + `${indentString.repeat(2)}variables: ${JSON.stringify(graphqlVariables)}\n` + `${indentString}})`; case 'formdata': - return `formData: {\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + + return `{\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + indentString + '}'; case 'urlencoded': - return `form: {\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + + return `{\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + indentString + '}'; /* istanbul ignore next */ case 'file': // return 'formData: {\n' + // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + // indentString + '}'; - return 'body: ""\n'; + return '""\n'; default: return ''; } @@ -148,7 +148,7 @@ function parseBody (requestbody, indentString, trimBody, contentType) { */ function parseHeader (request, indentString) { var headerObject = request.getHeaders({enabled: true}), - headerSnippet = indentString + '\'headers\': {\n'; + headerSnippet = '{\n'; if (!_.isEmpty(headerObject)) { headerSnippet += _.reduce(Object.keys(headerObject), function (accumalator, key) { diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js index c1a0a84c8..c4891797b 100644 --- a/codegens/nodejs-superagent/lib/superagent.js +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -14,7 +14,6 @@ var _ = require('./lodash'), */ function makeSnippet (request, indentString, options) { var snippet, - optionsArray = [], isFormDataFile = false; if (options.ES6_enabled) { snippet = 'const '; @@ -39,25 +38,7 @@ function makeSnippet (request, indentString, options) { } snippet += 'fs = require(\'fs\');\n'; } - if (options.ES6_enabled) { - snippet += 'let '; - } - else { - snippet += 'var '; - } - snippet += 'options = {\n'; - /** - * creating string to represent options object using optionArray.join() - * example: - * options: { - * method: 'GET', - * url: 'www.google.com', - * timeout: 1000 - * } - */ - optionsArray.push(indentString + `'method': '${request.method}'`); - optionsArray.push(indentString + `'url': '${sanitize(request.url.toString())}'`); if (request.body && !request.headers.has('Content-Type')) { if (request.body.mode === 'file') { request.addHeader({ @@ -72,33 +53,35 @@ function makeSnippet (request, indentString, options) { }); } } - optionsArray.push(parseRequest.parseHeader(request, indentString)); + + snippet += 'superagent\n'; + snippet += indentString + `.${request.method.toLowerCase()}('${sanitize(request.url.toString())}')\n`; + snippet += indentString + `.send(${parseRequest.parseHeader(request, indentString)})\n`; if (request.body && request.body[request.body.mode]) { - optionsArray.push( - indentString + parseRequest.parseBody(request.body.toJSON(), indentString, options.trimRequestBody, - request.headers.get('Content-Type')) - ); + snippet += indentString + `.set(${parseRequest.parseBody(request.body.toJSON(), + indentString, options.trimRequestBody, request.headers.get('Content-Type'))})\n`; } + if (options.requestTimeout) { - optionsArray.push(indentString + `timeout: ${options.requestTimeout}`); + snippet += indentString + `.timeout(${options.requestTimeout})\n`; } + if (options.followRedirect === false) { - optionsArray.push(indentString + 'followRedirect: false'); + snippet += indentString + '.redirects(0)\n'; } - snippet += optionsArray.join(',\n') + '\n'; - snippet += '};\n'; - snippet += 'superagent(options, '; + snippet += indentString + '.end('; if (options.ES6_enabled) { snippet += '(error, response) => {\n'; } else { snippet += 'function (error, response) {\n'; } - snippet += indentString + 'if (error) throw new Error(error);\n'; - snippet += indentString + 'console.log(response.body);\n'; - snippet += '});\n'; + snippet += indentString.repeat(2) + 'if (error) throw new Error(error);\n'; + snippet += indentString.repeat(2) + 'console.log(response.body);\n'; + snippet += indentString + '});'; + return snippet; } @@ -157,7 +140,7 @@ function getOptions () { } /** - * Converts Postman sdk request object to nodejs request code snippet + * Converts Postman sdk request object to nodejs superagent code snippet * * @param {Object} request - postman-SDK request object * @param {Object} options @@ -166,12 +149,12 @@ function getOptions () { * @param {Boolean} options.followRedirect - whether to enable followredirect * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not * @param {Boolean} options.ES6_enabled - whether to generate snippet with ES6 features - * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out + * @param {Number} options.requestTimeout : time in milliseconds after which request will bail out * @param {Function} callback - callback function with parameters (error, snippet) */ function convert (request, options, callback) { if (!_.isFunction(callback)) { - throw new Error('NodeJS-Request-Converter: callback is not valid function'); + throw new Error('NodeJS-SuperAgent-Converter: callback is not valid function'); } options = sanitizeOptions(options, getOptions()); From 9c2457ae2ded4966ea5d08fe30dd4ab3119de866 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Wed, 1 Apr 2020 23:59:20 +0530 Subject: [PATCH 10/14] snippet test added --- .../test/unit/snippet.test.js | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/codegens/nodejs-superagent/test/unit/snippet.test.js b/codegens/nodejs-superagent/test/unit/snippet.test.js index e1a228684..3d750ca98 100644 --- a/codegens/nodejs-superagent/test/unit/snippet.test.js +++ b/codegens/nodejs-superagent/test/unit/snippet.test.js @@ -1,4 +1,3 @@ -// TODO var expect = require('chai').expect, sdk = require('postman-collection'), sanitize = require('../../lib/util').sanitize, @@ -30,7 +29,7 @@ describe('nodejs-superagent convert function', function () { expect(snippet).to.be.a('string'); snippetArray = snippet.split('\n'); for (var i = 0; i < snippetArray.length; i++) { - if (snippetArray[i] === 'var options = {') { line_no = i + 1; } + if (snippetArray[i] === 'superagent') { line_no = i + 1; } } expect(snippetArray[line_no].charAt(0)).to.equal('\t'); }); @@ -48,7 +47,7 @@ describe('nodejs-superagent convert function', function () { } expect(snippet).to.be.a('string'); - expect(snippet).to.include('timeout: 1000'); + expect(snippet).to.include('.timeout(1000)'); }); }); @@ -65,9 +64,8 @@ describe('nodejs-superagent convert function', function () { expect(snippet).to.be.a('string'); snippetArray = snippet.split('\n'); - expect(snippetArray[0]).to.equal('const request = require(\'request\');'); - expect(snippetArray).to.include('let options = {'); - expect(snippetArray).to.include('request(options, (error, response) => {'); + expect(snippetArray[0]).to.equal('const superagent = require(\'superagent\');'); + expect(snippetArray).to.include('.end((error, response) => {'); }); }); @@ -84,7 +82,7 @@ describe('nodejs-superagent convert function', function () { } expect(snippet).to.be.a('string'); - expect(snippet).to.include('followRedirect: false'); + expect(snippet).to.include('.redirects(0)'); }); }); @@ -101,7 +99,7 @@ describe('nodejs-superagent convert function', function () { return; } expect(snippet).to.be.a('string'); - expect(snippet).to.include('\'headers\': {\n }'); + expect(snippet).to.include('.set({})'); }); }); @@ -117,7 +115,7 @@ describe('nodejs-superagent convert function', function () { return; } expect(snippet).to.be.a('string'); - expect(snippet).to.not.include('body:'); + expect(snippet).to.include('.set({})'); }); }); @@ -146,6 +144,7 @@ describe('nodejs-superagent convert function', function () { }); }); + // TODO it('should return snippet with proper semicolon placed where required', function () { // testing for the below snippet /* @@ -172,7 +171,7 @@ describe('nodejs-superagent convert function', function () { expect(snippet).to.be.a('string'); var snippetArray = snippet.split('\n'); snippetArray.forEach(function (line, index) { - if (line.charAt(line.length - 2) === ')') { + if (line.contains('.') === ')') { expect(line.charAt(line.length - 1)).to.equal(';'); } expect(line.charAt(line.length - 1)).to.not.equal(')'); @@ -185,6 +184,7 @@ describe('nodejs-superagent convert function', function () { }); }); + // TODO it('should return snippet with no trailing comma when requestTimeout ' + 'is set to non zero and followRedirect as true', function () { request = new sdk.Request(mainCollection.item[0].request); @@ -203,6 +203,7 @@ describe('nodejs-superagent convert function', function () { }); }); + // TODO: it('should return snippet with just a single comma when requestTimeout ' + 'is set to non zero and followRedirect as false', function () { request = new sdk.Request(mainCollection.item[0].request); @@ -238,7 +239,7 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.not.include('var fs = require(\'fs\')'); + expect(snippet).to.not.include('var fs = require(\'fs\');'); }); }); @@ -262,7 +263,7 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.include('var fs = require(\'fs\')'); + expect(snippet).to.include('var fs = require(\'fs\');'); }); }); @@ -323,7 +324,7 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.include('body: JSON.stringify({"json":"Test-Test"})'); + expect(snippet).to.include('JSON.stringify({"json":"Test-Test"})'); }); }); From 9566c880c178eb44bcc5420313a6ca015e5269fb Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Thu, 2 Apr 2020 18:02:14 +0530 Subject: [PATCH 11/14] update parsing functions for superagent --- .../nodejs-superagent/lib/parseRequest.js | 71 ++++++++----------- codegens/nodejs-superagent/lib/superagent.js | 9 +-- 2 files changed, 33 insertions(+), 47 deletions(-) diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index 9e6367632..f5d57e7e9 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -10,8 +10,9 @@ var _ = require('./lodash'), * @param {Array} dataArray - array containing body elements of request * @param {String} indentString - string required for indentation * @param {Boolean} trimBody - indicates whether to trim body or not + * @param {String} requestType - indicates whether the requestBody is to be parsed as urlencoded or formdata */ -function extractFormData (dataArray, indentString, trimBody) { +function extractFormData (dataArray, indentString, trimBody, requestType) { if (!dataArray) { return ''; } @@ -34,14 +35,12 @@ function extractFormData (dataArray, indentString, trimBody) { * } */ if (Array.isArray(item.src) && item.src.length) { - let fileSnippet = '', - fileArray = []; + let fileSnippet = ''; _.forEach(item.src, (filePath) => { - fileArray.push(`${indentString.repeat(3)}fs.createReadStream('${sanitize(filePath, trimBody)}')`); + fileSnippet += indentString + `.attach('${sanitize(item.key, trimBody)}', + '${sanitize(filePath, trimBody)}')\n`; }); - if (fileArray.length) { - fileSnippet += `${indentString.repeat(2)}'${sanitize(item.key, trimBody)}': ` + - `[\n${fileArray.join(',\n')}\n${indentString.repeat(2)}]`; + if (fileSnippet !== '') { accumalator.push(fileSnippet); } else { @@ -49,39 +48,26 @@ function extractFormData (dataArray, indentString, trimBody) { } } else if (typeof item.src !== 'string') { - accumalator.push([ - indentString.repeat(2) + `'${sanitize(item.key, trimBody)}': {`, - indentString.repeat(3) + '\'value\': fs.createReadStream(\'/path/to/file\'),', - indentString.repeat(3) + '\'options\': {', - indentString.repeat(4) + '\'filename\': \'filename\'', - indentString.repeat(4) + '\'contentType\': null', - indentString.repeat(3) + '}', - indentString.repeat(2) + '}' - ].join('\n')); + accumalator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', '/path/to/file')`); } else { var pathArray = item.src.split(path.sep), fileName = pathArray[pathArray.length - 1]; - accumalator.push([ - indentString.repeat(2) + `'${sanitize(item.key, trimBody)}': {`, - indentString.repeat(3) + `'value': fs.createReadStream('${sanitize(item.src, trimBody)}'),`, - indentString.repeat(3) + '\'options\': {', - indentString.repeat(4) + `'filename': '${sanitize(fileName, trimBody)}',`, - indentString.repeat(4) + '\'contentType\': null', - indentString.repeat(3) + '}', - indentString.repeat(2) + '}' - ].join('\n')); + accumalator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', + '${sanitize(item.src, trimBody)}', '${sanitize(fileName, trimBody)}')`); } } - else { - accumalator.push( - indentString.repeat(2) + - `'${sanitize(item.key, trimBody)}': '${sanitize(item.value, trimBody)}'` - ); + else if (requestType === 'urlencoded') { + accumalator.push(indentString + + `.send({'${sanitize(item.key, trimBody)}':'${sanitize(item.value, trimBody)}'})`); + } + else if (requestType === 'formdata') { + accumalator.push(indentString + + `.field('${sanitize(item.key, trimBody)}', '${sanitize(item.value, trimBody)}')`); } return accumalator; }, []); - return snippetString.join(',\n') + '\n'; + return snippetString.join('\n') + '\n'; } /** @@ -99,13 +85,13 @@ function parseBody (requestbody, indentString, trimBody, contentType) { if (contentType === 'application/json') { try { let jsonBody = JSON.parse(requestbody[requestbody.mode]); - return `JSON.stringify(${JSON.stringify(jsonBody)})\n`; + return `.send(JSON.stringify(${JSON.stringify(jsonBody)}))\n`; } catch (error) { - return `${JSON.stringify(requestbody[requestbody.mode])}\n`; + return `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; } } - return `${JSON.stringify(requestbody[requestbody.mode])}\n`; + return `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; // eslint-disable-next-line no-case-declarations case 'graphql': let query = requestbody[requestbody.mode].query, @@ -116,22 +102,21 @@ function parseBody (requestbody, indentString, trimBody, contentType) { catch (e) { graphqlVariables = {}; } - return 'JSON.stringify({\n' + + return '.send(JSON.stringify({\n' + `${indentString.repeat(2)}query: '${sanitize(query, trimBody)}',\n` + `${indentString.repeat(2)}variables: ${JSON.stringify(graphqlVariables)}\n` + - `${indentString}})`; + `${indentString}}))\n`; case 'formdata': - return `{\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + - indentString + '}'; + return `${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}`; case 'urlencoded': - return `{\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` + - indentString + '}'; + return `.type('form')\n${extractFormData(requestbody[requestbody.mode], + indentString, trimBody, requestbody.mode)}\n`; /* istanbul ignore next */ case 'file': // return 'formData: {\n' + // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + // indentString + '}'; - return '""\n'; + return '.send("")\n'; default: return ''; } @@ -140,11 +125,11 @@ function parseBody (requestbody, indentString, trimBody, contentType) { } /** - * parses header of request object and returns code snippet of nodejs superagent to add header + * parses header of request object and returns code snippet of nodejs request to add header * * @param {Object} request - Postman SDK request object * @param {String} indentString - indentation required in code snippet - * @returns {String} - code snippet of nodejs superagent to add header + * @returns {String} - code snippet of nodejs request to add header */ function parseHeader (request, indentString) { var headerObject = request.getHeaders({enabled: true}), diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js index c4891797b..9a5e70964 100644 --- a/codegens/nodejs-superagent/lib/superagent.js +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -38,6 +38,7 @@ function makeSnippet (request, indentString, options) { } snippet += 'fs = require(\'fs\');\n'; } + snippet += '\n'; if (request.body && !request.headers.has('Content-Type')) { if (request.body.mode === 'file') { @@ -56,11 +57,11 @@ function makeSnippet (request, indentString, options) { snippet += 'superagent\n'; snippet += indentString + `.${request.method.toLowerCase()}('${sanitize(request.url.toString())}')\n`; - snippet += indentString + `.send(${parseRequest.parseHeader(request, indentString)})\n`; + snippet += indentString + `.set(${parseRequest.parseHeader(request, indentString)})\n`; if (request.body && request.body[request.body.mode]) { - snippet += indentString + `.set(${parseRequest.parseBody(request.body.toJSON(), - indentString, options.trimRequestBody, request.headers.get('Content-Type'))})\n`; + snippet += indentString + parseRequest.parseBody(request.body.toJSON(), + indentString, options.trimRequestBody, request.headers.get('Content-Type')); } if (options.requestTimeout) { @@ -79,7 +80,7 @@ function makeSnippet (request, indentString, options) { snippet += 'function (error, response) {\n'; } snippet += indentString.repeat(2) + 'if (error) throw new Error(error);\n'; - snippet += indentString.repeat(2) + 'console.log(response.body);\n'; + snippet += indentString.repeat(2) + 'console.log(JSON.stringify(response.body));\n'; snippet += indentString + '});'; return snippet; From f570590bc755c2efab82cc9a050d1ce76ff7a4a6 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Thu, 2 Apr 2020 20:20:33 +0530 Subject: [PATCH 12/14] updated codegen level tests --- .../nodejs-superagent/lib/parseRequest.js | 34 ++++--- codegens/nodejs-superagent/lib/superagent.js | 4 +- .../test/unit/snippet.test.js | 94 ++----------------- 3 files changed, 31 insertions(+), 101 deletions(-) diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index f5d57e7e9..f6f9af97e 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -67,7 +67,7 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { } return accumalator; }, []); - return snippetString.join('\n') + '\n'; + return snippetString.join('\n'); } /** @@ -80,18 +80,22 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { */ function parseBody (requestbody, indentString, trimBody, contentType) { if (requestbody) { + var bodySnippet = indentString; switch (requestbody.mode) { case 'raw': if (contentType === 'application/json') { try { let jsonBody = JSON.parse(requestbody[requestbody.mode]); - return `.send(JSON.stringify(${JSON.stringify(jsonBody)}))\n`; + bodySnippet += `.send(JSON.stringify(${JSON.stringify(jsonBody)}))\n`; + break; } catch (error) { - return `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + bodySnippet += `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + break; } } - return `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + bodySnippet += `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + break; // eslint-disable-next-line no-case-declarations case 'graphql': let query = requestbody[requestbody.mode].query, @@ -102,24 +106,29 @@ function parseBody (requestbody, indentString, trimBody, contentType) { catch (e) { graphqlVariables = {}; } - return '.send(JSON.stringify({\n' + + bodySnippet += '.send(JSON.stringify({\n' + `${indentString.repeat(2)}query: '${sanitize(query, trimBody)}',\n` + `${indentString.repeat(2)}variables: ${JSON.stringify(graphqlVariables)}\n` + `${indentString}}))\n`; + break; case 'formdata': - return `${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}`; + bodySnippet = `${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}`; + break; case 'urlencoded': - return `.type('form')\n${extractFormData(requestbody[requestbody.mode], + bodySnippet += `.type('form')\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}\n`; + break; /* istanbul ignore next */ case 'file': // return 'formData: {\n' + // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + // indentString + '}'; - return '.send("")\n'; + bodySnippet += '.send("")\n'; + break; default: - return ''; + bodySnippet = ''; } + return bodySnippet; } return ''; } @@ -133,7 +142,7 @@ function parseBody (requestbody, indentString, trimBody, contentType) { */ function parseHeader (request, indentString) { var headerObject = request.getHeaders({enabled: true}), - headerSnippet = '{\n'; + headerSnippet = `${indentString}.set({\n`; if (!_.isEmpty(headerObject)) { headerSnippet += _.reduce(Object.keys(headerObject), function (accumalator, key) { @@ -154,8 +163,11 @@ function parseHeader (request, indentString) { return accumalator; }, []).join(',\n') + '\n'; } + else { + return ''; + } - headerSnippet += indentString + '}'; + headerSnippet += indentString + '})\n'; return headerSnippet; } diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js index 9a5e70964..7f59de422 100644 --- a/codegens/nodejs-superagent/lib/superagent.js +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -57,10 +57,10 @@ function makeSnippet (request, indentString, options) { snippet += 'superagent\n'; snippet += indentString + `.${request.method.toLowerCase()}('${sanitize(request.url.toString())}')\n`; - snippet += indentString + `.set(${parseRequest.parseHeader(request, indentString)})\n`; + snippet += parseRequest.parseHeader(request, indentString); if (request.body && request.body[request.body.mode]) { - snippet += indentString + parseRequest.parseBody(request.body.toJSON(), + snippet += parseRequest.parseBody(request.body.toJSON(), indentString, options.trimRequestBody, request.headers.get('Content-Type')); } diff --git a/codegens/nodejs-superagent/test/unit/snippet.test.js b/codegens/nodejs-superagent/test/unit/snippet.test.js index 3d750ca98..cc5bcfe9f 100644 --- a/codegens/nodejs-superagent/test/unit/snippet.test.js +++ b/codegens/nodejs-superagent/test/unit/snippet.test.js @@ -65,7 +65,7 @@ describe('nodejs-superagent convert function', function () { expect(snippet).to.be.a('string'); snippetArray = snippet.split('\n'); expect(snippetArray[0]).to.equal('const superagent = require(\'superagent\');'); - expect(snippetArray).to.include('.end((error, response) => {'); + expect(snippet).to.include('.end((error, response) => {'); }); }); @@ -99,7 +99,7 @@ describe('nodejs-superagent convert function', function () { return; } expect(snippet).to.be.a('string'); - expect(snippet).to.include('.set({})'); + expect(snippet).to.not.include('.set('); }); }); @@ -115,7 +115,6 @@ describe('nodejs-superagent convert function', function () { return; } expect(snippet).to.be.a('string'); - expect(snippet).to.include('.set({})'); }); }); @@ -144,87 +143,6 @@ describe('nodejs-superagent convert function', function () { }); }); - // TODO - it('should return snippet with proper semicolon placed where required', function () { - // testing for the below snippet - /* - var request = require('request'); - var fs = require('fs'); - var options = { - 'method': 'GET', - 'url': 'https://postman-echo.com/headers', - 'headers': { - 'my-sample-header': 'Lorem ipsum dolor sit amet', - 'not-disabled-header': 'ENABLED' - } - }; - request(options, function (error, response) { - if (error) throw new Error(error); - console.log(response.body); - }); */ - request = new sdk.Request(mainCollection.item[0].request); - options = {}; - convert(request, options, function (error, snippet) { - if (error) { - expect.fail(null, null, error); - } - expect(snippet).to.be.a('string'); - var snippetArray = snippet.split('\n'); - snippetArray.forEach(function (line, index) { - if (line.contains('.') === ')') { - expect(line.charAt(line.length - 1)).to.equal(';'); - } - expect(line.charAt(line.length - 1)).to.not.equal(')'); - // check for the closing curly bracket of options object - if (line.startsWith('request')) { - var previousLine = snippetArray[index - 1]; - expect(previousLine.charAt(previousLine.length - 1)).to.equal(';'); - } - }); - }); - }); - - // TODO - it('should return snippet with no trailing comma when requestTimeout ' + - 'is set to non zero and followRedirect as true', function () { - request = new sdk.Request(mainCollection.item[0].request); - options = { - requestTimeout: 1000 - }; - convert(request, options, function (error, snippet) { - if (error) { - expect.fail(null, null, error); - return; - } - - expect(snippet).to.be.a('string'); - expect(snippet).to.not.include('timeout: 1000,'); - expect(snippet).to.include('timeout: 1000'); - }); - }); - - // TODO: - it('should return snippet with just a single comma when requestTimeout ' + - 'is set to non zero and followRedirect as false', function () { - request = new sdk.Request(mainCollection.item[0].request); - options = { - requestTimeout: 1000, - followRedirect: false, - indentCount: 1, - indentType: 'space' - }; - convert(request, options, function (error, snippet) { - if (error) { - expect.fail(null, null, error); - return; - } - - expect(snippet).to.be.a('string'); - expect(snippet).to.not.include('timeout: 1000,,'); - expect(snippet).to.include('timeout: 1000,\n followRedirect: false'); - }); - }); - it('should not require unused fs', function () { request = new sdk.Request({ 'url': 'https://postman-echo.com/get', @@ -371,10 +289,10 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.include('\'no file\': {'); - expect(snippet).to.include('\'no src\': {'); - expect(snippet).to.include('\'invalid src\': {'); - expect(snippet).to.include('\'value\': fs.createReadStream(\'/path/to/file\')'); + expect(snippet).to.include('\'no file\','); + expect(snippet).to.include('\'no src\','); + expect(snippet).to.include('\'invalid src\','); + expect(snippet).to.include(', \'/path/to/file\')'); }); }); From 8cbe4455fe7d4c18f539fee3fbd9387a375f5b2a Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Thu, 2 Apr 2020 20:29:56 +0530 Subject: [PATCH 13/14] README update and fix typos --- README.md | 1 + .../nodejs-superagent/lib/parseRequest.js | 68 ++++++++----------- codegens/nodejs-superagent/lib/superagent.js | 2 +- .../test/unit/snippet.test.js | 6 +- 4 files changed, 33 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 621b16d69..76ef9e9f3 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ List of supported code generators: | JavaScript | XHR | | NodeJs | Native | | NodeJs | Request | +| NodeJs | SuperAgent | | NodeJs | Unirest | | Objective-C| NSURLSession| | OCaml | Cohttp | diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index f6f9af97e..2463c1047 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -16,24 +16,12 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { if (!dataArray) { return ''; } - var snippetString = _.reduce(dataArray, (accumalator, item) => { + var snippetString = _.reduce(dataArray, (accumulator, item) => { if (item.disabled) { - return accumalator; + return accumulator; } /* istanbul ignore next */ if (item.type === 'file') { - /** - * creating snippet to send file in nodejs request - * for example: - * 'fieldname': { - * 'value': fs.createStream('filename.ext'), - * 'options': { - * 'filename': 'filename.ext', - * 'contentType: null - * } - * } - * } - */ if (Array.isArray(item.src) && item.src.length) { let fileSnippet = ''; _.forEach(item.src, (filePath) => { @@ -41,31 +29,31 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { '${sanitize(filePath, trimBody)}')\n`; }); if (fileSnippet !== '') { - accumalator.push(fileSnippet); + accumulator.push(fileSnippet); } else { - return accumalator; + return accumulator; } } else if (typeof item.src !== 'string') { - accumalator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', '/path/to/file')`); + accumulator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', '/path/to/file')`); } else { var pathArray = item.src.split(path.sep), fileName = pathArray[pathArray.length - 1]; - accumalator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', + accumulator.push(indentString + `.attach('${sanitize(item.key, trimBody)}', '${sanitize(item.src, trimBody)}', '${sanitize(fileName, trimBody)}')`); } } else if (requestType === 'urlencoded') { - accumalator.push(indentString + + accumulator.push(indentString + `.send({'${sanitize(item.key, trimBody)}':'${sanitize(item.value, trimBody)}'})`); } else if (requestType === 'formdata') { - accumalator.push(indentString + + accumulator.push(indentString + `.field('${sanitize(item.key, trimBody)}', '${sanitize(item.value, trimBody)}')`); } - return accumalator; + return accumulator; }, []); return snippetString.join('\n'); } @@ -73,35 +61,35 @@ function extractFormData (dataArray, indentString, trimBody, requestType) { /** * Parses body object based on mode of body and returns code snippet * - * @param {Object} requestbody - json object for body of request + * @param {Object} requestBody - json object for body of request * @param {String} indentString - string for indentation * @param {Boolean} trimBody - indicates whether to trim body fields or not * @param {String} contentType Content type of the body being sent */ -function parseBody (requestbody, indentString, trimBody, contentType) { - if (requestbody) { +function parseBody (requestBody, indentString, trimBody, contentType) { + if (requestBody) { var bodySnippet = indentString; - switch (requestbody.mode) { + switch (requestBody.mode) { case 'raw': if (contentType === 'application/json') { try { - let jsonBody = JSON.parse(requestbody[requestbody.mode]); + let jsonBody = JSON.parse(requestBody[requestBody.mode]); bodySnippet += `.send(JSON.stringify(${JSON.stringify(jsonBody)}))\n`; break; } catch (error) { - bodySnippet += `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + bodySnippet += `.send(${JSON.stringify(requestBody[requestBody.mode])})\n`; break; } } - bodySnippet += `.send(${JSON.stringify(requestbody[requestbody.mode])})\n`; + bodySnippet += `.send(${JSON.stringify(requestBody[requestBody.mode])})\n`; break; // eslint-disable-next-line no-case-declarations case 'graphql': - let query = requestbody[requestbody.mode].query, + let query = requestBody[requestBody.mode].query, graphqlVariables; try { - graphqlVariables = JSON.parse(requestbody[requestbody.mode].variables); + graphqlVariables = JSON.parse(requestBody[requestBody.mode].variables); } catch (e) { graphqlVariables = {}; @@ -112,16 +100,16 @@ function parseBody (requestbody, indentString, trimBody, contentType) { `${indentString}}))\n`; break; case 'formdata': - bodySnippet = `${extractFormData(requestbody[requestbody.mode], indentString, trimBody, requestbody.mode)}`; + bodySnippet = `${extractFormData(requestBody[requestBody.mode], indentString, trimBody, requestBody.mode)}`; break; case 'urlencoded': - bodySnippet += `.type('form')\n${extractFormData(requestbody[requestbody.mode], - indentString, trimBody, requestbody.mode)}\n`; + bodySnippet += `.type('form')\n${extractFormData(requestBody[requestBody.mode], + indentString, trimBody, requestBody.mode)}\n`; break; /* istanbul ignore next */ case 'file': // return 'formData: {\n' + - // extractFormData(requestbody[requestbody.mode], indentString, trimBody) + + // extractFormData(requestBody[requestBody.mode], indentString, trimBody) + // indentString + '}'; bodySnippet += '.send("")\n'; break; @@ -134,33 +122,33 @@ function parseBody (requestbody, indentString, trimBody, contentType) { } /** - * parses header of request object and returns code snippet of nodejs request to add header + * parses header of request object and returns code snippet of nodejs superagent to add header * * @param {Object} request - Postman SDK request object * @param {String} indentString - indentation required in code snippet - * @returns {String} - code snippet of nodejs request to add header + * @returns {String} - code snippet of nodejs superagent to add header */ function parseHeader (request, indentString) { var headerObject = request.getHeaders({enabled: true}), headerSnippet = `${indentString}.set({\n`; if (!_.isEmpty(headerObject)) { - headerSnippet += _.reduce(Object.keys(headerObject), function (accumalator, key) { + headerSnippet += _.reduce(Object.keys(headerObject), function (accumulator, key) { if (Array.isArray(headerObject[key])) { var headerValues = []; _.forEach(headerObject[key], (value) => { headerValues.push(`'${sanitize(value)}'`); }); - accumalator.push( + accumulator.push( indentString.repeat(2) + `'${sanitize(key, true)}': [${headerValues.join(', ')}]` ); } else { - accumalator.push( + accumulator.push( indentString.repeat(2) + `'${sanitize(key, true)}': '${sanitize(headerObject[key])}'` ); } - return accumalator; + return accumulator; }, []).join(',\n') + '\n'; } else { diff --git a/codegens/nodejs-superagent/lib/superagent.js b/codegens/nodejs-superagent/lib/superagent.js index 7f59de422..76d7b0eff 100644 --- a/codegens/nodejs-superagent/lib/superagent.js +++ b/codegens/nodejs-superagent/lib/superagent.js @@ -147,7 +147,7 @@ function getOptions () { * @param {Object} options * @param {String} options.indentType - type for indentation eg: Space, Tab * @param {String} options.indentCount - number of spaces or tabs for indentation. - * @param {Boolean} options.followRedirect - whether to enable followredirect + * @param {Boolean} options.followRedirect - whether to enable follow redirect * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not * @param {Boolean} options.ES6_enabled - whether to generate snippet with ES6 features * @param {Number} options.requestTimeout : time in milliseconds after which request will bail out diff --git a/codegens/nodejs-superagent/test/unit/snippet.test.js b/codegens/nodejs-superagent/test/unit/snippet.test.js index cc5bcfe9f..bc2339826 100644 --- a/codegens/nodejs-superagent/test/unit/snippet.test.js +++ b/codegens/nodejs-superagent/test/unit/snippet.test.js @@ -190,8 +190,8 @@ describe('nodejs-superagent convert function', function () { 'method': 'GET', 'header': [ { - 'key': ' key_containing_whitespaces ', - 'value': ' value_containing_whitespaces ' + 'key': ' key_containing_whitespace ', + 'value': ' value_containing_whitespace ' } ], 'url': { @@ -208,7 +208,7 @@ describe('nodejs-superagent convert function', function () { expect.fail(null, null, error); } expect(snippet).to.be.a('string'); - expect(snippet).to.include('\'key_containing_whitespaces\': \' value_containing_whitespaces \''); + expect(snippet).to.include('\'key_containing_whitespace\': \' value_containing_whitespace \''); }); }); From 230025d1b05756eaa3588eb54269c35127e80940 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Tue, 12 May 2020 11:39:44 +0530 Subject: [PATCH 14/14] Added missing newline character --- codegens/nodejs-superagent/lib/parseRequest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegens/nodejs-superagent/lib/parseRequest.js b/codegens/nodejs-superagent/lib/parseRequest.js index 2463c1047..cb6ca8861 100644 --- a/codegens/nodejs-superagent/lib/parseRequest.js +++ b/codegens/nodejs-superagent/lib/parseRequest.js @@ -100,7 +100,7 @@ function parseBody (requestBody, indentString, trimBody, contentType) { `${indentString}}))\n`; break; case 'formdata': - bodySnippet = `${extractFormData(requestBody[requestBody.mode], indentString, trimBody, requestBody.mode)}`; + bodySnippet = `${extractFormData(requestBody[requestBody.mode], indentString, trimBody, requestBody.mode)}\n`; break; case 'urlencoded': bodySnippet += `.type('form')\n${extractFormData(requestBody[requestBody.mode],