diff --git a/README.md b/README.md index ced0b01c5..f0e82baf3 100644 --- a/README.md +++ b/README.md @@ -347,7 +347,7 @@ newman.run({ "_postman_exported_at": "2016-10-17T14:31:26.200Z", "_postman_exported_using": "Postman/4.8.0" }, - globalVar: [ + globalVar: [ { "key":"glboalSecret", "value":"globalSecretValue" }, { "key":"globalAnotherSecret", "value":`${process.env.GLOBAL_ANOTHER_SECRET}`} ], @@ -367,7 +367,7 @@ newman.run({ "_postman_exported_at": "2016-10-17T14:26:34.940Z", "_postman_exported_using": "Postman/4.8.0" }, - envVar: [ + envVar: [ { "key":"secret", "value":"secretValue" }, { "key":"anotherSecret", "value":`${process.env.ANOTHER_SECRET}`} ], @@ -445,14 +445,14 @@ such a scenario. | CLI Option | Description | |-------------|-------------------| | `--reporter-cli-silent` | The CLI reporter is internally disabled and you see no output to terminal. | - -| `--reporter-cli-show-timestamps` | This prints the local time for each request made. | +| `--reporter-cli-show-timestamps` | This prints the local time for each request made. | | `--reporter-cli-no-summary` | The statistical summary table is not shown. | | `--reporter-cli-no-failures` | This prevents the run failures from being separately printed. | | `--reporter-cli-no-assertions` | This turns off the output for request-wise assertions as they happen. | | `--reporter-cli-no-success-assertions` | This turns off the output for successful assertions as they happen. | | `--reporter-cli-no-console` | This turns off the output of `console.log` (and other console calls) from collection's scripts. | | `--reporter-cli-no-banner` | This turns off the `newman` banner shown at the beginning of each collection run. | +| `--reporter-cli-truncate-body-output ` | Specify the truncation size of body in verbose CLI output for requests and responses. You can pass inputs like `1KB`, `1024`, `2.5kb`, etc. By default, the truncation size is set to `2KB`. Pass `infinity` to remove any truncation size limit of verbose CLI output body. | ### JSON Reporter The built-in JSON reporter is useful in producing a comprehensive output of the run summary. It takes the path to the diff --git a/bin/util.js b/bin/util.js index c1913a834..8262c5296 100644 --- a/bin/util.js +++ b/bin/util.js @@ -20,6 +20,7 @@ module.exports = { return num.valueOf(); }, + /** * Helper for collecting argument passed multiple times. * diff --git a/lib/reporters/cli/index.js b/lib/reporters/cli/index.js index 3728a2874..d30be1c1f 100644 --- a/lib/reporters/cli/index.js +++ b/lib/reporters/cli/index.js @@ -2,6 +2,7 @@ var _ = require('lodash'), sdk = require('postman-collection'), colors = require('colors/safe'), Table = require('cli-table3'), + bytes = require('bytes'), format = require('util').format, util = require('../../util'), @@ -70,6 +71,7 @@ extractSNR = function (executions) { * @param {Boolean=} reporterOptions.noFailures - Boolean flag to turn off failure reporting altogether, if set to true. * @param {Boolean=} reporterOptions.noConsole - Boolean flag to turn off console logging, if set to true. * @param {Boolean=} reporterOptions.noBanner - Boolean flag to turn off newman banner, if set to true. + * @param {String=} reporterOptions.truncateBodyOutput - Specify the truncation size of body in verbose CLI output. * @param {Object} options - A set of generic collection run options. * @returns {*} */ @@ -233,9 +235,24 @@ PostmanCLIReporter = function (emitter, reporterOptions, options) { `${mime.mimeType}`, `${mime.mimeFormat}`, `${mime.charset}` - ].join(` ${colors.gray(symbols.star)} `); - + ].join(` ${colors.gray(symbols.star)} `), + // eslint-disable-next-line max-len + bodyClipSize = BODY_CLIP_SIZE; + if (reporterOptions.truncateBodyOutput) { + // if infinite is passed to truncate-body-output + if (reporterOptions.truncateBodyOutput.toLowerCase() === 'infinity') { + bodyClipSize = Number.POSITIVE_INFINITY; + } + else { + bodyClipSize = bytes.parse(reporterOptions.truncateBodyOutput); + } + } + if (isNaN(bodyClipSize)) { + // eslint-disable-next-line max-len + print(LF + 'Invalid value passed to --reporter-cli-truncate-body-output flag, defaulting to 2KB. You can pass values like 1KB, 1024, 2.5kb or infinite. For more info, view https://github.com/visionmedia/bytes.js' + LF); + bodyClipSize = 2048; // If invalid size, set to 2048 B + } print.lf(SPC); // also flushes out the circling progress icon // for clean readability of code. this section compiles the cli string for one line of @@ -249,13 +266,14 @@ PostmanCLIReporter = function (emitter, reporterOptions, options) { `${resHeadersLen}${colors.gray(symbols.down)} ${colors.gray('headers')}`, `${_.get(res, 'cookies.members.length')} ${colors.gray('cookies')}` ].join(` ${colors.gray(symbols.star)} `)); - // print request body + + print.lf('Req Text Len : ', req.size()); if (reqTextLen) { - // truncate very large request (is 2048 large enough?) - if (reqTextLen > BODY_CLIP_SIZE) { - reqText = reqText.substr(0, BODY_CLIP_SIZE) + - colors.brightWhite(`\n(showing ${util.filesize(BODY_CLIP_SIZE)}/${util.filesize(reqTextLen)})`); + // truncate very large request + if (reqTextLen > bodyClipSize) { + reqText = reqText.substr(0, bodyClipSize) + + colors.brightWhite(`\n(showing ${util.filesize(bodyClipSize)}/${util.filesize(reqTextLen)})`); } reqText = wrap(reqText, ` ${colors.white(symbols.console.middle)} `); @@ -271,10 +289,10 @@ PostmanCLIReporter = function (emitter, reporterOptions, options) { // print response body if (resTextLen) { - // truncate very large response (is 2048 large enough?) - if (resTextLen > BODY_CLIP_SIZE) { - resText = resText.substr(0, BODY_CLIP_SIZE) + - colors.brightWhite(`\n(showing ${util.filesize(BODY_CLIP_SIZE)}/${util.filesize(resTextLen)})`); + // truncate very large response + if (resTextLen > bodyClipSize) { + resText = resText.substr(0, bodyClipSize) + + colors.brightWhite(`\n(showing ${util.filesize(bodyClipSize)}/${util.filesize(resTextLen)})`); } resText = wrap(resText, ` ${colors.white(symbols.console.middle)} `); diff --git a/package-lock.json b/package-lock.json index 83daccc40..f5f704010 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,10 +6,11 @@ "packages": { "": { "name": "newman", - "version": "5.3.0", + "version": "5.3.1", "license": "Apache-2.0", "dependencies": { "async": "3.2.3", + "bytes": "^3.1.1", "chardet": "1.4.0", "cli-progress": "3.10.0", "cli-table3": "0.6.1", @@ -1086,6 +1087,14 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "node_modules/bytes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cache-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-2.0.0.tgz", @@ -7231,6 +7240,11 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "bytes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" + }, "cache-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-2.0.0.tgz", diff --git a/package.json b/package.json index 842533438..018862296 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "license": "Apache-2.0", "dependencies": { "async": "3.2.3", + "bytes": "^3.1.1", "chardet": "1.4.0", "cli-progress": "3.10.0", "cli-table3": "0.6.1", diff --git a/test/cli/verbose.test.js b/test/cli/verbose.test.js index 108ca8b4c..54e0a0935 100644 --- a/test/cli/verbose.test.js +++ b/test/cli/verbose.test.js @@ -2,17 +2,21 @@ var _ = require('lodash'); describe('newman run --verbose', function () { var verboseStrings = [ - 'prepare', - 'wait', - 'dns-lookup', - 'tcp-handshake', - 'ssl-handshake', - 'transfer-start', - 'download', - 'process', - 'average DNS lookup time:', - 'average first byte time:' - ]; + 'prepare', + 'wait', + 'dns-lookup', + 'tcp-handshake', + 'ssl-handshake', + 'transfer-start', + 'download', + 'process', + 'average DNS lookup time:', + 'average first byte time:' + ], + endTags = [ + '', + '' + ]; it('should include verbose with --verbose option', function (done) { exec('node ./bin/newman.js run test/fixtures/run/single-get-request.json --verbose', function (code, stdout) { @@ -33,4 +37,96 @@ describe('newman run --verbose', function () { done(); }); }); + + it('should limit to 2KB with --verbose option only without setting truncate-body-output', function (done) { + // eslint-disable-next-line max-len + exec('node ./bin/newman.js run test/fixtures/run/large-output-get-request.json --verbose', function (_code, stdout) { + _.forEach(endTags, function (str) { + expect(stdout).to.not.contain(str); + }); + + done(); + }); + }); + + it('should log the entire output when infinity is passed to --truncate-body-output', function (done) { + // eslint-disable-next-line max-len + exec('node ./bin/newman.js run test/fixtures/run/large-output-get-request.json --verbose --reporter-cli-truncate-body-output infinity', function (_code, stdout) { + _.forEach(endTags, function (str) { + expect(stdout).to.contain(str); + }); + + done(); + }); + }); + + // eslint-disable-next-line max-len + it('should log the entire output when infinity is passed to --truncate-body-output without considering case', function (done) { + // eslint-disable-next-line max-len + exec('node ./bin/newman.js run test/fixtures/run/large-output-get-request.json --verbose --reporter-cli-truncate-body-output InFiNiTy', function (_code, stdout) { + _.forEach(endTags, function (str) { + expect(stdout).to.contain(str); + }); + // eslint-disable-next-line max-len + exec('node ./bin/newman.js run test/fixtures/run/large-output-get-request.json --verbose --reporter-cli-truncate-body-output INFINITY', function (_code, stdout) { + _.forEach(endTags, function (str) { + expect(stdout).to.contain(str); + }); + + done(); + }); + }); + }); + + it('should display twice as much as verbose output when limit set to 2KB than 1KB', function (done) { + var output_response_start = '"args"', + output_response_end = '(showing'; + + // eslint-disable-next-line max-len + exec('node ./bin/newman.js run test/fixtures/run/continuous-data.json --verbose --reporter-cli-truncate-body-output 2kb', function (_code, largeStdout) { + // eslint-disable-next-line max-len + exec('node ./bin/newman.js run test/fixtures/run/continuous-data.json --verbose --reporter-cli-truncate-body-output 1kb', function (_code, smallStdout) { + // eslint-disable-next-line max-len + var largeStdoutResponseOnly = largeStdout.slice(largeStdout.indexOf(output_response_start), largeStdout.lastIndexOf(output_response_end)), + // eslint-disable-next-line max-len + smallStdoutResponseOnly = smallStdout.slice(smallStdout.indexOf(output_response_start), smallStdout.lastIndexOf(output_response_end)); + + /* + 1000-1193 = 193 characters + 1000-1398 = 398 ~= 193 * 2 characters + Thus setting output limit to 2kb ensure almost twice output size as compared to 1kb + */ + expect(smallStdoutResponseOnly).to.contain('1193'); + expect(largeStdoutResponseOnly).to.contain('1398'); + expect(largeStdoutResponseOnly.length).to.be.greaterThan(smallStdoutResponseOnly.length); + // eslint-disable-next-line max-len + expect(Math.abs(largeStdoutResponseOnly.length - smallStdoutResponseOnly.length * 2)).to.be.lessThanOrEqual(1); + done(); + }); + }); + }); + + it('should display a warning and fallback to 2KB when invalid truncate-body-output is passed', function (done) { + // eslint-disable-next-line max-len + exec('node ./bin/newman.js run test/fixtures/run/large-output-get-request.json --verbose --reporter-cli-truncate-body-output postman', function (_code, stdout) { + expect(stdout).to.contain('Invalid value'); + expect(stdout).to.contain('showing 2.05'); + done(); + }); + }); + + it('should limit both request and response body output when truncate-body-output is passed', function (done) { + var output_response_start = '"args"'; + + // eslint-disable-next-line max-len + exec('node ./bin/newman.js run test/fixtures/run/continuous-data.json --verbose --reporter-cli-truncate-body-output 0.5kb', function (_code, stdout) { + var responseStartIndex = stdout.indexOf(output_response_start), + request = stdout.slice(0, responseStartIndex), + response = stdout.slice(0, responseStartIndex); + + expect(request).to.contain('512B'); + expect(response).to.contain('512B'); + done(); + }); + }); }); diff --git a/test/fixtures/run/continuous-data.json b/test/fixtures/run/continuous-data.json new file mode 100644 index 000000000..79bb08c14 --- /dev/null +++ b/test/fixtures/run/continuous-data.json @@ -0,0 +1,73 @@ +{ + "info": { + "_postman_id": "81f0e310-03a1-4897-bc07-f31bd863ec05", + "name": "Continuous Data", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" + }, + "item": [ + { + "name": "Continuous Data Test", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const ARRAY_SIZE = 1500;", + "const continuousNumberArray = Array(ARRAY_SIZE).fill().map((_element, index) => index + 1000);", + "pm.collectionVariables.set('continuousNumberArray', continuousNumberArray);" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "pm.test(\"Status code name has string OK\", function () {", + " pm.response.to.have.status(\"OK\");", + "});", + "pm.test(\"Body contains string continuousNumberArray\", function () {", + " pm.expect(pm.response.text()).to.include(\"continuousNumberArray\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"continuousNumberArray\": {{continuousNumberArray}}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://postman-echo.com/post", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + "post" + ] + } + }, + "response": [] + } + ], + "variable": [ + { + "key": "continuousNumberArray", + "value": "" + } + ] +} diff --git a/test/fixtures/run/large-output-get-request.json b/test/fixtures/run/large-output-get-request.json new file mode 100644 index 000000000..258c15016 --- /dev/null +++ b/test/fixtures/run/large-output-get-request.json @@ -0,0 +1,18 @@ +{ + "info": { + "_postman_id": "6d0dfccd-5998-43bb-a0a5-f88065c8c5d1", + "name": "Large Output Test for --output-size Flag", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" + }, + "item": [ + { + "name": "Postman Get Request", + "request": { + "method": "GET", + "header": [], + "url": "https://www.postman.com/" + }, + "response": [] + } + ] +}