diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..b1efa5d --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,39 @@ +#---------------------------------# +# environment configuration # +#---------------------------------# + +# scripts that are called at very beginning, before repo cloning +init: + - git config --global core.autocrlf input + +# environment variables +environment: + matrix: + - nodejs_version: "6" + - nodejs_version: "8" + - nodejs_version: "10" + +# scripts that run after cloning repository +install: + - ps: Install-Product node $env:nodejs_version + - npm cache clean --force + - appveyor-retry npm install + +build: off # Disable MSBuilds, not related to the regular build process + +# to run your custom scripts instead of automatic tests +test_script: + - node --version && npm --version + - cmd: "npm test" + +# to disable deployment +deploy: off + +#---------------------------------# +# notifications # +#---------------------------------# + +notifications: + - provider: Slack + incoming_webhook: + secure: PRDZ1nhG/cQrwMgCLXsWvTDJtYxv78GJrSlVYpMzpUploVWDzBlpMqmFr9WxZQkY/lxsqCSpGX4zgTYzlte1WMWnghqTIFE8u7svlXHa/tk= diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..303be14 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +max_length = 120 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{json, yml, html, hbs}] +indent_size = 2 diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..f0ea042 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,411 @@ +{ + "plugins": [ + "jsdoc", + "lodash", + "security" + ], + "env": { + "browser": false, + "node": true, + "es6": true + }, + "globals": {}, + "settings": { + "lodash": { + "pragma": "_" + } + }, + "rules": { + // Possible Errors + "for-direction": "error", + "getter-return": "error", + "no-await-in-loop": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": "error", + "no-console": ["error", { + "allow": ["info", "warn", "error"] + }], + "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": "error", + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-obj-calls": "error", + "no-prototype-builtins": "error", + "no-regex-spaces": "error", + "no-sparse-arrays": "error", + "no-template-curly-in-string": "error", + "no-unexpected-multiline": "error", + "no-unreachable": "error", + "no-unsafe-finally": "error", + "no-unsafe-negation": "error", + "use-isnan": "error", + "valid-jsdoc": "off", + "valid-typeof": "error", + + // Best Practices + "accessor-pairs": "error", + "array-callback-return": "off", + "block-scoped-var": "error", + "class-methods-use-this": "error", + "complexity": "off", + "consistent-return": "warn", + "curly": "error", + "default-case": "error", + "dot-location": ["error", "property"], + "dot-notation": "error", + "eqeqeq": "error", + "guard-for-in": "warn", + "max-classes-per-file": ["error", 1], + "max-lines-per-function": "off", + "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-global-assign": "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-new": "error", + "no-new-func": "error", + "no-new-wrappers": "error", + "no-octal": "error", + "no-octal-escape": "error", + "no-param-reassign": "off", + "no-proto": "error", + "no-redeclare": "error", + "no-restricted-properties": "error", + "no-return-assign": "error", + "no-return-await": "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-useless-return": "error", + "no-void": "error", + "no-warning-comments": "off", + "no-with": "error", + "prefer-object-spread": "error", + "prefer-promise-reject-errors": "error", + "radix": "error", + "require-await": "error", + "vars-on-top": "off", + "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": "off", + "no-shadow-restricted-names": "error", + "no-undef": "error", + "no-undef-init": "error", + "no-undefined": "off", + "no-unused-vars": "error", + "no-use-before-define": "error", + + // Node.js and CommonJS + "callback-return": "error", + "global-require": "off", + "handle-callback-err": "error", + "no-buffer-constructor": "error", + "no-mixed-requires": "off", + "no-new-require": "off", + "no-path-concat": "error", + "no-process-env": "error", + "no-process-exit": "off", + "no-restricted-modules": "error", + "no-sync": "off", + + // Stylistic Issues + "array-bracket-newline": "off", + "array-bracket-spacing": "error", + "array-element-newline": "off", + "block-spacing": "error", + "brace-style": ["error", "stroustrup", { + "allowSingleLine": true + }], + "camelcase": "off", + "capitalized-comments": "off", + "comma-dangle": ["error", "never"], + "comma-spacing": ["error", { + "before": false, + "after": true + }], + "comma-style": ["error", "last"], + "computed-property-spacing": "error", + "consistent-this": "off", + "eol-last": "error", + "func-call-spacing": "error", + "func-name-matching": "error", + "func-names": "off", + "func-style": "off", + "function-paren-newline": ["error", "never"], + "id-blacklist": "error", + "id-length": "off", + "id-match": "error", + "implicit-arrow-linebreak": ["error", "beside"], + "indent": ["error", 4, { + "VariableDeclarator": { + "var": 1, + "let": 1, + "const": 1 + }, + "SwitchCase": 1 + }], + "jsx-quotes": ["error", "prefer-single"], + "key-spacing": "error", + "keyword-spacing": "error", + "line-comment-position": "off", + "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 + }], + "lines-between-class-members": ["error", "always", { + "exceptAfterSingleLine": true + }], + "max-depth": "error", + "max-len": ["error", { + "code": 120 + }], + "max-lines": "off", + "max-nested-callbacks": "error", + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": ["error", { + "max": 2 + }], + "multiline-comment-style": "off", + "multiline-ternary": "off", + "new-cap": "off", + "new-parens": "error", + "newline-per-chained-call": ["error", { + "ignoreChainWithDepth": 4 + }], + "no-array-constructor": "error", + "no-bitwise": "off", + "no-continue": "off", + "no-inline-comments": "off", + "no-lonely-if": "error", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": "error", + "no-multi-assign": "off", + "no-multiple-empty-lines": "error", + "no-negated-condition": "error", + "no-nested-ternary": "error", + "no-new-object": "error", + "no-plusplus": "off", + "no-restricted-syntax": "error", + "no-tabs": "error", + "no-ternary": "off", + "no-trailing-spaces": "error", + "no-underscore-dangle": "off", + "no-unneeded-ternary": "error", + "no-whitespace-before-property": "error", + "nonblock-statement-body-position": "error", + "object-curly-newline": "off", + "object-curly-spacing": ["error", "always"], + "object-property-newline": "off", + "one-var": ["error", "always"], + "one-var-declaration-per-line": "error", + "operator-assignment": "error", + "operator-linebreak": ["error", "after"], + "padded-blocks": ["error", "never"], + "padding-line-between-statements": ["error", + { + "blankLine": "always", + "prev": "*", + "next": "return" + }, + { + "blankLine": "always", + "prev": ["const", "let", "var"], + "next": "*" + }, + { + "blankLine": "any", + "prev": ["const", "let", "var"], + "next": ["const", "let", "var"] + } + ], + "quote-props": ["error", "as-needed"], + "quotes": ["error", "single"], + "require-jsdoc": "warn", + "semi": "error", + "semi-spacing": "error", + "semi-style": ["error", "last"], + "sort-keys": "off", + "sort-vars": "off", + "space-before-blocks": "error", + "space-before-function-paren": "error", + "space-in-parens": "error", + "space-infix-ops": "error", + "space-unary-ops": "error", + "spaced-comment": ["error", "always", { + "block": { + "exceptions": ["!"] + } + }], + "switch-colon-spacing": "error", + "template-tag-spacing": "error", + "unicode-bom": "error", + "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": "error", + "no-useless-rename": "error", + "no-var": "off", + "object-shorthand": ["error", "consistent-as-needed"], + "prefer-arrow-callback": "off", + "prefer-const": "off", + "prefer-destructuring": "off", + "prefer-numeric-literals": "off", + "prefer-rest-params": "off", + "prefer-spread": "error", + "prefer-template": "off", + "require-yield": "error", + "rest-spread-spacing": "error", + "sort-imports": "off", + "symbol-description": "off", + "template-curly-spacing": "error", + "yield-star-spacing": "error", + + // Lodash + "lodash/callback-binding": "error", + "lodash/collection-method-value": "warn", + "lodash/collection-return": "error", + "lodash/no-double-unwrap": "error", + "lodash/no-extra-args": "error", + "lodash/no-unbound-this": "error", + "lodash/unwrap": "error", + + "lodash/chain-style": ["error", "as-needed"], + "lodash/chaining": ["error", "always", 3], + "lodash/consistent-compose": ["error", "flow"], + "lodash/identity-shorthand": ["error", "always"], + "lodash/import-scope": "off", + "lodash/matches-prop-shorthand": ["error", "always"], + "lodash/matches-shorthand": ["error", "always", 3], + "lodash/no-commit": "error", + "lodash/path-style": ["error", "as-needed"], + "lodash/prefer-compact": "error", + "lodash/prefer-filter": ["off", 3], + "lodash/prefer-flat-map": "error", + "lodash/prefer-invoke-map": "error", + "lodash/prefer-map": "error", + "lodash/prefer-reject": ["error", 3], + "lodash/prefer-thru": "error", + "lodash/prefer-wrapper-method": "error", + "lodash/preferred-alias": "error", + "lodash/prop-shorthand": ["error", "always"], + + "lodash/prefer-constant": "off", + "lodash/prefer-get": ["warn", 4], + "lodash/prefer-includes": ["error", { + "includeNative": true + }], + "lodash/prefer-is-nil": "error", + "lodash/prefer-lodash-chain": "error", + "lodash/prefer-lodash-method": "off", + "lodash/prefer-lodash-typecheck": "off", + "lodash/prefer-matches": ["off", 3], + "lodash/prefer-noop": "off", + "lodash/prefer-over-quantifier": "warn", + "lodash/prefer-some": "off", + "lodash/prefer-startswith": "off", + "lodash/prefer-times": "off", + + // JsDoc + "jsdoc/check-param-names": "error", + "jsdoc/check-tag-names": "off", + "jsdoc/check-types": "off", + "jsdoc/newline-after-description": "error", + "jsdoc/require-description-complete-sentence": "off", + "jsdoc/require-example": "off", + "jsdoc/require-hyphen-before-param-description": "off", + "jsdoc/require-param": "error", + "jsdoc/require-param-description": "error", + "jsdoc/require-param-type": "error", + "jsdoc/require-returns-description": "off", + "jsdoc/require-returns-type": "error", + + // Security + "security/detect-unsafe-regex": "off", + "security/detect-buffer-noassert": "error", + "security/detect-child-process": "error", + "security/detect-disable-mustache-escape": "error", + "security/detect-eval-with-expression": "error", + "security/detect-no-csrf-before-method-override": "error", + "security/detect-non-literal-fs-filename": "off", + "security/detect-non-literal-regexp": "off", + "security/detect-non-literal-require": "error", + "security/detect-object-injection": "off", + "security/detect-possible-timing-attacks": "error", + "security/detect-pseudoRandomBytes": "error" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5854b37 --- /dev/null +++ b/.gitignore @@ -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 +.vscode + +# 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 diff backups from SourceTree from showing as commit. +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*.orig + +# Prevent unit test coverage reports from being added +.coverage diff --git a/.jsdoc-config.json b/.jsdoc-config.json new file mode 100644 index 0000000..90e6d5d --- /dev/null +++ b/.jsdoc-config.json @@ -0,0 +1,34 @@ +{ + "tags": { + "allowUnknownTags": true, + "dictionaries": ["jsdoc", "closure"] + }, + "source": { + "include": [ ], + "includePattern": ".+\\.js(doc)?$", + "excludePattern": "(^|\\/|\\\\)_" + }, + + "plugins": [ + "plugins/markdown" + ], + + "templates": { + "cleverLinks": false, + "monospaceLinks": false, + "highlightTutorialCode" : true + }, + + "opts": { + "template": "./node_modules/postman-jsdoc-theme", + "encoding": "utf8", + "destination": "./out/docs", + "recurse": true, + "readme": "README.md" + }, + + "markdown": { + "parser": "gfm", + "hardwrap": false + } +} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..5854b37 --- /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 +.vscode + +# 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 diff backups from SourceTree from showing as commit. +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*.orig + +# Prevent unit test coverage reports from being added +.coverage diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6166d75 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: node_js +node_js: +- '6' +- '8' +- '10' +notifications: + slack: + secure: Fdl/sQMTl86jYN1r1CRRRQRgyFoslvrhkkfnM2JSdx4gODPgyg4nCPSKtU5j9wpSbbkq9A+YBeFv+Suh+xYNviegqa0AZbztydfFzVDS7xw43B/uR9Y4LwaP5Kis1WGuIOHawwFISNO3hTUei6aybKiKKlxvfqrARJaO01+Xxrg= diff --git a/CHANGELOG.yaml b/CHANGELOG.yaml new file mode 100644 index 0000000..f7d7c67 --- /dev/null +++ b/CHANGELOG.yaml @@ -0,0 +1 @@ +# Newman HTML Reporter Changelog diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..632c64b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,203 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + 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 + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + 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. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e4ed37 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# newman-reporter-html \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..2c10fca --- /dev/null +++ b/index.js @@ -0,0 +1,14 @@ +/**! + * @license Copyright 2018 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 0000000..75e8038 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,186 @@ +var fs = require('fs'), + path = require('path'), + + _ = require('lodash'), + handlebars = require('handlebars'), + + util = require('./util'), + + /** + * An object of the default file read preferences. + * + * @type {Object} + */ + FILE_READ_OPTIONS = { encoding: 'utf8' }, + + /** + * The default Handlebars template to use when no user specified template is provided. + * + * @type {String} + */ + DEFAULT_TEMPLATE = 'template-default.hbs', + + /** + * A reference object for run stats properties to use for various assertion states. + * + * @type {Object} + */ + ASSERTION_STATE = { false: 'passed', true: 'failed' }, + + /** + * The list of execution data fields that are aggregated over multiple requests for the collection run + * + * @type {String[]} + */ + AGGREGATED_FIELDS = ['item', 'request', 'response'], + + IS_NODE_V4 = _(process && process.version).split('.').get(0) === 'v4', + + PostmanHTMLReporter; + +/** + * A function that creates raw markup to be written to Newman HTML reports. + * + * @param {Object} newman - The collection run object, with a event handler setter, used to enable event wise reporting. + * @param {Object} options - The set of HTML reporter run options. + * @param {String=} options.template - Optional path to the custom user defined HTML report template (Handlebars). + * @param {String=} options.export - Optional custom path to create the HTML report at. + * @returns {*} + */ +PostmanHTMLReporter = function (newman, options) { + handlebars.registerHelper('add', function (addend, augend) { + return addend + augend; + }); + handlebars.registerHelper('gt', function (value, threshold, options) { + return value > threshold ? options.fn(this) : options.inverse(this); + }); + + // @todo throw error here or simply don't catch them and it will show up as warning on newman + var htmlTemplate = options.template || path.join(__dirname, DEFAULT_TEMPLATE), + compiler = handlebars.compile(fs.readFileSync(htmlTemplate, FILE_READ_OPTIONS)); + + newman.on('beforeDone', function () { + var items = {}, + executionMeans = {}, + netTestCounts = {}, + aggregations = [], + traversedRequests = {}, + aggregatedExecutions = {}, + executions = _.get(this, 'summary.run.executions'), + assertions = _.transform(executions, function (result, currentExecution) { + var stream, + reducedExecution, + executionId = currentExecution.id; + + if (!_.has(traversedRequests, executionId)) { + // mark the current request instance as traversed + _.set(traversedRequests, executionId, 1); + + // set the base assertion and cumulative test details for the current request instance + _.set(result, executionId, {}); + _.set(netTestCounts, executionId, { passed: 0, failed: 0 }); + + // set base values for overall response size and time values + _.set(executionMeans, executionId, { time: { sum: 0, count: 0 }, size: { sum: 0, count: 0 } }); + + reducedExecution = _.pick(currentExecution, AGGREGATED_FIELDS); + + if (reducedExecution.response && _.isFunction(reducedExecution.response.toJSON)) { + reducedExecution.response = reducedExecution.response.toJSON(); + stream = reducedExecution.response.stream; + + // Use deprecated Buffer constructor for Node v4, contemporary one for other versions + // @todo remove when dropping support for node < v6, to save some memory. + // eslint-disable-next-line no-buffer-constructor + reducedExecution.response.body = (IS_NODE_V4 ? new Buffer(stream && stream.data) : + Buffer.from(stream)).toString(); + } + + // set sample request and response details for the current request + items[reducedExecution.item.id] = reducedExecution; + } + + executionMeans[executionId].time.sum += _.get(currentExecution, 'response.responseTime', 0); + executionMeans[executionId].size.sum += _.get(currentExecution, 'response.responseSize', 0); + + ++executionMeans[executionId].time.count; + ++executionMeans[executionId].size.count; + + _.forEach(currentExecution.assertions, function (assertion) { + var aggregationResult, + assertionName = assertion.assertion, + isError = _.get(assertion, 'error') !== undefined, + updateKey = _.get(ASSERTION_STATE, isError); + + result[executionId][assertionName] = result[executionId][assertionName] || { + name: assertionName, + passed: 0, + failed: 0 + }; + aggregationResult = result[executionId][assertionName]; + + ++aggregationResult[updateKey]; + ++netTestCounts[executionId][updateKey]; + }); + }, {}), + + aggregator = function (execution) { + // fetch aggregated run times and response sizes for items, (0 for failed requests) + var aggregationMean = executionMeans[execution.item.id], + meanTime = _.get(aggregationMean, 'time', 0), + meanSize = _.get(aggregationMean, 'size', 0), + parent = execution.item.parent(), + previous = _.last(aggregations), + current = _.merge(items[execution.item.id], { + assertions: _.values(assertions[execution.item.id]), + mean: { + time: util.prettyms(meanTime.sum / meanTime.count), + size: util.filesize(meanSize.sum / meanSize.count) + }, + cumulativeTests: netTestCounts[execution.item.id] + }); + + if (aggregatedExecutions[execution.id]) { return; } + + aggregatedExecutions[execution.id] = true; + + if (previous && parent.id === previous.parent.id) { + previous.executions.push(current); + } + else { + aggregations.push({ + parent: { + id: parent.id, + name: util.getFullName(parent) + }, + executions: [current] + }); + } + }; + + _.forEach(this.summary.run.executions, aggregator); + + this.exports.push({ + name: 'html-reporter', + default: 'newman-run-report.html', + path: options.export, + content: compiler({ + timestamp: Date(), + version: util.version, + aggregations: aggregations, + summary: { + stats: this.summary.run.stats, + collection: this.summary.collection, + globals: _.isObject(this.summary.globals) ? this.summary.globals : undefined, + environment: _.isObject(this.summary.environment) ? this.summary.environment : undefined, + failures: this.summary.run.failures, + responseTotal: util.filesize(this.summary.run.transfers.responseTotal), + responseAverage: util.prettyms(this.summary.run.timings.responseAverage), + duration: util.prettyms(this.summary.run.timings.completed - this.summary.run.timings.started) + } + }) + }); + }); +}; + +module.exports = PostmanHTMLReporter; diff --git a/lib/template-default.hbs b/lib/template-default.hbs new file mode 100644 index 0000000..3491eaf --- /dev/null +++ b/lib/template-default.hbs @@ -0,0 +1,160 @@ + + +
+ +Name | Pass count | Fail count |
---|---|---|
{{this.name}} | {{this.passed}} | {{this.failed}} |