From 7dc2267f0e5e0d540be2d288644cfa5d02addedd Mon Sep 17 00:00:00 2001 From: Shamasis Bhattacharya Date: Tue, 12 Jul 2016 16:41:58 +0530 Subject: [PATCH] Newman v3 initial development codebase and updated repository structure - windows compatible ci scripts "npm/*" - system tests - eslint - uses postman-runtime as underlying module --- .editorconfig | 16 + .eslintrc | 240 +++ .gitignore | 89 +- .jshintignore | 5 - .jshintrc | 14 - .npmignore | 38 + .nsprc | 4 + .travis.yml | 13 +- CHANGELOG.md | 214 -- Gruntfile.js | 72 - LICENSE => LICENSE.md | 8 +- NOTICE | 2 - README.md | 229 +- bin/newman | 268 --- bin/newman.js | 21 + index.js | 15 +- lib/index.js | 3 + lib/reporters/cli.js | 146 ++ lib/reporters/json.js | 0 lib/run.js | 65 + npm/test-integration.js | 6 + npm/test-lint.js | 40 + npm/test-system.js | 85 + npm/test-unit.js | 31 + npm/test.js | 12 + package.json | 100 +- scripts/preinstall.js | 12 - src/Newman.js | 134 -- src/models/CollectionModel.js | 145 -- src/models/FolderModel.js | 21 - src/models/ParentModel.js | 19 - src/models/RequestModel.js | 40 - src/models/ResultSummaryModel.js | 20 - .../AbstractResponseHandler.js | 88 - .../DefaultResponseHandler.js | 18 - .../ResponseHandlerFactory.js | 36 - src/responseHandlers/TestResponseHandler.js | 380 ---- src/runners/AbstractRunner.js | 21 - src/runners/CollectionRunner.js | 84 - src/runners/IterationRunner.js | 227 -- src/runners/RequestRunner.js | 341 --- src/templates/htmlResponseTemplate.js | 66 - src/templates/htmlResponseTemplate.jst | 90 - src/utilities/CsvHelper.js | 105 - src/utilities/ErrorHandler.js | 43 - src/utilities/EventEmitter.js | 39 - src/utilities/Globals.js | 48 - src/utilities/HelperProcessor.js | 670 ------ src/utilities/Helpers.js | 228 -- src/utilities/HtmlExporter.js | 28 - src/utilities/HttpStatusCodes.js | 290 --- src/utilities/Importer.js | 107 - src/utilities/Logger.js | 176 -- src/utilities/Options.js | 17 - src/utilities/PreRequestScriptProcessor.js | 286 --- src/utilities/Queue.js | 43 - src/utilities/ResponseExporter.js | 373 ---- src/utilities/Symbols.js | 18 - src/utilities/VariableProcessor.js | 188 -- src/utilities/oauth.js | 571 ----- test/system/nsp.test.js | 42 + test/system/repository.test.js | 175 ++ test/system/travis-yml.test.js | 31 + test/unit/run.test.js | 25 + tests/data/PostmanCollection.json | 372 ---- tests/data/data.csv | 3 - tests/data/data.json | 12 - tests/data/environment.json | 33 - tests/data/formdata.json | 88 - .../CommaTest.json.postman_collection | 42 - tests/integ_tests/caseInsenHeader.json | 32 - tests/integ_tests/clearVars.json | 69 - .../crypto-md5.json.postman_collection | 34 - tests/integ_tests/csvComma.csv | 2 - tests/integ_tests/d2.json | 1 - tests/integ_tests/d3.json | 1 - tests/integ_tests/e2.json | 23 - tests/integ_tests/e3.json | 51 - tests/integ_tests/echo-v2.json | 1894 ----------------- tests/integ_tests/esc.postman_collection | 47 - tests/integ_tests/esc.postman_environment | 23 - ...unction_var_replacement.postman_collection | 51 - tests/integ_tests/g3.json | 51 - .../hawkAuthTest.json.postman_collection | 46 - tests/integ_tests/headRequests.json | 56 - tests/integ_tests/helper.postman_collection | 107 - tests/integ_tests/multiValueData.json | 32 - ...multipleFormValues.json.postman_collection | 74 - .../newmangziptest.json.postman_collection | 35 - ...-var-in-url-params.json.postman_collection | 50 - .../prototypeCheck.json.postman_collection | 34 - tests/integ_tests/randomIntC.json | 52 - .../redirectTest.json.postman_collection | 34 - ...equestNameInScript.json.postman_collection | 34 - tests/integ_tests/semicolon_tests.json | 38 - tests/integ_tests/setNextRequest.json | 72 - tests/integ_tests/steph.json | 47 - tests/integ_tests/steph_data.csv | 3 - tests/integ_tests/tc2.json | 47 - tests/integ_tests/tc3.json | 50 - tests/integ_tests/tc4.json | 35 - tests/integ_tests/uploadFile.json | 4 - tests/integ_tests/varReplacement.json | 50 - .../AbstractResponseHandler.js | 29 - .../ResponseHandlerFactory.js | 32 - tests/responseHandlers/TestResponseHandler.js | 204 -- tests/runners/CollectionRunner.js | 43 - tests/runners/IterationRunner.js | 42 - tests/utilities/EventEmitter.js | 86 - tests/utilities/Queue.js | 35 - tests/utilities/VariableProcessor.js | 142 -- 111 files changed, 1068 insertions(+), 10255 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintrc delete mode 100644 .jshintignore delete mode 100644 .jshintrc create mode 100644 .npmignore create mode 100644 .nsprc delete mode 100644 Gruntfile.js rename LICENSE => LICENSE.md (98%) delete mode 100644 NOTICE delete mode 100755 bin/newman create mode 100755 bin/newman.js create mode 100644 lib/index.js create mode 100644 lib/reporters/cli.js create mode 100644 lib/reporters/json.js create mode 100644 lib/run.js create mode 100755 npm/test-integration.js create mode 100755 npm/test-lint.js create mode 100755 npm/test-system.js create mode 100755 npm/test-unit.js create mode 100755 npm/test.js delete mode 100644 scripts/preinstall.js delete mode 100644 src/Newman.js delete mode 100644 src/models/CollectionModel.js delete mode 100644 src/models/FolderModel.js delete mode 100644 src/models/ParentModel.js delete mode 100644 src/models/RequestModel.js delete mode 100644 src/models/ResultSummaryModel.js delete mode 100644 src/responseHandlers/AbstractResponseHandler.js delete mode 100644 src/responseHandlers/DefaultResponseHandler.js delete mode 100644 src/responseHandlers/ResponseHandlerFactory.js delete mode 100644 src/responseHandlers/TestResponseHandler.js delete mode 100644 src/runners/AbstractRunner.js delete mode 100644 src/runners/CollectionRunner.js delete mode 100644 src/runners/IterationRunner.js delete mode 100644 src/runners/RequestRunner.js delete mode 100644 src/templates/htmlResponseTemplate.js delete mode 100644 src/templates/htmlResponseTemplate.jst delete mode 100644 src/utilities/CsvHelper.js delete mode 100644 src/utilities/ErrorHandler.js delete mode 100644 src/utilities/EventEmitter.js delete mode 100644 src/utilities/Globals.js delete mode 100644 src/utilities/HelperProcessor.js delete mode 100644 src/utilities/Helpers.js delete mode 100644 src/utilities/HtmlExporter.js delete mode 100644 src/utilities/HttpStatusCodes.js delete mode 100644 src/utilities/Importer.js delete mode 100644 src/utilities/Logger.js delete mode 100644 src/utilities/Options.js delete mode 100644 src/utilities/PreRequestScriptProcessor.js delete mode 100644 src/utilities/Queue.js delete mode 100644 src/utilities/ResponseExporter.js delete mode 100644 src/utilities/Symbols.js delete mode 100644 src/utilities/VariableProcessor.js delete mode 100644 src/utilities/oauth.js create mode 100644 test/system/nsp.test.js create mode 100644 test/system/repository.test.js create mode 100644 test/system/travis-yml.test.js create mode 100644 test/unit/run.test.js delete mode 100644 tests/data/PostmanCollection.json delete mode 100644 tests/data/data.csv delete mode 100644 tests/data/data.json delete mode 100644 tests/data/environment.json delete mode 100644 tests/data/formdata.json delete mode 100644 tests/integ_tests/CommaTest.json.postman_collection delete mode 100644 tests/integ_tests/caseInsenHeader.json delete mode 100644 tests/integ_tests/clearVars.json delete mode 100644 tests/integ_tests/crypto-md5.json.postman_collection delete mode 100644 tests/integ_tests/csvComma.csv delete mode 100644 tests/integ_tests/d2.json delete mode 100644 tests/integ_tests/d3.json delete mode 100644 tests/integ_tests/e2.json delete mode 100644 tests/integ_tests/e3.json delete mode 100644 tests/integ_tests/echo-v2.json delete mode 100644 tests/integ_tests/esc.postman_collection delete mode 100644 tests/integ_tests/esc.postman_environment delete mode 100644 tests/integ_tests/function_var_replacement.postman_collection delete mode 100644 tests/integ_tests/g3.json delete mode 100644 tests/integ_tests/hawkAuthTest.json.postman_collection delete mode 100644 tests/integ_tests/headRequests.json delete mode 100644 tests/integ_tests/helper.postman_collection delete mode 100644 tests/integ_tests/multiValueData.json delete mode 100644 tests/integ_tests/multipleFormValues.json.postman_collection delete mode 100644 tests/integ_tests/newmangziptest.json.postman_collection delete mode 100644 tests/integ_tests/oauth1-var-in-url-params.json.postman_collection delete mode 100644 tests/integ_tests/prototypeCheck.json.postman_collection delete mode 100644 tests/integ_tests/randomIntC.json delete mode 100644 tests/integ_tests/redirectTest.json.postman_collection delete mode 100644 tests/integ_tests/requestNameInScript.json.postman_collection delete mode 100644 tests/integ_tests/semicolon_tests.json delete mode 100644 tests/integ_tests/setNextRequest.json delete mode 100644 tests/integ_tests/steph.json delete mode 100644 tests/integ_tests/steph_data.csv delete mode 100644 tests/integ_tests/tc2.json delete mode 100644 tests/integ_tests/tc3.json delete mode 100644 tests/integ_tests/tc4.json delete mode 100644 tests/integ_tests/uploadFile.json delete mode 100644 tests/integ_tests/varReplacement.json delete mode 100644 tests/responseHandlers/AbstractResponseHandler.js delete mode 100644 tests/responseHandlers/ResponseHandlerFactory.js delete mode 100644 tests/responseHandlers/TestResponseHandler.js delete mode 100644 tests/runners/CollectionRunner.js delete mode 100644 tests/runners/IterationRunner.js delete mode 100644 tests/utilities/EventEmitter.js delete mode 100644 tests/utilities/Queue.js delete mode 100644 tests/utilities/VariableProcessor.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..c8cb1c3ba --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.json] +indent_size = 2 + +[*.yml] +indent_size = 2 diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..8468dc776 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,240 @@ +{ + "plugins": [ + "security" + ], + "env": { + "browser": true, + "node": true + }, + "rules": { + // Possible Errors + "comma-dangle": ["error", "never"], + "no-cond-assign": "error", + "no-console": "off", + "no-constant-condition": "error", + "no-control-regex": "error", + "no-debugger": "error", + "no-dupe-args": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-empty": "error", + "no-empty-character-class": "error", + "no-ex-assign": "error", + "no-extra-boolean-cast": "error", + "no-extra-parens": "off", + "no-extra-semi": "error", + "no-func-assign": "error", + "no-inner-declarations": "off", + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-negated-in-lhs": "error", + "no-obj-calls": "error", + "no-regex-spaces": "error", + "no-sparse-arrays": "error", + "no-unexpected-multiline": "error", + "no-unreachable": "error", + "no-unsafe-finally": "error", + "use-isnan": "error", + "valid-jsdoc": "off", + "valid-typeof": "error", + + // Best Practices + "accessor-pairs": "error", + "array-callback-return": "error", + "block-scoped-var": "error", + "complexity": "off", + "consistent-return": "warn", + "curly": "error", + "default-case": "error", + "dot-location": ["error", "property"], + "dot-notation": "error", + "eqeqeq": "error", + "guard-for-in": "warn", + "no-alert": "error", + "no-caller": "error", + "no-case-declarations": "error", + "no-div-regex": "error", + "no-else-return": "error", + "no-empty-function": "error", + "no-empty-pattern": "error", + "no-eq-null": "error", + "no-eval": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-label": "error", + "no-fallthrough": "error", + "no-floating-decimal": "error", + "no-implicit-coercion": "error", + "no-implicit-globals": "error", + "no-implied-eval": "error", + "no-invalid-this": "error", + "no-iterator": "error", + "no-labels": "error", + "no-lone-blocks": "error", + "no-loop-func": "error", + "no-magic-numbers": "off", + "no-multi-spaces": "error", + "no-multi-str": "error", + "no-native-reassign": "error", + "no-new": "error", + "no-new-func": "error", + "no-new-wrappers": "error", + "no-octal": "error", + "no-octal-escape": "error", + // "_no-param-reassign": "error", + "no-proto": "error", + "no-redeclare": "error", + "no-return-assign": "error", + "no-script-url": "error", + "no-self-assign": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-throw-literal": "error", + "no-unmodified-loop-condition": "error", + "no-unused-expressions": "off", + "no-unused-labels": "error", + "no-useless-call": "error", + "no-useless-concat": "error", + "no-useless-escape": "error", + "no-void": "error", + "no-warning-comments": "off", + "no-with": "error", + "radix": "off", + // "vars-on-top": "error", + "wrap-iife": "error", + "yoda": "error", + + // Strict Mode + "strict": "off", + + // Variables + "init-declarations": "off", + "no-catch-shadow": "error", + "no-delete-var": "error", + "no-label-var": "error", + "no-restricted-globals": "error", + //"no-shadow": "error", + "no-shadow-restricted-names": "error", + "no-undef": "off", + "no-undef-init": "error", + "no-undefined": "off", + "no-unused-vars": "error", + "no-use-before-define": "error", + + // Stylistic Issues + "array-bracket-spacing": "error", + "block-spacing": "error", + "brace-style": [2, "stroustrup", { "allowSingleLine": true }], + "camelcase": "off", + "comma-spacing": [2, { "before": false, "after": true }], + "comma-style": ["error", "last"], + "computed-property-spacing": "error", + "consistent-this": "warn", + "eol-last": "error", + "func-names": "off", + "func-style": "off", + "id-blacklist": "error", + "id-length": "off", + "id-match": "error", + "indent": ["error", 4, { + "VariableDeclarator": { "var": 1, "let": 1, "const": 1 }, + "SwitchCase": 1, + }], + "jsx-quotes": ["error", "prefer-single"], + "key-spacing": "error", + "keyword-spacing": "error", + "linebreak-style": ["error", "unix"], + "lines-around-comment": ["error", { + "beforeBlockComment": true, + "afterBlockComment": false, + "beforeLineComment": false, + "afterLineComment": false, + "allowBlockStart": true, + "allowBlockEnd": false, + "allowObjectStart": true, + "allowObjectEnd": false, + "allowArrayStart": true, + "allowArrayEnd": false + }], + "max-depth": "error", + "max-len": "off", + "max-nested-callbacks": "error", + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": "off", + "new-cap": "off", + "new-parens": "error", + "newline-after-var": ["off", "always"], + "newline-before-return": "off", + "newline-per-chained-call": "off", + "no-array-constructor": "error", + // "no-bitwise": "error", + // "no-continue": "error", + "no-inline-comments": "off", + "no-lonely-if": "error", + "no-mixed-spaces-and-tabs": "error", + "no-multiple-empty-lines": "error", + "no-negated-condition": "off", + "no-nested-ternary": "off", + "no-new-object": "error", + "no-plusplus": "off", + "no-restricted-syntax": "error", + "no-spaced-func": "error", + "no-ternary": "off", + "no-trailing-spaces": "error", + "no-underscore-dangle": "off", + "no-unneeded-ternary": "error", + "no-whitespace-before-property": "error", + "object-curly-spacing": "error", + "one-var": ["error", "always"], + "one-var-declaration-per-line": "error", + "operator-assignment": "error", + "operator-linebreak": ["error", "after"], + "padded-blocks": "off", + "quote-props": "off", + "quotes": ["error", "single"], + "require-jsdoc": "warn", + "semi": "error", + "semi-spacing": "error", + "sort-vars": "off", + "space-before-blocks": "error", + "space-in-parens": "error", + "space-infix-ops": "error", + "space-unary-ops": "error", + "spaced-comment": ["error", "always", { + "block": { + "exceptions": ["!"] + } + }], + "wrap-regex": "error", + + // ECMAScript 6 + "arrow-body-style": ["error", "always"], + "arrow-parens": ["error", "always"], + "arrow-spacing": "error", + "constructor-super": "error", + "generator-star-spacing": "error", + "no-class-assign": "error", + "no-confusing-arrow": "error", + "no-const-assign": "error", + "no-dupe-class-members": "error", + "no-duplicate-imports": "error", + "no-new-symbol": "error", + "no-restricted-imports": "error", + "no-this-before-super": "error", + "no-useless-computed-key": "error", + "no-useless-constructor": "off", + "no-var": "off", + "object-shorthand": "off", + // "_prefer-arrow-callback": "error", + "prefer-const": "off", + "prefer-reflect": "off", + // "prefer-rest-params": "error", + "prefer-spread": "error", + "prefer-template": "off", + "require-yield": "error", + "sort-imports": "off", + "template-curly-spacing": "error", + "yield-star-spacing": "error" + } +} diff --git a/.gitignore b/.gitignore index acf86c5d4..adabf0392 100644 --- a/.gitignore +++ b/.gitignore @@ -1,59 +1,38 @@ -node_modules/ -docs/* -.idea/* -./*.postman_collection -./*.globals +# PLATFORM +# ======== +# All exclusions that are specific to the NPM, GIT, IDE and Operating Systems. +# - Do not allow installed node modules to be committed. Doing `npm install -d` will bring them in root or other places. +node_modules -#Visual Studio Code specific files -.vscode/* -jsconfig.json +# - Do not commit any log file from anywhere +*.log +*.log.* -#ctags -tags -src/tags -tests/tags - -#Custom files - to prevent inclusion in npm package +# - Prevent addition of OS specific file explorer files +Thumbs.db .DS_Store -Angelist%20API.json.postman_collection -Backup.postman_dump -Backup2 -authPost.postman_collection -baHelper.postman_collection -c1.json.postman_collection -c2.json -c3.json.postman_collection -cstat.json.postman_collection -data/ -dauth.json.postman_collection -e.postman_environment -fileTest.postman_collection -globals.postman_globals -h.html -headerTest.json.postman_collection -helper.postman_collection -ht.html -jqTest.json.postman_collection -junit.xml -nmRegex.json.postman_collection -noctest.json.postman_collection -nodeserver.js -o.json -oauth.json.postman_collection -oauth.postman_collection -orderTest.json.postman_collection -outfile.json -postCollection.json.postman_collection -rep.html -split.postman_collection -src/templates/temp -statusChecj.json.postman_collection -td.csv -tem/ -testC1.json -testpost.js -tests/data/data1.json -tests/integ_tests/dCSV.csv - -npm-debug.log* + +# Prevent IDE stuff +.idea + + +# PROJECT +# ======= +# Configuration pertaining to project specific repository structure. + +# - Prevent Sublime text IDE files from being commited to repository +*.sublime-* + +# - Allow sublime text project file to be commited in the development directory. +!/develop/*.sublime-project + +# - Prevent CI output files from being Added +/out/ + +# - Prevent diff backups from SourceTree from showing as commit. +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*.orig diff --git a/.jshintignore b/.jshintignore deleted file mode 100644 index 3eab4a562..000000000 --- a/.jshintignore +++ /dev/null @@ -1,5 +0,0 @@ -src/utilities/oauth.js -src/utilities/HelperProcessor.js -src/utilities/CsvHelper.js -src/templates/htmlResponseTemplate.js - diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 08a220f9c..000000000 --- a/.jshintrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "curly": true, // true: Require {} for every new block or scope - "eqeqeq": true, // true: Require triple equals (===) for comparison - "immed": true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` - "noarg": true, // true: Prohibit use of `arguments.caller` and `arguments.callee` - "sub": true, // true: Tolerate using `[]` notation when it can still be expressed in dot notation - "undef": true, // true: Require all non-global variables to be declared (prevents global leaks) - "unused": "vars", // true: This option warns when you define and never use your variables. It is very useful for general code cleanup, especially when used in addition to undef. - "boss": true, // true: Tolerate assignments where comparisons would be expected - "eqnull": true, // true: Tolerate use of `== null` - "trailing": true, - "multistr": true, - "node": true // Node.js -} diff --git a/.npmignore b/.npmignore new file mode 100644 index 000000000..adabf0392 --- /dev/null +++ b/.npmignore @@ -0,0 +1,38 @@ +# PLATFORM +# ======== +# All exclusions that are specific to the NPM, GIT, IDE and Operating Systems. + +# - Do not allow installed node modules to be committed. Doing `npm install -d` will bring them in root or other places. +node_modules + +# - Do not commit any log file from anywhere +*.log +*.log.* + +# - Prevent addition of OS specific file explorer files +Thumbs.db +.DS_Store + +# Prevent IDE stuff +.idea + + +# PROJECT +# ======= +# Configuration pertaining to project specific repository structure. + +# - Prevent Sublime text IDE files from being commited to repository +*.sublime-* + +# - Allow sublime text project file to be commited in the development directory. +!/develop/*.sublime-project + +# - Prevent CI output files from being Added +/out/ + +# - Prevent diff backups from SourceTree from showing as commit. +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*.orig diff --git a/.nsprc b/.nsprc new file mode 100644 index 000000000..06ae68a40 --- /dev/null +++ b/.nsprc @@ -0,0 +1,4 @@ +{ + "exceptions": [], + "exclusions": ["postman-collection", "postman-runtime"] +} diff --git a/.travis.yml b/.travis.yml index fd744a1e1..c5da781db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,3 @@ language: node_js node_js: - - "4" - - "5" -before_install: npm install -g grunt-cli -install: npm install -# deploy: -# provider: npm -# email: help@getpostman.com -# api_key: -# secure: lL/1+mZAroisLT8OCF4vmPVvUz7WDjQbtIMLlbm4aHoYCu8Yg/dY00RCUZsdz0FluMu7C+hgU2nNcKUu5NJe8ve5sLY+ghaK1RAuzyHv055fhbYcw6wcMHs5nBgZW+FSpv+E/jhiWH6iWzj7bcsIDC2NZBdfDV8oOafqJFUp7eU= -# on: -# tags: true -# repo: postmanlabs/newman + - '4' diff --git a/CHANGELOG.md b/CHANGELOG.md index 44258e8a2..e69de29bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,214 +0,0 @@ -##CHANGELOG - -####2.1.2 (June 30, 2016) -* Latest version of the transformer -* Fixed a bug where requests containing files from the Cloud API were not handled correctly - -####2.1.1 (June 07, 2016) -* Latest version of the transformer -* Fixed #402 (Newman breaks if header is empty) -* Update lodash version, fixes #418 -* Fixed #406 (Newman breaks with underscore 1.5.2) - -####2.1.0 (May 26, 2016) -* Added support for cloud APIs - -####2.0.9 (April 22, 2016) -* Fixed a bug where OAuth1 helper failed with URLs containing variables. (postman-app-support#2011) - -####2.0.8 (April 18, 2016) -* Better handling of Request timeouts (@ramblinwreck35) -* Fixed errors with HEAD requests on Node v5 -* Support for "deflate" encoding - -####2.0.7 (April 13, 2016) -* Fixed #377 (Function variables in the request body not being replaced) - -####2.0.6 (April 05, 2016) -* Fixed redirect behavior (redirects on POST requests are now followed by default) -* Added an option to replace Unicode symbols with text (for older terminals) - -####2.0.5 (March 24, 2016) -* Fixed Postman.GH#1903 (request.data object inside the sandbox) -* Fixed #361 (Better formatting of HTML report) -* Fixed a bug in Hawk Auth, where nonce generation resulted in an error - -####2.0.4 (March 24, 2016) -* Allow PATCH and DELETE requests to have a request body, fixes GH#360 - -####2.0.3 (March 18, 2016) -* Fixed listeners not being removed after a collection -* Added support for postman.setNextRequest - -####2.0.2 (March 15, 2016) -* removed check for empty strings from CSV to be consistent with Postman (by @bwolski) -* Fixed AWS Auth with raw body (Github #345) - -####2.0.1 (March 01, 2016) -* Added support for custom ports in AWS Signature v4 auth (by @harshavardhana) -* Updated postman-collection-transformer version - -####2.0.0 (February 25, 2016) -* Dropped support for Node v0.10 and v0.12 -* Added support for running collections in the new collection format (Details: schema.getpostman.com) -* Bugfix for AWS Auth with a service name [User contributed] - -####1.3.0 (February 17, 2016) -* Added support for console.* functions (error, warn) -* Fixed a bug which caused a crash when the request data is empty - -####1.2.29 (February 02, 2016) -* Fixed #310 (Better error messages) -* Fixed #311 (Response body logging in verbose output) -* Fixed #320 (Variable replacement for special variables "{{$guid}}" etc) - -####1.2.28 (January 08, 2016) -* Fixed handling of null values to be compatible with Postman -* Fixed a bug in handling of OAuth - -####1.2.27 (December 18, 2015) -* Set default service name to API Gateway for AWS Authentication - -####1.2.26 (December 18, 2015) -* Fixed json traversal https://github.com/postmanlabs/newman/issues/301 -* Added support for AWS Signature v4 authentication - -####1.2.25 (December 01, 2015) -* Added support for Hawk Authentication - -####1.2.24 (November 27, 2015) -* Added `name` and `description` to request object in the Sandbox -* Fixed null OAuth params https://github.com/postmanlabs/postman-app-support/issues/1543 -* Fixed a bug where GZip requests failed for no reason - -####1.2.23 (October 20, 2015) -* Empty data array fields don't cause errors - -####1.2.22 (October 18, 2015) -* Adding option to limit recursive resolution depth - -####1.2.21 (September 24, 2015) -* Adding --whiteScreen flag -* Adding option to print all requests and responses in a file - -####1.2.20 (September 24, 2015) -* Adding -R option to block redirects -* Adding sugarJS number prototype -* Adding clearVariables sandbox function - -####1.2.19 (September 14, 2015) -* Fix for https://github.com/postmanlabs/postman-app-support/issues/1329 (Backslashes in variables) -* JSON.parse shows parsing errors, if any - -####1.2.18 (August 7, 2015) -* When used as a library, the callback returns the exit code correctly -* Form fields that are disabled are not sent -* CryptoJS (https://code.google.com/p/crypto-js/) available in the test/pre-request script sandbox -* Repository link updated in CLI - -####1.2.17 (July 1, 2015) -* -x / --exitCode works correctly in standalone/library mode - -####1.2.16 (June 18, 2015) -* Custom paths to export environment/global files after the run -* Support for custom request timeouts -* Jenkins-compatible JUnit output - -####1.2.15 (March 19, 2015) -* Support for authentication helpers (Basic, Digest, OAuth1.0) - -####1.2.14 (March 13, 2015) -* Removing dead code for BOM-removal. This also fixes zero-length body cases -* Adding support for commas in data file fields, and double-quotes to surround fields (in line with Postman) - -####1.2.13 (February 24, 2015) -* Set Jsdom version to 3.x.x for NodeJS-compatibility - -####1.2.11/12 (February 13, 2015) -* Node v0.12.0 supported - -####1.2.10 (February 13, 2015) -* Incorrect rawModeData being handled properly -* New sandbox method - xml2Json added. Compatible with POSTMAN -* Envs and Globals set in scripts are available in the env and global arrays instantly - -####1.2.9 (February 2, 2015) -* SugarJS object definitions working as expected - https://github.com/a85/Newman/issues/176 - -####1.2.8 (January 30, 2015) -* Spaces in variable names working - -####1.2.7 (January 20, 2015) -* Accepting truthy/falsy values as test results - -####1.2.6 (January 17, 2015) -* Fixing tests for different names across iterations - -####1.2.5 (January 14, 2015) -* Correcting jUnit export format -* Test results are now parsed consistently (truthy/falsy values are accepted) - -####1.2.4 (December 20, 2014) -* Fixed command-line flag for HTML report - -####1.2.3 (December 16, 2014) -* Fixed jQuery dependecny issue - -####1.2.1 (December 8, 2014) -* Added HTML reporting capability - -####1.2.0 (December 2, 2014) -* Adding option for jUnit-style output of test runs - Courtesy @pal-thomassen (BETA) -* Configurable SSL/TLS behavior while running collections - Courtesy @gituser4 - -####1.1.9 (November 4, 2014) -* Summary correctly shown for folder-only runs - -####1.1.8 (November 4, 2014) -* Iteration-wise summary is shown by default - -####1.1.7 (October 23, 2014) -* postman.clearEnvironmentVariables() and postman.clearGlobalVariables() available to clear environment and global variables -* postman.getResponseHeader(headerKey) available to get response headers in a case-insensitive manner - -####1.1.6 (September 30, 2014) -* Postman backup files can now be imported - -####1.1.5 (September 22, 2014) -* Test cases with semicolons in them work properly -* HttpStatusCodes and descriptions are in-line with Postman - -####1.1.4 (September 18, 2014) -* Corrected version nummber - -####1.1.3 (September 17, 2014) -* {{$randomInt}} works as expected -* {{$guid}} functionality added -* atob and btoa functions now available in tests and pre-request scripts -* Added an option to exit with code=1 if any test in the collection fails - -####1.1.2 (September 13, 2014) -* Ability to add a delay between requests - -####1.1.1 (September 2, 2014) -* Newman handles the latest version of Postman collections - -####1.1.0 (August 19, 2014) -* If used as a library, the exit code is now passed to the callback function - - -####1.0.9 (July 29, 2014) -* Header names are now converted to title case (Content-Type, instead of content-type) -* An explicit iteration count overrides the data-file -* No separate global file is needed to use global variables - - -####1.0.7 (July 7, 2014) -* Https requests are now handled by newman. -* Form data can now be taken from data files -* No separate environment file needs to be specified to use env. variables -* Wrong env file paths print a human-readable error message -* "http://" is prefixed to urls without (if not already present) -* Data files do not overwrite all env properties -* Can run only folders by specifying -f -* Pre-Request scripting diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 62bdcf6dd..000000000 --- a/Gruntfile.js +++ /dev/null @@ -1,72 +0,0 @@ -module.exports = function (grunt) { - // defining tasks - grunt.initConfig({ - jshint: { - all: ['src/*.js', 'src/**/*.js'], - options: { - jshintrc: '.jshintrc' - } - }, - jsdoc: { - dist: { - src: ['src/*.js', 'src/**/*.js', 'tests/**/*.js'], - options: { - destination: 'docs' - } - } - }, - mochaTest: { - test: { - options: { - reporter: 'spec', - timeout: 200, - slow: 200 - }, - src: ["tests/**/*.js"] - } - }, - run: { - integTest: { - exec: 'node bin/newman -c tests/integ_tests/tc2.json -d tests/integ_tests/d2.json -e tests/integ_tests/e2.json -s && ' + - 'node bin/newman -c tests/integ_tests/tc3.json -d tests/integ_tests/d3.json -e tests/integ_tests/e3.json -g tests/integ_tests/g3.json -s && ' + - 'node bin/newman -c tests/integ_tests/tc4.json -s && ' + - 'node bin/newman -c tests/integ_tests/randomIntC.json -s && ' + - 'node bin/newman -c tests/integ_tests/semicolon_tests.json -s && ' + - 'node bin/newman -c tests/integ_tests/varReplacement.json -s && ' + - 'node bin/newman -c tests/integ_tests/clearVars.json -s && ' + - 'node bin/newman -c tests/integ_tests/helper.postman_collection -n 3 -s && ' + - 'node bin/newman -c tests/integ_tests/steph.json -s -d tests/integ_tests/steph_data.csv -n 2 -s && ' + - 'node bin/newman -c tests/integ_tests/caseInsenHeader.json -s && ' + - 'node bin/newman -c tests/integ_tests/CommaTest.json.postman_collection -d tests/integ_tests/csvComma.csv -s && ' + - 'node bin/newman -c tests/integ_tests/crypto-md5.json.postman_collection -s && ' + - 'node bin/newman -c tests/integ_tests/esc.postman_collection -e tests/integ_tests/esc.postman_environment -s && ' + - 'node bin/newman -c tests/integ_tests/prototypeCheck.json.postman_collection -s && ' + - 'node bin/newman -c tests/integ_tests/redirectTest.json.postman_collection -s -R && ' + - 'node bin/newman -c tests/integ_tests/requestNameInScript.json.postman_collection -s && ' + - 'node bin/newman -c tests/integ_tests/multipleFormValues.json.postman_collection -s &&' + - 'node bin/newman -c tests/integ_tests/randomIntC.json -s -W &&' + - 'node bin/newman -c tests/integ_tests/newmangziptest.json.postman_collection -s &&' + - 'node bin/newman -c tests/integ_tests/hawkAuthTest.json.postman_collection -s &&' + - 'node bin/newman -c tests/integ_tests/echo-v2.json -s &&' + - 'node bin/newman -c tests/integ_tests/multiValueData.json -s &&' + - 'node bin/newman -c tests/integ_tests/setNextRequest.json -s -n 2 &&' + - 'node bin/newman -c tests/integ_tests/headRequests.json -s &&' + - 'node bin/newman -c tests/integ_tests/function_var_replacement.postman_collection -s &&' + - 'node bin/newman -c tests/integ_tests/oauth1-var-in-url-params.json.postman_collection -s' - } - } - }); - - // plugins - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-jsdoc'); - grunt.loadNpmTasks('grunt-mocha-test'); - grunt.loadNpmTasks('grunt-run'); - - // register tasks - grunt.registerTask('prepare_release', ['lint', 'mochaTest', 'jsdoc']); - grunt.registerTask('default', ['mochaTest', 'jsdoc', 'jshint']); - grunt.registerTask('test', ['mochaTest', 'jshint', 'run:*']); - grunt.registerTask('integ_test', ['run:*']); - grunt.registerTask('docs', 'jsdoc'); -}; diff --git a/LICENSE b/LICENSE.md similarity index 98% rename from LICENSE rename to LICENSE.md index ad410e113..632c64b84 100644 --- a/LICENSE +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Apache License + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -175,6 +175,7 @@ Apache License END OF TERMS AND CONDITIONS + APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following @@ -186,7 +187,7 @@ Apache License same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright 2016 Postdot Technologies, Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -198,4 +199,5 @@ Apache License distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. + diff --git a/NOTICE b/NOTICE deleted file mode 100644 index c44ba8118..000000000 --- a/NOTICE +++ /dev/null @@ -1,2 +0,0 @@ -Newman -Copyright 2014 Abhinav Asthana diff --git a/README.md b/README.md index 9c35146f2..4e7ca0c7f 100644 --- a/README.md +++ b/README.md @@ -1,228 +1 @@ - - -# Newman [![Build Status](https://travis-ci.org/postmanlabs/newman.svg?branch=master)](https://travis-ci.org/postmanlabs/newman) - -**Update Feb 25 2016:** Newman v2 (which only works with Node v4.0+) has been released. If you are using Node v0.10 or Node v0.12, check the supported Node versions below. - -Newman is a command-line collection runner for [Postman](http://getpostman.com). It allows you to effortlessly run and test a Postman collection directly from the command-line. It is built with extensibility in mind so that you can easily integrate it with your continuous integration servers and build systems. - -Newman maintains feature parity with Postman and allows you to run collections just the way they are executed inside the collection runner in Postman. - -[![NPM](https://nodei.co/npm/newman.png?downloads=true)](https://nodei.co/npm-dl/newman/) - - -## Supported Node Versions - -| Node Version | Newman Version | Installation Command | -|-----------------|----------------|------------------------------| -| 0.10.x - 0.12.x | 1.x.x | `npm install -g newman@1` | -| 4.0+ | 2.x.x+ | `npm install -g newman` | - -##### DOM Deprecation -Keeping in line with the [Postman Sandbox](https://www.getpostman.com/docs/sandbox) roadmap, the next major version of Newman (`v3.0.0+`) will drop support for DOM (and associated libraries such as jQuery and Backbone) inside the tests. Any tests that you might have, which use these libraries might break. - -## Getting Started -Newman is built on Node.js. To run Newman, make sure you have Node.js installed. Node.js can be downloaded and installed from [here](http://nodejs.org/download/) on Linux, Windows and Mac OSX. - -#### Updating Newman -If you already have Newman, you can update with a simple command -```bash -$ npm update -g newman -``` - -#### Running Newman -The easiest way to run Newman is to run it with a collection. With the `-c` flag you can run any collection file lying on your file-system. Refer [the collection documentation](http://www.getpostman.com/docs/collections) to learn how to use and download collections. - -```bash -$ newman -c mycollection.json -``` - -The `-u` flag allows you to pass a postman collection as a URL. Your collection probably uses environment variables. To provide an accompanying set of environment variables, [export them from Postman](http://www.getpostman.com/docs/environments) and run them with the `-e` flag. -```bash -$ newman -u https://www.getpostman.com/collections/cb208e7e64056f5294e5 -e devenvironment.json -``` - -## Options -Newman provides a rich set of options to customize a run. A list of options can be retrieved by running it with the `-h` flag. - -```bash -$ newman -h - -Options: - -Utility: --h, --help output usage information --V, --version output the version number - -Basic setup: --c, --collection [file] Specify a Postman collection as a JSON [file] --u, --url [url] Specify a Postman collection as a [url] --f, --folder [folderName] Specify a single folder to run from a collection. To be used with -c or -u. --e, --environment [file] Specify a Postman environment as a JSON [file] ---environment-url [url] Specify a Postman environment as a URL [url] --d, --data [file] Specify a data file to use either json or csv --g, --global [file] Specify a Postman globals file as JSON [file] --n, --number [number] Define the number of iterations to run --i, --import [file] Import a Postman backup file, and save collections, environments, and globals. [file] --p, --pretty (Use with -i) Enable pretty-print while saving imported collections, environments, and globals --G, --exportGlobals [file] Specify an output file to dump Globals before exiting [file] --E, --exportEnvironment [file] Specify an output file to dump the Postman environment before exiting [file] - -Request options: --y, --delay [number] Specify a delay (in ms) between requests [number] --r, --requestTimeout [number] Specify a request timeout (in ms) for a request (Defaults to 15000 if not set) - -Misc.: --s, --stopOnError Stops the runner when a test case fails --j, --noSummary Does not show the summary for each iteration --C, --noColor Disable colored output --S, --noTestSymbols Disable symbols in test output and use PASS|FAIL instead --k, --insecure Disable strict ssl --l, --tls Use TLSv1 --x, --exitCode Continue running tests even after a failure, but exit with code=1 --W, --whiteScreen Black text for white screen - - -Output: --o, --outputFile [file] Path to file where output should be written. [file] --t, --testReportFile [file] Path to file where results should be written as JUnit XML [file] --H, --html Export a HTML report to a specified file [file] --O, --outputFileVerbose [file] Path to file where full request and responses should be logged [file] - -``` - -Use the `-n` option to set the number of iterations you want to run the collection for. - -```bash -$ newman -c mycollection.json -n 10 # runs the collection 10 times -``` - -To provide a different set of data i.e. variables for each iteration you can use the `-d` to specify a `json` or `csv` file. For example, a data file such as the one shown below will run *2* iterations, with each iteration using a set of variables. -```javascript -[{ - "url": "http://127.0.0.1:5000", - "user_id": "1", - "id": "1", - "token_id": "123123", -}, -{ - "url": "http://dump.getpostman.com", - "user_id": "2", - "id": "2", - "token_id": "899899", -}] -``` - -```bash -$ newman -c mycollection.json -d data.json -``` - -The csv file for the above set of variables would look like -``` -url, user_id, id, token_id -http://127.0.0.1:5000, 1, 1, 123123123 -http://dump.getpostman.com, 2, 2, 899899 -``` - -Newman, by default exits with a status code of 0 if everything runs well i.e. without any exceptions. Continuous integration tools respond to these exit codes and correspondingly pass or fail a build. You can use `-s` flag to tell Newman to halt on a test case error with a status code of 1 which can then be picked up by a CI tool or build system. - -```bash -$ newman -c PostmanCollection.json -e environment.json -s - -Iteration 1 of 1 -200 17ms Blog posts http://127.0.0.1:5000/blog/posts - ✔ Status code is 200 -404 5ms Blog post http://127.0.0.1:5000/blog/posts/1 -200 4ms New post without token http://127.0.0.1:5000/blog/posts - ✔ Body has a message - ✔ invalid credentials -Test case failed: Status code is 404 -``` - -The results of all tests and requests can be exported into file and later imported in Postman for further analysis. Use the `-o` flag and a file name to save the runner output into a file. - -```bash -$ newman -c mycollection.json -o outputfile.json -``` - -Newman can also be used to import a Postman backup file. The collections, environments, and globals will be saved to the 'data' folder. (Use the -p option to enable pretty-print) -```bash -newman -i /path/to/Backup.json -p -``` - - - -**NOTE** Newman allows you to use all [libraries](http://www.getpostman.com/docs/jetpacks_writing_tests) that Postman supports for running tests. For [x2js](https://code.google.com/p/x2js/) however, only function `xmlToJson` is supported. - -## Library -Newman has been built as a library from the ground-up so that it can be extended and put to varied uses. You can use it like so - - -```javascript -var Newman = require('newman'); - -// read the collectionjson file -var collectionJson = JSON5.parse(fs.readFileSync("collection.json", 'utf8')); - -// define Newman options -newmanOptions = { - envJson: JSON5.parse(fs.readFileSync("envjson.json", "utf-8")), // environment file (in parsed json format) - dataFile: data.csv, // data file if required - iterationCount: 10, // define the number of times the runner should run - outputFile: "outfile.json", // the file to export to - responseHandler: "TestResponseHandler", // the response handler to use - asLibrary: true, // this makes sure the exit code is returned as an argument to the callback function - stopOnError: true -} - -// Optional Callback function which will be executed once Newman is done executing all its tasks. -Newman.execute(collectionJson, newmanOptions, callback); -``` - - -## Cron -Want your test suite to run every hour? Newman can be used to schedule tests to run hourly, daily or weekly automatically in combination with the awesome Unix scheduler **CRON**. - -Lets setup a simple script called `run_newman` to run our tests -```bash -#!/bin/bash - -timestamp=$(date +"%s") -collection=/var/www/myapp/tests/collection.json -env=/var/www/myapp/tests/envfile.json - -# create separate outfile for each run -outfile=/var/www/myapp/tests/outfile-$timestamp.json - -# redirect all output to /dev/null -newman -c $collection -e $env -o $outfile > /dev/null2>&1 -``` -Make it an executable -```bash -$ chmod +x run_newman -``` - -To run Newman every hour, run `crontab -e` and enter the following - -```bash -0 * * * * /path/to/run_newman -``` -Check your `cron` if it has been setup -```bash -$ crontab -l -0 * * * * /path/to/run_newman -``` -With this, your Newman is set to run automatically every hour. - -Note: Exact location for `cron` is dependent on the linux distribution you are running. See specific `cron` instructions for your distribution. For an introduction to `cron` checkout [this](http://code.tutsplus.com/tutorials/scheduling-tasks-with-cron-jobs--net-8800) article. - -## Community Support - - -If you are interested in talking to the team and other Newman users, we are there on Slack. Feel free to drop by and say hello. Our upcoming features and beta releases are discussed here along with world peace. - -Get your invitation for Postman Slack Community from: https://www.getpostman.com/slack-invite.
-Already member? Sign in at https://postmancommunity.slack.com - -## License -Apache-2.0. See the LICENSE file for more information - -[![Analytics](https://ga-beacon.appspot.com/UA-43979731-9/newman/readme)](https://www.getpostman.com) +# Newman diff --git a/bin/newman b/bin/newman deleted file mode 100755 index cf5c790f8..000000000 --- a/bin/newman +++ /dev/null @@ -1,268 +0,0 @@ -#!/usr/bin/env node - -/** - * @Authors Abhijit Kane & Arjun Variar & Prakhar Srivastav. - * @Purpose Integerates POSTMAN Collection runner/tests with CI systems. - * - * Main file which parses the command line arguments and runs Newman, Supports JSON5. - */ - -var _ = require('lodash'), - color = require('cli-color'), - program = require('commander'), - path = require('path'), - request = require('unirest'), - fs = require('fs'), - Helpers = require('../src/utilities/Helpers'), - Importer = require('../src/utilities/Importer'), - Errors = require('../src/utilities/ErrorHandler'), - JSON5 = require('json5'), - Globals = require('../src/utilities/Globals'), - Newman = require('../src/Newman'); - - -function parseArguments() { - program - .version(Globals.newmanVersion) - .usage('[options]') - .option('-c, --collection [file]', 'Specify a Postman collection as a JSON [file]', null) - .option('-u, --url [url]', 'Specify a Postman collection as a [url]', null) - .option('-f, --folder [folder-name]', 'Run a single folder from a collection. To be used with -c or -u', null) - .option('-e, --environment [file]', 'Specify a Postman environment as a JSON [file]', null) - .option('--environment-url [url]', 'Specify a Postman environment as a URL', null) - .option('-E, --exportEnvironment [file]', 'Specify an output file to dump the Postman environment before exiting [file]', null) - .option('-d, --data [file]', 'Specify a data file to use either json or csv', null) - .option('-g, --global [file]', 'Specify a Postman globals file [file]', null) - .option('-G, --exportGlobals [file]', 'Specify an output file to dump Globals before exiting [file]', null) - .option('-y, --delay [number]', "Specify a delay (in ms) between requests", null) - .option('-r, --requestTimeout [number]', "Specify a request timeout (in ms) for requests (Defaults to 15000 if not set)", null) - .option('-R, --avoidRedirects', "Prevents Newman from automatically following redirects", null) - .option('-s, --stopOnError', "Stops the runner with code=1 when a test case fails", null) - .option('-j, --noSummary', "Doesn't show the summary for each iteration", null) - .option('-n, --number [number]', 'Define the number of iterations to run', null) - .option('-C, --noColor', 'Disable colored output', null) - .option('-S, --noTestSymbols', 'Disable symbols in test output and use PASS|FAIL instead', null) - .option('-k, --insecure', 'Disable strict ssl', null) - .option('-l, --tls', 'Use TLSv1', null) - .option('-N, --encoding [encoding-type]', 'Specify an encoding for the response. Supported values are ascii,utf8,utf16le,ucs2,base64,binary,hex', null) - .option('-x, --exitCode', 'Continue running tests even after a failure, but exit with code=1. Incompatible with --stopOnError', null) - .option('-o, --outputFile [file]', 'Path to file where output should be written [file]', null) - .option('-O, --outputFileVerbose [file]', 'Path to file where full request and responses should be logged [file]', null) - .option('-t, --testReportFile [file]', 'Path to file where results should be written as JUnit XML [file]', null) - .option('-i, --import [file]', 'Import a Postman backup file, and save collections, environments, and globals [file] (Incompatible with any option except pretty)', null) - .option('-p, --pretty', 'Enable pretty-print while saving imported collections, environments, and globals', null) - .option('-H, --html [file]', 'Export a HTML report to a specified file [file]', null) - .option('-W, --whiteScreen', 'Black text for white screen', null) - .option('-L, --recurseLimit [limit]', 'Do not run recursive resolution more than [limit] times. Default = 10. Using 0 will prevent any variable resolution', null); - - program.on('--help', function () { - console.log(' Newman is a command-line collection runner for Postman. You must specify a collection file or a collection URL to run newman'); - console.log(''); - console.log(' A collection file or URL is mandatory'); - console.log(' Examples:'); - console.log(''); - console.log(' newman -c POSTMAN_COLLECTION'); - console.log(' newman -u POSTMAN_COLLECTION -e POSTMAN_ENVIRONMENT'); - console.log(' newman -c POSTMAN_COLLECTION -f SAMPLE_FOLDER'); - console.log(''); - console.log(' For more documentation, issues and examples head over to https://github.com/postmanlabs/newman'); - console.log(''); - }); - - program.parse(process.argv); - - - if (program.import) { - Importer.importFile(program.import, program.pretty); - return; - } - - if (program.collection) { - Helpers.validateCollectionFile(program.collection); - } else if (program.url) { - Helpers.validateCollectionUrl(program.url); - } else { - program.help(); - console.log("Please provide a valid collection file / url to run"); - //Errors.terminateWithError("Please provide a valid collection file / url to run"); - } - - if (!program.folder) { - if (process.argv.indexOf("-f") != -1 || process.argv.indexOf("--folder") != -1) { - Errors.terminateWithError("The --folder / -f switch requires a folder name."); - } - } - - if (program.encoding) { - Helpers.validateEncoding(program.encoding); - } - - if (program.data) { - Helpers.validateDataFile(program.data); - } - - if (program.global) { - Helpers.validateGlobalFile(program.global); - } - - if (program.environment) { - Helpers.validateEnvironmentFile(program.environment); - } -} - -function main() { - parseArguments(); - - newmanOptions = {}; - - if (program.import) { - //the importer function will print all relevant messages - return; - } - - if (program.environment) { - // in case of environment variable set the envJson property - // on the options object - try { - newmanOptions.envJson = JSON5.parse(fs.readFileSync(program.environment, 'utf8')); - } - catch (err) { - Errors.terminateWithError("The environment file " + program.environment + " could not be parsed."); - } - } - - newmanOptions.responseHandler = 'TestResponseHandler'; - - if (program.number) { - newmanOptions.iterationCount = program.number; - } - - newmanOptions.responseEncoding = program.encoding; - - newmanOptions.avoidRedirects = program.avoidRedirects; - - newmanOptions.summary = !program.noSummary; - - newmanOptions.html = program.html; - - if (program.outputFile) { - newmanOptions.outputFile = program.outputFile; - } - - if (program.recurseLimit) { - newmanOptions.recurseLimit = parseInt(program.recurseLimit); - } - - if (program.outputFileVerbose) { - newmanOptions.outputFileVerbose = program.outputFileVerbose; - } - - if (program.testReportFile) { - newmanOptions.testReportFile = program.testReportFile; - } - - if (program.data) { - newmanOptions.dataFile = program.data; - } - - if (program.delay) { - if (isNaN(program.delay) || parseFloat(program.delay) % 1 !== 0) { - Errors.terminateWithError("The delay must be an integer"); - } - newmanOptions.delay = parseInt(program.delay); - } - - if (program.requestTimeout) { - if (isNaN(program.requestTimeout) || parseFloat(program.requestTimeout) % 1 !== 0) { - Errors.terminateWithError("The request Timeout must be an integer"); - } - newmanOptions.requestTimeout = parseInt(program.requestTimeout); - } - - if (program.global) { - try { - newmanOptions.globalJSON = JSON5.parse(fs.readFileSync(program.global, 'utf8')); - } - catch (err) { - Errors.terminateWithError("The global file " + program.global + " could not be parsed."); - } - } - - if (program.exportGlobals) { - newmanOptions.exportGlobalsFile = program.exportGlobals; - } - - if (program.exportEnvironment) { - newmanOptions.exportEnvironmentFile = program.exportEnvironment; - } - - if (program.tls) { - newmanOptions.secureProtocol = 'TLSv1_method'; - } - - if (program.folder) { - newmanOptions.folderName = program.folder; - } - - newmanOptions.stopOnError = !!program.stopOnError; - newmanOptions.noColor = !!program.noColor; - newmanOptions.noTestSymbols = !!program.noTestSymbols; - newmanOptions.strictSSL = !program.insecure; - newmanOptions.asLibrary = false; - newmanOptions.exitCode = !!program.exitCode; - newmanOptions.whiteScreen = !!program.whiteScreen; - - var collectionJson; - if (program.collection) { - try { - // read collection from the filesystem - collectionJson = JSON5.parse(fs.readFileSync(program.collection, 'utf8')); - } - catch (err) { - Errors.terminateWithError("The collection file " + program.collection + " could not be parsed."); - } - - if (program.environmentUrl) { - request.get(program.environmentUrl).type('json').end(function (data) { - if (data.error) { - Errors.terminateWithError('Unable to fetch a valid environment. Error: ' + data.code); - } - newmanOptions.envJson = data.body; - Newman.execute(collectionJson, newmanOptions, function (exitCode) { - process.exit(exitCode); - }); - }); - } - else { - Newman.execute(collectionJson, newmanOptions, function (exitCode) { - process.exit(exitCode); - }); - } - } else { - // get collection from url - request.get(program.url).type('json').end(function (collectionData) { - if (collectionData.error) { - Errors.terminateWithError('Unable to fetch a valid collection. Error: ' + collectionData.code); - } - collectionJson = collectionData.body; - if (program.environmentUrl) { - request.get(program.environmentUrl).type('json').end(function (environmentData) { - if (environmentData.error) { - Errors.terminateWithError('Unable to fetch a valid environment. Error: ' + environmentData.code); - } - newmanOptions.envJson = environmentData.body; - Newman.execute(collectionJson, newmanOptions, function (exitCode) { - process.exit(exitCode); - }); - }); - } - else { - Newman.execute(collectionJson, newmanOptions, function (exitCode) { - process.exit(exitCode); - }); - } - }); - } -} - -main(); diff --git a/bin/newman.js b/bin/newman.js new file mode 100755 index 000000000..e90c43d6d --- /dev/null +++ b/bin/newman.js @@ -0,0 +1,21 @@ +#!/usr/bin/env node + +var ArgumentParser = require('argparse').ArgumentParser, + pkg = require('../package.json'), + parser; + +parser = new ArgumentParser({ + prog: pkg.name, + version: pkg.version, + addHelp: true, + description: pkg.description +}); + +parser.addArgument(['-f', '--foo'], { + help: 'foo bar' +}); +parser.addArgument(['-b', '--bar'], { + help: 'bar foo' +}); + +console.dir(parser.parseArgs()); diff --git a/index.js b/index.js index 813e198d6..bf728e847 100644 --- a/index.js +++ b/index.js @@ -1 +1,14 @@ -module.exports = require('./src/Newman'); +/**! + * @license Copyright 2016 Postdot Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ +module.exports = require('./lib'); diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 000000000..abb378da1 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,3 @@ +module.exports = { + run: require('./run') +}; diff --git a/lib/reporters/cli.js b/lib/reporters/cli.js new file mode 100644 index 000000000..015a0eb4c --- /dev/null +++ b/lib/reporters/cli.js @@ -0,0 +1,146 @@ +var colors = require('colors/safe'), + format = require('util').format, + Table = require('cli-table2'), + TABLE_FAILURE_CONFIG = { + head: [{ + hAlign: 'right', + content: colors.red('#') + }, colors.red.underline('Request'), colors.red.underline('Failure'), + colors.red.underline('Details')], + chars: {'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''}, + wordWrap: true + }, + print, + padLeft; + +padLeft = function (nr, n, str) { + return Array(n - String(nr).length + 1).join(str || '0') + nr; +}; + +print = function () { + return print.print.apply(this, arguments); +}; + +print.print = function () { + print.unwait(); + process.stdout.write(format.apply(this, arguments).replace(/\n/g, '\n' + print._indentPrefix)); + return print; +}; + +print._waitFrames = ['⠄', '⠆', '⠇', '⠋', '⠙', '⠸', '⠰', '⠠', '⠰', '⠸', '⠙', '⠋', '⠇', '⠆']; +print._waitMaxFrames = print._waitFrames.length - 1; +print._waitPosition = 0; + +print.wait = function (color) { + print.unwait(); + + process.stdout.write(' '); + print.waiting = setInterval(function () { + process.stdout.write('\b' + (color ? color(print._waitFrames[print._waitPosition++]) : + print._waitFrames[print._waitPosition++])); + (print._waitPosition > print._waitMaxFrames) && (print._waitPosition = 0); + }, 100); + return print; +}; + +print.unwait = function () { + if (!print.waiting) { return print; } + print.waiting = clearInterval(print.waiting); + print._waitPosition = 0; + process.stdout.write('\b'); + return print; +}; + +print._indentPrefix = ''; +// print.indent = function (count) { +// // @todo -comlete +// }; +// print.unindent = function (count) { +// // @todo -comlete +// }; + +module.exports = function PostmanCLIReporter (emitter, options) { + var currentGroup = options.collection, + failures = new Table(TABLE_FAILURE_CONFIG); + + emitter.on('start', function () { + print('%s\n\n%s\n', colors.reset('newman'), colors.bold(currentGroup.name)); + }); + + emitter.on('beforeIteration', function (err, cur) { + (cur.cycles > 1) && + print('\n' + colors.gray.underline('Iteration %d/%d') + '\n\n', cur.iteration + 1, cur.cycles); + }); + + emitter.on('beforeItem', function (err, cursor, item) { + if (currentGroup !== item.__parent.__parent) { + // reset indentation before folder + // @todo this assumes no nested folder + print._indentPrefix = ((currentGroup === options.collection) ? '' : ' '); + + (item.__parent.__parent !== options.collection) && + print('\n▢ %s', colors.bold(item.__parent.__parent.name)); + currentGroup = item.__parent.__parent; + + print._indentPrefix = ((currentGroup === options.collection) ? '' : ' '); + print('\n'); + } + + print('↳ %s\n', colors.reset(item.name)); + }); + + emitter.on('prerequest', function (err, cur, results, item) { + results && results.forEach(function (execution) { + var error = execution.error; + + if (error) { + failures.push([(item.name || item.id), 'PrerequestScript~' + error.name, error.message]); + print(colors.red.bold('%s⠄ %s in prerequest script\n'), padLeft(failures.length, 3, ' '), error.name); + } + }); + }); + + emitter.on('beforeRequest', function (err, cur, request) { + print(' %s %s ', colors.gray(request.method), colors.gray(request.url)).wait(); + }); + + emitter.on('request', function (err, cur, _response, request, item, response) { + // @todo - trap request errors + print(colors.gray('[%d, %dms]') + '\n', response.code, response.responseTime); + }); + + emitter.on('test', function (err, cur, results, item) { + results && results.forEach(function (execution) { + var tests = execution.result && execution.result.globals && execution.result.globals.tests || {}, // phew + error = execution.error; + + Object.keys(tests).forEach(function (testName) { + var passed = Boolean(tests[testName]); + + // increment failure count + !passed && failures.push([(item.name || item.id), 'TestFail', testName]); + + print('%s %s\n', passed ? colors.green(' ✔ ') : colors.red.bold(padLeft(failures.length, 3, ' ') + '⠄'), + passed ? colors.gray(testName) : colors.red.bold(testName)); + }); + + if (error) { + failures.push([(item.name || item.id), 'TestScript~' + error.name, error.message]); + print(colors.red.bold('%s⠄ %s in test script\n'), padLeft(failures.length, 3, ' '), error.name); + } + }); + }); + + emitter.on('done', function () { + if (failures.length) { + for (var i = 0, ii = failures.length; i < ii; i++) { + failures[i].unshift({ + hAlign: 'right', + content: padLeft(Number(i + 1), (failures.length.toString()).length).toString() + }); + } + print._indentPrefix = ''; + print('\n' + failures.toString() + '\n'); + } + }); +}; diff --git a/lib/reporters/json.js b/lib/reporters/json.js new file mode 100644 index 000000000..e69de29bb diff --git a/lib/run.js b/lib/run.js new file mode 100644 index 000000000..aba8049d8 --- /dev/null +++ b/lib/run.js @@ -0,0 +1,65 @@ +var EventEmitter = require('eventemitter3'), + runtime = require('postman-runtime'), + + runtimeEvents = ['start', 'beforeIteration', 'beforeItem', 'beforePrerequest', 'prerequest', + 'beforeRequest', 'request', 'beforeTest', 'test', 'item', 'iteration', 'beforeScript', 'script', 'console', + 'exception', 'done']; + +/** + * @param {Object} options + * @param {Collection} options.collection + * @param {Array|String} options.reporter + * @param {Function} callback + * + * @returns {EventEmitter} + */ +module.exports = function (options, callback) { + // validate all options. it is to be notet that `options` parameter is option and is polymorphic + (!callback && typeof options === 'function') && ( + (callback = options), + (options = {}) + ); + (!options) && (options = {}); // we initialise this as object to avoid needless validations + + var emitter = new EventEmitter(), // @todo: create a new inherited constructor + runner = new runtime.Runner(); + + if (!options.collection) { + (typeof callback === 'function') && callback(new Error('newman: expecting a collection to run')); + } + + options.collection && runner.run(options.collection, {}, function (err, run) { + var callbacks = {}; + + // emit events for all the callbacks triggered by the runtime + runtimeEvents.forEach(function (eventName) { + callbacks[eventName] = emitter.emit.bind(emitter, eventName); + }); + + // override the `done` event to fire the end callback + callbacks.done = function (err) { // @todo - do some meory cleanup here? + (typeof callback === 'function') && callback(err); + emitter.emit('done', err); // we now trigger the actual done event which we had overridden + }; + + // ensure that the reporter option type polymorphism is handled + (typeof options.reporter === 'string') && (options.reporter = [options.reporter]); + + // initialise all the reporters + Array.isArray(options.reporter) && options.reporter.forEach(function (reporterName) { + // @todo + // - validate reporter name to exist + // - look up for node module "newman-reporter-" as reporters if one is not found locally + // - sanitise the reporter name for security reasons + (emitter.reporters || (emitter.reporters = {}))[reporterName] = + new (require('./reporters/' + reporterName))(emitter, options); + }); + + // we ensure that everything is async to comply with event paradigm and start the run + setImmediate(function () { + run.start(callbacks); + }); + }); + + return emitter; +}; diff --git a/npm/test-integration.js b/npm/test-integration.js new file mode 100755 index 000000000..7ae10986a --- /dev/null +++ b/npm/test-integration.js @@ -0,0 +1,6 @@ +#!/usr/bin/env node +require('shelljs/global'); // set shelljs globals + +// banner line +echo('Running Integration Tests'); +echo('- nothing to run yet!'); diff --git a/npm/test-lint.js b/npm/test-lint.js new file mode 100755 index 000000000..51ffc0362 --- /dev/null +++ b/npm/test-lint.js @@ -0,0 +1,40 @@ +#!/usr/bin/env node +require('shelljs/global'); +require('colors'); + +var async = require('async'), + ESLintCLIEngine = require('eslint').CLIEngine, + + LINT_SOURCE_DIRS = [ + './lib', + './bin', + './test', + './npm/*.js', + './index.js' + ]; + +module.exports = function (exit) { + // banner line + console.log('\nLinting files using eslint...'.yellow.bold); + + async.waterfall([ + // execute the CLI engine + function (next) { + next(null, (new ESLintCLIEngine()).executeOnFiles(LINT_SOURCE_DIRS)); + }, + + // output results + function (report, next) { + var errorReport = ESLintCLIEngine.getErrorResults(report.results); + // log the result to CLI + console.log(ESLintCLIEngine.getFormatter()(report.results)); + // log the success of the parser if it has no errors + (errorReport && !errorReport.length) && console.log('eslint ok!'.green); + // 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(exit); diff --git a/npm/test-system.js b/npm/test-system.js new file mode 100755 index 000000000..632733b7d --- /dev/null +++ b/npm/test-system.js @@ -0,0 +1,85 @@ +#!/usr/bin/env node +require('shelljs/global'); +require('colors'); + +var async = require('async'), + _ = require('lodash'), + fs = require('fs'), + path = require('path'), + Mocha = require('mocha'), + + SPEC_SOURCE_DIR = './test/system', + + /** + * Load a JSON from file synchronously + * + * @param {String} file + * @returns {String} + */ + loadJSON = function (file) { + return JSON.parse(require('fs').readFileSync(path.join(__dirname, file)).toString()); + }; + +module.exports = function (exit) { + // banner line + console.log('\nRunning system tests using mocha and nsp...'.yellow.bold); + + async.series([ + // run test specs using mocha + function (next) { + var mocha = new Mocha(); + + fs.readdir(SPEC_SOURCE_DIR, function (err, files) { + files.filter(function (file) { + return (file.substr(-8) === '.test.js'); + }).forEach(function (file) { + mocha.addFile(path.join(SPEC_SOURCE_DIR, file)); + }); + + // start the mocha run + mocha.run(next); + mocha = null; // cleanup + }); + }, + + // execute nsp + // programatically executing nsp is a bit tricky as we have to emulate the cli script's usage of internal + // nsp functions. + function (next) { + var nsp = require('nsp'), + pkg = loadJSON('../package.json'), + nsprc = loadJSON('../.nsprc'); + + console.log('processing nsp for security vulnerabilities...\n'); + + // we do not pass full package for privacy concerns and also to add the ability to ignore exclude packages, + // hence we customise the package before we send it + nsp.check({ + offline: false, + package: { + name: pkg.name, + dependencies: _.omit(pkg.dependencies, nsprc.exclusions || []) + } + }, function (err, result) { + // if processing nsp had an error, simply print that and exit + if (err) { + console.error('There was an error processing NSP!\n'.red + (err.message || err).gray + '\n\n' + + 'Since NSP server failure is not a blocker for tests, tests are not marked as failure!'); + return next(); + } + + // in case an nsp vialation is found, we raise an error + if (result.length) { + console.error(nsp.formatters.default(err, result)); + return next(1); + } + + console.log('nsp ok!\n'.green); + return next(); + }); + } + ], exit); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(exit); diff --git a/npm/test-unit.js b/npm/test-unit.js new file mode 100755 index 000000000..3fd776eb8 --- /dev/null +++ b/npm/test-unit.js @@ -0,0 +1,31 @@ +#!/usr/bin/env node +require('shelljs/global'); +require('colors'); + +var fs = require('fs'), + path = require('path'), + Mocha = require('mocha'), + + SPEC_SOURCE_DIR = './test/unit'; + +module.exports = function (exit) { + // banner line + console.log('Running unit tests using mocha...'.yellow.bold); + + var mocha = new Mocha(); + + fs.readdir(SPEC_SOURCE_DIR, function (err, files) { + files.filter(function (file) { + return (file.substr(-8) === '.test.js'); + }).forEach(function (file) { + mocha.addFile(path.join(SPEC_SOURCE_DIR, file)); + }); + + // start the mocha run + mocha.run(exit); + mocha = null; // cleanup + }); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(exit); diff --git a/npm/test.js b/npm/test.js new file mode 100755 index 000000000..4c8c0ea0b --- /dev/null +++ b/npm/test.js @@ -0,0 +1,12 @@ +#!/usr/bin/env node +require('shelljs/global'); +require('colors'); + +require('async').series([ + require('./test-lint'), + require('./test-system'), + require('./test-unit') +], function (code) { + !code && console.log('\npostman-runtime tests: all ok!'.green); + exit(code); +}); diff --git a/package.json b/package.json index 2e43947e0..7160d9ed0 100644 --- a/package.json +++ b/package.json @@ -1,89 +1,55 @@ { "name": "newman", - "version": "2.1.2", - "author": "Postman Labs =0.6.x" - }, "keywords": [ + "newman", "postman", "api", + "testing", + "ci", "rest-client", "rest" ], + "main": "index.js", "bin": { - "newman": "./bin/newman" + "newman-beta": "./bin/newman.js" }, "preferGlobal": true, + "scripts": { + "test": "node npm/test.js", + "test-system": "node npm/test-system.js", + "test-lint": "node npm/test-lint.js", + "test-unit": "node npm/test-unit.js" + }, + "author": "Postman Labs (=)", + "license": "Apache-2.0", "dependencies": { - "atob": "1.1.2", - "aws4": "1.3.1", - "backbone": "^1.1.2", - "btoa": "1.1.2", - "cli-color": "0.2.x", - "commander": "2.x.x", - "crypto-js": "^3.1.5", - "dot": "1.0.3", - "hawk": "3.1.2", - "jquery": "2.1.1", - "jsdom": "7.1.0", - "jsface": "2.2.x", - "json5": "^0.4.0", - "lodash": "^3.10.0", - "mkdirp": "^0.5.0", - "node-uuid": "1.4.1", - "postman-collection-transformer": "^1.7.2", - "postman_validator": "0.0.4", - "request": "2.72.0", - "sugar": "1.3.9", - "tv4": "^1.1.9", - "underscore": ">=1.6.0 <2", - "unirest": "^0.4.0", - "xml2js": "^0.4.5" + "postman-runtime": "2.0.1-rc.2", + "argparse": "1.0.7", + "async": "2.0.0-rc.6", + "cli-table2": "0.2.0", + "colors": "1.1.2", + "eventemitter3": "1.2.0", + "lodash": "4.13.1", + "postman-collection": "0.4.0", + "shelljs": "0.7.0" }, "devDependencies": { - "grunt": "~0.4.2", - "grunt-contrib-jshint": "~0.6.3", - "grunt-contrib-nodeunit": "~0.2.0", - "grunt-jsdoc": "^0.6.7", - "grunt-mocha-test": "0.12.7", - "grunt-run": "~0.2.2", - "mocha": "2.3.4", - "sinon": "^1.15.4" + "eslint": "3.0.0", + "eslint-plugin-security": "1.2.0", + "expect.js": "0.3.1", + "js-yaml": "3.6.1", + "mocha": "2.5.3", + "nsp": "2.5.0" }, - "scripts": { - "test": "grunt test", - "preinstall": "node ./scripts/preinstall.js" - }, - "license": "Apache" + "engines": { + "node": ">=4" + } } diff --git a/scripts/preinstall.js b/scripts/preinstall.js deleted file mode 100644 index ff4192413..000000000 --- a/scripts/preinstall.js +++ /dev/null @@ -1,12 +0,0 @@ -console.log('******************************************************************'); -console.log('* Notice *'); -console.log('******************************************************************'); -console.log('* If you are using Node v0.12 or v0.10, you should install *'); -console.log('* Newman v1.x: *'); -console.log('* *'); -console.log('* npm install newman@1 *'); -console.log('* *'); -console.log('* Deprecation: Newman v3 onwards will deprecate the use of DOM *'); -console.log('* related libraries, such as JQuery and Backbone. For details, *'); -console.log('* check https://www.getpostman.com/docs/sandbox *'); -console.log('******************************************************************'); diff --git a/src/Newman.js b/src/Newman.js deleted file mode 100644 index 61aed1b72..000000000 --- a/src/Newman.js +++ /dev/null @@ -1,134 +0,0 @@ -var jsface = require("jsface"), -//Validator = require("postman_validator"), -//Errors = require('./utilities/ErrorHandler'), - IterationRunner = require("./runners/IterationRunner"), - EventEmitter = require('./utilities/EventEmitter'), - Globals = require('./utilities/Globals'), - Options = require('./utilities/Options'), - log = require('./utilities/Logger'), - fs = require('fs'), - _ = require('lodash'), - transformer = require('postman-collection-transformer'), - exec = require('child_process').exec; - -/** - * @name Newman - * @classdesc Bootstrap Newman class, mixin from Options class - * @namespace - */ -var Newman = jsface.Class([Options, EventEmitter], { - $singleton: true, - - /** - * Executes XHR Requests for the Postman request, and logs the responses - * & runs tests on them. - * @param {JSON} requestJSON Takes the Postman Collection JSON from a file or url. - * @memberOf Newman - * @param {object} Newman options - */ - execute: function(requestJSON, options, callback) { - var checking = false, - onChecked = null, - self = this; - // var collectionParseError = Validator.validateJSON('c',requestJSON); - // if(!collectionParseError.status) { - // Errors.terminateWithError("Not a valid POSTMAN collection"); - // } - - // if(options.envJson) { - // var envParseError = Validator.validateJSON('e',options.envJson); - // if(!envParseError.status) { - // Errors.terminateWithError("Not a valid POSTMAN environment"); - // } - // } - - // if(options.globalJSON) { - // var globalParseError = Validator.validateJSON('g',options.globalJSON); - // if(!globalParseError.status) { - // Errors.terminateWithError("Not a valid POSTMAN globals file"); - // } - // } - - // Handle Cloud API - if (_.get(options, 'envJson.environment.id')) { - options.envJson = options.envJson.environment; - } - if (_.get(requestJSON, 'collection.info.schema')) { - requestJSON = requestJSON.collection; - } - - // Handle collection conversion - if (_.get(requestJSON, 'info.schema')) { - try { - requestJSON = transformer.convert(requestJSON, { - inputVersion: '2.0.0', - outputVersion: '1.0.0' - }); - } - catch (e) { - return console.error(e.stack || e); - } - } - - - if(Math.random()<0.3) { - checking = true; - exec("npm show newman version", {timeout:1500}, function(error, stdout, stderr) { - checking = false; - stdout = stdout.trim(); - if (stdout !== Globals.newmanVersion && stdout.length > 0) { - Globals.updateMessage = "\nINFO: Newman v" + stdout + " is available. Use `npm update -g newman` to update.\n"; - } - else { - Globals.updateMessage = ""; - } - if(typeof onChecked==='function') { - onChecked(); - } - }); - } - - Globals.addEnvironmentGlobals(requestJSON, options); - this.setOptions(options); - - if (typeof callback === "function") { - this.addEventListener('iterationRunnerOver', function (exitCode) { - if (options.exportGlobalsFile) { - fs.writeFileSync(options.exportGlobalsFile, JSON.stringify(Globals.globalJson.values, null, 1)); - log.note("\n\nGlobals File Exported To: " + options.exportGlobalsFile + "\n"); - } - - if (options.exportEnvironmentFile) { - fs.writeFileSync(options.exportEnvironmentFile, JSON.stringify(Globals.envJson, null, 1)); - log.note("\n\nEnvironment File Exported To: " + options.exportEnvironmentFile + "\n"); - } - - self.removeAllListeners(); - - function wrapUp() { - //if -x is set, return the exit code - if(options.exitCode) { - callback(exitCode); - } - else if(options.stopOnError && exitCode===1) { - callback(1); - } - else { - callback(0); - } - } - - if(!checking) { - wrapUp(); - } else { - onChecked = wrapUp; - } - }); - } - - this.iterationRunner = new IterationRunner(requestJSON, this.getOptions()); - this.iterationRunner.execute(); - } -}); - -module.exports = Newman; diff --git a/src/models/CollectionModel.js b/src/models/CollectionModel.js deleted file mode 100644 index 766c4393f..000000000 --- a/src/models/CollectionModel.js +++ /dev/null @@ -1,145 +0,0 @@ -var jsface = require('jsface'), - _und = require('underscore'), - FolderModel = require('./FolderModel.js'), - RequestModel = require('./RequestModel.js'), - ParentModel = require('./ParentModel.js'); - -/** - * @class CollectionModel - * @classdesc Collection class that inherits from ParentModel representing - * a postman collection object. - * @extends ParentModel - * @param collectionJson {JSON} Takes the Postman Collection as the input. - */ -var CollectionModel = jsface.Class(ParentModel, { - constructor: function (collectionJson) { - this.$class.$super.call(this, collectionJson); - this.order = collectionJson.order; - this.requests = this.initModel(RequestModel, collectionJson.requests); - this.folders = this.initModel(FolderModel, collectionJson.folders); - }, - /** - * Initializes a Model object with the modelsJson as the initial data - * @param {ParentModel} Model Type of Model - * @param {Array} modelsJson Array of JSON objets - * @return {Model} - * @memberOf CollectionModel - */ - initModel: function (Model, modelsJson) { - var models = _und.map(modelsJson, function (model) { - return new Model(model); - }); - return models; - }, - /** - * - * @function getOrderOfIds - * @desc Returns the total order of request IDs in the collection as an array - * Order - - * 1. Folders (order as per the collection) - * 2. Collection level order - * @memberOf CollectionModel - * @return {Array} Flattens array of request Id's. - */ - getOrderOfIds: function () { - var totalOrder = _und.map(this.folders, function (folder) { - return folder.order; - }); - totalOrder = _und.union(_und.flatten(totalOrder), this.order); - return totalOrder; - }, - - /** - * - * @function getOrderOfFolderIds - * @desc Returns the total order of request IDs in the folders of the collection as an array - * Order - - * 1. Folders (order as per the collection) - * @memberOf CollectionModel - * @return {Array} Flattens array of request Id's. - */ - getOrderOfFolderIds: function () { - var totalOrder = _und.map(this.folders, function (folder) { - return folder.order; - }); - totalOrder = _und.flatten(totalOrder); - return totalOrder; - }, - - - /** - * - * @function getOrderOfRootIds - * @desc Returns the total order of request IDs in the root collection as an array - * Order - - * 1. Collection level order - * @memberOf CollectionModel - * @return {Array} Flattens array of request Id's. - */ - getOrderOfRootIds: function () { - return this.order; - }, - /** - * Returns the request with the given request ID if exists null otherwise - * @param {String} id RequestId - * @return {RequestModel} The RequestModel with the given id. - * @memberOf CollectionModel - */ - getRequestWithId: function (id) { - return _und.find(this.requests, function (request) { - return request.id === id; - }); - }, - /** - * Returns an array of request objects as ordered as per the getOrderIds method - * @return {Array} Array with RequestModel ordered occording to the right id's. - * @memberOf CollectionModel - */ - getOrderedRequests: function () { - this.assignRequestsToFolders(); - var orderedRequests = []; - this.folderOrder = this.getOrderOfFolderIds(); - if (this.order === undefined) { - // handling case for older postman collection format - orderedRequests = this.requests; - } else { - var orderedIds = this.getOrderOfIds(); - _und.each(orderedIds, function (id) { - var thisRequest = this.getRequestWithId(id); - if (thisRequest) { - thisRequest.collectionName = this.name; - thisRequest.collectionID = this.id; - var folderData = this.requestFolderMap[id]; - if (folderData) { - thisRequest.folderName = folderData.folderName; - thisRequest.folderId = folderData.folderId; - } - orderedRequests.push(thisRequest); - } - else { - //request with this ID not found - console.log("Missing request: " + id); - } - }, this); - } - return orderedRequests; - }, - - assignRequestsToFolders: function () { - var requestFolderMap = {}; - _und.map(this.folders, function (folder) { - var order = folder.order; - var fname = folder.name; - var fid = folder.id; - _und.map(order, function (requestId) { - requestFolderMap[requestId] = { - folderName: fname, - folderId: fid - }; - }); - }); - this.requestFolderMap = requestFolderMap; - } -}); - -module.exports = CollectionModel; diff --git a/src/models/FolderModel.js b/src/models/FolderModel.js deleted file mode 100644 index cf20cf294..000000000 --- a/src/models/FolderModel.js +++ /dev/null @@ -1,21 +0,0 @@ -var jsface = require('jsface'), - ParentModel = require('./ParentModel.js'); - -/** - * @class FolderModel - * @classdesc FolderModel class that inherits from ParentModel representing - * a postman folder object. - * @extends ParentModel - * @param folderJson {JSON} Folder JSON object from Postman. - */ -var FolderModel = jsface.Class(ParentModel, { - constructor: function (folderJson) { - this.$class.$super.call(this, folderJson); - this.order = folderJson.order; - }, - toString: function () { - return "Folder: " + this.name; - } -}); - -module.exports = FolderModel; diff --git a/src/models/ParentModel.js b/src/models/ParentModel.js deleted file mode 100644 index cce0e8633..000000000 --- a/src/models/ParentModel.js +++ /dev/null @@ -1,19 +0,0 @@ -var jsface = require('jsface'); - -/** - * @class ParentModel - * @param modelJson {JSON} Takes a JSON as the input - */ -var ParentModel = jsface.Class({ - constructor: function (modelJson) { - this.id = modelJson.id; - this.name = modelJson.name; - this.description = modelJson.description; - }, - toString: function () { - // models extending this class should override this method - return this.name; - } -}); - -module.exports = ParentModel; diff --git a/src/models/RequestModel.js b/src/models/RequestModel.js deleted file mode 100644 index a96c57516..000000000 --- a/src/models/RequestModel.js +++ /dev/null @@ -1,40 +0,0 @@ -var jsface = require('jsface'), - ParentModel = require('./ParentModel.js'); - -/** - * @class RequestModel - * @classdef Request class that inherits from ParentModel representing - * a postman request object. - * @param requestJson {JSON} Takes the Postman Request JSON as the input. - * @extends ParentModel - */ -var RequestModel = jsface.Class(ParentModel, { - constructor: function (requestJson) { - this.$class.$super.call(this, requestJson); - this.headers = requestJson.headers; - this.url = requestJson.url; - this.method = requestJson.method; - this.pathVariables = requestJson.pathVariables; - this.data = requestJson.data; - this.rawModeData = requestJson.rawModeData; - this.dataMode = requestJson.dataMode; - this.responses = requestJson.responses; - this.tests = requestJson.tests; - this.preRequestScript = requestJson.preRequestScript; - this.currentHelper = requestJson.currentHelper; - this.helperAttributes = requestJson.helperAttributes; - }, - toString: function () { - return "Request: [" + this.method + "]: " + this.url; - }, - /** - * Function that returns a boolean to indicate if the url has template - * @memberOf RequestModel - * @return {Boolean} - */ - hasTemplate: function () { - return this.url.match(/{\w+}/) !== null; - } -}); - -module.exports = RequestModel; diff --git a/src/models/ResultSummaryModel.js b/src/models/ResultSummaryModel.js deleted file mode 100644 index 2f358c956..000000000 --- a/src/models/ResultSummaryModel.js +++ /dev/null @@ -1,20 +0,0 @@ -var jsface = require('jsface'); - -/** - * @class RequestModel - * @classdef Request class that inherits from ParentModel representing - * a postman request object. - * @param requestJson {JSON} Takes the Postman Request JSON as the input. - * @extends ParentModel - */ -var ResultSummaryModel = jsface.Class({ - constructor: function (summary) { - this.type = summary.type; - this.parentId = summary.parentId; - this.parentName = summary.parentName; - this.passCount = summary.passCount; - this.failCount = summary.failCount; - }, -}); - -module.exports = ResultSummaryModel; diff --git a/src/responseHandlers/AbstractResponseHandler.js b/src/responseHandlers/AbstractResponseHandler.js deleted file mode 100644 index f90a60eb9..000000000 --- a/src/responseHandlers/AbstractResponseHandler.js +++ /dev/null @@ -1,88 +0,0 @@ -var jsface = require('jsface'), - log = require('../utilities/Logger'), - Globals = require('../utilities/Globals'), - path = require('path'), - fs = require('fs'), - _ = require('lodash'), - ErrorHandler = require('../utilities/ErrorHandler'), - EventEmitter = require('../utilities/EventEmitter'), - ResponseExporter = require('../utilities/ResponseExporter'); - -/** - * @class AbstractResponseHandler - * @classdesc - * @mixes EventEmitter - */ -var AbstractResponseHandler = jsface.Class([EventEmitter], { - $singleton: true, - - /** - * Sets up the event listener for the request executed event emitted on each - * request execution - * @memberOf AbstractResponseHandler - */ - initialize: function () { - this._bindedOnRequestExecuted = this._onRequestExecuted.bind(this); - this.addEventListener('requestExecuted', this._bindedOnRequestExecuted); - }, - - // method to be over-ridden by the inheriting classes - _onRequestExecuted: function (error, response, body, request, tests) { - if (error) { - ErrorHandler.requestError(request, error); - } else { - this._printResponse(error, response, body, request); - } - ResponseExporter.addResult(request, response, tests); - }, - - _printResponse: function (error, response, body, request) { - if (Globals.outputFileVerbose) { - var filepath = path.resolve(Globals.outputFileVerbose); - var requestData; - - try { - requestData = _.isArray(request.transformed.data) ? JSON.stringify(_.object(_.pluck(request.transformed.data, "key"), - _.pluck(request.transformed.data, "value")), null, 2) : request.transformed.data; - } - catch (e) { - // Not JSON. - requestData = request.transformed.data; - } - - var requestString = "-------------------------------------------------------------------------------------------\n" + - response.statusCode + " " + - response.stats.timeTaken + "ms" + " " + - request.name + " " + "[" + request.method + "] " + - request.transformed.url + - "\n------------------------------------------------------------" + - "\nRequest headers:\n" + - JSON.stringify(response.req._headers, undefined, 1) + - "\nRequest data:\n" + - requestData + - "\n------------------------------------------------------------" + - "\nResponse headers:\n" + - JSON.stringify(response.headers, undefined, 1) + - "\nResponse body:\n" + response.body + "\n"; - - fs.appendFileSync(filepath, requestString); - } - - if (response.statusCode >= 200 && response.statusCode < 300) { - log.success(response.statusCode); - } else { - ErrorHandler.responseError(response); - } - log.notice(" " + response.stats.timeTaken + "ms") - .normal(" " + request.name + " ") - .notice("[" + request.method + "] ") - .light(request.transformed.url + "\n"); - }, - - // clears up the set event - clear: function () { - this.removeEventListener('requestExecuted', this._bindedOnRequestExecuted); - } -}); - -module.exports = AbstractResponseHandler; diff --git a/src/responseHandlers/DefaultResponseHandler.js b/src/responseHandlers/DefaultResponseHandler.js deleted file mode 100644 index 272548ee9..000000000 --- a/src/responseHandlers/DefaultResponseHandler.js +++ /dev/null @@ -1,18 +0,0 @@ -var jsface = require('jsface'), - AbstractResponseHandler = require('./AbstractResponseHandler'); - -/** - * @class DefaultResponseHandler - * @classdesc - * @extends AbstractResponseHandler - */ -var DefaultResponseHandler = jsface.Class(AbstractResponseHandler, { - $singleton: true, - - // function called when the event "requestExecuted" is fired. Takes 4 self-explanatory parameters - _onRequestExecuted: function (error, response, body, request) { - AbstractResponseHandler._onRequestExecuted.call(this, error, response, body, request); - } -}); - -module.exports = DefaultResponseHandler; diff --git a/src/responseHandlers/ResponseHandlerFactory.js b/src/responseHandlers/ResponseHandlerFactory.js deleted file mode 100644 index b04b12813..000000000 --- a/src/responseHandlers/ResponseHandlerFactory.js +++ /dev/null @@ -1,36 +0,0 @@ -var jsface = require('jsface'), - DefaultResponseHandler = require('./DefaultResponseHandler'), - path = require('path'), - fs = require('fs'); - -/** - * @class ResponseHandlerFactory - * @classdesc - */ -var ResponseHandlerFactory = jsface.Class({ - $singleton: true, - - /** - * @function - * @memberOf ResponseHandlerFactory - * @param {JSON} options - * returns a responseHandler that inherits from the - * AbstractRequestHandler class - */ - createResponseHandler: function (options) { - if (options.responseHandler === undefined) { - return DefaultResponseHandler; - } else { - var filePath = path.join(__dirname, options.responseHandler.split(".")[0] + '.js'); - try { - fs.statSync(filePath); // make sure the file exists - return require(filePath); - } - catch (e) { - return false; - } - } - } -}); - -module.exports = ResponseHandlerFactory; diff --git a/src/responseHandlers/TestResponseHandler.js b/src/responseHandlers/TestResponseHandler.js deleted file mode 100644 index c22b9a86d..000000000 --- a/src/responseHandlers/TestResponseHandler.js +++ /dev/null @@ -1,380 +0,0 @@ -var jsface = require('jsface'), - _und = require('underscore'), - vm = require('vm'), - ErrorHandler = require('../utilities/ErrorHandler'), - AbstractResponseHandler = require('./AbstractResponseHandler'), - jsdom = require("jsdom"), - _jq = null, - _lod = require("lodash"), - Helpers = require('../utilities/Helpers'), - log = require('../utilities/Logger'), - Backbone = require("backbone"), - xmlToJson = require("xml2js"), - CryptoJS = require('crypto-js'), - Globals = require("../utilities/Globals"), - HttpStatusCodes = require("../utilities/HttpStatusCodes"), - ResponseExporter = require("../utilities/ResponseExporter"), - btoa = require("btoa"), - atob = require("atob"), - tv4 = require("tv4"); -require('sugar'); -/** - * @class TestResponseHandler - * @classdesc - */ -var TestResponseHandler = jsface.Class(AbstractResponseHandler, { - $singleton: true, - throwErrorOnLog: false, - - main: function () { - jsdom.env("", function (err, window) { - _jq = require('jquery')(window); - }); - }, - - - // function called when the event "requestExecuted" is fired. Takes 4 self-explanatory parameters - _onRequestExecuted: function (error, response, body, request) { - var results = this._runTestCases(error, response, body, request); - AbstractResponseHandler._onRequestExecuted.call(this, error, response, body, request, results); - this._logTestResults(results); - - if (this.throwErrorOnLog !== false) { - ResponseExporter.exportResults(); - ErrorHandler.terminateWithError(this.throwErrorOnLog); - } - }, - - _runTestCases: function (error, response, body, request) { - if (this._hasTestCases(request)) { - var tests = request.tests; - var sandbox = this._createSandboxedEnvironment(error, response, body, request); - return this._runAndGenerateTestResults(tests, sandbox); - } - return {}; - }, - - _hasTestCases: function (request) { - return !!request.tests; - }, - - // run and generate test results. Also exit if any of the tests has failed - // given the users passes the flag - _runAndGenerateTestResults: function (testCases, sandbox) { - var testResults = this._evaluateInSandboxedEnvironment(testCases, sandbox); - var testResultsToReturn = {}; - if (Globals.stopOnError) { - for (var key in testResults) { - if (testResults.hasOwnProperty(key)) { - if (!testResults[key]) { - testResultsToReturn[key] = false; - this.throwErrorOnLog = "Test case failed: " + key; - return testResultsToReturn; - } - else { - testResultsToReturn[key] = true; - } - } - } - } - else { - testResultsToReturn = testResults; - } - return testResultsToReturn; - }, - - // evaluates a list of testcases in a sandbox generated by _createSandboxedEnvironment - // catches exceptions and throws a custom error message - _evaluateInSandboxedEnvironment: function (testCases, sandbox) { - var sweet = ""; - sweet += "for(p in sugar.object) {Object.prototype[p] = sugar.object[p];}"; - sweet += "for(p in sugar.array) {if(p==='create'){Array.create=sugar.array.create} else{Array.prototype[p]= sugar.array[p];}}"; - sweet += "for(p in sugar.string) String.prototype[p] = sugar.string[p];"; - sweet += "for(p in sugar.date) {if(p==='create'){Date.create=sugar.date.create} else{Date.prototype[p]= sugar.date[p];}}"; - sweet += "for(p in sugar.number) Number.prototype[p]= sugar.number[p];"; - sweet += "for(p in sugar.funcs) {" + - "Object.defineProperty(Function.prototype, p, sugar.funcs[p]);" + - "}"; - - var setEnvHack = "postman.setEnvironmentVariable = function(key,val) {postman.setEnvironmentVariableReal(key,val);environment[key]=val;};"; - setEnvHack += "postman.setGlobalVariable = function(key,val) {postman.setGlobalVariableReal(key,val);globals[key]=val;};"; - setEnvHack += "postman.clearGlobalVariable = function(key) {postman.clearGlobalVariableReal(key);delete globals[key];};"; - setEnvHack += "postman.clearEnvironmentVariable = function(key) {postman.clearEnvironmentVariableReal(key);delete environment[key];};"; - setEnvHack += "postman.clearGlobalVariables = function() {postman.clearGlobalVariablesReal();globals={};};"; - setEnvHack += "postman.clearEnvironmentVariables = function() {postman.clearEnvironmentVariablesReal();environment={};};"; - - //to ensure that JSON.parse throws the right error - setEnvHack += '(function () { \ - var nativeJSONParser = JSON.parse; \ - JSON.parse = function () { \ - try { \ - return nativeJSONParser.apply(JSON, arguments); \ - } catch (e) { \ - e && (e.message = "Encountered an error during JSON.parse(): " + e.message);\ - throw e; \ - } \ - }; \ - }());'; - - testCases = sweet + 'String.prototype.has = function(value){ return this.indexOf(value) > -1};' + setEnvHack + testCases; - - try { - vm.runInNewContext(testCases, sandbox); - } catch (err) { - if (err.toString() === "SyntaxError: Unexpected token u") { - ErrorHandler.exceptionError("No response from URL"); - } - else { - ErrorHandler.exceptionError(err); - } - } - return sandbox.tests; - }, - - _getTransformedRequestData: function (request) { - var transformedData; - - if (request.transformed.data === "") { - return {}; - } - if (request.dataMode === "raw") { - transformedData = request.transformed.data; - } else { - transformedData = Helpers.transformFromKeyValueForRequestData(request.transformed.data); - } - return transformedData; - }, - - //sets env vars - _setEnvironmentContext: function () { - if (!Globals.envJson) { - return {}; - } - return Helpers.transformFromKeyValue(Globals.envJson.values); - }, - - // sets the global vars json as a key value pair - _setGlobalContext: function () { - if (!Globals.globalJson) { - return {}; - } - return Helpers.transformFromKeyValue(Globals.globalJson.values); - }, - - // sets the data vars json as a key value pair - _setDataContext: function () { - if (!Globals.dataJson) { - return {}; - } - return Helpers.transformFromKeyValue(Globals.dataJson.values); - }, - - _getResponseCodeObject: function (code) { - var obj = { - 'code': code, - 'name': "", - 'detail': "" - }; - code = code.toString(); - var statusCodes = HttpStatusCodes.getCodes(); - if (statusCodes.hasOwnProperty(code)) { - obj.name = statusCodes[code].name; - obj.detail = statusCodes[code].detail; - } - return obj; - - }, - - _createSandboxedEnvironment: function (error, response, body, request) { - var responseCodeObject = this._getResponseCodeObject(response.statusCode); - var sugar = { array: {}, object: {}, string: {}, funcs: {}, date: {}, number: {} }; - Object.extend(); - Object.getOwnPropertyNames(Array.prototype).each(function (p) { - sugar.array[p] = Array.prototype[p]; - }); - sugar.array["create"] = Array.create; - Object.getOwnPropertyNames(Object.prototype).each(function (p) { - sugar.object[p] = Object.prototype[p]; - }); - sugar.object["extended"] = Object.extended; - - Object.getOwnPropertyNames(String.prototype).each(function (p) { - sugar.string[p] = String.prototype[p]; - }); - Object.getOwnPropertyNames(Number.prototype).each(function (p) { - sugar.number[p] = Number.prototype[p]; - }); - Object.getOwnPropertyNames(Date.prototype).each(function (p) { - sugar.date[p] = Date.prototype[p]; - }); - sugar.date["create"] = Date.create; - Object.getOwnPropertyNames(Function.prototype).each(function(p) { - sugar.funcs[p] = Object.getOwnPropertyDescriptor(Function.prototype, p); - }); - return { - sugar: sugar, - tests: {}, - responseHeaders: Helpers.createProperCasedHeaderObject(response.headers), - responseBody: body, - responseTime: response.stats.timeTaken, - request: { - url: request.transformed.url, - method: request.method, - headers: Helpers.generateHeaderObj(request.transformed.headers), - data: this._getTransformedRequestData(request), - dataMode: request.dataMode, - name: request.name, - description: request.description - }, - responseCode: responseCodeObject, - btoa: btoa, - atob: atob, - CryptoJS: CryptoJS, - iteration: Globals.iterationNumber, - environment: this._setEnvironmentContext(), - globals: this._setGlobalContext(), - data: this._setDataContext(), - $: _jq, - jQuery: _jq, - _: _lod, - Backbone: Backbone, - xmlToJson: function (string) { - var JSON = {}; - xmlToJson.parseString(string, { - explicitArray: false, - async: false - }, function (err, result) { - JSON = result; - }); - return JSON; - }, - - xml2Json: function (string) { - var JSON = {}; - xmlToJson.parseString(string, { - explicitArray: false, - async: false, - trim: true, - mergeAttrs: false - }, function (err, result) { - JSON = result; - }); - return JSON; - }, - tv4: tv4, - console: { - log: function () { - console.log.apply(console, arguments); - }, - error: function () { - console.error.apply(console, arguments); - }, - warn: function () { - console.warn.apply(console, arguments); - } - }, - postman: { - getResponseHeader: function (headerString) { - return Helpers.getResponseHeader(headerString, response.headers); - }, - setEnvironmentVariableReal: function (key, value) { - var envVar = _und.find(Globals.envJson.values, function (envObject) { - return envObject["key"] === key; - }); - - if (envVar) { // if the envVariable exists replace it - envVar["value"] = value; - } else { // else add a new envVariable - Globals.envJson.values.push({ - key: key, - value: value, - type: "text", - name: key - }); - } - }, - getEnvironmentVariable: function (key) { - var envVar = _und.find(Globals.envJson.values, function (envObject) { - return envObject["key"] === key; - }); - if (envVar) { - return envVar["value"]; - } - return null; - }, - clearEnvironmentVariablesReal: function () { - Globals.envJson.values = []; - }, - clearEnvironmentVariableReal: function (key) { - var oldLength = Globals.envJson.values.length; - _lod.remove(Globals.envJson.values, function (envObject) { - return envObject["key"] === key; - }); - if (oldLength === Globals.envJson.values.length) { - return false; - } - else { - return true; - } - }, - getGlobalVariable: function (key) { - var envVar = _und.find(Globals.globalJson.values, function (envObject) { - return envObject["key"] === key; - }); - if (envVar) { - return envVar["value"]; - } - return null; - }, - setGlobalVariableReal: function (key, value) { - var envVar = _und.find(Globals.globalJson.values, function (envObject) { - return envObject["key"] === key; - }); - - if (envVar) { // if the envVariable exists replace it - envVar["value"] = value; - } else { // else add a new envVariable - Globals.globalJson.values.push({ - key: key, - value: value, - type: "text", - name: key - }); - } - //globals["key"]=value; - }, - clearGlobalVariablesReal: function () { - Globals.globalJson.values = []; - }, - clearGlobalVariableReal: function (key) { - var oldLength = Globals.globalJson.values.length; - _lod.remove(Globals.globalJson.values, function (envObject) { - return envObject["key"] === key; - }); - if (oldLength === Globals.globalJson.values.length) { - return false; - } - else { - return true; - } - }, - setNextRequest: function (requestName) { - Globals.nextRequestName = requestName; - } - } - }; - }, - - // logger for test case results - _logTestResults: function (results) { - _und.each(_und.keys(results), function (key) { - if (results[key]) { - log.testCaseSuccess(key); - } else { - ErrorHandler.testCaseError(key); - } - }); - } -}); - -module.exports = TestResponseHandler; diff --git a/src/runners/AbstractRunner.js b/src/runners/AbstractRunner.js deleted file mode 100644 index 16c1efa13..000000000 --- a/src/runners/AbstractRunner.js +++ /dev/null @@ -1,21 +0,0 @@ -var jsface = require("jsface"); - -/** - * @class AbstractRunner - * @param CollectionJson {JSON} Takes a JSON as the input - */ -var AbstractRunner = jsface.Class({ - constructor: function (collection) { - this.collection = collection || []; - }, - - /** - * Executes the runner - * All runners override this function - */ - execute: function () { - return this; - } -}); - -module.exports = AbstractRunner; diff --git a/src/runners/CollectionRunner.js b/src/runners/CollectionRunner.js deleted file mode 100644 index 8e2720aa4..000000000 --- a/src/runners/CollectionRunner.js +++ /dev/null @@ -1,84 +0,0 @@ -var jsface = require("jsface"), - AbstractRunner = require("./AbstractRunner"), - RequestRunner = require("./RequestRunner"), - ResponseHandlerFactory = require('../responseHandlers/ResponseHandlerFactory'), - Errors = require('../utilities/ErrorHandler'), - _und = require('underscore'), - log = require('../utilities/Logger'), - EventEmitter = require('../utilities/EventEmitter'), - Options = require('../utilities/Options'), - ResponseExporter = require("../utilities/ResponseExporter"); - - -/** - * @class CollectionRunner - * @param {CollectionModel} collection Takes a Collection of RequestModel - * as a input and executes the RequestRunner on them. - * @extends AbstractRunner - * @mixes Options - */ -var CollectionRunner = jsface.Class([AbstractRunner, Options, EventEmitter], { - constructor: function (collection, options) { - this.$class.$super.call(this, collection); - this.setOptions(options); - }, - - /** - * @function - * @memberOf CollectionRunner - */ - execute: function () { - // Initialize the response handler using a factory - this.ResponseHandler = ResponseHandlerFactory.createResponseHandler(this.getOptions()); - if (!this.ResponseHandler) { - log.throwError('The module provided does not exist.'); - } - - this._addEventListeners(); - - // Sets up the response handler to respond to the requestExecuted event - this.ResponseHandler.initialize(); - - RequestRunner.resetIndex(); - _und.each(this.collection, function (postmanRequest) { - RequestRunner.addRequest(postmanRequest); - }, this); - - RequestRunner.setDelay(this.opts.delay); - - if (!isNaN(this.opts.requestTimeout) && this.opts.requestTimeout % 1 === 0) { - RequestRunner.setRequestTimeout(this.opts.requestTimeout); - } - else if (this.opts.requestTimeout == null) { - RequestRunner.setRequestTimeout(15000); - } - else { - Errors.terminateWithError('The request timeout must be an integer'); - } - - RequestRunner.setStrictSSL(this.opts.strictSSL); - RequestRunner.setSecureProtocol(this.opts.secureProtocol); - RequestRunner.start(); - - this.$class.$superp.execute.call(this); - }, - - // adding event listeners to signal end of requestRunner and collectionRunner - _addEventListeners: function () { - this._onRequestRunnerOverBinded = this._onRequestRunnerOver.bind(this); - this.addEventListener('requestRunnerOver', this._onRequestRunnerOverBinded); - }, - - // run when requestRunner runs over the ordered requests in this collection - _onRequestRunnerOver: function () { - this.ResponseHandler.clear(); - if (this.opts.summary) { - ResponseExporter.showIterationSummary(); - } - - this.removeEventListener('requestRunnerOver', this._onRequestRunnerOverBinded); - this.emit('collectionRunnerOver'); - } -}); - -module.exports = CollectionRunner; diff --git a/src/runners/IterationRunner.js b/src/runners/IterationRunner.js deleted file mode 100644 index c3386b758..000000000 --- a/src/runners/IterationRunner.js +++ /dev/null @@ -1,227 +0,0 @@ -var jsface = require("jsface"), - Options = require('../utilities/Options'), - log = require('../utilities/Logger'), - Helpers = require('../utilities/Helpers'), - Globals = require('../utilities/Globals'), - EventEmitter = require('../utilities/EventEmitter'), - CollectionModel = require('../models/CollectionModel'), - FolderModel = require('../models/FolderModel'), - CollectionRunner = require("../runners/CollectionRunner"), - Errors = require('../utilities/ErrorHandler'), - fs = require('fs'), - path = require('path'), - JSON5 = require('json5'), - _und = require('underscore'), - ResponseExporter = require("../utilities/ResponseExporter"); -/** - * @class IterationRunner - * @param CollectionJson {JSON} Takes a JSON as the input - * @param Options {JSON} Set of options to pass to the collection runner - * @param numOfIterations {int} Number of times the iteration has to run - */ -var IterationRunner = jsface.Class([Options, EventEmitter], { - constructor: function (requestJSON, options) { - this.setOptions(options); - this.collection = this._getOrderedCollection(requestJSON); - this.collectionName = requestJSON.name; - if (!Globals.requestJSON) { - Globals.requestJSON = requestJSON; - } - - //check if only a folder has to be run - if (options.folderName) { - this.folder = this._getFolderFromCollection(requestJSON, options.folderName); - if (!this.folder) { - Errors.terminateWithError('The folder [' + options.folderName + '] does not exist.'); - } - this.collection = this._getFolderRequestsFromCollection(this.collection, this.folder); - } - - if (!isNaN(options.delay) && options.delay % 1 === 0) { - this.delay = options.delay; - } - else if (options.delay == null) { - this.delay = 0; - } - else { - Errors.terminateWithError('The delay must be an integer'); - } - - // collection of environment jsons passed from datafile - this.dataVars = this._getJsonArraysFromFile(); - this.globalVars = this._getJsonArraysFromGlobalFile(); - - var iterationCount = this.getOptions().iterationCount; - if (iterationCount && this.dataVars.length && iterationCount > this.dataVars.length) { - log.warn("WARNING: The iterationCount is greater than the number of records in the data file. This could lead to unexpected results\n"); - } - - this.numOfIterations = iterationCount || this.dataVars.length || 1; - this.iteration = 0; - - // run the next iteration when the collection run is over - this.addEventListener('collectionRunnerOver', this._runNextIteration.bind(this)); - }, - - _getOrderedCollection: function (requestJSON) { - var collectionModel = new CollectionModel(requestJSON); - var orderedCollection = collectionModel.getOrderedRequests(this.getOptions()); - return orderedCollection; - }, - - _getFolderFromCollection: function (requestJSON, folderName) { - var folders = requestJSON.folders; - var folderNeeded = _und.find(folders, function (folder) { - return folder.name === folderName; - }); - if (!folderNeeded) { - return null; - } - var folderModel = new FolderModel(folderNeeded); - return folderModel; - }, - - _getFolderRequestsFromCollection: function (collection, folder) { - if (!folder || !folder.order) { - return []; - } - var retVal = []; - var folderOrders = folder.order; - _und.each(collection, function (request) { - if (folderOrders.indexOf(request.id) !== -1) { - retVal.push(request); - } - }); - return retVal; - }, - - _kvArrayToObject: function (array) { - var obj = {}; - _und.each(array, function (kv) { - obj[kv.key] = kv.value; - }); - return obj; - }, - - _objectToKvArray: function (obj) { - var arr = []; - for (var property in obj) { - if (obj.hasOwnProperty(property)) { - arr.push({ "key": property, "value": obj[property] }); - } - } - return arr; - }, - - // sets the global environment object property as the env vars + globals + dataFiles - _setGlobalEnvJson: function () { - if (typeof Globals.envJson.values === "undefined") { - Globals.envJson.values = []; - } - - //add the globals (globalJSON, overriden by envJson) - if (this.globalVars && this.globalVars.length) { - Globals.globalJson.values = this.globalVars;//Helpers.augmentDataArrays(this.globalVars,Globals.envJson.values); - } - else { - Globals.globalJson = { values: [] }; - } - - //add the dataFile vars (overrides everything else) - if (this.dataVars.length) { - var dataJson = { values: this.dataVars[this.iteration - 1] }; //data file - Globals.dataJson.values = dataJson.values; - } - }, - - _getJsonArraysFromGlobalFile: function () { - var globalFile = this.getOptions().globalJSON; - if (globalFile === null) { - return []; - } - return globalFile; -// var jsonArray = []; -// if (globalFile) { -// jsonArray = JSON5.parse(fs.readFileSync(globalFile, 'utf8')); -// } -// return jsonArray; - }, - - // parses the json from data file and sends it for transformation - _getJsonArraysFromFile: function () { - var dataFile = this.getOptions().dataFile; - var jsonArray = []; - if (dataFile) { - if (path.extname(dataFile) === ".json") { - // json file - jsonArray = JSON5.parse(fs.readFileSync(dataFile, 'utf8')); - } else { - // assumed csv file - jsonArray = []; - var headers; - var strContents = fs.readFileSync(dataFile, 'utf-8'); - - var array = Helpers.CSVUtil.csvToArray(strContents); - if (array && array.length > 0) { - headers = array[0]; - - var numRows = array.length; - for (var i = 1; i < numRows; i++) { - jsonArray.push(_und.object(headers, array[i])); - } - } - } - - var envJsonArray = _und.map(jsonArray, function (rawJson) { - return Helpers.transformToKeyValue(rawJson); - }, this); - return envJsonArray; - } - return jsonArray; - }, - - // logs the iteration count - _logStatus: function () { - log.note("\nIteration " + this.iteration + " of " + this.numOfIterations + "\n"); - }, - - // set the global envjson and then run the next iteration - _runNextIteration: function () { - if (this.iteration < this.numOfIterations) { - Globals.iterationNumber = ++this.iteration; - Globals.dataJson = { "values": [] }; - var currentGlobalEnv = Globals.envJson; - this._setGlobalEnvJson(); - this._runCollection(); - Globals.envJson = currentGlobalEnv; - Globals.nextRequestName = undefined; - } else { - this._exportResponses(); - this.emit('iterationRunnerOver', Globals.exitCode); - if (Globals.updateMessage) { - console.log(Globals.updateMessage); - } - } - }, - - _runCollection: function () { - if (this.collection.length) { - this._logStatus(); - var runner = new CollectionRunner(this.collection, this.getOptions()); - runner.execute(); - } - }, - - _exportResponses: function () { - ResponseExporter.exportResults(); - }, - - /** - * Runs the iteration. Instantiates a new CollectionRunner and executes it - */ - execute: function () { - this._runNextIteration(); - } -}); - -module.exports = IterationRunner; diff --git a/src/runners/RequestRunner.js b/src/runners/RequestRunner.js deleted file mode 100644 index 7ec68dd6a..000000000 --- a/src/runners/RequestRunner.js +++ /dev/null @@ -1,341 +0,0 @@ -var jsface = require('jsface'), - requestLib = require('request'), - Queue = require('../utilities/Queue'), - Helpers = require('../utilities/Helpers'), - HelperProcessor = require('../utilities/HelperProcessor'), - Globals = require('../utilities/Globals'), - EventEmitter = require('../utilities/EventEmitter'), - Errors = require('../utilities/ErrorHandler'), - VariableProcessor = require('../utilities/VariableProcessor.js'), - prScripter = require('../utilities/PreRequestScriptProcessor.js'), - _und = require('underscore'), - path = require('path'), - fs = require('fs'); - -/** - * @class RequestRunner - * @classdesc RequestRunner is a singleton object which fires the XHR and takes the - * appropriate action on the response. - * @mixes EventEmitter , Queue - */ -var RequestRunner = jsface.Class([Queue, EventEmitter], { - $singleton: true, - - delay: 0, - strictSSL: true, - secureProtocol: null, - - $statics: { - METHODS_WHICH_ALLOW_BODY: ['POST', 'PUT', 'PATCH', 'DELETE', 'LINK', 'UNLINK', 'LOCK', 'PROPFIND'] - }, - - /** - * Sets a delay to be used between requests - * @param delay - */ - setDelay: function (delay) { - this.delay = delay; - }, - - /** - * Sets a timeout to be used waiting for a requests - * @param requestTimeout - */ - setRequestTimeout: function (timeout) { - this.requestTimeout = timeout; - }, - - /** - * Sets strictSSL - * @param strictSSL - */ - setStrictSSL: function (strictSSL) { - this.strictSSL = strictSSL; - }, - - /** - * Sets secure protocol - * @param secureProtocol - */ - setSecureProtocol: function (secureProtocol) { - this.secureProtocol = secureProtocol; - }, - - /* - * Adds the Request to the RequestRunner's queue. - * @memberOf RequestRunner - * @param {RequestModel} request Takes a RequestModel Object. - */ - addRequest: function (request) { - this.addToQueue(request); - }, - - resetIndex: function() { - this._queue = []; - this._currentIndex = -1; - }, - - /** - * Starts the RequestRunner going to each request in the queue. - * @memberOf RequestRunner - */ - start: function () { - this._bindedOnRequestExecuted = this._onRequestExecuted.bind(this); - this.addEventListener('requestExecuted', this._bindedOnRequestExecuted); - var runner = this; - setTimeout(function () { - runner._execute(); - }, this.delay); - }, - - _getPropertyFromArray: function (array, propName) { - return _und.find(array, function (elem) { - return (propName === ("{{" + elem.key + "}}")); - }); - }, - - _addGlobalData: function (oldArray, newArray) { - var finalArray = []; - var oLen = oldArray.length; - for (var i = 0; i < oLen; i++) { - var thisValue = oldArray[i].value; - var actualValue = this._getPropertyFromArray(newArray, thisValue); - if (typeof actualValue === "undefined") { - finalArray.push({ "key": oldArray[i].key, "value": thisValue, "type": oldArray[i].type }); - } - else { - finalArray.push({ "key": oldArray[i].key, "value": actualValue.value, "type": oldArray[i].type }); - } - } - return finalArray; - }, - - _getNextRequest: function() { - if (Globals.nextRequestName === undefined) { - //will get the next item based on the index saved in the queue - return this.getNextItemFromQueue(); - } - else if (Globals.nextRequestName === null) { - return null; - } - else { - var queue = this.getAllItems(); - var indexToUse = -1; - for (var i = 0; i < queue.length; i++) { - if (queue[i].name === Globals.nextRequestName) { - indexToUse = i; - break; - } - } - var requestToSend = this.getItemWithIndexWithoutRemoval(indexToUse); - Globals.nextRequestName = undefined; - return requestToSend; - } - }, - - // Gets a request from the queue and executes it. - _execute: function () { - if (Globals.exitCode === 1 && Globals.stopOnError === true) { - return; - } - - var request = this._getNextRequest(); - if (request) { - //To be uncommented if each prScript/test should set transient env. vars - //var oldGlobals = Globals.envJson; - var oldRequestData = request.data; - - //To remain compatible with Postman - ensure consistency of request.data - if (request.dataMode === "raw" && request.hasOwnProperty("rawModeData")) { - if (request.rawModeData !== undefined) { - request.data = request.rawModeData; - } - } - - //making sure empty arrays are not sent. This messes up the request library - if (request.data instanceof Array && request.data.length === 0) { - request.data = ""; - } - - //to add Environment and Data variables to the request, because the processed URL is available in the PR script - this._processUrlUsingEnvVariables(request); - prScripter.runPreRequestScript(request); - //to process PreRequestScript variables - this._processUrlUsingEnvVariables(request); - - HelperProcessor._useAuthHelpers(request); - - request.transformed.url = this._ensureUrlPrefix(request.transformed.url); - - var RequestOptions = this._getRequestOptions(request); - - request.data = request.transformed.data; - - request.startTime = new Date().getTime(); - RequestOptions.rejectUnauthorized = false; - RequestOptions.strictSSL = this.strictSSL; - - if (this.secureProtocol) { - RequestOptions.secureProtocol = this.secureProtocol; - } - var unireq = requestLib(RequestOptions, function (error, response, body) { - if (response) { - // save some stats, only if response exists - this._appendStatsToReponse(request, response); - } else { - // initialize response for reporting and testcases - response = { - stats: { timeTaken: 0 }, - statusCode: 0, - headers: [] - }; - } - - // emit event to signal request has been executed - var delay = this.delay; - if (this.isEmptyQueue()) { - delay = 0; - } - this.emit('requestExecuted', error, response, body, request, delay); - }.bind(this)); - - this._setFormDataIfParamsInRequest(unireq, request); - //To be uncommented if each prScript/test should set transient env. vars - //Globals.envJson = oldGlobals; - - request.data = oldRequestData; - } else { - this._destroy(); - } - }, - - // clean up the requestrunner - _destroy: function () { - this.removeEventListener('requestExecuted', this._bindedOnRequestExecuted); - this.emit('requestRunnerOver'); - }, - - _onRequestExecuted: function (error, response, body, request, delay) { - // Call the next request to execute - var runner = this; - setTimeout(function () { - runner._execute(); - }, delay); - }, - - // Generates and returns the request Options to be used by unirest. - _getRequestOptions: function (request) { - var RequestOptions = {}; - RequestOptions.url = request.transformed.url; - RequestOptions.method = request.method; - RequestOptions.headers = Helpers.generateHeaderObj(request.transformed.headers); - RequestOptions.followAllRedirects = !Globals.avoidRedirects; - RequestOptions.followRedirect = !Globals.avoidRedirects; - RequestOptions.jar = true; - RequestOptions.timeout = this.requestTimeout; - if (Globals.responseEncoding) { - RequestOptions.encoding = Globals.responseEncoding; - } - RequestOptions.gzip = true; - this._setBodyData(RequestOptions, request); - return RequestOptions; - }, - - // Takes request as the input, parses it for different types and - // sets it as the request body for the unirest request. - _setBodyData: function (RequestOptions, request) { - var self = this; - - if (RequestRunner.METHODS_WHICH_ALLOW_BODY.indexOf(request.method) > -1) { - if (request.dataMode === "raw") { - RequestOptions.body = request.transformed.data; - } else if (request.dataMode === "urlencoded") { - var reqData = request.transformed.data; - RequestOptions.form = self._parseFormParams(reqData); - } - } - }, - - // Request Mumbo jumbo for `multipart/form-data`. - _setFormDataIfParamsInRequest: function (unireq, request) { - if (RequestRunner.METHODS_WHICH_ALLOW_BODY.indexOf(request.method) > -1 && request.dataMode === "params" && - request.data && request.data.length > 0) { - var form = unireq.form(); - _und.each(request.data, function (dataObj) { - //do not send form fields if they're disabled - if (dataObj.enabled === false) { - return; - } - if(dataObj.key == null) { - dataObj.key = ""; - } - if(dataObj.value == null) { - dataObj.value = ""; - } - if (dataObj.type === 'text') { - form.append(dataObj.key, dataObj.value); - } else if (dataObj.type === 'file' && (typeof dataObj.value === 'string')) { - var loc = path.resolve(dataObj.value); - - try { - fs.statSync(loc); - } - catch (e) { - Errors.terminateWithError("No file found - " + loc); - } - - form.append(dataObj.key, fs.createReadStream(loc)); - } - }); - - } - }, - - // placeholder function to append stats to response - _appendStatsToReponse: function (req, res) { - res.stats = {}; - res.stats.timeTaken = new Date().getTime() - req.startTime; - }, - - //ensures the return value is prefixed with http:// - _ensureUrlPrefix: function (str) { - if (str.indexOf("http://") === -1 && str.indexOf("https://") === -1) { - return "http://" + str; - } - return str; - }, - - _processUrlUsingEnvVariables: function (request) { - var mergedArray = { "values": [] }; - mergedArray.values = Helpers.augmentDataArrays(Globals.globalJson.values, Globals.envJson.values); - mergedArray.values = Helpers.augmentDataArrays(mergedArray.values, Globals.dataJson.values); - - VariableProcessor.processRequestVariables(request, { - envJson: mergedArray - }); - }, - - _parseFormParams: function (reqData) { - var params = {}; - if (reqData instanceof Array) { //may also be a string for empty array - reqData.forEach(function (paramData) { - if (paramData.enabled) { - // Check if this is a duplicate - if (params[paramData.key]) { - var original = params[paramData.key]; - if (Array.isArray(original)) { - original.push(paramData.value); - } else { - params[paramData.key] = [original].concat(paramData.value); - } - } else { - params[paramData.key] = paramData.value; - } - } - }); - } - return params; - } -}); - -module.exports = RequestRunner; diff --git a/src/templates/htmlResponseTemplate.js b/src/templates/htmlResponseTemplate.js deleted file mode 100644 index 4084ed35a..000000000 --- a/src/templates/htmlResponseTemplate.js +++ /dev/null @@ -1,66 +0,0 @@ -(function() { - function htmlResponseTemplate(it) { - var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : (function(doNotSkipEncoded) { - var encodeHTMLRules = { - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'", - "/": "/" - }, - matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g; - return function(code) { - return code ? code.toString().replace(matchHTML, function(m) { - return encodeHTMLRules[m] || m; - }) : ""; - }; - }()); - var out = '

Newman test report

Collection:
' + (it.collection.name) + '

Iterations:
' + encodeHTML(it.count) + '

Description:
' + (it.collection.description) + '
'; - if (it.target_type == "folder") { - out += '
Folder:
' + (it.folder) + '
'; - } - out += '

Requests:


'; - for (var index = 0; index < it.results.length; index++) { - var result = it.results[index]; - var finalDescription = "null"; - for (var i=0; i < it.collection.requests.length; i++ ) { - if ( it.collection.requests[i].id === result.id ) { - finalDescription = it.collection.requests[i].description; - } - }; - out += '
Description:
' + finalDescription + '

Mean time per request:
' + (result.meanResponseTime) + ' ms

Total tests that passed:
' + (result.totalPassFailCounts.pass) + '

Total tests that failed:
' + (result.totalPassFailCounts.fail) + '

Individual tests:
'; - for (var testName in result.testPassFailCounts) { - out += ' '; - } - out += '
Test name Pass count Fail count
' + (testName) + ' ' + (result.testPassFailCounts[testName].pass) + ' ' + (result.testPassFailCounts[testName].fail) + '
'; - } - out += '
'; - return out; - } - var itself = htmlResponseTemplate, - _encodeHTML = (function(doNotSkipEncoded) { - var encodeHTMLRules = { - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'", - "/": "/" - }, - matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g; - return function(code) { - return code ? code.toString().replace(matchHTML, function(m) { - return encodeHTMLRules[m] || m; - }) : ""; - }; - }()); - if (typeof module !== 'undefined' && module.exports) module.exports = itself; - else if (typeof define === 'function') define(function() { - return itself; - }); - else { - window.render = window.render || {}; - window.render['htmlResponseTemplate'] = itself; - } -}()); diff --git a/src/templates/htmlResponseTemplate.jst b/src/templates/htmlResponseTemplate.jst deleted file mode 100644 index 12c5fa03f..000000000 --- a/src/templates/htmlResponseTemplate.jst +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - -
-

Newman test report

- -
-
Collection:
-
{{=it.collection.name}}
-
- - {{?it.target_type=="folder"}} -
-
Folder:
-
{{=it.folder}}
-
- {{?}} - -
-

Requests:

-
- {{ for(var index=0;index -
- - -
-
-

Iterations: {{!it.count}}

-

Mean time per request: {{=result.meanResponseTime}} ms

-

Total tests that passed: {{=result.totalPassFailCounts.pass}}

-

Total tests that failed: {{=result.totalPassFailCounts.fail}}

-
-
Individual tests:
- - - - - - - - - - - - {{for(testName in result.testPassFailCounts) { }} - - - - - - - {{ } }} - -
Test namePass countFail count
{{=testName}}{{=result.testPassFailCounts[testName].pass}}{{=result.testPassFailCounts[testName].fail}}
-
-
- -
-
- {{}}} - - - \ No newline at end of file diff --git a/src/utilities/CsvHelper.js b/src/utilities/CsvHelper.js deleted file mode 100644 index d573243f3..000000000 --- a/src/utilities/CsvHelper.js +++ /dev/null @@ -1,105 +0,0 @@ -var jsface = require('jsface'); - -var CsvHelper = jsface.Class({ - $singleton: true, - CSV: function () { - var a = /^\d+$/, - b = /^\d*\.\d+$|^\d+\.\d*$/, - c = /^\s|\s$|,|"|\n/, - d = function () { - return String.prototype.trim ? function (a) { - return a.trim() - } : function (a) { - return a.replace(/^\s*/, "").replace(/\s*$/, "") - } - }(), - e = function (a) { - return "[object Number]" === Object.prototype.toString.apply(a) - }, - f = function (a) { - return "[object String]" === Object.prototype.toString.apply(a) - }, - g = function (a) { - return "\n" !== a.charAt(a.length - 1) ? a : a.substring(0, a.length - 1) - }, - h = function (d) { - return f(d) ? (d = d.replace(/"/g, '""'), c.test(d) || a.test(d) || b.test(d) ? d = '"' + d + '"' : "" === d && (d = '""')) : d = e(d) ? d.toString(10) : null === d || void 0 === d ? "" : d.toString(), d - }, - i = { - arrayToCsv: function (a) { - var b, c, d, e, f = ""; - for (d = 0; d < a.length; d += 1) { - for (c = a[d], e = 0; e < c.length; e += 1) b = c[e], b = h(b), f += e < c.length - 1 ? b + "," : b; - f += "\n" - } - return f - }, - csvToArray: function (c, e) { - c = g(c), e = e === !0 ? { - trim: !0 - } : e || {}; - var f, h = "", - i = !1, - j = !1, - k = "", - l = [], - m = [], - n = e.trim === !0 ? !0 : !1, - o = function (c) { - var e = d(c); - return j !== !0 && ("" === c ? c = c : n === !0 && (c = e), (a.test(e) || b.test(e)) && (c = +e)), c - }; - for (f = 0; f < c.length; f += 1) h = c.charAt(f), i !== !1 || "," !== h && "\n" !== h ? '"' !== h ? k += h : i ? '"' === c.charAt(f + 1) ? (k += '"', f += 1) : i = !1 : (i = !0, j = !0) : (k = o(k), l.push(k), "\n" === h && (m.push(l), l = []), k = "", j = !1); - return k = o(k), l.push(k), m.push(l), m - }, - csvToObject: function (a, b) { - b = void 0 !== b ? b : {}; - var c = b.columns, - d = !!b.trim, - e = this.csvToArray(a, d); - return c || (c = e.shift()), e.map(function (a) { - for (var b = {}, d = 0, e = c.length; e > d; d += 1) b[c[d]] = a[d]; - return b - }) - }, - objectToCsv: function (a, b) { - b = void 0 !== b ? b : {}; - var c = b.columns, - d = b.includeColumns, - e = "", - f = "", - g = function (b) { - var d, e, f, g = "", - i = a.length, - j = c.length; - for (e = 0; i > e; e += 1) { - for (b = a[e], f = 0; j > f; f += 1) d = c[f], g += h(b[d]), g += j - 1 > f ? "," : ""; - g += "\n" - } - return g - }, - i = function () { - var b, d, e, f, g, i, j, k = [], - l = a.length, - m = []; - for (g = 0; l > g; g += 1) { - e = a[g], j = []; - for (f in e) e.hasOwnProperty(f) && (i = k.indexOf(f), -1 === i && (i = k.push(f), i -= 1), j[i] = h(e[f])); - 0 === g && (b = j.length), m.push(j) - } - return d = k.length, b !== d && m.forEach(function (a) { - a.length = d - }), c = k, m.map(function (a) { - return a.join(",") - }).join("\n") + "\n" - }; - return d = void 0 === d ? !0 : !!d, e = void 0 !== c ? g() : i(), d && (c.forEach(function (a) { - f += h(a) + "," - }), f = f.substring(0, f.length - 1), e = f + "\n" + e), e - } - }; - return "object" == typeof exports && (exports.arrayToCsv = i.arrayToCsv, exports.csvToArray = i.csvToArray, exports.objectToCsv = i.objectToCsv, exports.csvToObject = i.csvToObject), i - }() -}); - -module.exports = CsvHelper; diff --git a/src/utilities/ErrorHandler.js b/src/utilities/ErrorHandler.js deleted file mode 100644 index 475a95484..000000000 --- a/src/utilities/ErrorHandler.js +++ /dev/null @@ -1,43 +0,0 @@ -var jsface = require('jsface'), - log = require('./Logger'), - Globals = require('./Globals'); - -/** - * @name ErrorHandler - * Error Handler class for Newman - */ -var ErrorHandler = jsface.Class({ - $singleton: true, - - requestError: function (request, error) { - log.error("RequestError: [" + request.id + "] '" + request.name + "' terminated. Complete error: \n"); - log.error(error.stack); - log.error('\n'); - }, - - responseError: function (response) { - log.error(response.statusCode); - }, - - parseError: function (msg) { - log.error("ParseError: " + msg); - }, - - testCaseError: function (testcase) { - log.testCaseError(testcase); - }, - - exceptionError: function (err) { - log.exceptionError(err); - }, - - terminateWithError: function (msg) { - log.error(msg + "\n"); - if (Globals.updateMessage) { - console.log(Globals.updateMessage); - } - process.exit(1); - } -}); - -module.exports = ErrorHandler; diff --git a/src/utilities/EventEmitter.js b/src/utilities/EventEmitter.js deleted file mode 100644 index 8b1afc431..000000000 --- a/src/utilities/EventEmitter.js +++ /dev/null @@ -1,39 +0,0 @@ -var jsface = require("jsface"), - events = require("events"), - emitter = new events.EventEmitter(); - -/** - * @name EventEmitter - * @namespace - * @classdesc Mixin class providing event functionality. - */ -var EventEmitter = jsface.Class({ - addEventListener: function (name, callback) { - emitter.on(name, callback); - return this; - }, - addEventListenerOnce: function (name, callback) { - emitter.once(name, callback); - return this; - }, - removeEventListener: function (name, callback) { - emitter.removeListener(name, callback); - return this; - }, - removeAllListeners: function () { - emitter.removeAllListeners(); - return this; - }, - getAllListeners: function (name) { - return emitter.listeners(name); - }, - listenerCount: function (name) { - return events.EventEmitter.listenerCount(emitter, name); - }, - emit: function (name) { - emitter.emit.apply(emitter, arguments); - return this; - } -}); - -module.exports = EventEmitter; diff --git a/src/utilities/Globals.js b/src/utilities/Globals.js deleted file mode 100644 index f8d46bb7a..000000000 --- a/src/utilities/Globals.js +++ /dev/null @@ -1,48 +0,0 @@ -var jsface = require('jsface'); -var packageVersion = require('../../package.json').version; - -/** - * @name Globals - * @namespace - * @classdesc Globals to be used throught Newman. - */ -var Globals = jsface.Class({ - $singleton: true, - - newmanVersion: packageVersion, - - /** - * Used to add the Globals used through out the app - * @param {Object} requestJSON Request JSON. - * @param {Object} options Newman Options. - */ - addEnvironmentGlobals: function (requestJSON, options) { - this.requestJSON = requestJSON; - this.envJson = options.envJson || {}; - this.iterationNumber = 1; - this.outputFile = options.outputFile || ''; - this.outputFileVerbose = options.outputFileVerbose || ''; - this.testReportFile = options.testReportFile || ''; - this.globalJson = options.globalJSON || []; - this.dataJson = []; - this.stopOnError = options.stopOnError; - this.noColor = options.noColor; - this.noTestSymbols = options.noTestSymbols; - this.asLibrary = options.asLibrary; - this.strictSSL = options.strictSSL || true; - this.exitCode = 0; - this.updateMessage = ""; - this.folder = options.folderName || false; - this.iterationCount = options.iterationCount || 1; - this.html = options.html || false; - this.responseEncoding = options.responseEncoding; - this.avoidRedirects = options.avoidRedirects; - this.whiteScreen = options.whiteScreen; - this.recurseLimit = 10; - if (typeof options.recurseLimit !== "undefined") { - this.recurseLimit = options.recurseLimit; - } - } -}); - -module.exports = Globals; diff --git a/src/utilities/HelperProcessor.js b/src/utilities/HelperProcessor.js deleted file mode 100644 index 48b0299c3..000000000 --- a/src/utilities/HelperProcessor.js +++ /dev/null @@ -1,670 +0,0 @@ -var jsface = require('jsface'), - fs = require('fs'), - Errors = require('./ErrorHandler'), - Helpers = require('./Helpers'), - CryptoJS = require('crypto-js'), - OAuth = require('./oauth.js'), - Hawk = require('hawk'), - btoa = require("btoa"), - aws4 = require('aws4'), - url = require('url'), - queryString = require('querystring'), - _und = require('underscore'), - _ = require('lodash'); - -/** - * @name Helpers - * @namespace - * @classdesc Helper class to use Auth Helpers - */ -var HelperProcessor = jsface.Class({ - $singleton: true, - - _useAuthHelpers: function (request) { - if (request.currentHelper === "normal") { - return; - } - else if (request.currentHelper === "basicAuth") { - this._useBasicAuth(request); - } - else if (request.currentHelper === "digestAuth") { - this._useDigestAuth(request); - } - else if (request.currentHelper === "oAuth1") { - this._useOAuth1(request); - } - else if (request.currentHelper === "hawkAuth") { - this._useHawkAuth(request); - } - else if(request.currentHelper==="awsSigV4") { - this._useAWSSigV4Auth(request) - } - }, - - _useAWSSigV4Auth: function(request) { - var properties = request.transformed.helperAttributes; - var credentials = { - accessKeyId: properties.accessKey, - secretAccessKey: properties.secretKey - }; - var parsedURL = url.parse(request.transformed.url); - var allHeaders = Helpers.generateHeaderObj(request.transformed.headers); - var body = this._getRequestBody(request); - - if (allHeaders['x-amz-date']) { // The AWS signing library hates lowercase header - allHeaders['X-Amz-Date'] = allHeaders['x-amz-date']; - delete allHeaders['x-amz-date']; - } - var signedParams = aws4.sign({ - host: parsedURL.hostname, - protocol: parsedURL.protocol, - port: parsedURL.port, - path: parsedURL.path, - service: properties.serviceName || properties.service || 'execute-api', - region: properties.awsRegion || properties.region, - method: request.method, - body: body, - headers: allHeaders - }, credentials); - - var headerObj = _und.extend({}, Helpers.generateHeaderObj(request.transformed.headers), signedParams.headers); - var finalHeaders = {}; - - // Remove duplicate headers which may have difference cases, e.g: x-amx-date and X-Amz-Date - var headerKeys = Object.keys(headerObj); - headerKeys.forEach(function (key) { - if (key.toLowerCase() !== 'host') { - finalHeaders[key.toLowerCase()] = headerObj[key]; - } - }); - request.transformed.headers = Helpers.generateHeaderStringFromObj(finalHeaders); - }, - - _useBasicAuth: function (request) { - var authHeaderKey = "Authorization"; - var username = request.transformed.helperAttributes.username; - var password = request.transformed.helperAttributes.password; - - var rawString = username + ":" + password; - var encodedString = "Basic " + btoa(rawString); - - var headerObj = Helpers.generateHeaderObj(request.transformed.headers); - headerObj[authHeaderKey] = encodedString; - var headerString = Helpers.generateHeaderStringFromObj(headerObj); - request.transformed.headers = headerString; - }, - - _useHawkAuth: function (request) { - var authHeaderKey = "Authorization"; - var hawk_id = request.transformed.helperAttributes.hawk_id; - var hawk_key = request.transformed.helperAttributes.hawk_key; - var algorithm = request.transformed.helperAttributes.algorithm; - var user = request.transformed.helperAttributes.user || undefined; - var nonce = request.transformed.helperAttributes.nonce; - var ext = request.transformed.helperAttributes.ext || undefined; - var app = request.transformed.helperAttributes.app || undefined; - var dlg = request.transformed.helperAttributes.dlg || undefined; - var timestamp = request.transformed.helperAttributes.timestamp || undefined; - - var options = { - credentials: { - id: hawk_id, - key: hawk_key, - algorithm: algorithm - }, - nonce: nonce, - ext: ext, - app: app, - dlg: dlg, - timestamp: timestamp, - user: user - }; - - var result = Hawk.client.header(request.transformed.url, request.method, options); - if (result.err) { - Errors.requestError(request, new Error('Unable to compute Hawk Auth parameters: ' + result.err)); - return; - } - - var headerObj = Helpers.generateHeaderObj(request.transformed.headers); - headerObj[authHeaderKey] = result.field; - request.transformed.headers = Helpers.generateHeaderStringFromObj(headerObj); - }, - - _useDigestAuth: function (request) { - var authHeaderKey = "Authorization"; - var helperAttrs = request.transformed.helperAttributes; - - - var algorithm = helperAttrs.algorithm; - - var username = helperAttrs.username; - var realm = helperAttrs.realm; - var password = helperAttrs.password; - - var method = request.method; - - var nonce = helperAttrs.nonce; - var nonceCount = helperAttrs.nonceCount; - var clientNonce = helperAttrs.clientNonce; - - var opaque = helperAttrs.opaque; - var qop = helperAttrs.qop; - var body = this._getRequestBody(request); - - var url = request.url; - var urlParts = this._splitUrlIntoHostAndPath(url); - var digestUri = urlParts.path; - - var a1; - - if (algorithm === "MD5-sess") { - var a0 = CryptoJS.MD5(username + ":" + realm + ":" + password).toString(); - a1 = a0 + ":" + nonce + ":" + clientNonce; - } - else { - a1 = username + ":" + realm + ":" + password; - } - - var a2; - - if (qop === "auth-int") { - a2 = method + ":" + digestUri + ":" + body; - } - else { - a2 = method + ":" + digestUri; - } - - - var ha1 = CryptoJS.MD5(a1).toString(); - var ha2 = CryptoJS.MD5(a2).toString(); - - var response; - - if (qop === "auth-int" || qop === "auth") { - response = CryptoJS.MD5(ha1 + ":" + nonce + ":" + nonceCount + ":" + clientNonce + ":" + qop + ":" + ha2).toString(); - } - else { - response = CryptoJS.MD5(ha1 + ":" + nonce + ":" + ha2).toString(); - } - - var headerVal = "Digest "; - headerVal += "username=\"" + username + "\", "; - headerVal += "realm=\"" + realm + "\", "; - headerVal += "nonce=\"" + nonce + "\", "; - headerVal += "uri=\"" + digestUri + "\", "; - - if (qop === "auth" || qop === "auth-int") { - headerVal += "qop=" + qop + ", "; - } - - if (qop === "auth" || qop === "auth-int" || algorithm === "MD5-sess") { - headerVal += "nc=" + nonceCount + ", "; - headerVal += "cnonce=\"" + clientNonce + "\", "; - } - - headerVal += "response=\"" + response + "\", "; - headerVal += "opaque=\"" + opaque + "\""; - - var headerObj = Helpers.generateHeaderObj(request.transformed.headers); - headerObj[authHeaderKey] = headerVal; - var headerString = Helpers.generateHeaderStringFromObj(headerObj); - request.transformed.headers = headerString; - }, - - _useOAuth1: function (request) { - var i, j, count, length; - var params = [], bodyParams = []; - var urlParams = this._getUrlVars(request.transformed && request.transformed.url ? request.transformed.url : - request.url); - - var dataMode = request.dataMode; - - params = params.concat(urlParams); - - bodyParams = request.data || []; - if (bodyParams.length !== 0) { - params = params.concat(bodyParams); - } - - params = this._removeOAuthKeys(params); - - var signatureKey = "oauth_signature"; - var oAuthParams = []; - - var helperAttrs = request.transformed.helperAttributes; - helperAttrs.nonce = OAuth.nonce(6) + ""; - helperAttrs.timestamp = OAuth.timestamp() + ""; - - var signatureParams = [ - { key: "oauth_consumer_key", value: helperAttrs.consumerKey }, - { key: "oauth_token", value: helperAttrs.token }, - { key: "oauth_signature_method", value: helperAttrs.signatureMethod }, - { key: "oauth_timestamp", value: helperAttrs.timestamp }, - { key: "oauth_nonce", value: helperAttrs.nonce }, - { key: "oauth_version", value: helperAttrs.version } - ]; - - for (i = 0; i < signatureParams.length; i++) { - var param = signatureParams[i]; - oAuthParams.push(param); - } - - var signature = this.generateSignature(request, helperAttrs); - - if (signature === null) { - return; - } - - oAuthParams.push({ key: signatureKey, value: signature }); - - var addToHeader = helperAttrs.header; - - if (addToHeader) { - var realm = helperAttrs.realm; - var authHeaderKey = "Authorization"; - var rawString = "OAuth "; - if (realm != null && realm.trim() !== "") { - rawString += "realm=\"" + encodeURIComponent(realm) + "\","; - } - var len = oAuthParams.length; - - for (i = 0; i < len; i++) { - if (oAuthParams[i].value === null || oAuthParams[i].value.trim() === "") { - continue; - } - rawString += encodeURIComponent(oAuthParams[i].key) + "=\"" + encodeURIComponent(oAuthParams[i].value) + "\","; - } - - rawString = rawString.substring(0, rawString.length - 1); - var headerObj = Helpers.generateHeaderObj(request.transformed.headers); - headerObj[authHeaderKey] = rawString; - var headerString = Helpers.generateHeaderStringFromObj(headerObj); - request.transformed.headers = headerString; - - } else { - params = params.concat(oAuthParams); - var newParams = []; - _und.map(params, function (param) { - param.enabled = true; - param.type = "text"; - newParams.push(param); - }); - if (request.method.toLowerCase() !== "post" && request.method.toLowerCase() !== "put") { - //console.log("Setting URL params", params); - - this.setUrlParamStringWithOptBlankValRemoval(request, params, null, true); - } else { - if (dataMode === 'urlencoded') { - if (!request.transformed.data || !(request.transformed.data instanceof Array)) { - request.transformed.data = []; - } - request.transformed.data = request.transformed.data.concat(newParams); - } - else if (dataMode === 'params') { - if (!request.transformed.data || !(request.transformed.data instanceof Array)) { - request.transformed.data = []; - } - request.transformed.data = request.transformed.data.concat(newParams); - } - else if (dataMode === 'raw') { - this.setUrlParamStringWithOptBlankValRemoval(request, params, null, true); - } - } - } - - }, - - _getRequestBody: function (request) { - var numParams, params, retVal; - var i; - if (request.method.toLowerCase() === "post" || request.method.toLowerCase() === "put" || - request.method.toLowerCase() === "delete" || request.method.toLowerCase() === "patch") { - if (request.dataMode === "urlencoded") { - if (!request.transformed.data || (!request.transformed.data.length)) { - return ''; - } - params = this._parseFormParams(request.transformed.data); - return queryString.stringify(params); - } - else if (request.dataMode === "params") { - if (!(request.transformed.data && !request.transformed.data.length)) { - return ''; - } - numParams = request.transformed.data.length; - params = request.transformed.data; - retVal = this._getDummyFormDataBoundary(); - for (i = 0; i < numParams; i++) { - if (params[i].type === "text") { - retVal += '
Content-Disposition: form-data; name="' + params[i].key + '"

'; - retVal += params[i].value + "
"; - } - else if (params[i].type === "file") { - retVal += "
Content-Disposition: form-data; name=\"" + params[i].key + "\"; filename="; - retVal += "\"" + params[i].value.name + "\"
"; - retVal += "Content-Type: " + params[i].value.type; - retVal += "


"; - } - } - retVal += this._getDummyFormDataBoundary(); - return retVal; - } - else if (request.dataMode === "raw") { - return request.transformed.data; - } - else { - return false; - } - } - else { - return false; - } - }, - - // Fixed - _getDummyFormDataBoundary: function () { - var boundary = "----WebKitFormBoundaryE19zNvXGzXaLvS5C"; - return boundary; - }, - - _splitUrlIntoHostAndPath: function (url) { - var path = ""; - var host; - - var parts = url.split('/'); - host = parts[2]; - var partsCount = parts.length; - for (var i = 3; i < partsCount; i++) { - path += "/" + parts[i]; - } - - var quesLocation = path.indexOf('?'); - var hasParams = quesLocation >= 0 ? true : false; - - if (hasParams) { - parts = this.getUrlVars(path); - var count = parts.length; - var encodedPath = path.substr(0, quesLocation + 1); - for (var j = 0; j < count; j++) { - var value = parts[j].value; - var key = parts[j].key; - //value = encodeURIComponent(value); - //key = encodeURIComponent(key); - - encodedPath += key + "=" + value + "&"; - } - - encodedPath = encodedPath.substr(0, encodedPath.length - 1); - - path = encodedPath; - } - - return { host: host, path: path }; - }, - - removeOAuthKeys: function (params) { - var i, count; - var oauthParams = [ - "oauth_consumer_key", - "oauth_token", - "oauth_signature_method", - "oauth_timestamp", - "oauth_nonce", - "oauth_version", - "oauth_signature" - ]; - - var newParams = []; - var oauthIndexes = []; - - for (i = 0, count = params.length; i < count; i++) { - var index = _und.indexOf(oauthParams, params[i].key); - if (index < 0) { - newParams.push(params[i]); - } - } - - return newParams; - }, - - process: function () { - var request = this.get("request"); - this.processCustomRequest(request); - }, - - _getUrlVars: function (url, associative) { - if (url === null) { - return []; - } - - var quesLocation = url.indexOf('?'); - var equalLocation = url.indexOf('='); - - if (equalLocation < 0) { - return []; - } - - if (quesLocation < 0) { - quesLocation = -1; - return []; - } - - var vars = [], hash, varsAssoc = {}; - var hashes = url.slice(quesLocation + 1).split('&'); - var element; - - for (var i = 0; i < hashes.length; i++) { - equalLocation = hashes[i].indexOf('='); - - if (equalLocation !== -1) { - element = { - "key": hashes[i].slice(0, equalLocation), - "value": hashes[i].slice(equalLocation + 1) - }; - } - else { - element = { - "key": hashes[i].slice(0, hashes[i].length), - "value": "" - }; - } - - if (associative) { - varsAssoc[element.key] = element.value; - } - else { - vars.push(element); - } - } - - if (associative) { - return varsAssoc; - } else { - return vars; - } - }, - - setUrlParamStringWithOptBlankValRemoval: function (request, params, silent, removeBlankParams) { - var paramArr = []; - var url = _.get(request, 'transformed.url') ? request.transformed.url : request.url; - - for (var i = 0; i < params.length; i++) { - var p = params[i]; - if (p.key && p.key !== "") { - p.key = p.key.replace(/&/g, '%26'); - - if (!p.value) { - p.value = ""; - } - p.value = p.value.replace(/&/g, '%26'); - if (removeBlankParams === false || p.value !== "") { - paramArr.push(p.key + "=" + p.value); - } - } - } - - var baseUrl = url.split("?")[0]; - if (paramArr.length > 0) { - url = baseUrl + "?" + paramArr.join('&'); - } - else { - //Has key/val pair - if (url.indexOf("?") > 0 && url.indexOf("=") > 0) { - url = baseUrl; - } - } - - if (request.transformed) { - request.transformed.url = url; - } - else { - request.url = url; - } - - }, - - _removeOAuthKeys: function (params) { - var i, count; - var oauthParams = [ - "oauth_consumer_key", - "oauth_token", - "oauth_signature_method", - "oauth_timestamp", - "oauth_nonce", - "oauth_version", - "oauth_signature" - ]; - - var newParams = []; - var oauthIndexes = []; - - for (i = 0, count = params.length; i < count; i++) { - var index = _und.indexOf(oauthParams, params[i].key); - if (index < 0) { - newParams.push(params[i]); - } - } - - return newParams; - }, - - generateSignature: function (request, helperAttrs) { - //Make sure the URL is urlencoded properly - //Set the URL keyval editor as well. Other get params disappear when you click on URL params again - var i; - var url = request.transformed.url; - - var processedUrl; - - var realm = helperAttrs.realm; - var method = request.method; - var requestBody = request.body; //will this work? :S - - processedUrl = url; - //processedUrl = ensureProperUrl(processedUrl); - - if (processedUrl.indexOf('?') > 0) { - processedUrl = processedUrl.split("?")[0]; - } - - var message = { - action: processedUrl, - method: method, - parameters: [] - }; - - var signatureParams = [ - { key: "oauth_consumer_key", value: helperAttrs.consumerKey }, - { key: "oauth_token", value: helperAttrs.token }, - { key: "oauth_signature_method", value: helperAttrs.signatureMethod }, - { key: "oauth_timestamp", value: helperAttrs.timestamp }, - { key: "oauth_nonce", value: helperAttrs.nonce }, - { key: "oauth_version", value: helperAttrs.version } - ]; - - for (i = 0; i < signatureParams.length; i++) { - var param = signatureParams[i]; - if (param.value !== "") { - message.parameters.push([param.key, param.value]); - } - } - - //Get parameters - var urlParams = this._getUrlVars(request.transformed && request.transformed.url ? request.transformed.url : - request.url); - - var bodyParams; - - if (method.toLowerCase() === "post" || method.toLowerCase() === "put") { - bodyParams = request.transformed.data; - - if (typeof bodyParams === "undefined") { - bodyParams = []; - } - } - else { - bodyParams = []; - } - - var params = _und.union(urlParams, bodyParams); - var param; - var existingOAuthParams = _und.union(signatureParams, [{ key: "oauth_signature", value: "" }]); - var pos; - - for (i = 0; i < params.length; i++) { - param = params[i]; - if (param.key) { - pos = Helpers.findPosition(existingOAuthParams, "key", param.key); - if (pos < 0) { - if (param.value !== "") { - message.parameters.push([param.key, param.value]); - } - } - } - } - - var accessor = {}; - if (helperAttrs.consumerSecret !== '') { - accessor.consumerSecret = helperAttrs.consumerSecret; - } - if (helperAttrs.tokenSecret !== '') { - accessor.tokenSecret = helperAttrs.tokenSecret; - } - - return OAuth.SignatureMethod.sign(message, accessor); - }, - - htmlEscape: function (str) { - return String(str) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(//g, '>'); - }, - - _parseFormParams: function (reqData) { - var params = {}; - reqData.sort(function (a, b) { - return (a.key <= b.key) ? -1 : 1; - }); - reqData.forEach(function (paramData) { - if (paramData.enabled) { - // Check if this is a duplicate - if (params[paramData.key]) { - var original = params[paramData.key]; - if (Array.isArray(original)) { - original.push(paramData.value); - } else { - params[paramData.key] = [original].concat(paramData.value); - } - } else { - params[paramData.key] = paramData.value; - } - } - }); - return params; - } -}); - -module.exports = HelperProcessor; diff --git a/src/utilities/Helpers.js b/src/utilities/Helpers.js deleted file mode 100644 index 554c2f252..000000000 --- a/src/utilities/Helpers.js +++ /dev/null @@ -1,228 +0,0 @@ -var jsface = require('jsface'), - fs = require('fs'), - Errors = require('./ErrorHandler'), - CSVHelper = require('./CsvHelper'), - _und = require('underscore'); - -/** - * @name Helpers - * @namespace - * @classdesc Helper class with useful methods used throughout Newman - */ -var Helpers = jsface.Class({ - $singleton: true, - - /** - * @function - * @memberOf Helpers - * @param {String} url [Takes a URL as an input] - * @return {Boolean} [Returns is the url is valid or not.] - */ - validateCollectionUrl: function (url) { - var result = url.match(/(https|http):\/\/([_a-z\d\-]+(\.[_a-z\d\-]+)+)(([_a-z\d\-\\\.\/]+[_a-z\d\-\\\/])+)*/); - if (!result) { - Errors.terminateWithError("Please specify a valid URL"); - } - }, - - fileExists: function (path) { - try { - return fs.statSync(path); - } - catch (e) { - console.log(e.stack || e); - } - }, - - validateDataFile: function (file) { - if (!this.fileExists(file)) { - Errors.terminateWithError("Specified file does not exist: " + file); - } - }, - - validateCollectionFile: function (file) { - if (!this.fileExists(file)) { - Errors.terminateWithError("Specified collection file does not exist: " + file); - } - }, - - validateEnvironmentFile: function (file) { - if (!this.fileExists(file)) { - Errors.terminateWithError("Specified environment file does not exist: " + file); - } - }, - - validateGlobalFile: function (file) { - if (!this.fileExists(file)) { - Errors.terminateWithError("Specified globals does not exist: " + file); - } - }, - - validateEncoding: function (encoding) { - var validEncs = ['ascii', 'utf8', 'utf16le', 'ucs2', 'base64', 'binary', 'hex']; - if (validEncs.indexOf(encoding) === -1) { - Errors.terminateWithError("Please specify a valid encoding. Supported values are ascii,utf8,utf16le,ucs2,base64,binary,hex"); - } - }, - - // transforms an array of - // [{"id": 1, "name":"foo"}, { .. }, ..] - // into an object {"key": "id", "value": "foo"}] - transformToKeyValue: function (json) { - return _und.map(_und.pairs(json), function (pair) { - return { key: pair[0], value: pair[1] }; - }, []); - }, - - // transforms an array of - // [{ "key": "id", "value": "20" }, { "key": "name", "value": "joe" }] - // into an object {"id": "20", "name": "joe"} - transformFromKeyValue: function (kvpairs) { - return _und.object(_und.pluck(kvpairs, "key"), _und.pluck(kvpairs, "value")); - }, - - transformFromKeyValueForRequestData: function (kvpairs) { - if(!_und.isArray(kvpairs)) { - return {}; - } - var retVal = {}, - count = kvpairs.length; - for(var i = 0; i < count; i++) { - if(retVal.hasOwnProperty(kvpairs[i].key)) { - //2 properties with same key. convert to array - if(retVal[kvpairs[i].key] instanceof Array) { - retVal[kvpairs[i].key] = retVal[kvpairs[i].key].concat(kvpairs[i].value); - } - else { - retVal[kvpairs[i].key] = [retVal[kvpairs[i].key], kvpairs[i].value]; - } - } - else { - retVal[kvpairs[i].key] = kvpairs[i].value; - } - } - - return retVal; - }, - - // generates a header object from a string where headers are of the form - // Accept-Language: En\nCache-Control: 123\nPragma: Akamai\n - generateHeaderObj: function (headers) { - var headerObj = {}; - if (headers && headers.split) { - headers.split('\n').forEach(function (str) { - if (str) { - var splitIndex = str.indexOf(':'); - var headerName = str.substr(0, splitIndex); - if (headerName.indexOf("//") === 0) { - //do nothing...disabled header - } - else { - headerObj[headerName] = str.substr(splitIndex + 1).trim(); - } - } - }); - } - return headerObj; - }, - - generateHeaderStringFromObj: function (headerObj) { - var ret = ""; - for (var hKey in headerObj) { - if (headerObj.hasOwnProperty(hKey)) { - ret += hKey + ":" + headerObj[hKey] + "\n"; - } - } - return ret; - }, - - getResponseHeader: function (headerString, headers) { - if (headerString == null || headerString.length === 0) { - return null; - } - if (headers.hasOwnProperty(headerString.toLowerCase())) { - return headers[headerString.toLowerCase()]; - } - return null; - }, - - createProperCasedHeaderObject: function (headers) { - var retVal = {}; - for (var key in headers) { - if (headers.hasOwnProperty(key)) { - retVal[Helpers.toHeaderCase(key)] = headers[key]; - } - } - return retVal; - }, - - toHeaderCase: function (str) { - var toUpper = true; - var retVal = ""; - var len = str.length; - var wordBreakers = "- "; - for (var i = 0; i < len; i++) { - if (toUpper) { - toUpper = false; - retVal += str[i].toUpperCase(); - } - else { - retVal += str[i]; - } - if (wordBreakers.indexOf(str[i]) !== -1) { - toUpper = true; - } - } - return retVal; - }, - - kvArrayToObject: function (array) { - var obj = {}; - _und.each(array, function (kv) { - obj[kv.key] = kv.value; - }); - return obj; - }, - - objectToKvArray: function (obj) { - var arr = []; - for (var property in obj) { - if (obj.hasOwnProperty(property)) { - arr.push({ "key": property, "value": obj[property] }); - } - } - return arr; - }, - - augmentDataArrays: function (oldArray, newArray) { - var existingEnvVars = this.kvArrayToObject(oldArray); - var dataFileVars = this.kvArrayToObject(newArray); - var finalObject = existingEnvVars; - for (var property in dataFileVars) { - if (dataFileVars.hasOwnProperty(property)) { - finalObject[property] = dataFileVars[property]; - } - } - var finalArray = this.objectToKvArray(finalObject); - //Globals.envJson.values = finalArray; - return finalArray; - }, - - CSVUtil: CSVHelper.CSV, - - findPosition: function (list, key, value) { - var listLength = list.length; - var pos = -1; - for (var i = 0; i < listLength; i++) { - var h = list[i]; - if (h['key'] === value) { - pos = i; - break; - } - } - - return pos; - } -}); - -module.exports = Helpers; diff --git a/src/utilities/HtmlExporter.js b/src/utilities/HtmlExporter.js deleted file mode 100644 index 7636559be..000000000 --- a/src/utilities/HtmlExporter.js +++ /dev/null @@ -1,28 +0,0 @@ -var jsface = require('jsface'), - Globals = require('./Globals'), - log = require('./Logger'), - fs = require('fs'); - -/** - * @class HtmlExporter - * @classdesc Class Used to generate pretty html reports - */ -var HtmlExporter = jsface.Class({ - $singleton: true, - templates: null, - generateHTML: function (resultObj) { - var template; - //Always use existing file - template = require('../templates/htmlResponseTemplate'); - var htmlPath = Globals.html; - try { - fs.writeFileSync(htmlPath, template(resultObj)); - log.note("\nHTML Report written to: " + htmlPath + "\n"); - } - catch (e) { - log.error("Error writing to file. Try using sudo. Error: " + (e.stack || e)); - } - } -}); - -module.exports = HtmlExporter; diff --git a/src/utilities/HttpStatusCodes.js b/src/utilities/HttpStatusCodes.js deleted file mode 100644 index e59819b20..000000000 --- a/src/utilities/HttpStatusCodes.js +++ /dev/null @@ -1,290 +0,0 @@ -var jsface = require("jsface"); - -var HttpStatusCodes = jsface.Class({ - $singleton: true, - - getCodes: function () { - return this.httpStatusCodes; - }, - - httpStatusCodes: { - 100: { - "name": "Continue", - "detail": "This means that the server has received the request headers, and that the client should proceed to send the request body (in the case of a request for which a body needs to be sent; for example, a POST request). If the request body is large, sending it to a server when a request has already been rejected based upon inappropriate headers is inefficient. To have a server check if the request could be accepted based on the request's headers alone, a client must send Expect: 100-continue as a header in its initial request and check if a 100 Continue status code is received in response before continuing (or receive 417 Expectation Failed and not continue)." - }, - 101: { - "name": "Switching Protocols", - "detail": "This means the requester has asked the server to switch protocols and the server is acknowledging that it will do so." - }, - 102: { - "name": "Processing (WebDAV) (RFC 2518)", - "detail": "As a WebDAV request may contain many sub-requests involving file operations, it may take a long time to complete the request. This code indicates that the server has received and is processing the request, but no response is available yet. This prevents the client from timing out and assuming the request was lost." - }, - 103: { - "name": "Checkpoint", - "detail": "This code is used in the Resumable HTTP Requests Proposal to resume aborted PUT or POST requests." - }, - 122: { - "name": "Request-URI too long", - "detail": "This is a non-standard IE7-only code which means the URI is longer than a maximum of 2083 characters." - }, - 200: { - "name": "OK", - "detail": "Standard response for successful HTTP requests. The actual response will depend on the request method used. In a GET request, the response will contain an entity corresponding to the requested resource. In a POST request the response will contain an entity describing or containing the result of the action." - }, - 201: { - "name": "Created", - "detail": "The request has been fulfilled and resulted in a new resource being created." - }, - 202: { - "name": "Accepted", - "detail": "The request has been accepted for processing, but the processing has not been completed. The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place." - }, - 203: { - "name": "Non-Authoritative Information (since HTTP/1.1)", - "detail": "The server successfully processed the request, but is returning information that may be from another source." - }, - 204: { - "name": "No Content", - "detail": "The server successfully processed the request, but is not returning any content." - }, - 205: { - "name": "Reset Content", - "detail": "The server successfully processed the request, but is not returning any content. Unlike a 204 response, this response requires that the requester reset the document view." - }, - 206: { - "name": "Partial Content", - "detail": "The server is delivering only part of the resource due to a range header sent by the client. The range header is used by tools like wget to enable resuming of interrupted downloads, or split a download into multiple simultaneous streams" - }, - 207: { - "name": "Multi-Status (WebDAV) (RFC 4918)", - "detail": "The message body that follows is an XML message and can contain a number of separate response codes, depending on how many sub-requests were made." - }, - 208: { - "name": "Already Reported (WebDAV) (RFC 5842)", - "detail": "The members of a DAV binding have already been enumerated in a previous reply to this request, and are not being included again." - }, - 226: { - "name": "IM Used (RFC 3229)", - "detail": "The server has fulfilled a GET request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance. " - }, - 300: { - "name": "Multiple Choices", - "detail": "Indicates multiple options for the resource that the client may follow. It, for instance, could be used to present different format options for video, list files with different extensions, or word sense disambiguation." - }, - 301: { - "name": "Moved Permanently", - "detail": "This and all future requests should be directed to the given URI." - }, - 302: { - "name": "Found", - "detail": "This is an example of industrial practice contradicting the standard. HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect (the original describing phrase was \"Moved Temporarily\"), but popular browsers implemented 302 with the functionality of a 303. Therefore, HTTP/1.1 added status codes 303 and 307 to distinguish between the two behaviours. However, some Web applications and frameworks use the 302 status code as if it were the 303." - }, - 303: { - "name": "See Other", - "detail": "The response to the request can be found under another URI using a GET method. When received in response to a POST (or PUT/DELETE), it should be assumed that the server has received the data and the redirect should be issued with a separate GET message." - }, - 304: { - "name": "Not Modified", - "detail": "Indicates the resource has not been modified since last requested. Typically, the HTTP client provides a header like the If-Modified-Since header to provide a time against which to compare. Using this saves bandwidth and reprocessing on both the server and client, as only the header data must be sent and received in comparison to the entirety of the page being re-processed by the server, then sent again using more bandwidth of the server and client." - }, - 305: { - "name": "Use Proxy (since HTTP/1.1)", - "detail": "Many HTTP clients (such as Mozilla and Internet Explorer) do not correctly handle responses with this status code, primarily for security reasons." - }, - 306: { - "name": "Switch Proxy", - "detail": "No longer used. Originally meant \"Subsequent requests should use the specified proxy.\"" - }, - 307: { - "name": "Temporary Redirect (since HTTP/1.1)", - "detail": "In this occasion, the request should be repeated with another URI, but future requests can still use the original URI. In contrast to 303, the request method should not be changed when reissuing the original request. For instance, a POST request must be repeated using another POST request." - }, - 308: { - "name": "Resume Incomplete", - "detail": "This code is used in the Resumable HTTP Requests Proposal to resume aborted PUT or POST requests." - }, - 400: { - "name": "Bad Request", - "detail": "The request cannot be fulfilled due to bad syntax." - }, - 401: { - "name": "Unauthorized", - "detail": "Similar to 403 Forbidden, but specifically for use when authentication is possible but has failed or not yet been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the requested resource." - }, - 402: { - "name": "Payment Required", - "detail": "Reserved for future use. The original intention was that this code might be used as part of some form of digital cash or micropayment scheme, but that has not happened, and this code is not usually used. As an example of its use, however, Apple's MobileMe service generates a 402 error (\"httpStatusCode:402\" in the Mac OS X Console log) if the MobileMe account is delinquent." - }, - 403: { - "name": "Forbidden", - "detail": "The request was a legal request, but the server is refusing to respond to it. Unlike a 401 Unauthorized response, authenticating will make no difference." - }, - 404: { - "name": "Not Found", - "detail": "The requested resource could not be found but may be available again in the future. Subsequent requests by the client are permissible." - }, - 405: { - "name": "Method Not Allowed", - "detail": "A request was made of a resource using a request method not supported by that resource; for example, using GET on a form which requires data to be presented via POST, or using PUT on a read-only resource." - }, - 406: { - "name": "Not Acceptable", - "detail": "The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request." - }, - 407: { - "name": "Proxy Authentication Required", - "detail": "The client must first authenticate itself with the proxy." - }, - 408: { - "name": "Request Timeout", - "detail": "The server timed out waiting for the request. According to W3 HTTP specifications: \"The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.\"" - }, - 409: { - "name": "Conflict", - "detail": "Indicates that the request could not be processed because of conflict in the request, such as an edit conflict." - }, - 410: { - "name": "Gone", - "detail": "Indicates that the resource requested is no longer available and will not be available again. This should be used when a resource has been intentionally removed and the resource should be purged. Upon receiving a 410 status code, the client should not request the resource again in the future. Clients such as search engines should remove the resource from their indices. Most use cases do not require clients and search engines to purge the resource, and a \"404 Not Found\" may be used instead." - }, - 411: { - "name": "Length Required", - "detail": "The request did not specify the length of its content, which is required by the requested resource." - }, - 412: { - "name": "Precondition Failed", - "detail": "The server does not meet one of the preconditions that the requester put on the request." - }, - 413: { - "name": "Request Entity Too Large", - "detail": "The request is larger than the server is willing or able to process." - }, - 414: { - "name": "Request-URI Too Long", - "detail": "The URI provided was too long for the server to process." - }, - 415: { - "name": "Unsupported Media Type", - "detail": "The request entity has a media type which the server or resource does not support. For example, the client uploads an image as image/svg+xml, but the server requires that images use a different format." - }, - 416: { - "name": "Requested Range Not Satisfiable", - "detail": "The client has asked for a portion of the file, but the server cannot supply that portion. For example, if the client asked for a part of the file that lies beyond the end of the file." - }, - 417: { - "name": "Expectation Failed", - "detail": "The server cannot meet the requirements of the Expect request-header field." - }, - 418: { - "name": "I'm a teapot (RFC 2324)", - "detail": "This code was defined in 1998 as one of the traditional IETF April Fools' jokes, in RFC 2324, Hyper Text Coffee Pot Control Protocol, and is not expected to be implemented by actual HTTP servers. However, known implementations do exist." - }, - 422: { - "name": "Unprocessable Entity (WebDAV) (RFC 4918)", - "detail": "The request was well-formed but was unable to be followed due to semantic errors." - }, - 423: { - "name": "Locked (WebDAV) (RFC 4918)", - "detail": "The resource that is being accessed is locked." - }, - 424: { - "name": "Failed Dependency (WebDAV) (RFC 4918)", - "detail": "The request failed due to failure of a previous request (e.g. a PROPPATCH)." - }, - 425: { - "name": "Unordered Collection (RFC 3648)", - "detail": "Defined in drafts of \"WebDAV Advanced Collections Protocol\",[14] but not present in \"Web Distributed Authoring and Versioning (WebDAV) Ordered Collections Protocol\".[15]" - }, - 426: { - "name": "Upgrade Required (RFC 2817)", - "detail": "The client should switch to a different protocol such as TLS/1.0." - }, - 428: { - "name": "Precondition Required", - "detail": "The origin server requires the request to be conditional. Intended to prevent \"the 'lost update' problem, where a client GETs a resource's state, modifies it, and PUTs it back to the server, when meanwhile a third party has modified the state on the server, leading to a conflict.\"[17] Proposed in an Internet-Draft." - }, - 429: { - "name": "Too Many Requests", - "detail": "The user has sent too many requests in a given amount of time. Intended for use with rate limiting schemes. Proposed in an Internet-Draft." - }, - 431: { - "name": "Request Header Fields Too Large", - "detail": "The server is unwilling to process the request because either an individual header field, or all the header fields collectively, are too large. Proposed in an Internet-Draft." - }, - 444: { - "name": "No Response", - "detail": "An nginx HTTP server extension. The server returns no information to the client and closes the connection (useful as a deterrent for malware)." - }, - 449: { - "name": "Retry With", - "detail": "A Microsoft extension. The request should be retried after performing the appropriate action." - }, - 450: { - "name": "Blocked by Windows Parental Controls", - "detail": "A Microsoft extension. This error is given when Windows Parental Controls are turned on and are blocking access to the given webpage." - }, - 499: { - "name": "Client Closed Request", - "detail": "An Nginx HTTP server extension. This code is introduced to log the case when the connection is closed by client while HTTP server is processing its request, making server unable to send the HTTP header back." - }, - 500: { - "name": "Internal Server Error", - "detail": "A generic error message, given when no more specific message is suitable." - }, - 501: { - "name": "Not Implemented", - "detail": "The server either does not recognise the request method, or it lacks the ability to fulfill the request." - }, - 502: { - "name": "Bad Gateway", - "detail": "The server was acting as a gateway or proxy and received an invalid response from the upstream server." - }, - 503: { - "name": "Service Unavailable", - "detail": "The server is currently unavailable (because it is overloaded or down for maintenance). Generally, this is a temporary state." - }, - 504: { - "name": "Gateway Timeout", - "detail": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server." - }, - 505: { - "name": "HTTP Version Not Supported", - "detail": "The server does not support the HTTP protocol version used in the request." - }, - 506: { - "name": "Variant Also Negotiates (RFC 2295)", - "detail": "Transparent content negotiation for the request results in a circular reference.[21]" - }, - 507: { - "name": "Insufficient Storage (WebDAV) (RFC 4918)", - "detail": "The server is unable to store the representation needed to complete the request." - }, - 508: { - "name": "Loop Detected (WebDAV) (RFC 5842)", - "detail": "The server detected an infinite loop while processing the request (sent in lieu of 208)." - }, - 509: { - "name": "Bandwidth Limit Exceeded (Apache bw/limited extension)", - "detail": "This status code, while used by many servers, is not specified in any RFCs." - }, - 510: { - "name": "Not Extended (RFC 2774)", - "detail": "Further extensions to the request are required for the server to fulfill it.[22]" - }, - 511: { - "name": "Network Authentication Required", - "detail": "The client needs to authenticate to gain network access. Intended for use by intercepting proxies used to control access to the network (e.g. \"captive portals\" used to require agreement to Terms of Service before granting full Internet access via a Wi-Fi hotspot). Proposed in an Internet-Draft." - }, - 598: { - "name": "Network read timeout error", - "detail": "This status code is not specified in any RFCs, but is used by some HTTP proxies to signal a network read timeout behind the proxy to a client in front of the proxy." - }, - 599: { - "name": "Network connect timeout error[23]", - "detail": "This status code is not specified in any RFCs, but is used by some HTTP proxies to signal a network connect timeout behind the proxy to a client in front of the proxy." - } - } -}); - -module.exports = HttpStatusCodes; diff --git a/src/utilities/Importer.js b/src/utilities/Importer.js deleted file mode 100644 index 0f34fbc55..000000000 --- a/src/utilities/Importer.js +++ /dev/null @@ -1,107 +0,0 @@ -var jsface = require('jsface'), - fs = require('fs'), - Errors = require('./ErrorHandler'), - mkdirp = require('mkdirp'); - -/** - * @name Importer - * @namespace - * @classdesc Static class meant to parse and save Postman backup files - */ -var Importer = jsface.Class({ - $singleton: true, - - importFile: function (filePath, pretty) { - var jsonObj = {}; - try { - jsonObj = JSON.parse(fs.readFileSync(filePath, 'utf8')); - } catch (e) { - Errors.terminateWithError("Could not find file: " + filePath + "\n" + e); - } - - var indentLevel = (pretty) ? 2 : 0; - - var collections = jsonObj.collections; - var environments = jsonObj.environments; - var globals = jsonObj.globals; - var i; - - if (!collections instanceof Array) { - Errors.terminateWithError("Collections must be an array...aborting"); - } - if (!environments instanceof Array) { - Errors.terminateWithError("Environments must be an array...aborting"); - } - if (!globals instanceof Array) { - Errors.terminateWithError("Globals must be an array...aborting"); - } - - var numC = collections.length; - var numE = environments.length; - - mkdirp.sync('data/collections'); - mkdirp.sync('data/environments'); - mkdirp.sync('data/globals'); - - - for (i = 0; i < numC; i++) { - this._saveCollection(collections[i], indentLevel); - } - - for (i = 0; i < numE; i++) { - this._saveEnvironment(environments[i], indentLevel); - } - - this._saveGlobal(globals, indentLevel); - }, - - _saveCollection: function (thisCollection, indentLevel) { - var collectionName = thisCollection.name; - if (collectionName === null || collectionName === "") { - collectionName = thisCollection.id; - } - var collectionString = JSON.stringify(thisCollection, undefined, indentLevel) + "\n"; - - fs.writeFile('data/collections/' + collectionName + ".json", collectionString, function (err) { - if (err) { - return console.log(err); - } - else { - console.log('Collection (' + collectionName + ') saved'); - } - }); - }, - - _saveEnvironment: function (environment, indentLevel) { - var envName = environment.name; - if (envName === null || envName === "") { - envName = environment.id; - } - var envString = JSON.stringify(environment, undefined, indentLevel) + "\n"; - - fs.writeFile('data/environments/' + envName + ".json", envString, function (err) { - if (err) { - return console.log(err); - } - else { - console.log('Environment (' + envName + ') saved'); - } - }); - }, - - _saveGlobal: function (globals, indentLevel) { - var globalName = "global_" + (new Date().getTime()); - fs.writeFile('data/globals/' + globalName + ".json", JSON.stringify(globals, undefined, indentLevel) + "\n", function (err) { - if (err) { - return console.log(err); - } - else { - console.log('Global (' + globalName + ') saved'); - } - }); - } - - -}); - -module.exports = Importer; diff --git a/src/utilities/Logger.js b/src/utilities/Logger.js deleted file mode 100644 index 82aded6bc..000000000 --- a/src/utilities/Logger.js +++ /dev/null @@ -1,176 +0,0 @@ -var jsface = require("jsface"), - Symbols = require('./Symbols'), - Globals = require('./Globals'), - _und = require('underscore'), - EventEmitter = require('../utilities/EventEmitter'), - color = require("cli-color"), - ansiTrim = require("cli-color/lib/trim"); - -/** - * @name Logger - * @namespace - * @classdef Logger class, used for all logging inside newman - */ -var Logger = jsface.Class([EventEmitter], { - $singleton: true, - - main: function () { - _und.mixin({ - capitalize: function (string) { - return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase(); - }, - - padStringFromRight: function (string, length) { - if (string.length > length) { - return string.substring(0, length - 3) + "..."; - } - else { - var dif = length - string.length; - for (var i = 0; i < dif; i++) { - string += " "; - } - return string; - } - }, - - padStringFromLeft: function (string, length) { - if (string.length > length) { - return string.substring(0, length - 3) + "..."; - } - else { - var dif = length - string.length; - for (var i = 0; i < dif; i++) { - string = " " + string; - } - return string; - } - } - }); - }, - - _printMessage: function (string, colorFunc) { - if (Globals.noColor) { - string = ansiTrim(colorFunc(string)); - } else { - string = colorFunc(string); - } - process.stdout.write(string); - }, - - success: function (log) { - this._printMessage(log, color.green); - return this; - }, - - error: function (log) { - this._printMessage(log, color.red); - return this; - }, - - notice: function (log) { - this._printMessage(log, color.cyan); - return this; - }, - - warn: function (log) { - this._printMessage(log, color.yellow); - return this; - }, - - normal: function (log) { - if (Globals.whiteScreen) { - this._printMessage(log, color.black); - } - else { - this._printMessage(log, color.white); - } - return this; - }, - - light: function (log) { - this._printMessage(log, color.underline.xterm(245)); - return this; - }, - - note: function (log) { - this._printMessage(log, color.underline.xterm(33)); - return this; - }, - - testCaseSuccess: function (log) { - var msg = Symbols.symbols.ok; - if (Globals.noTestSymbols) { - msg = "PASS "; - } - this.success(" " + msg + log + "\n"); - return this; - }, - - testCaseError: function (log) { - var msg = Symbols.symbols.err; - if (Globals.noTestSymbols) { - msg = "FAIL "; - } - this.error(" " + msg + log + "\n"); - if (Globals.stopOnError) { - if (Globals.asLibrary) { - this.emit('iterationRunnerOver', 1); - } - else { - if (Globals.updateMessage) { - console.log(Globals.updateMessage); - } - process.exit(1); - } - } - else { - Globals.exitCode = 1; - } - return this; - }, - - throwError: function (msg) { - var err = new Error(msg); - this.error(err.message); - throw err; - }, - - exceptionError: function (err) { - this.error((err.message || err)); - if (Globals.stopOnError) { - if (Globals.asLibrary) { - this.emit('iterationRunnerOver', 1); - } - else { - if (Globals.updateMessage) { - console.log(Globals.updateMessage); - } - process.exit(1); - } - } - else { - Globals.exitCode = 1; - } - }, - - showIterationSummary: function (summaryArray) { - this.normal("\nSummary:\n\n"); - this.normal(_und.padStringFromRight("Parent", 25) + "\t" + _und.padStringFromLeft("Pass Count", 10) + "\t" + _und.padStringFromLeft("FailCount", 10) + "\n"); - this.normal("-------------------------------------------------------------\n"); - var oldThis = this; - _und.map(summaryArray, function (summary) { - if (summary.type === 'total') { - oldThis.normal("\n"); - } - - var col1 = _und.capitalize(summary.type) + " " + summary.parentName; - var col2 = summary.passCount + ""; - var col3 = summary.failCount + ""; - oldThis.normal(_und.padStringFromRight(col1, 25) + "\t"); - oldThis.success(_und.padStringFromLeft(col2, 10) + "\t"); - oldThis.error(_und.padStringFromLeft(col3, 10) + "\n"); - }); - } -}); - -module.exports = Logger; diff --git a/src/utilities/Options.js b/src/utilities/Options.js deleted file mode 100644 index 8f913d9c8..000000000 --- a/src/utilities/Options.js +++ /dev/null @@ -1,17 +0,0 @@ -var jsface = require("jsface"); - -/** - * @name Options - * @classdesc Options meant to be used as mixin - * @namespace - */ -var Options = jsface.Class({ - setOptions: function (opts) { - this.opts = opts; - }, - getOptions: function () { - return this.opts; - } -}); - -module.exports = Options; diff --git a/src/utilities/PreRequestScriptProcessor.js b/src/utilities/PreRequestScriptProcessor.js deleted file mode 100644 index 18ca7f176..000000000 --- a/src/utilities/PreRequestScriptProcessor.js +++ /dev/null @@ -1,286 +0,0 @@ -var jsface = require('jsface'), - _und = require('underscore'), - vm = require('vm'), - ErrorHandler = require('./ErrorHandler'), - jsdom = require("jsdom"), - _jq = null, - _lod = require("lodash"), - Helpers = require('./Helpers'), - Backbone = require("backbone"), - CryptoJS = require('crypto-js'), - xmlToJson = require("xml2js"), - Globals = require("./Globals"), - btoa = require("btoa"), - atob = require("atob"), - tv4 = require("tv4"); -require('sugar'); - - -/** - * @class PreRequestScriptProcessor - * @classdesc Class Used for exporting the generated responses. - */ -var PreRequestScriptProcessor = jsface.Class({ - $singleton: true, - _results: [], - - - main: function () { - jsdom.env("", function (err, window) { - _jq = require('jquery')(window); - }); - }, - - /** - * Execute the preRequestScript for this request, and add to the global env vars - * It's the responsibility of the CALLER to save and restore the original global state - * @param {Object} request: the request object - */ - runPreRequestScript: function (request) { - var requestScript = this._getScriptForRequest(request); - if (requestScript) { - var sandbox = this._createSandboxedEnvironment(request); - return this._runScript(request.preRequestScript, sandbox); - } - return {}; - }, - - _getScriptForRequest: function (request) { - return !!request.preRequestScript; - }, - - // run the preRequestScript in a sandbox. Add to the global env vars - _runScript: function (requestScript, sandbox) { - this._evaluateInSandboxedEnvironment(requestScript, sandbox); - //do we return here?? - //env vars are already set - no Impact on test results or anything - return; - }, - - _evaluateInSandboxedEnvironment: function (requestScript, sandbox) { - var sweet = "for(p in sugar.object) Object.prototype[p] = sugar.object[p];"; - sweet += "for(p in sugar.array) {if(p==='create'){Array.create=sugar.array.create} else{Array.prototype[p]= sugar.array[p];}}"; - sweet += "for(p in sugar.string) String.prototype[p] = sugar.string[p];"; - sweet += "for(p in sugar.date) {if(p==='create'){Date.create=sugar.date.create} else{Date.prototype[p]= sugar.date[p];}}"; - sweet += "for(p in sugar.number) Number.prototype[p]= sugar.number[p];"; - sweet += "for(p in sugar.funcs) {" + - "Object.defineProperty(Function.prototype, p, sugar.funcs[p]);" + - "}"; - - //to ensure that environment. and global. references are updated - var setEnvHack = "postman.setEnvironmentVariable = function(key,val) {postman.setEnvironmentVariableReal(key,val);environment[key]=val;};"; - setEnvHack += "postman.setGlobalVariable = function(key,val) {postman.setGlobalVariableReal(key,val);globals[key]=val;};"; - setEnvHack += "postman.clearGlobalVariable = function(key) {postman.clearGlobalVariableReal(key);delete globals[key];};"; - setEnvHack += "postman.clearEnvironmentVariable = function(key) {postman.clearEnvironmentVariableReal(key);delete environment[key];};"; - setEnvHack += "postman.clearGlobalVariables = function() {postman.clearGlobalVariablesReal();globals={};};"; - setEnvHack += "postman.clearEnvironmentVariables = function() {postman.clearEnvironmentVariablesReal();environment={};};"; - - //to ensure that JSON.parse throws the right error - setEnvHack += '(function () { \ - var nativeJSONParser = JSON.parse; \ - JSON.parse = function () { \ - try { \ - return nativeJSONParser.apply(JSON, arguments); \ - } catch (e) { \ - e && (e.message = "Encountered an error during JSON.parse(): " + e.message);\ - throw e; \ - } \ - }; \ - }());'; - - requestScript = sweet + 'String.prototype.has = function(value){ return this.indexOf(value) > -1};' + setEnvHack + requestScript; - - try { - vm.runInNewContext(requestScript, sandbox); - } catch (err) { - ErrorHandler.exceptionError(err); - } - //what do we return?? - //return sandbox.tests; - }, - - // sets the env vars json as a key value pair - _setEnvironmentContext: function () { - return Helpers.transformFromKeyValue(Globals.envJson.values); - }, - - // sets the global vars json as a key value pair - _setGlobalContext: function () { - return Helpers.transformFromKeyValue(Globals.globalJson.values); - }, - - // sets the data vars json as a key value pair - _setDataContext: function () { - return Helpers.transformFromKeyValue(Globals.dataJson.values); - }, - - _getTransformedRequestData: function (request) { - var transformedData; - - if (request.transformed.data === "") { - return {}; - } - if (request.dataMode === "raw") { - transformedData = request.transformed.data; - } else { - transformedData = Helpers.transformFromKeyValueForRequestData(request.transformed.data); - } - return transformedData; - }, - - _createSandboxedEnvironment: function (request) { - var sugar = { array: {}, object: {}, string: {}, funcs: {}, date: {}, number: {} }; - Object.extend(); - Object.getOwnPropertyNames(Array.prototype).each(function (p) { - sugar.array[p] = Array.prototype[p]; - }); - sugar.array["create"] = Array.create; - Object.getOwnPropertyNames(Object.prototype).each(function (p) { - sugar.object[p] = Object.prototype[p]; - }); - sugar.object["extended"] = Object.extended; - - Object.getOwnPropertyNames(String.prototype).each(function (p) { - sugar.string[p] = String.prototype[p]; - }); - Object.getOwnPropertyNames(Number.prototype).each(function (p) { - sugar.number[p] = Number.prototype[p]; - }); - Object.getOwnPropertyNames(Date.prototype).each(function (p) { - sugar.date[p] = Date.prototype[p]; - }); - sugar.date["create"] = Date.create; - Object.getOwnPropertyNames(Function.prototype).each(function(p) { - sugar.funcs[p] = Object.getOwnPropertyDescriptor(Function.prototype, p); - }); - return { - sugar: sugar, - request: { - url: request.transformed.url, - method: request.method, - headers: Helpers.generateHeaderObj(request.transformed.headers), - data: this._getTransformedRequestData(request), - dataMode: request.dataMode, - name: request.name, - description: request.description - }, - iteration: Globals.iterationNumber, - environment: this._setEnvironmentContext(), - globals: this._setGlobalContext(), - data: this._setDataContext(), - $: _jq, - jQuery: _jq, - _: _lod, - btoa: btoa, - atob: atob, - CryptoJS: CryptoJS, - Backbone: Backbone, - xmlToJson: function (string) { - var JSON = {}; - xmlToJson.parseString(string, { explicitArray: false, async: false }, function (err, result) { - JSON = result; - }); - return JSON; - }, - tv4: tv4, - console: { - log: function () { - console.log.apply(console, arguments); - }, - error: function () { - console.error.apply(console, arguments); - }, - warn: function () { - console.warn.apply(console, arguments); - } - }, - postman: { - setEnvironmentVariableReal: function (key, value) { - var envVar = _und.find(Globals.envJson.values, function (envObject) { - return envObject["key"] === key; - }); - - if (envVar) { // if the envVariable exists replace it - envVar["value"] = value; - } else { // else add a new envVariable - Globals.envJson.values.push({ - key: key, - value: value, - type: "text", - name: key - }); - } - }, - getEnvironmentVariable: function (key) { - var envVar = _und.find(Globals.envJson.values, function (envObject) { - return envObject["key"] === key; - }); - if (envVar) { - return envVar["value"]; - } - return null; - }, - clearEnvironmentVariablesReal: function () { - Globals.envJson.values = []; - }, - clearEnvironmentVariableReal: function (key) { - var oldLength = Globals.envJson.values.length; - _lod.remove(Globals.envJson.values, function (envObject) { - return envObject["key"] === key; - }); - if (oldLength === Globals.envJson.values.length) { - return false; - } - else { - return true; - } - }, - setGlobalVariableReal: function (key, value) { - var envVar = _und.find(Globals.globalJson.values, function (envObject) { - return envObject["key"] === key; - }); - - if (envVar) { // if the envVariable exists replace it - envVar["value"] = value; - } else { // else add a new envVariable - Globals.globalJson.values.push({ - key: key, - value: value, - type: "text", - name: key - }); - } - }, - getGlobalVariable: function (key) { - var envVar = _und.find(Globals.globalJson.values, function (envObject) { - return envObject["key"] === key; - }); - if (envVar) { - return envVar["value"]; - } - return null; - }, - clearGlobalVariablesReal: function () { - Globals.globalJson.values = []; - }, - clearGlobalVariableReal: function (key) { - var oldLength = Globals.globalJson.values.length; - _lod.remove(Globals.globalJson.values, function (envObject) { - return envObject["key"] === key; - }); - if (oldLength === Globals.globalJson.values.length) { - return false; - } - else { - return true; - } - }, - setNextRequest: function (requestName) { - Globals.nextRequestName = requestName; - } - } - }; - } -}); - -module.exports = PreRequestScriptProcessor; diff --git a/src/utilities/Queue.js b/src/utilities/Queue.js deleted file mode 100644 index 1449fcab1..000000000 --- a/src/utilities/Queue.js +++ /dev/null @@ -1,43 +0,0 @@ -var jsface = require("jsface"), - _und = require('underscore'); - -/** - * @name Queue - * @classdesc Queue meant to be used as mixin - * @namespace - */ -var Queue = jsface.Class({ - _queue: [], - _currentIndex: -1, - addToQueue: function (obj) { - this._queue.push(obj); - }, - getFromQueueWithoutRemoving: function() { - return _und.clone(this._queue[0]); - }, - purgeAllItemsInQueue: function () { - this._queue.splice(0, this._queue.length); - }, - isEmptyQueue: function () { - return !this._queue.length; - }, - getAllItems: function () { - return this._queue; - }, - getItemWithIndex: function (index) { - return this._queue.splice(index, 1); - }, - getItemWithIndexWithoutRemoval: function (index) { - this._currentIndex = index; - return _und.clone(this._queue[index]); - }, - getNextItemFromQueue: function() { - this._currentIndex++; - if(this._currentIndex >= this._queue.length) { - return null; - } - return this._queue[this._currentIndex]; - }, -}); - -module.exports = Queue; diff --git a/src/utilities/ResponseExporter.js b/src/utilities/ResponseExporter.js deleted file mode 100644 index 258ed954d..000000000 --- a/src/utilities/ResponseExporter.js +++ /dev/null @@ -1,373 +0,0 @@ -var jsface = require('jsface'), - Globals = require('./Globals'), - log = require('./Logger'), - _und = require('underscore'), - ResultSummary = require('../models/ResultSummaryModel'), - path = require('path'), - HtmlExporter = require('./HtmlExporter'), - fs = require('fs'); - -/** - * @class ResponseExporter - * @classdesc Class Used for exporting the generated responses. - */ -var ResponseExporter = jsface.Class({ - $singleton: true, - - _results: [], - - //each element will be an object of type: {type:coll/folder, parentId, parentName, passCount, failCount} - _summaryResults: [], - - /** - * Adds the Response to the Result Array. - * @param {Object} request Request we got from Newman. - * @param {Object} response Response we got from Newman. - * @param {Object} tests Test Results. - * @memberOf ResponseExporter - */ - addResult: function (request, response, tests) { - var result = this._findResultObject(request); - if (result) { - this._appendToResultsObject(result, request, response, tests); - } else { - result = this._createResultObject(request, response, tests); - this._results.push(result); - } - this.summarizeResults(request, tests); - }, - - summarizeResults: function (request, tests) { - var passFailCount = this._getPassFailCount(tests); - this._addPassFailCountToCollection(request, passFailCount); - this._addPassFailCountToFolder(request, passFailCount); - this._addPassFailCountToTotal(request, passFailCount); - }, - - _getPassFailCount: function (tests) { - var vals = _und.values(tests); - var total = vals.length; - var passes = _und.filter(vals, function (val) { - return !!val; - }); - return { - pass: passes.length, - fail: total - passes.length - }; - }, - - _addPassFailCountToTotal: function (request, results) { - var existingModel = _und.find(this._summaryResults, function (summaryResult) { - return (summaryResult.type === "total"); - }); - if (!existingModel) { - var newModel = new ResultSummary({ - type: 'total', - parentId: null, - parentName: "", - passCount: results.pass, - failCount: results.fail - }); - this._summaryResults.push(newModel); - } - else { - existingModel.passCount = existingModel.passCount + results.pass; - existingModel.failCount = existingModel.failCount + results.fail; - } - }, - - _addPassFailCountToCollection: function (request, results) { - if (request.folderId && request.folderName) { - return; - } - var existingModel = _und.find(this._summaryResults, function (summaryResult) { - return (summaryResult.type === "collection" && summaryResult.parentId === request.collectionID); - }); - if (!existingModel) { - var newModel = new ResultSummary({ - type: 'collection', - parentId: request.collectionID, - parentName: request.collectionName, - passCount: results.pass, - failCount: results.fail - }); - this._summaryResults.push(newModel); - } - else { - existingModel.passCount = existingModel.passCount + results.pass; - existingModel.failCount = existingModel.failCount + results.fail; - } - }, - - _addPassFailCountToFolder: function (request, results) { - if (!request.folderId || !request.folderName) { - return; - } - - var existingModel = _und.find(this._summaryResults, function (summaryResult) { - return (summaryResult.type === "folder" && summaryResult.parentId === request.folderId); - }); - if (!existingModel) { - var newModel = new ResultSummary({ - type: 'folder', - parentId: request.folderId, - parentName: request.folderName, - passCount: results.pass, - failCount: results.fail - }); - this._summaryResults.push(newModel); - } - else { - existingModel.passCount = existingModel.passCount + results.pass; - existingModel.failCount = existingModel.failCount + results.fail; - } - }, - - showIterationSummary: function () { - var sortedSummaries = [], collectionSummary, totalSummary; - _und.map(this._summaryResults, function (res) { - if (res.type === 'folder') { - sortedSummaries.push(res); - } - else if (res.type === 'collection') { - collectionSummary = res; - } - else if (res.type === 'total') { - totalSummary = res; - } - }); - if (collectionSummary) { - sortedSummaries.push(collectionSummary); - } - if (totalSummary) { - sortedSummaries.push(totalSummary); - } - log.showIterationSummary(sortedSummaries); - this._summaryResults = []; - }, - - // Used to create a first result object, to be used while exporting the results. - _createResultObject: function (request, response, tests) { - if (!tests) { - tests = {}; - } - - var passFailCounts = this._extractPassFailCountFromTests(tests); - var totalPassFailCounts = this.extractTotalPassFailCount(tests); - - return { - "id": request.id, - "name": request.name, - "url": request.url, - "totalTime": response.stats.timeTaken, - "responseCode": { - "code": response.statusCode, - "name": "", // TODO: Fill these guys later on - "detail": "" - }, - "tests": tests, //this is meaningless. preserved for backward-compat - "totalPassFailCounts": totalPassFailCounts, - "testPassFailCounts": passFailCounts, //this will hold results per test, across all iterations - "times": [], // Not sure what to do with this guy - "allTests": [tests], - "time": response.stats.timeTaken //this is per request - }; - }, - - _findResultObject: function (request) { - return _und.find(this._results, function (result) { - return result.id === request.id; - }) || null; - }, - - _appendToResultsObject: function (result, request, response, tests) { - var newResultObject = this._createResultObject(request, response, tests); - newResultObject.totalTime += result.totalTime; - this._mergeTestCounts(newResultObject, result); - newResultObject.allTests = newResultObject.allTests.concat(result.allTests); - this._results[this._results.indexOf(result)] = newResultObject; - }, - - _mergeTestCounts: function (oldResult, thisResult) { - _und.each(_und.keys(thisResult.testPassFailCounts), function (testName) { - if (oldResult.testPassFailCounts.hasOwnProperty(testName)) { - oldResult.testPassFailCounts[testName].pass += thisResult.testPassFailCounts[testName].pass; - oldResult.testPassFailCounts[testName].fail += thisResult.testPassFailCounts[testName].fail; - } - else { - oldResult.testPassFailCounts[testName] = { - pass: thisResult.testPassFailCounts[testName].pass, - fail: thisResult.testPassFailCounts[testName].fail - }; - } - oldResult.totalPassFailCounts.pass += thisResult.testPassFailCounts[testName].pass; - oldResult.totalPassFailCounts.fail += thisResult.testPassFailCounts[testName].fail; - }); - }, - - // Creates a pass, fail object for a given test. - _extractPassFailCountFromTests: function (tests) { - return _und.reduce(_und.keys(tests), function (results, key) { - results[key] = { - pass: tests[key] ? 1 : 0, - fail: tests[key] ? 0 : 1 - }; - return results; - }, {}); - }, - - //creates a pass,fail count for all tests - extractTotalPassFailCount: function (tests) { - var pass = 0, fail = 0; - _und.each(_und.values(tests), function (bool) { - if (bool) { - pass++; - } - else { - fail++; - } - }); - return { - pass: pass, fail: fail - }; - }, - - /** - * This function when called creates a file with the JSON of the results. - * @memberOf ResponseExporter - */ - exportResults: function () { - var exportVariable = this._createExportVariable(); - - //calculate mean time - _und.each(exportVariable.results, function (result) { - result.meanResponseTime = parseInt(result.totalTime, 10) / exportVariable.count; - }); - - if (Globals.outputFile) { - var filepath = path.resolve(Globals.outputFile); - fs.writeFileSync(filepath, JSON.stringify(exportVariable, null, 4)); - log.note("\n\nOutput Log: " + filepath + "\n"); - } - - if (Globals.testReportFile) { - var outputpath = path.resolve(Globals.testReportFile); - fs.writeFileSync(outputpath, this._createJunitXML()); - log.note("\n\nJunit XML file written to: " + outputpath + "\n"); - } - - if (Globals.html) { - HtmlExporter.generateHTML(exportVariable); - } - }, - - _aggregateTestResults: function (runs) { - var retVal = {}; - _und.each(runs, function (run) { - for (var testName in run) { - if (run.hasOwnProperty(testName)) { - if (retVal.hasOwnProperty(testName)) { - if (run[testName]) { - retVal[testName].successes++; - } - else { - retVal[testName].failures++; - } - } - else { - if (run[testName]) { - retVal[testName] = { - successes: 1, failures: 0 - }; - } - else { - retVal[testName] = { - successes: 0, failures: 1 - }; - } - } - } - } - }); - return retVal; - }, - - /** - * Returns a JUnit-compatible XML string of the test results - * - * @memberOf ResponseExporter - * @return {string} JUnit XML - */ - _createJunitXML: function () { - var oldThis = this; - var xml = '\n'; - var suitesName = Globals.requestJSON.name || 'Collection name not found'; - xml += "\n"; - _und.each(this._results, function (suite) { - //var testRequest = _und.find(Globals.requestJSON.requests, function(request) { - // return suite.id === request.id; - //}); - var aggregateTestStats = oldThis._aggregateTestResults(suite.allTests); - - //var timeStamp = new Date(testRequest.time); - var iterations = suite.allTests.length; - - var timeStamp = new Date(); - //var time = testRequest.time; - var time = suite.time; - var meanTime = (time / iterations).toFixed(2); - var tests = Object.keys(suite.tests).length; - - var testcases = ""; - var totalFailuresForSuite = 0; - var totalSuccessesForSuite = 0; - - _und.each(suite.testPassFailCounts, function (testcase, testcaseName) { - var successes = aggregateTestStats[testcaseName].successes; - var failures = aggregateTestStats[testcaseName].failures; - totalFailuresForSuite += failures; - totalSuccessesForSuite += successes; - testcases += '\t\t 0 ? '' : '/') + '>\n'; - if (failures > 0) { - testcases += '\t\t\t 1 ? ' (failed ' + failures + '/' + iterations + ' iterations)' : '') + - ']]>\n' + - '\t\t\n'; - } - }, this); - - xml += '\t\n'; - - xml += testcases; - - xml += "\t\n"; - }, this); - - xml += "\n"; - return xml; - }, - - _createExportVariable: function () { - return { - id: '', - name: 'Default', - timestamp: new Date().getTime(), - collection_id: Globals.requestJSON.id, - folder_id: 0, - target_type: (Globals.folder) ? 'folder' : 'collection', - environment_id: Globals.envJson.id, - count: parseInt(Globals.iterationCount, 10), - collection: Globals.requestJSON, - folder: Globals.folder || null, - globals: Globals.globalJson, - results: this._results, - environment: Globals.envJson, - delay: 0, - synced: Globals.requestJSON.synced - }; - } -}); - -module.exports = ResponseExporter; diff --git a/src/utilities/Symbols.js b/src/utilities/Symbols.js deleted file mode 100644 index 6423c2b6d..000000000 --- a/src/utilities/Symbols.js +++ /dev/null @@ -1,18 +0,0 @@ -var jsface = require('jsface'); - -/** - * @name Symbols - * @namespace - * @classdesc class with symbols used for logging - */ -var Symbols = jsface.Class({ - $singleton: true -}); - -// symbols for logging -Symbols.symbols = { - err: (process.platform === "win32") ? "\u00D7 " : "✗ ", - ok: (process.platform === "win32") ? "\u221A " : "✔ " -}; - -module.exports = Symbols; diff --git a/src/utilities/VariableProcessor.js b/src/utilities/VariableProcessor.js deleted file mode 100644 index 202928ac6..000000000 --- a/src/utilities/VariableProcessor.js +++ /dev/null @@ -1,188 +0,0 @@ -var jsface = require('jsface'), - Helpers = require('./Helpers'), - uuid = require('node-uuid'), - _lod = require("lodash"), - Globals = require("./Globals"), - _und = require('underscore'); - -/** - * @name VariableProcessor - * @namespace - * @classdesc Helper singleton class that does the variable and environment processing for newman - */ -var VariableProcessor = jsface.Class({ - $singleton: true, - - // TODO: Make {{}} configurable - $statics: { - ENV_REGEX: /\{\{([a-z0-9\-._\s]+)\}\}/ig, - - FUNCTION_REGEX: /\{\{\$([a-z0-9\-._]+)\}\}/ig - }, - - // placeholders to define function variables - getFunctionVariables: { - guid: function () { - }, - timestamp: _und.now(), - randomInt: _und.random(0, 1000) - }, - - _resetFunctionVariables: function () { - var guid = uuid.v4(); - var timestamp = Date.now(); - var randomInt = _und.random(0, 1000); - this.getFunctionVariables.guid = guid; - this.getFunctionVariables.randomInt = randomInt; - this.getFunctionVariables.timestamp = timestamp; - }, - - // updates request url by the replacing it with pathVariables - _processPathVariable: function (request) { - if (typeof request.pathVariables !== undefined) { - var sourceObject = request.pathVariables; - // for each path variable - do a simple find replace - _und.each(_und.keys(sourceObject), function (key) { - var s = request.url; - request.url = s.replace(":" + key, sourceObject[key]); - }, this); - } - }, - - // updates request properties by the replacing them with function variables - _processFunctionVariable: function (request) { - var properties = ["url", "headers", "form", "data", "helperAttributes"]; - - request.transformed = request.transformed || {}; - - _und.each(properties, function (prop) { - // check if the prop exists - if (request[prop] !== undefined) { - if (typeof request[prop] === "string") { - // if string, use directly - request.transformed[prop] = this._findReplace(request[prop], this.getFunctionVariables, this.FUNCTION_REGEX); - } else { - // if not string, stringify it - // findReplace, unstringify it and set it - var jsonifiedProp = JSON.stringify(request[prop]); - var parsedJsonProp = JSON.parse(this._findReplace(jsonifiedProp, this.getFunctionVariables, this.FUNCTION_REGEX)); - request.transformed[prop] = parsedJsonProp; - } - } - }, this); - }, - - // replaces a string based on keys in the sourceObject as matched by a regex. Supports recursive replacement - // usage: _findReplace("{{url}}/blog/posts/{{id}}", {url: "http://localhost", id: 2}, this.ENV_REGEX) - // Note: The regex provided should capture the key to be replaced (use parenthesis) - _findReplace: function (stringSource, sourceObject, REGEX, recurseCount) { - if (typeof recurseCount === "undefined") { - recurseCount = 1; - } - //console.log("Limit: " + Globals.recurseLimit); - if (recurseCount > Globals.recurseLimit) { - return stringSource; - } - - function getKey(match, key) { - var fromSource = sourceObject[key]; - if (typeof fromSource === "undefined") { - return "{{" + key + "}}"; - } - return fromSource; - } - - var oldString = stringSource + ""; - stringSource = stringSource.replace(REGEX, getKey); - - if (oldString === stringSource) { - return stringSource; - } - - if (stringSource.match(REGEX)) { - return this._findReplace(stringSource, sourceObject, REGEX, recurseCount + 1); - } - return stringSource; - }, - - // transforms the request as per the environment json data passed - _processEnvVariable: function (request, envJson) { - var kvpairs = envJson.values; - var oldThis = this, - toReplace; - - request.transformed = request.transformed || {}; - - var properties = ["url", "headers", "form", "data", "helperAttributes"]; - - var pairObject = Helpers.transformFromKeyValue(kvpairs); - _und.each(properties, function (prop) { - // check if the prop exists - if (request[prop] !== undefined) { - - // If already processed by function vars - toReplace = request.transformed[prop] || request[prop]; - - if (typeof request[prop] === "string") { - request.transformed[prop] = this._findReplace(toReplace, pairObject, this.ENV_REGEX); - } else { - //The old option of stringify+replace+parse was removed. - request.transformed[prop] = _lod.cloneDeep(toReplace); - oldThis._traverseJson(request.transformed[prop], oldThis._processNode, pairObject); - } - } - }, this); - return true; - }, - - _processNode: function (key, value, pairObject) { - if (typeof key === "string") { - key = this._findReplace(key, pairObject, this.ENV_REGEX); - } - if (typeof value === "string") { - value = this._findReplace(value, pairObject, this.ENV_REGEX); - } - return { - "key": key, - "value": value - }; - }, - - _traverseJson: function (o, func, pairObject) { - if(!o) { - return; - } - if (o._visited) { - //To prevent traversing cycling objects - return; - } - o._visited = true; - for (var i in o) { - var newData = func.apply(this, [i, o[i], pairObject]); - delete o[i]; - o[newData.key] = newData.value; - i = newData.key; - if (o[i] !== null && typeof(o[i]) === "object") { - //going on step down in the object tree!! - this._traverseJson(o[i], func, pairObject); - } - } - delete o._visited; - }, - - - /** - * Modifies request by processing all the variables - * @param {RequestModel} request - * @memberof VariableProcessor - * @param {JSON} options passed to Newman runner - */ - processRequestVariables: function (request, options) { - this._resetFunctionVariables(); - this._processPathVariable(request); - this._processFunctionVariable(request); - this._processEnvVariable(request, options.envJson); - } -}); - -module.exports = VariableProcessor; diff --git a/src/utilities/oauth.js b/src/utilities/oauth.js deleted file mode 100644 index 45936335b..000000000 --- a/src/utilities/oauth.js +++ /dev/null @@ -1,571 +0,0 @@ -/* jshint ignore:start */ - -/* - * Copyright 2008 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Here's some JavaScript software for implementing OAuth. - - This isn't as useful as you might hope. OAuth is based around - allowing tools and websites to talk to each other. However, - JavaScript running in web browsers is hampered by security - restrictions that prevent code running on one website from - accessing data stored or served on another. - - Before you start hacking, make sure you understand the limitations - posed by cross-domain XMLHttpRequest. - - On the bright side, some platforms use JavaScript as their - language, but enable the programmer to access other web sites. - Examples include Google Gadgets, and Microsoft Vista Sidebar. - For those platforms, this library should come in handy. - */ - -// The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by -// http://pajhome.org.uk/crypt/md5/sha1.js - -/* An OAuth message is represented as an object like this: - {method: "GET", action: "http://server.com/path", parameters: ...} - - The parameters may be either a map {name: value, name2: value2} - or an Array of name-value pairs [[name, value], [name2, value2]]. - The latter representation is more powerful: it supports parameters - in a specific sequence, or several parameters with the same name; - for example [["a", 1], ["b", 2], ["a", 3]]. - - Parameter names and values are NOT percent-encoded in an object. - They must be encoded before transmission and decoded after reception. - For example, this message object: - {method: "GET", action: "http://server/path", parameters: {p: "x y"}} - ... can be transmitted as an HTTP request that begins: - GET /path?p=x%20y HTTP/1.0 - (This isn't a valid OAuth request, since it lacks a signature etc.) - Note that the object "x y" is transmitted as x%20y. To encode - parameters, you can call OAuth.addToURL, OAuth.formEncode or - OAuth.getAuthorization. - - This message object model harmonizes with the browser object model for - input elements of an form, whose value property isn't percent encoded. - The browser encodes each value before transmitting it. For example, - see consumer.setInputs in example/consumer.js. - */ - -/* This script needs to know what time it is. By default, it uses the local - clock (new Date), which is apt to be inaccurate in browsers. To do - better, you can load this script from a URL whose query string contains - an oauth_timestamp parameter, whose value is a current Unix timestamp. - For example, when generating the enclosing document using PHP: - -