├── .gitignore ├── .travis.yml ├── README.md ├── scripts └── test.sh ├── test ├── convert-spec.js ├── runscope1_postman.json ├── runscope1.json └── runscope2.json ├── package.json ├── .jshintrc ├── LICENSE ├── .jscsrc └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - '0.10' 5 | - '0.12' 6 | 7 | script: 8 | - npm test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # runscope-to-postman 2 | 3 | # Runscope-to-Postman [![Build Status](https://travis-ci.org/postmanlabs/runscope-to-postman.svg?branch=master)](https://travis-ci.org/postmanlabs/runscope-to-postman) 4 | 5 | Convert Runscope Radar Tests to Postman Collection v2 6 | 7 | npm test -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e; 4 | 5 | # echo "jscs v`jscs --version`"; 6 | # jscs ./index.js test/; 7 | 8 | # echo; 9 | 10 | jshint --version; 11 | jshint ./index.js test/; 12 | echo "No code lint issues found."; 13 | 14 | echo 15 | echo "Running unit tests..." 16 | echo "mocha v`mocha --version`"; 17 | 18 | mocha test/*-spec.js; 19 | -------------------------------------------------------------------------------- /test/convert-spec.js: -------------------------------------------------------------------------------- 1 | var expect = require('expect.js'), 2 | converter = require('../index.js'), 3 | fs = require('fs'); 4 | 5 | /* global describe, it */ 6 | describe('the converter', function () { 7 | it('must convert a basic runcope file', function () { 8 | var runscopeJson = fs.readFileSync('test/runscope2.json').toString(), 9 | convertedString = converter.convert(runscopeJson); 10 | //console.log(JSON.stringify(convertedString, null, 2)) 11 | expect(convertedString.name).to.be('MY TEST NAME'); 12 | }); 13 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@postman/runscope-to-postman", 3 | "version": "0.0.8", 4 | "description": "Convert Runscope Radar Tests to Postman Collection v2", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "registry": "https://npm.postmanlabs.com" 8 | }, 9 | "scripts": { 10 | "test": "scripts/test.sh" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/postmanlabs/runscope-to-postman.git" 15 | }, 16 | "keywords": [ 17 | "runscope", 18 | "postman" 19 | ], 20 | "dependencies": { 21 | "lodash": "^4.17.5", 22 | "uuid": "^3.2.1" 23 | }, 24 | "devDependencies": { 25 | "expect.js": "^0.3.1", 26 | "jscs": "^2.1.0", 27 | "jshint": "^2.8.0", 28 | "mocha": "^2.2.5" 29 | }, 30 | "author": "Postman Labs", 31 | "license": "MIT" 32 | } 33 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": false, 3 | "curly": true, 4 | "eqeqeq": false, 5 | "es3": false, 6 | "forin": false, 7 | "freeze": true, 8 | "immed": true, 9 | "indent": 1, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "noempty": true, 14 | "nonew": false, 15 | "plusplus": false, 16 | "quotmark": "single", 17 | "undef": true, 18 | "unused": true, 19 | "trailing": true, 20 | "asi": false, 21 | "boss": true, 22 | "debug": false, 23 | "eqnull": true, 24 | "evil": false, 25 | "expr": true, 26 | "funcscope": false, 27 | "globalstrict": false, 28 | "iterator": false, 29 | "lastsemic": false, 30 | "laxbreak": false, 31 | "laxcomma": false, 32 | "loopfunc": false, 33 | "maxlen": 120, 34 | "multistr": false, 35 | "notypeof": false, 36 | "proto": false, 37 | "scripturl": false, 38 | "smarttabs": false, 39 | "shadow": false, 40 | "sub": false, 41 | "supernew": false, 42 | 43 | "browser": false, 44 | "devel": false, 45 | "node": true, 46 | 47 | "onevar": true, 48 | 49 | "globals": { } 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Postman Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/runscope1_postman.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "a9b5466f-61f5-497c-a3ef-95e047720cba", 3 | "name": "MY TEST NAME", 4 | "description": "MY TEST DESC", 5 | "order": [ 6 | "d3cc5099-9ea3-421a-9b03-f55ebd2d8dd3", 7 | "03d8f53b-7ff7-408e-afd9-5658a56fe4ab", 8 | "a991ec5a-ffb2-41a0-97cf-f26112aae79d", 9 | "20fc1473-123a-4a42-8334-4eaec51c773c" 10 | ], 11 | "folders": [], 12 | "requests": [ 13 | { 14 | "id": "d3cc5099-9ea3-421a-9b03-f55ebd2d8dd3", 15 | "url": "http://httpbin.org/get?uk1=uk2", 16 | "headers": "hk2:hv2\nhk1:hv1\n", 17 | "pathVariables": {}, 18 | "method": "GET", 19 | "name": "http://httpbin.org/get?uk1=uk2", 20 | "description": "", 21 | "tests": "// You will need to convert this to a Postman-compliant script\nTEST SCRIPT 1;\nTEST SCRIPT 2;", 22 | "currentHelper": "basicAuth", 23 | "helperAttributes": { 24 | "id": "basic", 25 | "saveToRequest": true, 26 | "username": "BASIC_USERNAME", 27 | "password": "BASIC_PASSWORD" 28 | }, 29 | "preRequestScript": "// You will need to convert this to a Postman-compliant script\nPRESCRIPT 1\nPRE SCRIPT 2", 30 | "collectionId": "a9b5466f-61f5-497c-a3ef-95e047720cba" 31 | }, 32 | { 33 | "id": "03d8f53b-7ff7-408e-afd9-5658a56fe4ab", 34 | "url": "http://httpbin.org/post?uk1=uk2", 35 | "headers": "hk2:hv2\nhk1:hv1\n", 36 | "pathVariables": {}, 37 | "method": "POST", 38 | "name": "http://httpbin.org/post?uk1=uk2", 39 | "description": "", 40 | "tests": "// You will need to convert this to a Postman-compliant script\n", 41 | "dataMode": "raw", 42 | "data": "RAW BODY", 43 | "currentHelper": "basicAuth", 44 | "helperAttributes": { 45 | "id": "basic", 46 | "saveToRequest": true, 47 | "username": "", 48 | "password": "BASIC_PASSWORD" 49 | }, 50 | "preRequestScript": "// You will need to convert this to a Postman-compliant script\n", 51 | "collectionId": "a9b5466f-61f5-497c-a3ef-95e047720cba" 52 | }, 53 | { 54 | "id": "a991ec5a-ffb2-41a0-97cf-f26112aae79d", 55 | "url": "http://httpbin.org/post?uk1=uk2", 56 | "headers": "hk2:hv2\nhk1:hv1\n", 57 | "pathVariables": {}, 58 | "method": "POST", 59 | "name": "http://httpbin.org/post?uk1=uk2", 60 | "description": "", 61 | "tests": "// You will need to convert this to a Postman-compliant script\n", 62 | "dataMode": "urlencoded", 63 | "data": [ 64 | { 65 | "key": "fk1", 66 | "value": "fv1" 67 | } 68 | ], 69 | "currentHelper": "basicAuth", 70 | "helperAttributes": { 71 | "id": "basic", 72 | "saveToRequest": true, 73 | "username": "", 74 | "password": "BASIC_PASSWORD" 75 | }, 76 | "preRequestScript": "// You will need to convert this to a Postman-compliant script\n", 77 | "collectionId": "a9b5466f-61f5-497c-a3ef-95e047720cba" 78 | }, 79 | { 80 | "id": "20fc1473-123a-4a42-8334-4eaec51c773c", 81 | "url": "http://httpbin.org/post?uk1=uk2", 82 | "headers": "hk2:hv2\nhk1:hv1\nContent-Type:application/json\n", 83 | "pathVariables": {}, 84 | "method": "POST", 85 | "name": "http://httpbin.org/post?uk1=uk2", 86 | "description": "", 87 | "tests": "// You will need to convert this to a Postman-compliant script\n", 88 | "dataMode": "raw", 89 | "data": "{\r\n \"JSON BODY\": true\r\n}", 90 | "currentHelper": "basicAuth", 91 | "helperAttributes": { 92 | "id": "basic", 93 | "saveToRequest": true, 94 | "username": "", 95 | "password": "BASIC_PASSWORD" 96 | }, 97 | "preRequestScript": "// You will need to convert this to a Postman-compliant script\n", 98 | "collectionId": "a9b5466f-61f5-497c-a3ef-95e047720cba" 99 | } 100 | ], 101 | "timestamp": 1464167393703 102 | } -------------------------------------------------------------------------------- /test/runscope1.json: -------------------------------------------------------------------------------- 1 | { 2 | "trigger_url": "https://api.runscope.com/radar/a9b309bf-e614-484c-a1ca-a720c90ac331/trigger", 3 | "name": "MY TEST NAME", 4 | "version": "1.0", 5 | "exported_at": 1464167006, 6 | "steps": [ 7 | { 8 | "url": "http://httpbin.org/get?uk1=uk2", 9 | "variables": [], 10 | "args": {}, 11 | "step_type": "request", 12 | "auth": { 13 | "username": "BASIC_USERNAME", 14 | "auth_type": "basic", 15 | "password": "BASIC_PASSWORD" 16 | }, 17 | "fragment": "", 18 | "note": "", 19 | "headers": { 20 | "hk2": [ 21 | "hv2" 22 | ], 23 | "hk1": [ 24 | "hv1" 25 | ] 26 | }, 27 | "assertions": [ 28 | { 29 | "comparison": "equal_number", 30 | "value": 200, 31 | "source": "response_status" 32 | }, 33 | { 34 | "comparison": "equal", 35 | "property": "args.u1", 36 | "value": "k1", 37 | "source": "response_json" 38 | } 39 | ], 40 | "scripts": [ 41 | "TEST SCRIPT 1;", 42 | "TEST SCRIPT 2;" 43 | ], 44 | "before_scripts": [ 45 | "PRESCRIPT 1", 46 | "PRE SCRIPT 2" 47 | ], 48 | "data": "", 49 | "method": "GET" 50 | }, 51 | { 52 | "body": "RAW BODY", 53 | "form": {}, 54 | "url": "http://httpbin.org/post?uk1=uk2", 55 | "variables": [], 56 | "step_type": "request", 57 | "auth": { 58 | "username": "", 59 | "auth_type": "basic", 60 | "password": "BASIC_PASSWORD" 61 | }, 62 | "fragment": "", 63 | "note": "", 64 | "headers": { 65 | "hk2": [ 66 | "hv2" 67 | ], 68 | "hk1": [ 69 | "hv1" 70 | ] 71 | }, 72 | "assertions": [ 73 | { 74 | "comparison": "equal_number", 75 | "value": 200, 76 | "source": "response_status" 77 | }, 78 | { 79 | "comparison": "equal", 80 | "property": "args.u1", 81 | "value": "k1", 82 | "source": "response_json" 83 | } 84 | ], 85 | "scripts": [], 86 | "before_scripts": [], 87 | "method": "POST" 88 | }, 89 | { 90 | "body": "", 91 | "form": { 92 | "fk1": [ 93 | "fv1" 94 | ] 95 | }, 96 | "url": "http://httpbin.org/post?uk1=uk2", 97 | "variables": [], 98 | "step_type": "request", 99 | "auth": { 100 | "username": "", 101 | "auth_type": "basic", 102 | "password": "BASIC_PASSWORD" 103 | }, 104 | "fragment": "", 105 | "note": "", 106 | "headers": { 107 | "hk2": [ 108 | "hv2" 109 | ], 110 | "hk1": [ 111 | "hv1" 112 | ] 113 | }, 114 | "assertions": [ 115 | { 116 | "comparison": "equal_number", 117 | "value": 200, 118 | "source": "response_status" 119 | }, 120 | { 121 | "comparison": "equal", 122 | "property": "args.u1", 123 | "value": "k1", 124 | "source": "response_json" 125 | } 126 | ], 127 | "scripts": [], 128 | "before_scripts": [], 129 | "method": "POST" 130 | }, 131 | { 132 | "body": "{\r\n \"JSON BODY\": true\r\n}", 133 | "form": {}, 134 | "url": "http://httpbin.org/post?uk1=uk2", 135 | "variables": [], 136 | "step_type": "request", 137 | "auth": { 138 | "username": "", 139 | "auth_type": "basic", 140 | "password": "BASIC_PASSWORD" 141 | }, 142 | "fragment": "", 143 | "note": "", 144 | "headers": { 145 | "hk2": [ 146 | "hv2" 147 | ], 148 | "hk1": [ 149 | "hv1" 150 | ], 151 | "Content-Type": [ 152 | "application/json" 153 | ] 154 | }, 155 | "assertions": [ 156 | { 157 | "comparison": "equal_number", 158 | "value": 200, 159 | "source": "response_status" 160 | }, 161 | { 162 | "comparison": "equal", 163 | "property": "args.u1", 164 | "value": "k1", 165 | "source": "response_json" 166 | } 167 | ], 168 | "scripts": [], 169 | "before_scripts": [], 170 | "method": "POST" 171 | } 172 | ], 173 | "description": "MY TEST DESC" 174 | } -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | // "disallowAnonymousFunctions": false, 3 | // "disallowCapitalizedComments": false, 4 | // "disallowCommaBeforeLineBreak": false, 5 | "disallowDanglingUnderscores": true, 6 | "disallowEmptyBlocks": true, 7 | "disallowFunctionDeclarations": true, 8 | // "disallowImplicitTypeConversion": [], 9 | // "disallowKeywordsOnNewLine": [], 10 | "disallowKeywords": ["with"], 11 | "disallowMixedSpacesAndTabs": true, 12 | "disallowMultipleLineBreaks": true, 13 | "disallowMultipleLineStrings": true, 14 | // "disallowMultipleVarDecl": false, 15 | "disallowNewlineBeforeBlockStatements": true, 16 | // "disallowOperatorBeforeLineBreak": false, 17 | // "disallowPaddingNewlinesBeforeKeywords": false, 18 | "disallowPaddingNewlinesInBlocks": true, 19 | // "disallowPaddingNewLinesInObjects": false, 20 | // "disallowQuotedKeysInObjects": false, 21 | // "disallowSemicolons": false, 22 | // "disallowSpaceAfterBinaryOperators": false, 23 | // "disallowSpaceAfterKeywords": false, 24 | // "disallowSpaceAfterLineComment": false, 25 | // "disallowSpaceAfterObjectKeys": false, 26 | "disallowSpaceAfterPrefixUnaryOperators": true, 27 | // "disallowSpaceBeforeBinaryOperators": false, 28 | // "disallowSpaceBeforeBlockStatements": false, 29 | // "disallowSpaceBeforeKeywords": false, 30 | // "disallowSpaceBeforeObjectValues": false, 31 | "disallowSpaceBeforePostfixUnaryOperators": true, 32 | // "disallowSpaceBetweenArguments": false, 33 | // "disallowSpacesInAnonymousFunctionExpression": { 34 | // "beforeOpeningRoundBrace": false, 35 | // "beforeOpeningCurlyBrace": false 36 | // }, 37 | "disallowSpacesInCallExpression": true, 38 | // "disallowSpacesInConditionalExpression": { 39 | // "afterTest": false, 40 | // "beforeConsequent": false, 41 | // "afterConsequent": false, 42 | // "beforeAlternate": false 43 | // }, 44 | // "disallowSpacesInForStatement": false, 45 | // "disallowSpacesInFunctionDeclaration": { 46 | // "beforeOpeningRoundBrace": false, 47 | // "beforeOpeningCurlyBrace": false 48 | // }, 49 | // "disallowSpacesInFunctionExpression": { 50 | // "beforeOpeningRoundBrace": false, 51 | // "beforeOpeningCurlyBrace": false 52 | // }, 53 | // "disallowSpacesInFunctionExpression": { 54 | // "beforeOpeningRoundBrace": true, 55 | // "beforeOpeningCurlyBrace": true 56 | // }, 57 | // "disallowSpacesInNamedFunctionExpression": { 58 | // "beforeOpeningRoundBrace": false, 59 | // "beforeOpeningCurlyBrace": false 60 | // }, 61 | "disallowSpacesInsideArrayBrackets": "all", 62 | "disallowSpacesInsideObjectBrackets": "all", 63 | "disallowSpacesInsideParentheses": { "only": [ "{", "}" ] }, 64 | "disallowTrailingComma": true, 65 | "disallowTrailingWhitespace": true, 66 | // "disallowYodaConditions": false, 67 | "maximumLineLength": { 68 | "value": 120, 69 | "allowComments": false, 70 | "allowRegex": true 71 | }, 72 | 73 | // "requireAlignedObjectValues": false, 74 | // "requireAnonymousFunctions": false, 75 | "requireBlocksOnNewline": 2, 76 | "requireCamelCaseOrUpperCaseIdentifiers": true, 77 | // "requireCapitalizedComments": true, 78 | "requireCapitalizedConstructors": true, 79 | // "requireCommaBeforeLineBreak": false, 80 | "requireCurlyBraces": true, 81 | "requireDotNotation": "except_snake_case", 82 | // "requireFunctionDeclarations": false, 83 | "requireKeywordsOnNewLine": ["else", "catch", "case", "default", "finally"], 84 | "requireLineBreakAfterVariableAssignment": true, 85 | "requireLineFeedAtFileEnd": true, 86 | "requireMultipleVarDecl": "onevar", 87 | // "requireNewlineBeforeBlockStatements": false, 88 | "requireOperatorBeforeLineBreak": true, 89 | // "requirePaddingNewlinesBeforeKeywords": [], 90 | // "requirePaddingNewlinesInBlocks": false, 91 | // "requirePaddingNewlinesInBlocks": false, 92 | "requireParenthesesAroundIIFE": true, 93 | // "requireQuotedKeysInObjects": false, 94 | "requireSpaceAfterBinaryOperators": true, 95 | "requireSpaceAfterKeywords": true, 96 | "requireSpaceAfterLineComment": { 97 | "allExcept": ["!", "#", "%", "^", "*", "=", "?"] 98 | }, 99 | // "requireSpaceAfterObjectKeys": false, 100 | // "requireSpaceAfterPrefixUnaryOperators": false, 101 | "requireSpaceBeforeBinaryOperators": true, 102 | "requireSpaceBeforeBlockStatements": true, 103 | // "requireSpaceBeforeKeywords": false, 104 | "requireSpaceBeforeObjectValues": true, 105 | // "requireSpaceBeforePostfixUnaryOperators": false, 106 | "requireSpaceBetweenArguments": true, 107 | "requireSpacesInAnonymousFunctionExpression": { 108 | "beforeOpeningRoundBrace": true, 109 | "beforeOpeningCurlyBrace": true 110 | }, 111 | //"requireSpacesInCallExpression": false, 112 | "requireSpacesInConditionalExpression": { 113 | "afterTest": true, 114 | "beforeConsequent": true, 115 | "afterConsequent": true, 116 | "beforeAlternate": true 117 | }, 118 | "requireSpacesInForStatement": true, 119 | "requireSpacesInFunctionDeclaration": { 120 | "beforeOpeningRoundBrace": true, 121 | "beforeOpeningCurlyBrace": true 122 | }, 123 | "requireSpacesInFunctionExpression": { 124 | "beforeOpeningRoundBrace": true, 125 | "beforeOpeningCurlyBrace": true 126 | }, 127 | // "requireSpacesInNamedFunctionExpression": { 128 | // "beforeOpeningRoundBrace": true, 129 | // "beforeOpeningCurlyBrace": true 130 | // }, 131 | // "requireSpacesInsideArrayBrackets": false, 132 | "requireSpacesInsideObjectBrackets": "allButNested", 133 | // "requireSpacesInsideParentheses": false, 134 | // "requireTrailingComma": false, 135 | // "requireYodaConditions": false, 136 | // "safeContextKeyword": [ ], 137 | "validateIndentation": 4, 138 | "validateLineBreaks": "LF", 139 | "validateParameterSeparator": ", ", 140 | "validateQuoteMarks": "'" 141 | } 142 | -------------------------------------------------------------------------------- /test/runscope2.json: -------------------------------------------------------------------------------- 1 | { 2 | "trigger_url": "https://api.runscope.com/radar/a9b309bf-e614-484c-a1ca-a720c90ac331/trigger", 3 | "name": "MY TEST NAME", 4 | "version": "1.0", 5 | "exported_at": 1465133709, 6 | "steps": [ 7 | { 8 | "url": "http://httpbin.org/get?name=Request1", 9 | "variables": [], 10 | "args": {}, 11 | "step_type": "request", 12 | "auth": { 13 | "username": "BASIC_USERNAME", 14 | "auth_type": "basic", 15 | "password": "BASIC_PASSWORD" 16 | }, 17 | "note": "This is request 1", 18 | "headers": { 19 | "hk2": [ 20 | "hv2" 21 | ], 22 | "hk1": [ 23 | "hv1" 24 | ] 25 | }, 26 | "assertions": [ 27 | { 28 | "comparison": "equal_number", 29 | "value": 200, 30 | "source": "response_status" 31 | }, 32 | { 33 | "comparison": "equal", 34 | "property": "headers.property", 35 | "value": "headersEquals", 36 | "source": "response_headers" 37 | }, 38 | { 39 | "comparison": "not_equal", 40 | "property": "headers.property", 41 | "value": "does not equalValue", 42 | "source": "response_headers" 43 | }, 44 | { 45 | "comparison": "empty", 46 | "property": "headers.property", 47 | "value": null, 48 | "source": "response_headers" 49 | }, 50 | { 51 | "comparison": "not_empty", 52 | "property": "headers.property", 53 | "value": null, 54 | "source": "response_headers" 55 | }, 56 | { 57 | "comparison": "contains", 58 | "property": "headers.property", 59 | "value": "containsValue", 60 | "source": "response_headers" 61 | }, 62 | { 63 | "comparison": "does_not_contain", 64 | "property": "headers.property", 65 | "value": "doesNotContainValue", 66 | "source": "response_headers" 67 | }, 68 | { 69 | "comparison": "is_a_number", 70 | "property": "headers.property", 71 | "value": null, 72 | "source": "response_headers" 73 | }, 74 | { 75 | "comparison": "equal_number", 76 | "property": "headers.property", 77 | "value": "equalsNumber", 78 | "source": "response_headers" 79 | }, 80 | { 81 | "comparison": "is_less_than", 82 | "property": "headers.property", 83 | "value": "lessThanValue", 84 | "source": "response_headers" 85 | }, 86 | { 87 | "comparison": "is_less_than_or_equal", 88 | "property": "headers.property", 89 | "value": "<=Value", 90 | "source": "response_headers" 91 | }, 92 | { 93 | "comparison": "is_greater_than", 94 | "property": "headers.property", 95 | "value": ">value", 96 | "source": "response_headers" 97 | }, 98 | { 99 | "comparison": "is_greater_than_or_equal", 100 | "property": "headers.property", 101 | "value": ">=value", 102 | "source": "response_headers" 103 | }, 104 | { 105 | "comparison": "has_key", 106 | "property": "body.property", 107 | "value": "JsonbodyHasKey", 108 | "source": "response_json" 109 | }, 110 | { 111 | "comparison": "has_value", 112 | "property": "body.property", 113 | "value": "JsonbodyHasValue", 114 | "source": "response_json" 115 | }, 116 | { 117 | "comparison": "equal_number", 118 | "value": "responseSize=", 119 | "source": "response_size" 120 | }, 121 | { 122 | "comparison": "equal_number", 123 | "value": "responseTime=", 124 | "source": "response_time" 125 | }, 126 | { 127 | "comparison": "equal_number", 128 | "value": "StatusCode=", 129 | "source": "response_status" 130 | }, 131 | { 132 | "comparison": "equal", 133 | "value": "TextBodyEquals", 134 | "source": "response_text" 135 | }, 136 | { 137 | "comparison": "equal", 138 | "property": "xmlProp", 139 | "value": "XmlProp", 140 | "source": "response_xml" 141 | } 142 | ], 143 | "scripts": [ 144 | "TEST SCRIPT 1;", 145 | "TEST SCRIPT 2;" 146 | ], 147 | "fragment": "", 148 | "before_scripts": [ 149 | "PRESCRIPT 1", 150 | "PRE SCRIPT 2" 151 | ], 152 | "data": "", 153 | "method": "GET" 154 | }, 155 | { 156 | "body": "RAW BODY", 157 | "form": {}, 158 | "url": "http://httpbin.org/post?uk1=uk2", 159 | "variables": [], 160 | "step_type": "request", 161 | "auth": {}, 162 | "fragment": "", 163 | "note": "", 164 | "headers": { 165 | "hk2": [ 166 | "hv2" 167 | ], 168 | "hk1": [ 169 | "hv1" 170 | ] 171 | }, 172 | "assertions": [ 173 | { 174 | "comparison": "equal_number", 175 | "value": 200, 176 | "source": "response_status" 177 | }, 178 | { 179 | "comparison": "equal", 180 | "property": "args.u1", 181 | "value": "k1", 182 | "source": "response_json" 183 | } 184 | ], 185 | "scripts": [ 186 | "/**\n * TTTTTScript for request 2\n**/\n\n//Hello\n\nvar a = \"actual script line\";" 187 | ], 188 | "before_scripts": [ 189 | "/**\n * Script for request 2\n**/\n\n//Hello\n\nvar a = \"actual script line\";", 190 | "/**\n * Script for request 2.1\n**/\n\n//Hello.1\n\nvar a = \"actual script line.1\";" 191 | ], 192 | "method": "POST" 193 | }, 194 | { 195 | "body": "", 196 | "form": { 197 | "fk1": [ 198 | "fv1" 199 | ] 200 | }, 201 | "url": "http://httpbin.org/post?uk1=uk2", 202 | "variables": [], 203 | "step_type": "request", 204 | "auth": {}, 205 | "fragment": "", 206 | "note": "", 207 | "headers": { 208 | "hk2": [ 209 | "hv2" 210 | ], 211 | "hk1": [ 212 | "hv1" 213 | ] 214 | }, 215 | "assertions": [ 216 | { 217 | "comparison": "equal_number", 218 | "value": 200, 219 | "source": "response_status" 220 | }, 221 | { 222 | "comparison": "equal", 223 | "property": "args.u1", 224 | "value": "k1", 225 | "source": "response_json" 226 | } 227 | ], 228 | "scripts": [], 229 | "before_scripts": [], 230 | "method": "POST" 231 | }, 232 | { 233 | "body": "{\r\n \"JSON BODY\": true\r\n}", 234 | "form": {}, 235 | "url": "http://httpbin.org/post?uk1=uk2", 236 | "variables": [], 237 | "step_type": "request", 238 | "auth": {}, 239 | "fragment": "", 240 | "note": "", 241 | "headers": { 242 | "hk2": [ 243 | "hv2" 244 | ], 245 | "hk1": [ 246 | "hv1" 247 | ], 248 | "Content-Type": [ 249 | "application/json" 250 | ] 251 | }, 252 | "assertions": [ 253 | { 254 | "comparison": "equal_number", 255 | "value": 200, 256 | "source": "response_status" 257 | }, 258 | { 259 | "comparison": "equal", 260 | "property": "args.u1", 261 | "value": "k1", 262 | "source": "response_json" 263 | } 264 | ], 265 | "scripts": [], 266 | "before_scripts": [], 267 | "method": "POST" 268 | } 269 | ], 270 | "description": "MY TEST DESC" 271 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'), 2 | //SDK = require('postman-collection'), 3 | uuidv4 = require('uuid/v4'); 4 | 5 | // var runscopeConverterV2 = { 6 | // validateRunscope: function (runscopeJson) { 7 | // //validate 8 | // if (typeof runscopeJson === 'string') { 9 | // runscopeJson = JSON.parse(runscopeJson); 10 | // } 11 | 12 | // if (runscopeJson.hasOwnProperty('name') && 13 | // runscopeJson.hasOwnProperty('trigger_url')) { 14 | // return runscopeJson; 15 | // } 16 | // else { 17 | // throw { 18 | // 'message': 'Not a runscope test' 19 | // }; 20 | // } 21 | // }, 22 | 23 | // getHeadersForStep: function (runscopeJson, step) { 24 | // var retVal = []; 25 | // for (var prop in step) { 26 | // if (step.hasOwnProperty(prop)) { 27 | // retVal.push(new SDK.Header({ 28 | // key: prop, 29 | // value: step[prop][0] 30 | // })); 31 | // } 32 | // } 33 | // return retVal; 34 | // }, 35 | 36 | // getRequestsFromSteps: function (runscopeJson) { 37 | // var oldThis = this; 38 | // return _.map(runscopeJson.steps, function(step) { 39 | // console.log('URL: ' + step.url); 40 | // var r = new SDK.Request({ 41 | // url: step.url, 42 | // method: step.method 43 | // }); 44 | // r.headers = oldThis.getHeadersForStep(runscopeJson, step); 45 | // return r; 46 | // }); 47 | // }, 48 | 49 | // convert: function (runscopeJson) { 50 | // var oldThis = this; 51 | // runscopeJson = oldThis.validateRunscope(runscopeJson); 52 | // var collection = new SDK.Collection({ 53 | // info: { 54 | // name: runscopeJson.name, 55 | // description: runscopeJson.description 56 | // } 57 | // }); 58 | 59 | 60 | // var items = oldThis.getRequestsFromSteps(runscopeJson); 61 | // _.each(items, function (rItem) { 62 | // var cItem = new SDK.Item({ 63 | // id: uuid.v4(), 64 | // version: '1.0.0', 65 | // name: rItem.name, 66 | // request: rItem 67 | // }); 68 | // console.log('Added request: ' , rItem.toJSON()); 69 | // collection.items.add(cItem); 70 | // }); 71 | // //console.log(JSON.stringify(collection)); 72 | // } 73 | // }; 74 | 75 | 76 | var runscopeConverterV1 = { 77 | validateRunscope: function (runscopeJson) { 78 | //validate 79 | if(typeof runscopeJson === 'string') { 80 | runscopeJson = JSON.parse(runscopeJson); 81 | } 82 | 83 | if(runscopeJson.hasOwnProperty('name') && 84 | runscopeJson.hasOwnProperty('trigger_url')) { 85 | return runscopeJson; 86 | } 87 | else { 88 | throw { 89 | 'message': 'Not a runscope test' 90 | }; 91 | } 92 | }, 93 | 94 | initCollection: function (runscopeJson) { 95 | return { 96 | id: uuidv4(), 97 | name: runscopeJson.name, 98 | description: runscopeJson.description, 99 | order: [], 100 | folders: [], 101 | requests: [], 102 | timestamp: (new Date()).getTime() 103 | }; 104 | }, 105 | 106 | getPostmanHeadersFromRunscopeHeaders: function (runscopeHeaders) { 107 | var str = ''; 108 | for(var key in runscopeHeaders) { 109 | if(runscopeHeaders.hasOwnProperty(key)) { 110 | str += key+':'+runscopeHeaders[key]+'\n'; 111 | } 112 | } 113 | return str; 114 | }, 115 | 116 | addRequest: function (collection, request) { 117 | collection.order.push(request.id); 118 | request.collectionId = collection.id; 119 | collection.requests.push(request); 120 | }, 121 | 122 | handleAuth: function (request, step) { 123 | if(step.auth) { 124 | if (step.auth.auth_type === 'basic') { 125 | request.currentHelper = 'basicAuth'; 126 | request.helperAttributes = { 127 | id: 'basic', 128 | saveToRequest: true, 129 | username: step.auth.username, 130 | password: step.auth.password, 131 | }; 132 | } 133 | } 134 | //no other auth types supported yet 135 | //do oauth1 next 136 | }, 137 | 138 | handleData: function (request, step) { 139 | if((typeof step.body === 'string') && JSON.stringify(step.form) == '{}') { 140 | request.dataMode = 'raw'; 141 | request.data = step.body; 142 | } 143 | 144 | else if(step.form) { 145 | request.dataMode = 'urlencoded'; 146 | var formArray = []; 147 | for(var key in step.form) { 148 | if(step.form.hasOwnProperty(key)) { 149 | formArray.push({ 150 | key: key, 151 | value: step.form[key][0] 152 | }); 153 | } 154 | } 155 | request.data = formArray; 156 | } 157 | }, 158 | 159 | // handleAssertions: function (request, step) { 160 | // var tests = ''; 161 | // _.each(step.assertions, function(ass) { 162 | // }); 163 | // return tests; 164 | // }, 165 | 166 | handleScripts: function (request, step) { 167 | if(!step.before_scripts) { 168 | step.before_scripts = []; 169 | } 170 | 171 | request.preRequestScript = ''; 172 | 173 | var runscopePrScript = step.before_scripts.join('\n'); 174 | runscopePrScript = runscopePrScript.replace(/\n/g,'\n//'); 175 | if(!_.isEmpty(runscopePrScript)) { 176 | request.preRequestScript = '//==== You will need to convert this to a ' + 177 | 'Postman-compliant script ====\n' + 178 | '//==== (Select text and use Ctrl + / (Win) or Cmd + / (Mac) to uncomment ====\n' + 179 | '//' + runscopePrScript; 180 | } 181 | 182 | 183 | if(!step.scripts) { 184 | step.scripts = []; 185 | } 186 | var runscopeTestScript = step.scripts.join('\n'); 187 | runscopeTestScript = runscopeTestScript.replace(/\n/g,'\n//'); 188 | if(!_.isEmpty(runscopeTestScript)) { 189 | request.tests += '//==== You will need to convert this to a ' + 190 | 'Postman-compliant script ====\n' + 191 | '//==== (Select text and use Ctrl + / (Win) or Cmd + / (Mac) to uncomment ====\n' + 192 | '//' + runscopeTestScript; 193 | } 194 | }, 195 | 196 | getRHSFromComparisonAndOperands: function(comparison, oper1, oper2) { 197 | switch(comparison) { 198 | case 'equal_number': 199 | case 'equal': 200 | return oper1 + ' == ' + oper2; 201 | case 'not_equal': 202 | return oper1 + '!=' + oper2; 203 | case 'empty': 204 | return '_.isEmpty(' + oper1 + ')'; 205 | case 'not_empty': 206 | return '!_.isEmpty(' + oper1 + ')'; 207 | case 'contains': 208 | return '_.contains(' + oper1 + ')'; 209 | case 'does_not_contain': 210 | return '!_.contains(' + oper1 + ')'; 211 | case 'is_a_number': 212 | return '!isNaN('+oper1+')'; 213 | case 'is_less_than': 214 | return oper1 + ' < ' + oper2; 215 | case 'is_less_than_or_equal': 216 | return oper1 + ' <= ' + oper2; 217 | case 'is_greater_than': 218 | return oper1 + ' > ' + oper2; 219 | case 'is_greater_than_or_equal': 220 | return oper1 + ' >= ' + oper2; 221 | case 'has_key': 222 | return oper1 + '.hasOwnProperty(' + oper2 + ')'; 223 | case 'has_value': 224 | return '_.contains(_.values(' + oper1 + '), ' + oper2 + ')'; 225 | default: 226 | return ''; 227 | } 228 | }, 229 | 230 | handleAssertions: function (request, step) { 231 | var tests = '', 232 | oldThis = this; 233 | _.each(step.assertions, function (ass) { 234 | 235 | var testName = '', 236 | oper1 = null, 237 | oper2 = '\'' + ass.value + '\'', 238 | testScript = ''; 239 | 240 | // Handle source (LHS) 241 | switch(ass.source) { 242 | case 'response_status': 243 | testName += 'Status Code is correct'; 244 | oper1 = 'responseCode.code'; 245 | break; 246 | case 'response_headers': 247 | // this will have a property 248 | testName += '\''+ass.property+'\' Response Header is correct'; 249 | oper1 = 'postman.getResponseHeader(\''+ass.property+'\')'; 250 | break; 251 | case 'response_json': 252 | if(ass.property) { 253 | testName += 'Response.' + ass.property + ' is correct'; 254 | oper1 = 'JSON.parse(responseBody).'+ass.property; 255 | } 256 | else { 257 | testName += 'JSON Response is correct'; 258 | oper1 = 'JSON.parse(responseBody)'; 259 | } 260 | break; 261 | case 'response_size': 262 | testName += '//'; 263 | break; 264 | case 'response_text': 265 | testName += 'Response text is correct'; 266 | oper1 = 'responseBody'; 267 | break; 268 | case 'response_time': 269 | testName += 'Response time is correct'; 270 | oper1 = 'responseTime'; 271 | break; 272 | } 273 | 274 | if(oper1) { 275 | testScript = 'tests["' + testName + '"] = ' + 276 | oldThis.getRHSFromComparisonAndOperands(ass.comparison, oper1, oper2) + ';'; 277 | if(testScript.indexOf('JSON.parse') > -1) { 278 | testScript = 'try {\n\t' + testScript + '\n}\ncatch(e) {\n\t'+ 279 | 'tests["' + testName + '"] = false;\n\t' + 280 | 'console.log(\"Could not parse JSON\");\n}'; 281 | } 282 | tests += testScript + '\n\n'; 283 | } 284 | }); 285 | 286 | if(!_.isEmpty(tests)) { 287 | request.tests += '//==== This section is Postman-compliant ====\n' + 288 | tests + '\n'; 289 | } 290 | }, 291 | 292 | getRequestFromStep: function (step) { 293 | var oldThis = this; 294 | 295 | var request = { 296 | id: uuidv4(), 297 | url: step.url, 298 | headers: oldThis.getPostmanHeadersFromRunscopeHeaders(step.headers), 299 | pathVariables: {}, 300 | method: step.method, 301 | name: step.url, 302 | description: step.note, 303 | tests: '' 304 | }; 305 | 306 | oldThis.handleData(request, step); 307 | 308 | oldThis.handleAuth(request, step); 309 | 310 | oldThis.handleAssertions(request, step); 311 | 312 | oldThis.handleScripts(request, step); 313 | 314 | return request; 315 | }, 316 | 317 | convert: function (runscopeJson) { 318 | var oldThis = this; 319 | runscopeJson = this.validateRunscope(runscopeJson); 320 | var collection = this.initCollection(runscopeJson); 321 | 322 | _.each(runscopeJson.steps, function(step) { 323 | oldThis.addRequest(collection, oldThis.getRequestFromStep(step)); 324 | }); 325 | 326 | return collection; 327 | } 328 | }; 329 | 330 | module.exports = runscopeConverterV1; --------------------------------------------------------------------------------