diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b1f9e7..7407966 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## [1.16.0](https://github.com/joolfe/postman-to-openapi/compare/1.15.0...1.16.0) (2021-08-01) + + +### Features + +* replace variables from postman collection or new option ([75f8df1](https://github.com/joolfe/postman-to-openapi/commit/75f8df109bf6433c1933d08ebd1b11bab77a7e26)) +* var replacer first implementation ([768e59f](https://github.com/joolfe/postman-to-openapi/commit/768e59fc4a62a9d98ef394ca1ec3319e908b6531)) + + +### Documentation + +* update documentation with new replacement feature ([9cfd142](https://github.com/joolfe/postman-to-openapi/commit/9cfd1427d1d4735f8470077ca1a3a84b2a53c229)) + + +### Build System + +* update version for new feature ([32cdb47](https://github.com/joolfe/postman-to-openapi/commit/32cdb47b58289f453abb30407f3e6ed27384cf0b)) + ## [1.15.0](https://github.com/joolfe/postman-to-openapi/compare/1.14.0...1.15.0) (2021-07-30) diff --git a/docs/index.md b/docs/index.md index a7dfc8b..eb2da07 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,7 +18,8 @@ * Postman Collection v2.1 and v2.0. * OpenApi 3.0 -* 🆕 Cli available +* Cli available +* 🆕 Postman variables automatically replaced. * Basic info API from Postman info or customizable. * Basic method conversion (GET, POST, PUT...). * Support Postman folders as tags. @@ -31,7 +32,7 @@ * Provide meta-information as a markdown table. * Path depth configuration. * API Response parse from postman examples and from test code (status code). -* [x-logo](https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-logo) extension support +* [x-logo](https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-logo) extension support. See [Features](#features) section for more details about how to use each of this features. @@ -129,6 +130,8 @@ The third parameter used in the library method is an `options` object containing | [externalDocs](#externaldocs-object) | Info about the API external documentation. | | [folders](#folders-object) | Config object for folders and nested folders in postman collection. | | [responseHeaders](#responseheaders-boolean) | Indicate if should parse the response headers from the collection examples. | +| [replaceVars](#replacevars-boolean) | Boolean value to indicate if postman variables should be replaced.| +| [additionalVars](#additionalvars-object) | Object to provide additional values for variables replacement.| ### info (Object) @@ -316,6 +319,33 @@ This flag indicates if the headers that are saved as part of the postman collect The default value is `true`, so headers are by default added to the response definition. +### replaceVars (Boolean) + +This flag indicates if the [postman variables](https://learning.postman.com/docs/sending-requests/variables/) referenced in the postman collection should be replaced before generate the OpenAPI specs. + +If set to `true` all variable references contained in the postman collection as "{{variable}}" will be replaced by his value defined at [postman collection level](https://learning.postman.com/docs/sending-requests/variables/#defining-collection-variables) or values provided the [additionalVars Object](#additionalvars-object). + +Be aware that path variables defined as postman variables "{{variable}}" as for example a path like `https://api.io/users/{{user_id}}` will be also replaced if there exist a variable definition at postman collection or in the [additionalVars Object](#additionalvars-object). + +The default value for this flag is `false` as variable replacement has a performance cost. + +### additionalVars (Object) + +In postman, variables can be defined at different [scopes level](https://learning.postman.com/docs/sending-requests/variables/#variable-scopes) but only the ones defined at [postman collection level](https://learning.postman.com/docs/sending-requests/variables/#defining-collection-variables) will be saved inside collection file, to provide additional variable values, what we can call Global or Environment variables, there exist the `additionalVars` parameter. + +This parameter is a json Object that contain as key the variable name and as value the variable value, as for example: + +```js +{ + additionalVars: { + service : 'myService', + company : 'myCompany' + } +} +``` + +Take into account that variable values provided in the `additionalVars` Object supersede those defined at Postman collection level. + # Features ## Basic conversion @@ -352,7 +382,7 @@ This library automatically transform query and headers parameters from Postman o The default schema used for parameters is `string` but the library try to infer the type of the parameters based on the value using regular expressions, the detected types are `integer`, `number`, `boolean` and `string`, if you find any problem in the inference process please open an issue. -Path parameters are also automatically detected, this library look for [Postman variables](https://learning.postman.com/docs/sending-requests/variables/) in the url as `{{{variable}}}` and transform to a single curly brace expression as `{variable}` as supported by OpenAPI, also create the parameter definition using the variable name. To provide additional information about a path parameter you can [Pass Meta-information as markdown](#pass-meta-information-as-markdown). +Path parameters are also automatically detected, this library look for [Postman variables](https://learning.postman.com/docs/sending-requests/variables/) in the url as "{{variable}}" and transform to a single curly brace expression as `{variable}` as supported by OpenAPI, also create the parameter definition using the variable name. To provide additional information about a path parameter you can [Pass Meta-information as markdown](#pass-meta-information-as-markdown). Be aware that if you use the `replaceVar` option the path parameter using Postman variables can be affected. See [replaceVars option](#replacevars-boolean) For headers and query fields you can indicate that this parameter is mandatory/required adding into the description the literal `[required]`. The library use a case insensitive regexp so all variations are supported (`[REQUIRED]`, `[Required]`...) and never mind the location inside the description (at the beginning, at the end...). diff --git a/lib/index.js b/lib/index.js index 13d4e12..bff9c10 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,14 +4,18 @@ const { promises: { writeFile, readFile } } = require('fs') const { dump } = require('js-yaml') const { parseMdTable } = require('./md-utils') const { version } = require('../package.json') +const replacePostmanVariables = require('./var-replacer') async function postmanToOpenApi (input, output, { info = {}, defaultTag = 'default', pathDepth = 0, auth: optsAuth, servers, externalDocs = {}, folders = {}, - responseHeaders = true + responseHeaders = true, replaceVars = false, additionalVars = {} } = {}) { // TODO validate? - const collectionFile = await readFile(input) + let collectionFile = await readFile(input, 'utf8') + if (replaceVars) { + collectionFile = replacePostmanVariables(collectionFile, additionalVars) + } const postmanJson = JSON.parse(collectionFile) const { item: items, variable = [] } = postmanJson const paths = {} @@ -203,7 +207,7 @@ function mapFormData () { } /* Parse the Postman query and header and transform into OpenApi parameters */ -function parseParameters (query = [], header, paths, paramsMeta = {}) { +function parseParameters (query, header, paths, paramsMeta = {}) { // parse Headers let parameters = header.reduce(mapParameters('header'), []) // parse Query @@ -326,7 +330,7 @@ function parseOptsAuth (optAuth) { } /* From the path array compose the real path for OpenApi specs */ -function calculatePath (paths = [], pathDepth) { +function calculatePath (paths, pathDepth) { paths = paths.slice(pathDepth) // path depth // replace repeated '{' and '}' chars return '/' + paths.map(path => path.replace(/([{}])\1+/g, '$1')) @@ -337,24 +341,53 @@ function calculateDomains (protocol, hosts, port) { return protocol + '://' + hosts.join('.') + (port ? `:${port}` : '') } -/** Support for collection V2 */ +/** + * To support postman collection v2 and variable replace we should parse the `url` or `url.raw` data + * without trust in the object as in v2 could not exist and if replaceVars = true then values cannot + * be correctly parsed + * @param {Object | String} url + * @returns a url structure as in postman v2.1 collections + */ function scrapeURL (url) { + // Avoid parse empty url request if (url === '' || url.raw === '') { return { valid: false } } - if (typeof url === 'string' || url instanceof String) { - const objUrl = new URL(url) - return { - raw: url, - path: decodeURIComponent(objUrl.pathname).slice(1).split('/'), - query: [], - protocol: objUrl.protocol.slice(0, -1), - host: decodeURIComponent(objUrl.hostname).split('.'), - port: objUrl.port, - valid: true - } + const rawUrl = (typeof url === 'string' || url instanceof String) ? url : url.raw + const objUrl = new URL(rawUrl) + return { + raw: rawUrl, + path: decodeURIComponent(objUrl.pathname).slice(1).split('/'), + query: compoundQueryParams(objUrl.searchParams, url.query), + protocol: objUrl.protocol.slice(0, -1), + host: decodeURIComponent(objUrl.hostname).split('.'), + port: objUrl.port, + valid: true } - return { ...url, valid: true } +} + +/** + * Calculate query parameters as postman collection + * @param {*} searchParams The searchParam instance from an URL object + * @param {*} queryCollection The postman collection query section + * @returns A query params array as created by postman collections Array(Obj) + */ +function compoundQueryParams (searchParams, queryCollection = []) { + // Prepare desc in query collection for easy search + const descMap = queryCollection.reduce((agr, { key, description }) => { + agr[key] = description + return agr + }, {}) + // Create the query array of objects + const query = [] + searchParams.forEach((value, key) => { + query.push({ + key, + value, + ...(descMap[key] != null ? { description: descMap[key] } : {}) + }) + }) + return query } /* Parse domains from operations or options */ diff --git a/lib/var-replacer.js b/lib/var-replacer.js new file mode 100644 index 0000000..1a15657 --- /dev/null +++ b/lib/var-replacer.js @@ -0,0 +1,23 @@ +const Mustache = require('mustache') + +/** + * Rewrite escapedValue() function to not delete undefined variables + */ +Mustache.Writer.prototype.escapedValue = function escapedValue (token, context, config) { + const value = context.lookup(token[1]) || `{{${token[1]}}}` + return String(value) +} + +function replacePostmanVariables (collectionString, additionalVars = {}) { + const postmanJson = JSON.parse(collectionString) + const { variable } = postmanJson + const formatVars = variable.reduce((obj, { key, value }) => { + obj[key] = value + return obj + }, {}) + // Merge collection vars with additional vars + const context = { ...formatVars, ...additionalVars } + return Mustache.render(collectionString, context) +} + +module.exports = replacePostmanVariables diff --git a/package-lock.json b/package-lock.json index 62cd1bd..7136b5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { "name": "postman-to-openapi", - "version": "1.15.0", + "version": "1.16.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "1.15.0", + "version": "1.16.0", "license": "MIT", "dependencies": { "commander": "^7.2.0", "js-yaml": "^4.1.0", - "marked": "^2.0.7" + "marked": "^2.0.7", + "mustache": "^4.2.0" }, "bin": { "p2o": "bin/cli.js" @@ -3731,6 +3732,14 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/nanoid": { "version": "3.1.23", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", @@ -8286,6 +8295,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==" + }, "nanoid": { "version": "3.1.23", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", diff --git a/package.json b/package.json index 331124d..6228fd3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postman-to-openapi", - "version": "1.15.0", + "version": "1.16.0", "description": "Convert postman collection to OpenAPI spec", "main": "lib/index.js", "types": "types/index.d.ts", @@ -88,7 +88,8 @@ "dependencies": { "commander": "^7.2.0", "js-yaml": "^4.1.0", - "marked": "^2.0.7" + "marked": "^2.0.7", + "mustache": "^4.2.0" }, "husky": { "hooks": { diff --git a/test/index.spec.js b/test/index.spec.js index b540b5a..87a2124 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -50,6 +50,8 @@ const EXPECTED_AUTH_REQUEST = readFileSync('./test/resources/output/AuthRequest. const EXPECTED_RESPONSES_NO_HEADERS = readFileSync('./test/resources/output/ResponsesNoHeaders.yml', 'utf8') const EXPECTED_FORM_DATA = readFileSync('./test/resources/output/FormData.yml', 'utf8') const EXPECTED_FORM_URLENCODED = readFileSync('./test/resources/output/FormUrlencoded.yml', 'utf8') +const EXPECTED_VARIABLES = readFileSync('./test/resources/output/Variables.yml', 'utf8') +const EXPECTED_VARIABLES_ADDITIONAL = readFileSync('./test/resources/output/VariablesAdditional.yml', 'utf8') const AUTH_DEFINITIONS = { myCustomAuth: { @@ -106,6 +108,7 @@ describe('Library specs', function () { const COLLECTION_AUTH_REQUEST = `./test/resources/input/${version}/AuthRequest.json` const COLLECTION_FORM_DATA = `./test/resources/input/${version}/FormData.json` const COLLECTION_FORM_URLENCODED = `./test/resources/input/${version}/FormUrlencoded.json` + const COLLECTION_VARIABLES = `./test/resources/input/${version}/Variables.json` it('should work with a basic transform', async function () { const result = await postmanToOpenApi(COLLECTION_BASIC, OUTPUT_PATH, {}) @@ -409,6 +412,22 @@ describe('Library specs', function () { const result = await postmanToOpenApi(COLLECTION_FORM_URLENCODED, OUTPUT_PATH, {}) equal(result, EXPECTED_FORM_URLENCODED) }) + + it('should replace postman variables if feature activated', async function () { + const result = await postmanToOpenApi(COLLECTION_VARIABLES, OUTPUT_PATH, { replaceVars: true }) + equal(result, EXPECTED_VARIABLES) + }) + + it('should use additional variables for replace', async function () { + const result = await postmanToOpenApi(COLLECTION_VARIABLES, OUTPUT_PATH, { + replaceVars: true, + additionalVars: { + company: 'myCompany', + service: 'myService' + } + }) + equal(result, EXPECTED_VARIABLES_ADDITIONAL) + }) }) }) diff --git a/test/resources/input/v2/Variables.json b/test/resources/input/v2/Variables.json new file mode 100644 index 0000000..e3ffa38 --- /dev/null +++ b/test/resources/input/v2/Variables.json @@ -0,0 +1,178 @@ +{ + "info": { + "_postman_id": "747abd37-e913-4bf8-a7e7-01730737b973", + "name": "Variables", + "description": "Mi super test collection from postman", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" + }, + "item": [ + { + "name": "Create new User", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"example\": \"field\",\n \"other\": {\n \"data1\": \"yes\",\n \"service\": \"{{service}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "{{server}}/users", + "description": "Create a new user into your amazing API" + }, + "response": [] + }, + { + "name": "Create Post", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "company", + "value": "{{company}}", + "type": "text" + }, + { + "key": "text", + "value": "This is an example text", + "type": "text" + }, + { + "key": "auditor", + "value": "{{auditor}}", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "https://api.io/{{dinamic_path}}/post" + }, + "response": [] + }, + { + "name": "Consult User data", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Company", + "value": "{{company}}", + "type": "text" + } + ], + "url": { + "raw": "{{server}}/users/{{user_id}}?company={{company}}", + "host": [ + "{{server}}" + ], + "path": [ + "users", + "{{user_id}}" + ], + "query": [ + { + "key": "company", + "value": "{{company}}" + } + ] + }, + "description": "Get one user instance data" + }, + "response": [] + }, + { + "name": "Get a list of user", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{server}}/users?size={{page-size}}&company={{company}}", + "host": [ + "{{server}}" + ], + "path": [ + "users" + ], + "query": [ + { + "key": "size", + "value": "{{page-size}}", + "description": "{{desc-size}}" + }, + { + "key": "company", + "value": "{{company}}", + "description": "company for filter users" + } + ] + }, + "description": "Get a list of users" + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "version", + "value": "1.1.0" + }, + { + "key": "server", + "value": "https://api.io" + }, + { + "key": "page-size", + "value": "10" + }, + { + "key": "company", + "value": "ServicesLTD" + }, + { + "key": "auditor", + "value": "IHA" + }, + { + "key": "service", + "value": "s23434" + }, + { + "key": "desc-size", + "value": "size of the list" + }, + { + "key": "dinamic_path", + "value": "test/path/here" + } + ] +} \ No newline at end of file diff --git a/test/resources/input/v21/Variables.json b/test/resources/input/v21/Variables.json new file mode 100644 index 0000000..bffd43d --- /dev/null +++ b/test/resources/input/v21/Variables.json @@ -0,0 +1,197 @@ +{ + "info": { + "_postman_id": "747abd37-e913-4bf8-a7e7-01730737b973", + "name": "Variables", + "description": "Mi super test collection from postman", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Create new User", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"example\": \"field\",\n \"other\": {\n \"data1\": \"yes\",\n \"service\": \"{{service}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{server}}/users", + "host": [ + "{{server}}" + ], + "path": [ + "users" + ] + }, + "description": "Create a new user into your amazing API" + }, + "response": [] + }, + { + "name": "Create Post", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "company", + "value": "{{company}}", + "type": "text" + }, + { + "key": "text", + "value": "This is an example text", + "type": "text" + }, + { + "key": "auditor", + "value": "{{auditor}}", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://api.io/{{dinamic_path}}/post", + "protocol": "https", + "host": [ + "api", + "io" + ], + "path": [ + "{{dinamic_path}}", + "post" + ] + } + }, + "response": [] + }, + { + "name": "Consult User data", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Company", + "value": "{{company}}", + "type": "text" + } + ], + "url": { + "raw": "{{server}}/users/{{user_id}}?company={{company}}", + "host": [ + "{{server}}" + ], + "path": [ + "users", + "{{user_id}}" + ], + "query": [ + { + "key": "company", + "value": "{{company}}" + } + ] + }, + "description": "Get one user instance data" + }, + "response": [] + }, + { + "name": "Get a list of user", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{server}}/users?size={{page-size}}&company={{company}}", + "host": [ + "{{server}}" + ], + "path": [ + "users" + ], + "query": [ + { + "key": "size", + "value": "{{page-size}}", + "description": "{{desc-size}}" + }, + { + "key": "company", + "value": "{{company}}", + "description": "company for filter users" + } + ] + }, + "description": "Get a list of users" + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "version", + "value": "1.1.0" + }, + { + "key": "server", + "value": "https://api.io" + }, + { + "key": "page-size", + "value": "10" + }, + { + "key": "company", + "value": "ServicesLTD" + }, + { + "key": "auditor", + "value": "IHA" + }, + { + "key": "service", + "value": "s23434" + }, + { + "key": "desc-size", + "value": "size of the list" + }, + { + "key": "dinamic_path", + "value": "test/path/here" + } + ] +} \ No newline at end of file diff --git a/test/resources/output/Headers.yml b/test/resources/output/Headers.yml index 67fdf18..dc44b85 100644 --- a/test/resources/output/Headers.yml +++ b/test/resources/output/Headers.yml @@ -37,12 +37,6 @@ paths: schema: type: string description: header without value - - name: age - in: query - schema: - type: integer - description: Filter by age - example: '45' - name: name in: query schema: diff --git a/test/resources/output/Variables.yml b/test/resources/output/Variables.yml new file mode 100644 index 0000000..3f86967 --- /dev/null +++ b/test/resources/output/Variables.yml @@ -0,0 +1,104 @@ +openapi: 3.0.0 +info: + title: Variables + description: Mi super test collection from postman + version: 1.1.0 +servers: + - url: https://api.io +paths: + /users: + post: + tags: + - default + summary: Create new User + description: Create a new user into your amazing API + requestBody: + content: + application/json: + schema: + type: object + example: + example: field + other: + data1: 'yes' + service: s23434 + responses: + '200': + description: Successful response + content: + application/json: {} + get: + tags: + - default + summary: Get a list of user + description: Get a list of users + parameters: + - name: size + in: query + schema: + type: integer + description: size of the list + example: '10' + - name: company + in: query + schema: + type: string + description: company for filter users + example: ServicesLTD + responses: + '200': + description: Successful response + content: + application/json: {} + /test/path/here/post: + post: + tags: + - default + summary: Create Post + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + company: + type: string + example: ServicesLTD + text: + type: string + example: This is an example text + auditor: + type: string + example: IHA + responses: + '200': + description: Successful response + content: + application/json: {} + /users/{user_id}: + get: + tags: + - default + summary: Consult User data + description: Get one user instance data + parameters: + - name: X-Company + in: header + schema: + type: string + example: ServicesLTD + - name: company + in: query + schema: + type: string + example: ServicesLTD + - name: user_id + in: path + schema: + type: string + required: true + responses: + '200': + description: Successful response + content: + application/json: {} diff --git a/test/resources/output/VariablesAdditional.yml b/test/resources/output/VariablesAdditional.yml new file mode 100644 index 0000000..d2d2fe4 --- /dev/null +++ b/test/resources/output/VariablesAdditional.yml @@ -0,0 +1,104 @@ +openapi: 3.0.0 +info: + title: Variables + description: Mi super test collection from postman + version: 1.1.0 +servers: + - url: https://api.io +paths: + /users: + post: + tags: + - default + summary: Create new User + description: Create a new user into your amazing API + requestBody: + content: + application/json: + schema: + type: object + example: + example: field + other: + data1: 'yes' + service: myService + responses: + '200': + description: Successful response + content: + application/json: {} + get: + tags: + - default + summary: Get a list of user + description: Get a list of users + parameters: + - name: size + in: query + schema: + type: integer + description: size of the list + example: '10' + - name: company + in: query + schema: + type: string + description: company for filter users + example: myCompany + responses: + '200': + description: Successful response + content: + application/json: {} + /test/path/here/post: + post: + tags: + - default + summary: Create Post + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + company: + type: string + example: myCompany + text: + type: string + example: This is an example text + auditor: + type: string + example: IHA + responses: + '200': + description: Successful response + content: + application/json: {} + /users/{user_id}: + get: + tags: + - default + summary: Consult User data + description: Get one user instance data + parameters: + - name: X-Company + in: header + schema: + type: string + example: myCompany + - name: company + in: query + schema: + type: string + example: myCompany + - name: user_id + in: path + schema: + type: string + required: true + responses: + '200': + description: Successful response + content: + application/json: {} diff --git a/test/resources/var-replace/VariablesReplacedV2.json b/test/resources/var-replace/VariablesReplacedV2.json new file mode 100644 index 0000000..0574d13 --- /dev/null +++ b/test/resources/var-replace/VariablesReplacedV2.json @@ -0,0 +1,178 @@ +{ + "info": { + "_postman_id": "747abd37-e913-4bf8-a7e7-01730737b973", + "name": "Variables", + "description": "Mi super test collection from postman", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" + }, + "item": [ + { + "name": "Create new User", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"example\": \"field\",\n \"other\": {\n \"data1\": \"yes\",\n \"service\": \"s23434\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "https://api.io/users", + "description": "Create a new user into your amazing API" + }, + "response": [] + }, + { + "name": "Create Post", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "company", + "value": "ServicesLTD", + "type": "text" + }, + { + "key": "text", + "value": "This is an example text", + "type": "text" + }, + { + "key": "auditor", + "value": "IHA", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "https://api.io/test/path/here/post" + }, + "response": [] + }, + { + "name": "Consult User data", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Company", + "value": "ServicesLTD", + "type": "text" + } + ], + "url": { + "raw": "https://api.io/users/{{user_id}}?company=ServicesLTD", + "host": [ + "https://api.io" + ], + "path": [ + "users", + "{{user_id}}" + ], + "query": [ + { + "key": "company", + "value": "ServicesLTD" + } + ] + }, + "description": "Get one user instance data" + }, + "response": [] + }, + { + "name": "Get a list of user", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://api.io/users?size=10&company=ServicesLTD", + "host": [ + "https://api.io" + ], + "path": [ + "users" + ], + "query": [ + { + "key": "size", + "value": "10", + "description": "size of the list" + }, + { + "key": "company", + "value": "ServicesLTD", + "description": "company for filter users" + } + ] + }, + "description": "Get a list of users" + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "version", + "value": "1.1.0" + }, + { + "key": "server", + "value": "https://api.io" + }, + { + "key": "page-size", + "value": "10" + }, + { + "key": "company", + "value": "ServicesLTD" + }, + { + "key": "auditor", + "value": "IHA" + }, + { + "key": "service", + "value": "s23434" + }, + { + "key": "desc-size", + "value": "size of the list" + }, + { + "key": "dinamic_path", + "value": "test/path/here" + } + ] +} \ No newline at end of file diff --git a/test/resources/var-replace/VariablesReplacedV21.json b/test/resources/var-replace/VariablesReplacedV21.json new file mode 100644 index 0000000..28c96b4 --- /dev/null +++ b/test/resources/var-replace/VariablesReplacedV21.json @@ -0,0 +1,197 @@ +{ + "info": { + "_postman_id": "747abd37-e913-4bf8-a7e7-01730737b973", + "name": "Variables", + "description": "Mi super test collection from postman", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Create new User", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"example\": \"field\",\n \"other\": {\n \"data1\": \"yes\",\n \"service\": \"s23434\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://api.io/users", + "host": [ + "https://api.io" + ], + "path": [ + "users" + ] + }, + "description": "Create a new user into your amazing API" + }, + "response": [] + }, + { + "name": "Create Post", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "company", + "value": "ServicesLTD", + "type": "text" + }, + { + "key": "text", + "value": "This is an example text", + "type": "text" + }, + { + "key": "auditor", + "value": "IHA", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://api.io/test/path/here/post", + "protocol": "https", + "host": [ + "api", + "io" + ], + "path": [ + "test/path/here", + "post" + ] + } + }, + "response": [] + }, + { + "name": "Consult User data", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Company", + "value": "ServicesLTD", + "type": "text" + } + ], + "url": { + "raw": "https://api.io/users/{{user_id}}?company=ServicesLTD", + "host": [ + "https://api.io" + ], + "path": [ + "users", + "{{user_id}}" + ], + "query": [ + { + "key": "company", + "value": "ServicesLTD" + } + ] + }, + "description": "Get one user instance data" + }, + "response": [] + }, + { + "name": "Get a list of user", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://api.io/users?size=10&company=ServicesLTD", + "host": [ + "https://api.io" + ], + "path": [ + "users" + ], + "query": [ + { + "key": "size", + "value": "10", + "description": "size of the list" + }, + { + "key": "company", + "value": "ServicesLTD", + "description": "company for filter users" + } + ] + }, + "description": "Get a list of users" + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "version", + "value": "1.1.0" + }, + { + "key": "server", + "value": "https://api.io" + }, + { + "key": "page-size", + "value": "10" + }, + { + "key": "company", + "value": "ServicesLTD" + }, + { + "key": "auditor", + "value": "IHA" + }, + { + "key": "service", + "value": "s23434" + }, + { + "key": "desc-size", + "value": "size of the list" + }, + { + "key": "dinamic_path", + "value": "test/path/here" + } + ] +} \ No newline at end of file diff --git a/test/resources/var-replace/VariablesReplacedV21additional.json b/test/resources/var-replace/VariablesReplacedV21additional.json new file mode 100644 index 0000000..e190cdf --- /dev/null +++ b/test/resources/var-replace/VariablesReplacedV21additional.json @@ -0,0 +1,197 @@ +{ + "info": { + "_postman_id": "747abd37-e913-4bf8-a7e7-01730737b973", + "name": "Variables", + "description": "Mi super test collection from postman", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Create new User", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"example\": \"field\",\n \"other\": {\n \"data1\": \"yes\",\n \"service\": \"myService\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://api.io/users", + "host": [ + "https://api.io" + ], + "path": [ + "users" + ] + }, + "description": "Create a new user into your amazing API" + }, + "response": [] + }, + { + "name": "Create Post", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "company", + "value": "myCompany", + "type": "text" + }, + { + "key": "text", + "value": "This is an example text", + "type": "text" + }, + { + "key": "auditor", + "value": "IHA", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://api.io/test/path/here/post", + "protocol": "https", + "host": [ + "api", + "io" + ], + "path": [ + "test/path/here", + "post" + ] + } + }, + "response": [] + }, + { + "name": "Consult User data", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Company", + "value": "myCompany", + "type": "text" + } + ], + "url": { + "raw": "https://api.io/users/{{user_id}}?company=myCompany", + "host": [ + "https://api.io" + ], + "path": [ + "users", + "{{user_id}}" + ], + "query": [ + { + "key": "company", + "value": "myCompany" + } + ] + }, + "description": "Get one user instance data" + }, + "response": [] + }, + { + "name": "Get a list of user", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://api.io/users?size=10&company=myCompany", + "host": [ + "https://api.io" + ], + "path": [ + "users" + ], + "query": [ + { + "key": "size", + "value": "10", + "description": "size of the list" + }, + { + "key": "company", + "value": "myCompany", + "description": "company for filter users" + } + ] + }, + "description": "Get a list of users" + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "version", + "value": "1.1.0" + }, + { + "key": "server", + "value": "https://api.io" + }, + { + "key": "page-size", + "value": "10" + }, + { + "key": "company", + "value": "ServicesLTD" + }, + { + "key": "auditor", + "value": "IHA" + }, + { + "key": "service", + "value": "s23434" + }, + { + "key": "desc-size", + "value": "size of the list" + }, + { + "key": "dinamic_path", + "value": "test/path/here" + } + ] +} \ No newline at end of file diff --git a/test/resources/var-replace/VariablesReplacedV2additional.json b/test/resources/var-replace/VariablesReplacedV2additional.json new file mode 100644 index 0000000..70c8bef --- /dev/null +++ b/test/resources/var-replace/VariablesReplacedV2additional.json @@ -0,0 +1,178 @@ +{ + "info": { + "_postman_id": "747abd37-e913-4bf8-a7e7-01730737b973", + "name": "Variables", + "description": "Mi super test collection from postman", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" + }, + "item": [ + { + "name": "Create new User", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"example\": \"field\",\n \"other\": {\n \"data1\": \"yes\",\n \"service\": \"myService\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "https://api.io/users", + "description": "Create a new user into your amazing API" + }, + "response": [] + }, + { + "name": "Create Post", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "company", + "value": "myCompany", + "type": "text" + }, + { + "key": "text", + "value": "This is an example text", + "type": "text" + }, + { + "key": "auditor", + "value": "IHA", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "https://api.io/test/path/here/post" + }, + "response": [] + }, + { + "name": "Consult User data", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Company", + "value": "myCompany", + "type": "text" + } + ], + "url": { + "raw": "https://api.io/users/{{user_id}}?company=myCompany", + "host": [ + "https://api.io" + ], + "path": [ + "users", + "{{user_id}}" + ], + "query": [ + { + "key": "company", + "value": "myCompany" + } + ] + }, + "description": "Get one user instance data" + }, + "response": [] + }, + { + "name": "Get a list of user", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://api.io/users?size=10&company=myCompany", + "host": [ + "https://api.io" + ], + "path": [ + "users" + ], + "query": [ + { + "key": "size", + "value": "10", + "description": "size of the list" + }, + { + "key": "company", + "value": "myCompany", + "description": "company for filter users" + } + ] + }, + "description": "Get a list of users" + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "version", + "value": "1.1.0" + }, + { + "key": "server", + "value": "https://api.io" + }, + { + "key": "page-size", + "value": "10" + }, + { + "key": "company", + "value": "ServicesLTD" + }, + { + "key": "auditor", + "value": "IHA" + }, + { + "key": "service", + "value": "s23434" + }, + { + "key": "desc-size", + "value": "size of the list" + }, + { + "key": "dinamic_path", + "value": "test/path/here" + } + ] +} \ No newline at end of file diff --git a/test/var-replacer.spec.js b/test/var-replacer.spec.js new file mode 100644 index 0000000..c646a46 --- /dev/null +++ b/test/var-replacer.spec.js @@ -0,0 +1,41 @@ +'use strict' + +const { describe, it } = require('mocha') +const { readFileSync } = require('fs') +const { equal } = require('assert').strict +const replacePostmanVariables = require('../lib/var-replacer') + +describe('replacePostmanVariables specs', function () { + const VARIABLES_COLLECTION_V2 = readFileSync('./test/resources/input/v2/Variables.json', 'utf8') + const VARIABLES_COLLECTION_V21 = readFileSync('./test/resources/input/v21/Variables.json', 'utf8') + const RESULT_V2 = readFileSync('./test/resources/var-replace/VariablesReplacedV2.json', 'utf8') + const RESULT_V21 = readFileSync('./test/resources/var-replace/VariablesReplacedV21.json', 'utf8') + const RESULT_ADDITIONAL_V2 = readFileSync('./test/resources/var-replace/VariablesReplacedV2additional.json', 'utf8') + const RESULT_ADDITIONAL_V21 = readFileSync('./test/resources/var-replace/VariablesReplacedV21additional.json', 'utf8') + + it('should replace all variables successfully v2', async function () { + const output = replacePostmanVariables(VARIABLES_COLLECTION_V2) + equal(output, RESULT_V2) + }) + + it('should replace all variables successfully v2.1', async function () { + const output = replacePostmanVariables(VARIABLES_COLLECTION_V21) + equal(output, RESULT_V21) + }) + + it('should use additional vars', async function () { + const output = replacePostmanVariables(VARIABLES_COLLECTION_V2, { + company: 'myCompany', + service: 'myService' + }) + equal(output, RESULT_ADDITIONAL_V2) + }) + + it('should replace all variables successfully v2.1', async function () { + const output = replacePostmanVariables(VARIABLES_COLLECTION_V21, { + company: 'myCompany', + service: 'myService' + }) + equal(output, RESULT_ADDITIONAL_V21) + }) +})