From d65028fae8870333793ab82ab0ef125a2672b07b Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Fri, 16 Jun 2023 12:29:34 +0530 Subject: [PATCH 01/22] feat: runner results implented at 'done' event --- .../firecamp-collection-runner/dist/index.cjs | 13 +++++++++ .../dist/index.d.ts | 3 ++ .../firecamp-collection-runner/dist/index.js | 13 +++++++++ .../firecamp-collection-runner/src/index.ts | 29 +++++++++++++++++-- 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index b999723c6..c34d3c084 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -28,6 +28,13 @@ class Runner { __publicField(this, "currentRequestInExecution"); __publicField(this, "testResults", []); __publicField(this, "emitter"); + __publicField(this, "result", { + total: 0, + pass: 0, + fail: 0, + skip: 0 + }); + __publicField(this, "duration", 0); __publicField(this, "i", 0); this.collection = collection; this.options = options; @@ -84,6 +91,9 @@ class Runner { rootRequestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); } } + updateResult(response) { + console.log(response.testResult); + } async executeRequest(requestId) { const { folders, requests } = this.collection; const request = requests.find((r) => r.__ref.id == requestId); @@ -96,6 +106,7 @@ class Runner { }); await delay(500); const response = await this.options.executeRequest(request); + this.updateResult(response); this.emitter.emit("request" /* Request */, { id: request.__ref.id, response @@ -105,6 +116,8 @@ class Runner { async start() { try { const { value: requestId, done } = this.requestOrdersForExecution.values().next(); + if (this.i > 0) + return; this.i = this.i + 1; if (!done) { this.currentRequestInExecution = requestId; diff --git a/packages/firecamp-collection-runner/dist/index.d.ts b/packages/firecamp-collection-runner/dist/index.d.ts index 152027ecf..a4325ee15 100644 --- a/packages/firecamp-collection-runner/dist/index.d.ts +++ b/packages/firecamp-collection-runner/dist/index.d.ts @@ -12,6 +12,8 @@ declare class Runner { private currentRequestInExecution; private testResults; private emitter; + private result; + private duration; constructor(collection: any, options: any); /** * validate that the collection format is valid @@ -25,6 +27,7 @@ declare class Runner { * prepare an Set of request execution order */ private prepareRequestExecutionOrder; + updateResult(response: any): void; private executeRequest; i: number; private start; diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index 5ed7cee5f..854102482 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -28,6 +28,13 @@ class Runner { __publicField(this, "currentRequestInExecution"); __publicField(this, "testResults", []); __publicField(this, "emitter"); + __publicField(this, "result", { + total: 0, + pass: 0, + fail: 0, + skip: 0 + }); + __publicField(this, "duration", 0); __publicField(this, "i", 0); this.collection = collection; this.options = options; @@ -84,6 +91,9 @@ class Runner { rootRequestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); } } + updateResult(response) { + console.log(response.testResult); + } async executeRequest(requestId) { const { folders, requests } = this.collection; const request = requests.find((r) => r.__ref.id == requestId); @@ -96,6 +106,7 @@ class Runner { }); await delay(500); const response = await this.options.executeRequest(request); + this.updateResult(response); this.emitter.emit("request" /* Request */, { id: request.__ref.id, response @@ -105,6 +116,8 @@ class Runner { async start() { try { const { value: requestId, done } = this.requestOrdersForExecution.values().next(); + if (this.i > 0) + return; this.i = this.i + 1; if (!done) { this.currentRequestInExecution = requestId; diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index 6865f021a..34c0b0273 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -25,6 +25,14 @@ export default class Runner { private currentRequestInExecution: TId; private testResults: any = []; private emitter: EventEmitter; + private result = { + total: 0, + pass: 0, + fail: 0, + skip: 0, + duration: 0 + } + constructor(collection, options) { this.collection = collection; this.options = options; @@ -82,6 +90,15 @@ export default class Runner { } } + updateResult(response: any = {}) { + const { testResult: { total, passed, failed } = { + total: 0, passed: 0, failed: 0 + } } = response + if (Number.isInteger(total)) this.result.total += total; + if (Number.isInteger(passed)) this.result.pass += passed; + if (Number.isInteger(failed)) this.result.fail += failed; + } + private async executeRequest(requestId: TId) { const { folders, requests } = this.collection; const request = requests.find(r => r.__ref.id == requestId); @@ -97,7 +114,7 @@ export default class Runner { await delay(500); const response = await this.options.executeRequest(request); - + this.updateResult(response) /** emit 'request' event on request execution completion */ this.emitter.emit(ERunnerEvents.Request, { id: request.__ref.id, @@ -112,7 +129,7 @@ export default class Runner { try { const { value: requestId, done } = this.requestOrdersForExecution.values().next(); - // if (this.i > 0) return + if (this.i > 0) return this.i = this.i + 1 if (!done) { this.currentRequestInExecution = requestId; @@ -149,6 +166,7 @@ export default class Runner { const { collection } = this.collection; + const startTs: number = new Date().valueOf(); /** emit 'start' event on runner start */ this.emitter.emit(ERunnerEvents.Start, { name: collection.name, @@ -158,7 +176,12 @@ export default class Runner { await this.start(); /** emit 'done' event once runner iterations are completed */ - this.emitter.emit(ERunnerEvents.Done); + this.result.duration = new Date().valueOf() - startTs; + this.emitter.emit(ERunnerEvents.Done, { + result: { + ...this.result, + } + }); }); // return this.testResults; From 49f9c2ed35781b6c9d7aa0f517ec9c3360adade5 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Fri, 16 Jun 2023 13:19:28 +0530 Subject: [PATCH 02/22] feat: cli reporter table result implemented boxen removed dummy table command removed --- packages/firecamp-cli/package.json | 1 - packages/firecamp-cli/src/commands/run.ts | 11 ++-- packages/firecamp-cli/src/commands/table.ts | 49 ------------------ packages/firecamp-cli/src/helper/reporter.ts | 39 ++++++++++++++- .../firecamp-collection-runner/dist/index.cjs | 26 ++++++++-- .../dist/index.d.ts | 3 +- .../firecamp-collection-runner/dist/index.js | 26 ++++++++-- pnpm-lock.yaml | 50 ++----------------- 8 files changed, 91 insertions(+), 114 deletions(-) delete mode 100644 packages/firecamp-cli/src/commands/table.ts diff --git a/packages/firecamp-cli/package.json b/packages/firecamp-cli/package.json index bcb064017..b6e0b2e51 100644 --- a/packages/firecamp-cli/package.json +++ b/packages/firecamp-cli/package.json @@ -23,7 +23,6 @@ "@oclif/core": "^2.8.5", "@oclif/plugin-help": "^5.2.9", "@oclif/plugin-plugins": "^2.4.7", - "boxen": "^7.1.0", "cli-table3": "^0.6.3", "figlet": "^1.6.0", "figures": "^5.0.0", diff --git a/packages/firecamp-cli/src/commands/run.ts b/packages/firecamp-cli/src/commands/run.ts index 7525ccc4a..c5a86ee08 100644 --- a/packages/firecamp-cli/src/commands/run.ts +++ b/packages/firecamp-cli/src/commands/run.ts @@ -58,13 +58,14 @@ export default class Run extends Command { .on(ERunnerEvents.Start, () => { }) .on(ERunnerEvents.BeforeRequest, (request: any) => { // console.log(request) - return reporter.startRequest(request) + reporter.onBeforeRequest(request) }) - .on(ERunnerEvents.Request, async (result: any) => { - - reporter.done(result) + .on(ERunnerEvents.Request, (result: any) => { + reporter.onRequest(result) }) - // .on(ERunnerEvents.Done, console.log) + .on(ERunnerEvents.Done, (result: any) => { + reporter.onDone(result) + }); }) .then(testResults => { // console.log(testResults) diff --git a/packages/firecamp-cli/src/commands/table.ts b/packages/firecamp-cli/src/commands/table.ts deleted file mode 100644 index 76880867c..000000000 --- a/packages/firecamp-cli/src/commands/table.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Command, ux } from '@oclif/core' -import c from 'kleur'; -import Table from 'cli-table3'; -import boxen from 'boxen'; - -export default class Users extends Command { - static flags = {} - - - async run() { - const { flags } = await this.parse(Users) - // const { data: users } = await axios.get('https://jsonplaceholder.typicode.com/users') - - console.log(boxen('unicorn', { padding: 1 })); - - - const _header = (h: string) => c.magenta(h); - var table = new Table({ - head: [ - _header('method'), - _header('api'), - _header('status'), - _header('pass'), - _header('fail') - ], - // colWidths: [100, 400, 200, 150, 150 ], - wordWrap: true, - chars: { - 'top': '═', 'top-mid': '╤', 'top-left': '╔', 'top-right': '╗' - , 'bottom': '═', 'bottom-mid': '╧', 'bottom-left': '╚', 'bottom-right': '╝' - , 'left': '║', 'left-mid': '╟', 'mid': '─', 'mid-mid': '┼' - , 'right': '║', 'right-mid': '╢', 'middle': '│' - } - }); - - table.push( - [c.green('GET'), c.blue('https://localhost:300/api/post'), '200', 3, 2], - [c.blue('POST'), c.blue('https://localhost:300/api/post'), '200', 3, 1], - [c.red('DELETE'), c.blue('https://localhost:300/api/post'), '200', 3, 2] - ); - - this.log(table.toString()); - - // console.log(c.blue('Hello') + ' World' + c.red('!')); - - // boxen('unicorn', {padding: 1}) - - } -} \ No newline at end of file diff --git a/packages/firecamp-cli/src/helper/reporter.ts b/packages/firecamp-cli/src/helper/reporter.ts index de2bbc128..bdb5bd4a4 100644 --- a/packages/firecamp-cli/src/helper/reporter.ts +++ b/packages/firecamp-cli/src/helper/reporter.ts @@ -1,6 +1,7 @@ import ora, { Ora } from 'ora'; import c from 'kleur'; import figures from 'figures'; +import Table from 'cli-table3'; export default class Reporter { @@ -11,14 +12,14 @@ export default class Reporter { this.newLine(); } - startRequest(request: any) { + onBeforeRequest(request: any) { // console.log(request) this.init() this.request = request this.spinner.start(this._title()) } - done(result: any) { + onRequest(result: any) { if (result.response?.testResult) { const { testResult, testResult: { tests } } = result.response; @@ -36,6 +37,10 @@ export default class Reporter { } } + onDone(result: any) { + this.logResult(result) + } + newLine(n: number = 1) { if (n > 10) n = 5 if (n < 0) n = 1; @@ -76,4 +81,34 @@ export default class Reporter { ) } + logResult(summary: any) { + const { result: { } } = summary + + // const _header = (h: string) => c.magenta(h); + var table = new Table({ + // head: [ + // _header('method'), + // _header('api'), + // _header('status'), + // _header('pass'), + // _header('fail') + // ], + // colWidths: [100, 400, 200, 150, 150 ], + // wordWrap: true, + // chars: { 'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': '' } + + }); + + this.newLine(); + table.push( + [c.dim('Total Requests'), 28], + [c.dim('Total Time'), 5004], + [c.dim('Tests'), 8], + [c.green('Pass Tests'), 2], + [c.red('Fail Tests'), 1] + ); + + console.log(table.toString()); + } + } diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index c34d3c084..2c0729ddf 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -32,9 +32,9 @@ class Runner { total: 0, pass: 0, fail: 0, - skip: 0 + skip: 0, + duration: 0 }); - __publicField(this, "duration", 0); __publicField(this, "i", 0); this.collection = collection; this.options = options; @@ -91,8 +91,18 @@ class Runner { rootRequestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); } } - updateResult(response) { - console.log(response.testResult); + updateResult(response = {}) { + const { testResult: { total, passed, failed } = { + total: 0, + passed: 0, + failed: 0 + } } = response; + if (Number.isInteger(total)) + this.result.total += total; + if (Number.isInteger(passed)) + this.result.pass += passed; + if (Number.isInteger(failed)) + this.result.fail += failed; } async executeRequest(requestId) { const { folders, requests } = this.collection; @@ -148,12 +158,18 @@ class Runner { this.prepareRequestExecutionOrder(); setTimeout(async () => { const { collection } = this.collection; + const startTs = (/* @__PURE__ */ new Date()).valueOf(); this.emitter.emit("start" /* Start */, { name: collection.name, id: collection.__ref.id }); await this.start(); - this.emitter.emit("done" /* Done */); + this.result.duration = (/* @__PURE__ */ new Date()).valueOf() - startTs; + this.emitter.emit("done" /* Done */, { + result: { + ...this.result + } + }); }); return this.exposeOnlyOn(); } diff --git a/packages/firecamp-collection-runner/dist/index.d.ts b/packages/firecamp-collection-runner/dist/index.d.ts index a4325ee15..c9fdc5007 100644 --- a/packages/firecamp-collection-runner/dist/index.d.ts +++ b/packages/firecamp-collection-runner/dist/index.d.ts @@ -13,7 +13,6 @@ declare class Runner { private testResults; private emitter; private result; - private duration; constructor(collection: any, options: any); /** * validate that the collection format is valid @@ -27,7 +26,7 @@ declare class Runner { * prepare an Set of request execution order */ private prepareRequestExecutionOrder; - updateResult(response: any): void; + updateResult(response?: any): void; private executeRequest; i: number; private start; diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index 854102482..544a5a6de 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -32,9 +32,9 @@ class Runner { total: 0, pass: 0, fail: 0, - skip: 0 + skip: 0, + duration: 0 }); - __publicField(this, "duration", 0); __publicField(this, "i", 0); this.collection = collection; this.options = options; @@ -91,8 +91,18 @@ class Runner { rootRequestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); } } - updateResult(response) { - console.log(response.testResult); + updateResult(response = {}) { + const { testResult: { total, passed, failed } = { + total: 0, + passed: 0, + failed: 0 + } } = response; + if (Number.isInteger(total)) + this.result.total += total; + if (Number.isInteger(passed)) + this.result.pass += passed; + if (Number.isInteger(failed)) + this.result.fail += failed; } async executeRequest(requestId) { const { folders, requests } = this.collection; @@ -148,12 +158,18 @@ class Runner { this.prepareRequestExecutionOrder(); setTimeout(async () => { const { collection } = this.collection; + const startTs = (/* @__PURE__ */ new Date()).valueOf(); this.emitter.emit("start" /* Start */, { name: collection.name, id: collection.__ref.id }); await this.start(); - this.emitter.emit("done" /* Done */); + this.result.duration = (/* @__PURE__ */ new Date()).valueOf() - startTs; + this.emitter.emit("done" /* Done */, { + result: { + ...this.result + } + }); }); return this.exposeOnlyOn(); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5d606132..9626198e3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,9 +23,6 @@ importers: '@oclif/plugin-plugins': specifier: ^2.4.7 version: 2.4.7(@types/node@16.18.35)(typescript@4.9.5) - boxen: - specifier: ^7.1.0 - version: 7.1.0 cli-table3: specifier: ^0.6.3 version: 0.6.3 @@ -2663,12 +2660,6 @@ packages: require-from-string: 2.0.2 uri-js: 4.4.1 - /ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} - dependencies: - string-width: 4.2.3 - dev: false - /ansi-colors@4.1.1: resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} engines: {node: '>=6'} @@ -2732,6 +2723,7 @@ packages: /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + dev: true /ansicolors@0.3.2: resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} @@ -3009,20 +3001,6 @@ packages: readable-stream: 3.6.2 dev: false - /boxen@7.1.0: - resolution: {integrity: sha512-ScG8CDo8dj7McqCZ5hz4dIBp20xj4unQ2lXIDa7ff6RcZElCpuNzutdwzKVvRikfNjm7CFAlR3HJHcoHkDOExQ==} - engines: {node: '>=14.16'} - dependencies: - ansi-align: 3.0.1 - camelcase: 7.0.1 - chalk: 5.2.0 - cli-boxes: 3.0.0 - string-width: 5.1.2 - type-fest: 2.19.0 - widest-line: 4.0.1 - wrap-ansi: 8.1.0 - dev: false - /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -3261,11 +3239,6 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - /camelcase@7.0.1: - resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} - engines: {node: '>=14.16'} - dev: false - /caniuse-lite@1.0.30001498: resolution: {integrity: sha512-LFInN2zAwx3ANrGCDZ5AKKJroHqNKyjXitdV5zRIVIaQlXKj3GmxUKagoKsjqUfckpAObPCEWnk5EeMlyMWcgw==} dev: true @@ -3414,11 +3387,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /cli-boxes@3.0.0: - resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} - engines: {node: '>=10'} - dev: false - /cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -4243,6 +4211,7 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true /ejs@3.1.9: resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} @@ -4265,6 +4234,7 @@ packages: /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true /encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} @@ -9219,6 +9189,7 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 + dev: true /string.prototype.trim@1.2.7: resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} @@ -9777,11 +9748,6 @@ packages: engines: {node: '>=8'} dev: true - /type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} - engines: {node: '>=12.20'} - dev: false - /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} dependencies: @@ -10140,13 +10106,6 @@ packages: dependencies: string-width: 4.2.3 - /widest-line@4.0.1: - resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} - engines: {node: '>=12'} - dependencies: - string-width: 5.1.2 - dev: false - /word-wrap@1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} engines: {node: '>=0.10.0'} @@ -10195,6 +10154,7 @@ packages: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 + dev: true /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} From 11148e8bfc97f7d70ffe36a451ad361f64b23f0f Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Fri, 16 Jun 2023 13:25:16 +0530 Subject: [PATCH 03/22] feat: duration prettyfioed with pretty-ms --- packages/firecamp-cli/package.json | 1 + packages/firecamp-cli/src/helper/reporter.ts | 11 ++++++----- pnpm-lock.yaml | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/firecamp-cli/package.json b/packages/firecamp-cli/package.json index b6e0b2e51..a6ca0ca0e 100644 --- a/packages/firecamp-cli/package.json +++ b/packages/firecamp-cli/package.json @@ -30,6 +30,7 @@ "kleur": "^4.1.5", "load-json-file": "^7.0.1", "ora": "^6.3.1", + "pretty-ms": "^8.0.0", "react-fast-compare": "^3.2.2" }, "devDependencies": { diff --git a/packages/firecamp-cli/src/helper/reporter.ts b/packages/firecamp-cli/src/helper/reporter.ts index bdb5bd4a4..e46101850 100644 --- a/packages/firecamp-cli/src/helper/reporter.ts +++ b/packages/firecamp-cli/src/helper/reporter.ts @@ -2,6 +2,7 @@ import ora, { Ora } from 'ora'; import c from 'kleur'; import figures from 'figures'; import Table from 'cli-table3'; +import prettyMs from 'pretty-ms'; export default class Reporter { @@ -82,7 +83,7 @@ export default class Reporter { } logResult(summary: any) { - const { result: { } } = summary + const { result: { total, pass, fail, duration } } = summary // const _header = (h: string) => c.magenta(h); var table = new Table({ @@ -102,10 +103,10 @@ export default class Reporter { this.newLine(); table.push( [c.dim('Total Requests'), 28], - [c.dim('Total Time'), 5004], - [c.dim('Tests'), 8], - [c.green('Pass Tests'), 2], - [c.red('Fail Tests'), 1] + [c.dim('Total run duration'), prettyMs(duration)], + [c.dim('Tests'), total], + [c.green('Pass Tests'), pass], + [c.red('Fail Tests'), fail] ); console.log(table.toString()); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9626198e3..9da8405e2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: ora: specifier: ^6.3.1 version: 6.3.1 + pretty-ms: + specifier: ^8.0.0 + version: 8.0.0 react-fast-compare: specifier: ^3.2.2 version: 3.2.2 @@ -8203,6 +8206,11 @@ packages: lines-and-columns: 1.2.4 dev: true + /parse-ms@3.0.0: + resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} + engines: {node: '>=12'} + dev: false + /password-prompt@1.1.2: resolution: {integrity: sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA==} dependencies: @@ -8364,6 +8372,13 @@ packages: react-is: 18.2.0 dev: true + /pretty-ms@8.0.0: + resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} + engines: {node: '>=14.16'} + dependencies: + parse-ms: 3.0.0 + dev: false + /proc-log@1.0.0: resolution: {integrity: sha512-aCk8AO51s+4JyuYGg3Q/a6gnrlDO09NpVWePtjp7xwphcoQ04x5WAfCyugcsbLooWcMJ87CLkD4+604IckEdhg==} dev: true From d89e0be40505f0b7dc0921ca1fd9c806c11aa70d Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Fri, 16 Jun 2023 17:20:59 +0530 Subject: [PATCH 04/22] feat: cli runner optimized with standard practice of runners --- packages/firecamp-cli/src/commands/run.ts | 18 ++++---------- .../{helper/reporter.ts => reporters/cli.ts} | 24 +++++++++++++++---- 2 files changed, 23 insertions(+), 19 deletions(-) rename packages/firecamp-cli/src/{helper/reporter.ts => reporters/cli.ts} (83%) diff --git a/packages/firecamp-cli/src/commands/run.ts b/packages/firecamp-cli/src/commands/run.ts index c5a86ee08..5df18a43c 100644 --- a/packages/firecamp-cli/src/commands/run.ts +++ b/packages/firecamp-cli/src/commands/run.ts @@ -6,7 +6,7 @@ import Runner, { ERunnerEvents } from '@firecamp/collection-runner' import _RestExecutor from '@firecamp/rest-executor'; //@ts-ignore //TODO: rest-executor is commonjs lib while runner is esm. we'll move all lib in esm in future const RestExecutor = _RestExecutor.default -import Reporter from './../helper/reporter.js' +import CliReporter from '../reporters/cli.js' /** * Run command example * ./bin/dev run ../../test/data/FirecampRestEchoServer.firecamp_collection.json @@ -52,20 +52,10 @@ export default class Run extends Command { return executor.send(request, { collectionVariables: [], environment: [], globals: [] }); } }) - const reporter = new Reporter(); - return runner.run() - .on(ERunnerEvents.Start, () => { }) - .on(ERunnerEvents.BeforeRequest, (request: any) => { - // console.log(request) - reporter.onBeforeRequest(request) - }) - .on(ERunnerEvents.Request, (result: any) => { - reporter.onRequest(result) - }) - .on(ERunnerEvents.Done, (result: any) => { - reporter.onDone(result) - }); + + const emitter = runner.run() + new CliReporter(emitter); }) .then(testResults => { // console.log(testResults) diff --git a/packages/firecamp-cli/src/helper/reporter.ts b/packages/firecamp-cli/src/reporters/cli.ts similarity index 83% rename from packages/firecamp-cli/src/helper/reporter.ts rename to packages/firecamp-cli/src/reporters/cli.ts index e46101850..e551df939 100644 --- a/packages/firecamp-cli/src/helper/reporter.ts +++ b/packages/firecamp-cli/src/reporters/cli.ts @@ -1,3 +1,5 @@ + +import { ERunnerEvents } from '@firecamp/collection-runner'; import ora, { Ora } from 'ora'; import c from 'kleur'; import figures from 'figures'; @@ -8,14 +10,28 @@ export default class Reporter { private request: any; private spinner: Ora = ora(); - init() { + constructor(emitter: any) { + emitter + .on(ERunnerEvents.Start, () => { }) + .on(ERunnerEvents.BeforeRequest, (request: any) => { + // console.log(request) + this.onBeforeRequest(request) + }) + .on(ERunnerEvents.Request, (result: any) => { + this.onRequest(result) + }) + .on(ERunnerEvents.Done, (result: any) => { + this.onDone(result) + }); + } + initSpinner() { this.spinner = ora() this.newLine(); } onBeforeRequest(request: any) { // console.log(request) - this.init() + this.initSpinner() this.request = request this.spinner.start(this._title()) } @@ -32,9 +48,7 @@ export default class Reporter { else this.logTest(t, true) }) // console.log(testResult) - this.logResponseMeta(result.response.response) - } } @@ -51,7 +65,7 @@ export default class Reporter { _title() { const { method = '', name = '', url, path } = this.request const title = `${name} ${c.dim().cyan(`(${path})`)}`; - return title; + // return title; // title with url return `${title} From d0511bf603e3debecb8436f0db7d45a10c9a158f Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Fri, 16 Jun 2023 18:08:05 +0530 Subject: [PATCH 05/22] feat: log ui improvements --- packages/firecamp-cli/src/commands/run.ts | 3 +- packages/firecamp-cli/src/reporters/cli.ts | 47 +++++++++++----------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/firecamp-cli/src/commands/run.ts b/packages/firecamp-cli/src/commands/run.ts index 5df18a43c..de928615f 100644 --- a/packages/firecamp-cli/src/commands/run.ts +++ b/packages/firecamp-cli/src/commands/run.ts @@ -1,5 +1,6 @@ import { Args, Command, Flags } from '@oclif/core' import { loadJsonFile } from 'load-json-file'; +import c from 'kleur'; import figlet from 'figlet' //@ts-ignore https://github.com/egoist/tsup/issues/760 import Runner, { ERunnerEvents } from '@firecamp/collection-runner' @@ -36,7 +37,7 @@ export default class Run extends Command { this.logToStderr('error: The collection path is missing') return } - this.log(figlet.textSync("Firecamp")) + this.log(c.gray(figlet.textSync("Firecamp"))) // tasks.run() diff --git a/packages/firecamp-cli/src/reporters/cli.ts b/packages/firecamp-cli/src/reporters/cli.ts index e551df939..48e8a6c6a 100644 --- a/packages/firecamp-cli/src/reporters/cli.ts +++ b/packages/firecamp-cli/src/reporters/cli.ts @@ -1,4 +1,3 @@ - import { ERunnerEvents } from '@firecamp/collection-runner'; import ora, { Ora } from 'ora'; import c from 'kleur'; @@ -9,8 +8,10 @@ import prettyMs from 'pretty-ms'; export default class Reporter { private request: any; - private spinner: Ora = ora(); + private response: any; + private spinner: Ora; constructor(emitter: any) { + this.spinner = ora(); emitter .on(ERunnerEvents.Start, () => { }) .on(ERunnerEvents.BeforeRequest, (request: any) => { @@ -33,22 +34,23 @@ export default class Reporter { // console.log(request) this.initSpinner() this.request = request + this.response = null; this.spinner.start(this._title()) } onRequest(result: any) { - + this.response = result?.response?.response if (result.response?.testResult) { const { testResult, testResult: { tests } } = result.response; this.spinner.stopAndPersist({ - symbol: testResult.failed == 0 ? c.green(figures.tick) : c.red(figures.cross) + symbol: '↳', //testResult.failed == 0 ? c.green(figures.tick) : c.red(figures.cross), + text: this._title() }); tests.map((t: any) => { if (t.isPassed) this.logTest(t) else this.logTest(t, true) }) // console.log(testResult) - this.logResponseMeta(result.response.response) } } @@ -64,38 +66,35 @@ export default class Reporter { _title() { const { method = '', name = '', url, path } = this.request - const title = `${name} ${c.dim().cyan(`(${path})`)}`; - // return title; + let title = `${name} ${c.dim().cyan(`(${path})`)}`; // title with url - return `${title} - ${c.dim(method.toUpperCase() + ' ' + url)}` + title = `${title} + ${c.gray(method.toUpperCase() + ' ' + url)}`; + + if (this.response) + title += ' ' + this._responseMeta() + return title; + } + + _responseMeta() { + const { code, status, responseTime, responseSize } = this.response + const line = `[${code + ' ' + status}, ${responseSize}B, ${prettyMs(responseTime)}]`; + return c.dim(line) } logTest(test: any, failed = false) { const { name, error } = test const log = !failed - ? `${c.green(' ' + figures.tick)} ${c.dim(name)}` - : `${c.red(' ' + figures.cross)} ${c.red().dim(name)}` + ? `${c.green(' ' + figures.tick)} ${c.gray(name)}` + : `${c.red(' ' + figures.cross)} ${c.gray(name)}` console.log(log) if (error) - console.log(` `, c.italic().dim(error.message)) + console.log(` `, c.italic().gray().dim(error.message)) // throw new Error(error) } - logResponseMeta(response: any) { - const { code, status, responseTime, responseSize } = response - - console.log(c.dim(' ----------------')) - console.log( - ` `, - c.dim(`${code} ${status}`), - c.dim(`${responseTime}ms`), - c.dim(`${responseSize}B`) - ) - } - logResult(summary: any) { const { result: { total, pass, fail, duration } } = summary From a370b4e42f0f424c21b9d7910f01313a44ee03ef Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Fri, 16 Jun 2023 18:35:53 +0530 Subject: [PATCH 06/22] feat: command changed to 'firecamp collection run ./collection.json' --- packages/firecamp-cli/src/commands/{ => collection}/run.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename packages/firecamp-cli/src/commands/{ => collection}/run.ts (94%) diff --git a/packages/firecamp-cli/src/commands/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts similarity index 94% rename from packages/firecamp-cli/src/commands/run.ts rename to packages/firecamp-cli/src/commands/collection/run.ts index de928615f..0e1cb8172 100644 --- a/packages/firecamp-cli/src/commands/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -7,7 +7,7 @@ import Runner, { ERunnerEvents } from '@firecamp/collection-runner' import _RestExecutor from '@firecamp/rest-executor'; //@ts-ignore //TODO: rest-executor is commonjs lib while runner is esm. we'll move all lib in esm in future const RestExecutor = _RestExecutor.default -import CliReporter from '../reporters/cli.js' +import CliReporter from '../../reporters/cli.js' /** * Run command example * ./bin/dev run ../../test/data/FirecampRestEchoServer.firecamp_collection.json @@ -43,7 +43,7 @@ export default class Run extends Command { // tasks.run() // return - const _filepath = new URL(`../../${file}`, import.meta.url).pathname + const _filepath = new URL(`../../../${file}`, import.meta.url).pathname loadJsonFile(_filepath) .then(collection => { // this.logJson(collection); From bd563a603e1e928a8f2a8a07455efd065c3ecf69 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Sat, 17 Jun 2023 16:28:08 +0530 Subject: [PATCH 07/22] feat(runner): IRunnerOptions interface added --- .../firecamp-collection-runner/src/index.ts | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index 34c0b0273..4e1a64f8b 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -16,10 +16,21 @@ export enum ERunnerEvents { Done = 'done' } +interface IRunnerOptions { + executeRequest: (request: any) => Promise; + environment?: TId | string; + globals?: TId | string; + iterationCount?: number; + iterationData?: string; + delayRequest?: number; + timeout?: number; + timeoutRequest?: number; +} + export default class Runner { private collection: any; - private options: any; + private options: IRunnerOptions; private requestOrdersForExecution: Set; private executedRequestQueue: Set; private currentRequestInExecution: TId; @@ -33,13 +44,33 @@ export default class Runner { duration: 0 } - constructor(collection, options) { + constructor(collection, options: IRunnerOptions) { this.collection = collection; this.options = options; this.requestOrdersForExecution = new Set(); this.executedRequestQueue = new Set(); this.currentRequestInExecution = ''; this.emitter = new EventEmitter(); + this.assignDefaultOptions(); + } + + private assignDefaultOptions() { + const { iterationCount, delayRequest, timeout, timeoutRequest } = this.options; + if (!this.options.hasOwnProperty('iterationCount')) this.options.iterationCount = 1; + if (!this.options.hasOwnProperty('delayRequest')) this.options.delayRequest = 0; + if (!this.options.hasOwnProperty('timeout')) this.options.timeout = 0; + if (!this.options.hasOwnProperty('timeoutRequest')) this.options.timeoutRequest = 0; + + + if (typeof this.options.iterationCount != 'number') + throw new Error('--iteration-count is invalid', { cause: 'invalidOption' }) + if (typeof this.options.delayRequest != 'number') + throw new Error('--delay-request is invalid', { cause: 'invalidOption' }) + if (typeof this.options.timeout != 'number') + throw new Error('--timeout is invalid', { cause: 'invalidOption' }) + if (typeof this.options.timeoutRequest != 'number') + throw new Error('--timeout-request is invalid', { cause: 'invalidOption' }) + } /** From 679bc938947887d2f17ea372d9102e4ae52d35fc Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Sat, 17 Jun 2023 16:37:17 +0530 Subject: [PATCH 08/22] feat(runner): validation flow changed to initialization --- packages/firecamp-collection-runner/src/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index 4e1a64f8b..373ed47f5 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -51,11 +51,11 @@ export default class Runner { this.executedRequestQueue = new Set(); this.currentRequestInExecution = ''; this.emitter = new EventEmitter(); + this.validate(); this.assignDefaultOptions(); } private assignDefaultOptions() { - const { iterationCount, delayRequest, timeout, timeoutRequest } = this.options; if (!this.options.hasOwnProperty('iterationCount')) this.options.iterationCount = 1; if (!this.options.hasOwnProperty('delayRequest')) this.options.delayRequest = 0; if (!this.options.hasOwnProperty('timeout')) this.options.timeout = 0; @@ -121,7 +121,7 @@ export default class Runner { } } - updateResult(response: any = {}) { + private updateResult(response: any = {}) { const { testResult: { total, passed, failed } = { total: 0, passed: 0, failed: 0 } } = response @@ -190,7 +190,6 @@ export default class Runner { run() { - try { this.validate() } catch (e) { throw e } this.prepareRequestExecutionOrder(); setTimeout(async () => { From 28ee2ab1a1d37ed11bbf2baea1970ac281306059 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Sat, 17 Jun 2023 18:04:20 +0530 Subject: [PATCH 09/22] feat(runner): iteration implementation started --- packages/firecamp-cli/src/reporters/cli.ts | 1 - .../firecamp-collection-runner/dist/index.cjs | 34 ++++++++++++++----- .../dist/index.d.ts | 17 ++++++++-- .../firecamp-collection-runner/dist/index.js | 34 ++++++++++++++----- .../firecamp-collection-runner/src/index.ts | 13 +++---- 5 files changed, 72 insertions(+), 27 deletions(-) diff --git a/packages/firecamp-cli/src/reporters/cli.ts b/packages/firecamp-cli/src/reporters/cli.ts index 48e8a6c6a..3ac19309a 100644 --- a/packages/firecamp-cli/src/reporters/cli.ts +++ b/packages/firecamp-cli/src/reporters/cli.ts @@ -15,7 +15,6 @@ export default class Reporter { emitter .on(ERunnerEvents.Start, () => { }) .on(ERunnerEvents.BeforeRequest, (request: any) => { - // console.log(request) this.onBeforeRequest(request) }) .on(ERunnerEvents.Request, (result: any) => { diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index 2c0729ddf..7a2dba51f 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -42,6 +42,26 @@ class Runner { this.executedRequestQueue = /* @__PURE__ */ new Set(); this.currentRequestInExecution = ""; this.emitter = new (0, _eventemitter32.default)(); + this.validate(); + this.assignDefaultOptions(); + } + assignDefaultOptions() { + if (!this.options.hasOwnProperty("iterationCount")) + this.options.iterationCount = 2; + if (!this.options.hasOwnProperty("delayRequest")) + this.options.delayRequest = 0; + if (!this.options.hasOwnProperty("timeout")) + this.options.timeout = 0; + if (!this.options.hasOwnProperty("timeoutRequest")) + this.options.timeoutRequest = 0; + if (typeof this.options.iterationCount != "number") + throw new Error("--iteration-count is invalid", { cause: "invalidOption" }); + if (typeof this.options.delayRequest != "number") + throw new Error("--delay-request is invalid", { cause: "invalidOption" }); + if (typeof this.options.timeout != "number") + throw new Error("--timeout is invalid", { cause: "invalidOption" }); + if (typeof this.options.timeoutRequest != "number") + throw new Error("--timeout-request is invalid", { cause: "invalidOption" }); } /** * validate that the collection format is valid @@ -114,7 +134,7 @@ class Runner { path: fetchRequestPath(folders, request), id: request.__ref.id }); - await delay(500); + await delay(this.options.delayRequest); const response = await this.options.executeRequest(request); this.updateResult(response); this.emitter.emit("request" /* Request */, { @@ -126,8 +146,6 @@ class Runner { async start() { try { const { value: requestId, done } = this.requestOrdersForExecution.values().next(); - if (this.i > 0) - return; this.i = this.i + 1; if (!done) { this.currentRequestInExecution = requestId; @@ -150,11 +168,6 @@ class Runner { }; } run() { - try { - this.validate(); - } catch (e) { - throw e; - } this.prepareRequestExecutionOrder(); setTimeout(async () => { const { collection } = this.collection; @@ -163,7 +176,10 @@ class Runner { name: collection.name, id: collection.__ref.id }); - await this.start(); + for (let i = 0; i < this.options.iterationCount; i++) { + await this.start(); + console.log(i, "----"); + } this.result.duration = (/* @__PURE__ */ new Date()).valueOf() - startTs; this.emitter.emit("done" /* Done */, { result: { diff --git a/packages/firecamp-collection-runner/dist/index.d.ts b/packages/firecamp-collection-runner/dist/index.d.ts index c9fdc5007..2249222e2 100644 --- a/packages/firecamp-collection-runner/dist/index.d.ts +++ b/packages/firecamp-collection-runner/dist/index.d.ts @@ -1,9 +1,21 @@ +import { TId } from '@firecamp/types'; + declare enum ERunnerEvents { Start = "start", BeforeRequest = "beforeRequest", Request = "request", Done = "done" } +interface IRunnerOptions { + executeRequest: (request: any) => Promise; + environment?: TId | string; + globals?: TId | string; + iterationCount?: number; + iterationData?: string; + delayRequest?: number; + timeout?: number; + timeoutRequest?: number; +} declare class Runner { private collection; private options; @@ -13,7 +25,8 @@ declare class Runner { private testResults; private emitter; private result; - constructor(collection: any, options: any); + constructor(collection: any, options: IRunnerOptions); + private assignDefaultOptions; /** * validate that the collection format is valid * TODO: late we need to add the zod or json schema here for strong validation @@ -26,7 +39,7 @@ declare class Runner { * prepare an Set of request execution order */ private prepareRequestExecutionOrder; - updateResult(response?: any): void; + private updateResult; private executeRequest; i: number; private start; diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index 544a5a6de..505122bae 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -42,6 +42,26 @@ class Runner { this.executedRequestQueue = /* @__PURE__ */ new Set(); this.currentRequestInExecution = ""; this.emitter = new EventEmitter(); + this.validate(); + this.assignDefaultOptions(); + } + assignDefaultOptions() { + if (!this.options.hasOwnProperty("iterationCount")) + this.options.iterationCount = 2; + if (!this.options.hasOwnProperty("delayRequest")) + this.options.delayRequest = 0; + if (!this.options.hasOwnProperty("timeout")) + this.options.timeout = 0; + if (!this.options.hasOwnProperty("timeoutRequest")) + this.options.timeoutRequest = 0; + if (typeof this.options.iterationCount != "number") + throw new Error("--iteration-count is invalid", { cause: "invalidOption" }); + if (typeof this.options.delayRequest != "number") + throw new Error("--delay-request is invalid", { cause: "invalidOption" }); + if (typeof this.options.timeout != "number") + throw new Error("--timeout is invalid", { cause: "invalidOption" }); + if (typeof this.options.timeoutRequest != "number") + throw new Error("--timeout-request is invalid", { cause: "invalidOption" }); } /** * validate that the collection format is valid @@ -114,7 +134,7 @@ class Runner { path: fetchRequestPath(folders, request), id: request.__ref.id }); - await delay(500); + await delay(this.options.delayRequest); const response = await this.options.executeRequest(request); this.updateResult(response); this.emitter.emit("request" /* Request */, { @@ -126,8 +146,6 @@ class Runner { async start() { try { const { value: requestId, done } = this.requestOrdersForExecution.values().next(); - if (this.i > 0) - return; this.i = this.i + 1; if (!done) { this.currentRequestInExecution = requestId; @@ -150,11 +168,6 @@ class Runner { }; } run() { - try { - this.validate(); - } catch (e) { - throw e; - } this.prepareRequestExecutionOrder(); setTimeout(async () => { const { collection } = this.collection; @@ -163,7 +176,10 @@ class Runner { name: collection.name, id: collection.__ref.id }); - await this.start(); + for (let i = 0; i < this.options.iterationCount; i++) { + await this.start(); + console.log(i, "----"); + } this.result.duration = (/* @__PURE__ */ new Date()).valueOf() - startTs; this.emitter.emit("done" /* Done */, { result: { diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index 373ed47f5..55585c6c1 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -56,7 +56,7 @@ export default class Runner { } private assignDefaultOptions() { - if (!this.options.hasOwnProperty('iterationCount')) this.options.iterationCount = 1; + if (!this.options.hasOwnProperty('iterationCount')) this.options.iterationCount = 2; if (!this.options.hasOwnProperty('delayRequest')) this.options.delayRequest = 0; if (!this.options.hasOwnProperty('timeout')) this.options.timeout = 0; if (!this.options.hasOwnProperty('timeoutRequest')) this.options.timeoutRequest = 0; @@ -143,7 +143,7 @@ export default class Runner { id: request.__ref.id }); - await delay(500); + await delay(this.options.delayRequest); const response = await this.options.executeRequest(request); this.updateResult(response) /** emit 'request' event on request execution completion */ @@ -151,16 +151,14 @@ export default class Runner { id: request.__ref.id, response }); - return { request, response }; } i = 0; private async start() { - try { const { value: requestId, done } = this.requestOrdersForExecution.values().next(); - if (this.i > 0) return + // if (this.i > 0) return this.i = this.i + 1 if (!done) { this.currentRequestInExecution = requestId; @@ -203,7 +201,10 @@ export default class Runner { id: collection.__ref.id }); - await this.start(); + for (let i = 0; i < this.options.iterationCount; i++) { + await this.start(); + console.log(i, '----') + } /** emit 'done' event once runner iterations are completed */ this.result.duration = new Date().valueOf() - startTs; From dd68a8b4955b010cbd51cbf48b473c3e1ad83479 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Mon, 19 Jun 2023 09:29:27 +0530 Subject: [PATCH 10/22] feat: get folder sequence method added --- .../firecamp-cli/src/commands/collection/run.ts | 5 +++-- .../firecamp-collection-runner/dist/index.cjs | 9 +++++++++ .../firecamp-collection-runner/dist/index.d.ts | 1 + packages/firecamp-collection-runner/dist/index.js | 9 +++++++++ packages/firecamp-collection-runner/src/index.ts | 15 +++++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/firecamp-cli/src/commands/collection/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts index 0e1cb8172..43111ff45 100644 --- a/packages/firecamp-cli/src/commands/collection/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -55,8 +55,9 @@ export default class Run extends Command { }) - const emitter = runner.run() - new CliReporter(emitter); + const emitter = runner.getFolderIds() + console.log(emitter) + // new CliReporter(emitter); }) .then(testResults => { // console.log(testResults) diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index 7a2dba51f..156b830a9 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -82,6 +82,15 @@ class Runner { throw new Error("The collection's request items format is invalid"); return true; } + getFolderIds() { + const { collection, folders } = this.collection; + console.log(folders.length); + const folderMap = new Map(folders.map((folder) => [folder.__ref.id, folder])); + const traverseFolders = (order) => order.flatMap( + (folderId) => folderMap.has(folderId) ? [folderId, ...traverseFolders([folderMap.get(folderId).__ref.folderId])] : [] + ); + return traverseFolders(collection.__meta.fOrders); + } /** * prepare an Set of request execution order */ diff --git a/packages/firecamp-collection-runner/dist/index.d.ts b/packages/firecamp-collection-runner/dist/index.d.ts index 2249222e2..6d4e851f0 100644 --- a/packages/firecamp-collection-runner/dist/index.d.ts +++ b/packages/firecamp-collection-runner/dist/index.d.ts @@ -35,6 +35,7 @@ declare class Runner { * @returns boolean */ private validate; + getFolderIds(): any; /** * prepare an Set of request execution order */ diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index 505122bae..59be826c9 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -82,6 +82,15 @@ class Runner { throw new Error("The collection's request items format is invalid"); return true; } + getFolderIds() { + const { collection, folders } = this.collection; + console.log(folders.length); + const folderMap = new Map(folders.map((folder) => [folder.__ref.id, folder])); + const traverseFolders = (order) => order.flatMap( + (folderId) => folderMap.has(folderId) ? [folderId, ...traverseFolders([folderMap.get(folderId).__ref.folderId])] : [] + ); + return traverseFolders(collection.__meta.fOrders); + } /** * prepare an Set of request execution order */ diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index 55585c6c1..3af28dfc7 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -89,6 +89,21 @@ export default class Runner { return true; } + getFolderIds() { + const { collection, folders } = this.collection + console.log(folders.length) + const folderMap = new Map(folders.map(folder => [folder.__ref.id, folder])); + const traverseFolders = (order) => + order.flatMap(folderId => + folderMap.has(folderId) + //@ts-ignore + ? [folderId, ...traverseFolders([folderMap.get(folderId).__ref.folderId])] + : [] + ); + return traverseFolders(collection.__meta.fOrders); + } + + /** * prepare an Set of request execution order */ From 1e258eb3d8697efb6e74958246ae51d31cb5a423 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Mon, 19 Jun 2023 13:15:53 +0530 Subject: [PATCH 11/22] feat: iteration wise run implemeted and folder vise iteration logic implemented runner optimised with folder and iteration vise run new events are introduced for runner. beforeIteration, iteration, beforeFolder, folder cli reporter ui changes base on new runner events --- .../src/commands/collection/run.ts | 6 +- packages/firecamp-cli/src/reporters/cli.ts | 37 ++++- .../firecamp-collection-runner/dist/index.cjs | 119 ++++++++------- .../dist/index.d.ts | 22 ++- .../firecamp-collection-runner/dist/index.js | 119 ++++++++------- .../firecamp-collection-runner/src/index.ts | 137 +++++++++--------- 6 files changed, 224 insertions(+), 216 deletions(-) diff --git a/packages/firecamp-cli/src/commands/collection/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts index 43111ff45..1092db458 100644 --- a/packages/firecamp-cli/src/commands/collection/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -55,9 +55,9 @@ export default class Run extends Command { }) - const emitter = runner.getFolderIds() - console.log(emitter) - // new CliReporter(emitter); + const emitter = runner.run() + // console.log(emitter) + new CliReporter(emitter); }) .then(testResults => { // console.log(testResults) diff --git a/packages/firecamp-cli/src/reporters/cli.ts b/packages/firecamp-cli/src/reporters/cli.ts index 3ac19309a..586008d08 100644 --- a/packages/firecamp-cli/src/reporters/cli.ts +++ b/packages/firecamp-cli/src/reporters/cli.ts @@ -13,7 +13,25 @@ export default class Reporter { constructor(emitter: any) { this.spinner = ora(); emitter - .on(ERunnerEvents.Start, () => { }) + .on(ERunnerEvents.Start, (col: any) => { + this.log(figures.squareCenter, c.bold(col.name)) + this.newLine(); + }) + .on(ERunnerEvents.BeforeIteration, (it: any) => { + if (it.total > 1) { + this.log(c.gray().dim(`Iteration ${it.current}`)); + this.newLine(); + } + }) + .on(ERunnerEvents.Iteration, () => { + this.newLine(); + }) + .on(ERunnerEvents.BeforeFolder, (folder: any) => { + this.log(figures.triangleRight, c.bold(folder.name)); + }) + .on(ERunnerEvents.Folder, (folder: any) => { + this.newLine(); + }) .on(ERunnerEvents.BeforeRequest, (request: any) => { this.onBeforeRequest(request) }) @@ -26,7 +44,7 @@ export default class Reporter { } initSpinner() { this.spinner = ora() - this.newLine(); + // this.newLine(); } onBeforeRequest(request: any) { @@ -51,16 +69,18 @@ export default class Reporter { }) // console.log(testResult) } + this.newLine(); } onDone(result: any) { + this.newLine(); this.logResult(result) } newLine(n: number = 1) { if (n > 10) n = 5 if (n < 0) n = 1; - Array.from({ length: n }).forEach(() => console.log('')) + Array.from({ length: n }).forEach(() => this.log('')) } _title() { @@ -87,10 +107,10 @@ export default class Reporter { const log = !failed ? `${c.green(' ' + figures.tick)} ${c.gray(name)}` : `${c.red(' ' + figures.cross)} ${c.gray(name)}` - console.log(log) + this.log(log) if (error) - console.log(` `, c.italic().gray().dim(error.message)) + this.log(` `, c.italic().gray().dim(error.message)) // throw new Error(error) } @@ -112,7 +132,6 @@ export default class Reporter { }); - this.newLine(); table.push( [c.dim('Total Requests'), 28], [c.dim('Total run duration'), prettyMs(duration)], @@ -121,7 +140,11 @@ export default class Reporter { [c.red('Fail Tests'), fail] ); - console.log(table.toString()); + this.log(table.toString()); + } + + log(...l: any[]) { + console.log(...l) } } diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index 156b830a9..c68de2055 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -16,6 +16,10 @@ var ERunnerEvents = /* @__PURE__ */ ((ERunnerEvents2) => { ERunnerEvents2["Start"] = "start"; ERunnerEvents2["BeforeRequest"] = "beforeRequest"; ERunnerEvents2["Request"] = "request"; + ERunnerEvents2["BeforeFolder"] = "beforeFolder"; + ERunnerEvents2["Folder"] = "folder"; + ERunnerEvents2["BeforeIteration"] = "beforeIteration"; + ERunnerEvents2["Iteration"] = "iteration"; ERunnerEvents2["Done"] = "done"; return ERunnerEvents2; })(ERunnerEvents || {}); @@ -23,9 +27,7 @@ class Runner { constructor(collection, options) { __publicField(this, "collection"); __publicField(this, "options"); - __publicField(this, "requestOrdersForExecution"); - __publicField(this, "executedRequestQueue"); - __publicField(this, "currentRequestInExecution"); + __publicField(this, "folderRunSequence"); __publicField(this, "testResults", []); __publicField(this, "emitter"); __publicField(this, "result", { @@ -35,19 +37,17 @@ class Runner { skip: 0, duration: 0 }); - __publicField(this, "i", 0); this.collection = collection; this.options = options; - this.requestOrdersForExecution = /* @__PURE__ */ new Set(); - this.executedRequestQueue = /* @__PURE__ */ new Set(); - this.currentRequestInExecution = ""; + this.folderRunSequence = /* @__PURE__ */ new Set(); this.emitter = new (0, _eventemitter32.default)(); this.validate(); this.assignDefaultOptions(); + this.prepareFolderRunSequence(); } assignDefaultOptions() { if (!this.options.hasOwnProperty("iterationCount")) - this.options.iterationCount = 2; + this.options.iterationCount = 1; if (!this.options.hasOwnProperty("delayRequest")) this.options.delayRequest = 0; if (!this.options.hasOwnProperty("timeout")) @@ -82,43 +82,14 @@ class Runner { throw new Error("The collection's request items format is invalid"); return true; } - getFolderIds() { + prepareFolderRunSequence() { const { collection, folders } = this.collection; - console.log(folders.length); const folderMap = new Map(folders.map((folder) => [folder.__ref.id, folder])); const traverseFolders = (order) => order.flatMap( (folderId) => folderMap.has(folderId) ? [folderId, ...traverseFolders([folderMap.get(folderId).__ref.folderId])] : [] ); - return traverseFolders(collection.__meta.fOrders); - } - /** - * prepare an Set of request execution order - */ - prepareRequestExecutionOrder() { - const { collection, folders } = this.collection; - const { __meta: { fOrders: rootFolderIds = [], rOrders: rootRequestIds = [] } } = collection; - const extractRequestIdsFromFolder = (fId, requestIds = []) => { - const folder = folders.find((f) => f.__ref.id == fId); - if (!folder) - return requestIds; - if (_optionalChain([folder, 'access', _2 => _2.__meta, 'access', _3 => _3.fOrders, 'optionalAccess', _4 => _4.length])) { - const rIds = folder.__meta.fOrders.map((fId2) => extractRequestIdsFromFolder(fId2, requestIds)); - requestIds = [...requestIds, ...rIds]; - } - if (_optionalChain([folder, 'access', _5 => _5.__meta, 'access', _6 => _6.rOrders, 'optionalAccess', _7 => _7.length])) { - requestIds = [...requestIds, ...folder.__meta.rOrders]; - } - return requestIds; - }; - if (Array.isArray(rootFolderIds)) { - rootFolderIds.map((fId) => { - const requestIds = extractRequestIdsFromFolder(fId); - requestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); - }); - } - if (Array.isArray(rootRequestIds)) { - rootRequestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); - } + const ids = traverseFolders(collection.__meta.fOrders); + ids.forEach(this.folderRunSequence.add, this.folderRunSequence); } updateResult(response = {}) { const { testResult: { total, passed, failed } = { @@ -133,7 +104,7 @@ class Runner { if (Number.isInteger(failed)) this.result.fail += failed; } - async executeRequest(requestId) { + async runRequest(requestId) { const { folders, requests } = this.collection; const request = requests.find((r) => r.__ref.id == requestId); this.emitter.emit("beforeRequest" /* BeforeRequest */, { @@ -152,32 +123,41 @@ class Runner { }); return { request, response }; } - async start() { + async runFolder(folderId) { + const folder = this.collection.folders.find((f) => f.__ref.id == folderId); + this.emitter.emit("beforeFolder" /* BeforeFolder */, { + name: folder.name, + id: folder.__ref.id + }); try { - const { value: requestId, done } = this.requestOrdersForExecution.values().next(); - this.i = this.i + 1; - if (!done) { - this.currentRequestInExecution = requestId; - const res = await this.executeRequest(requestId); + const requestIds = folder.__meta.rOrders || []; + for (let i = 0; i < requestIds.length; i++) { + const res = await this.runRequest(requestIds[i]); this.testResults.push(res); - this.executedRequestQueue.add(requestId); - this.requestOrdersForExecution.delete(requestId); - await this.start(); } - } catch (error) { - console.error(`Error while running the collection:`, error); + } catch (e) { + console.error(`Error while running the collection:`, e); } + this.emitter.emit("folder" /* Folder */, { + id: folder.__ref.id + }); } - exposeOnlyOn() { - return { - on: (evt, fn) => { - this.emitter.on(evt, fn); - return this.exposeOnlyOn(); - } - }; + async runIteration() { + try { + const folderSet = this.folderRunSequence.values(); + const next = async () => { + const { value: folderId, done } = folderSet.next(); + if (!done) { + await this.runFolder(folderId); + await next(); + } + }; + await next(); + } catch (e) { + console.error(`Error while running the collection:`, e); + } } run() { - this.prepareRequestExecutionOrder(); setTimeout(async () => { const { collection } = this.collection; const startTs = (/* @__PURE__ */ new Date()).valueOf(); @@ -186,8 +166,15 @@ class Runner { id: collection.__ref.id }); for (let i = 0; i < this.options.iterationCount; i++) { - await this.start(); - console.log(i, "----"); + this.emitter.emit("beforeIteration" /* BeforeIteration */, { + current: i + 1, + total: this.options.iterationCount + }); + await this.runIteration(); + this.emitter.emit("iteration" /* Iteration */, { + current: i + 1, + total: this.options.iterationCount + }); } this.result.duration = (/* @__PURE__ */ new Date()).valueOf() - startTs; this.emitter.emit("done" /* Done */, { @@ -198,6 +185,14 @@ class Runner { }); return this.exposeOnlyOn(); } + exposeOnlyOn() { + return { + on: (evt, fn) => { + this.emitter.on(evt, fn); + return this.exposeOnlyOn(); + } + }; + } } const fetchRequestPath = (folders, request) => { const requestPath = []; diff --git a/packages/firecamp-collection-runner/dist/index.d.ts b/packages/firecamp-collection-runner/dist/index.d.ts index 6d4e851f0..676457641 100644 --- a/packages/firecamp-collection-runner/dist/index.d.ts +++ b/packages/firecamp-collection-runner/dist/index.d.ts @@ -4,6 +4,10 @@ declare enum ERunnerEvents { Start = "start", BeforeRequest = "beforeRequest", Request = "request", + BeforeFolder = "beforeFolder", + Folder = "folder", + BeforeIteration = "beforeIteration", + Iteration = "iteration", Done = "done" } interface IRunnerOptions { @@ -19,9 +23,7 @@ interface IRunnerOptions { declare class Runner { private collection; private options; - private requestOrdersForExecution; - private executedRequestQueue; - private currentRequestInExecution; + private folderRunSequence; private testResults; private emitter; private result; @@ -35,19 +37,15 @@ declare class Runner { * @returns boolean */ private validate; - getFolderIds(): any; - /** - * prepare an Set of request execution order - */ - private prepareRequestExecutionOrder; + private prepareFolderRunSequence; private updateResult; - private executeRequest; - i: number; - private start; - private exposeOnlyOn; + private runRequest; + private runFolder; + private runIteration; run(): { on: (evt: string, fn: (...a: any[]) => void) => any; }; + private exposeOnlyOn; } export { ERunnerEvents, Runner as default }; diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index 59be826c9..9718d7413 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -16,6 +16,10 @@ var ERunnerEvents = /* @__PURE__ */ ((ERunnerEvents2) => { ERunnerEvents2["Start"] = "start"; ERunnerEvents2["BeforeRequest"] = "beforeRequest"; ERunnerEvents2["Request"] = "request"; + ERunnerEvents2["BeforeFolder"] = "beforeFolder"; + ERunnerEvents2["Folder"] = "folder"; + ERunnerEvents2["BeforeIteration"] = "beforeIteration"; + ERunnerEvents2["Iteration"] = "iteration"; ERunnerEvents2["Done"] = "done"; return ERunnerEvents2; })(ERunnerEvents || {}); @@ -23,9 +27,7 @@ class Runner { constructor(collection, options) { __publicField(this, "collection"); __publicField(this, "options"); - __publicField(this, "requestOrdersForExecution"); - __publicField(this, "executedRequestQueue"); - __publicField(this, "currentRequestInExecution"); + __publicField(this, "folderRunSequence"); __publicField(this, "testResults", []); __publicField(this, "emitter"); __publicField(this, "result", { @@ -35,19 +37,17 @@ class Runner { skip: 0, duration: 0 }); - __publicField(this, "i", 0); this.collection = collection; this.options = options; - this.requestOrdersForExecution = /* @__PURE__ */ new Set(); - this.executedRequestQueue = /* @__PURE__ */ new Set(); - this.currentRequestInExecution = ""; + this.folderRunSequence = /* @__PURE__ */ new Set(); this.emitter = new EventEmitter(); this.validate(); this.assignDefaultOptions(); + this.prepareFolderRunSequence(); } assignDefaultOptions() { if (!this.options.hasOwnProperty("iterationCount")) - this.options.iterationCount = 2; + this.options.iterationCount = 1; if (!this.options.hasOwnProperty("delayRequest")) this.options.delayRequest = 0; if (!this.options.hasOwnProperty("timeout")) @@ -82,43 +82,14 @@ class Runner { throw new Error("The collection's request items format is invalid"); return true; } - getFolderIds() { + prepareFolderRunSequence() { const { collection, folders } = this.collection; - console.log(folders.length); const folderMap = new Map(folders.map((folder) => [folder.__ref.id, folder])); const traverseFolders = (order) => order.flatMap( (folderId) => folderMap.has(folderId) ? [folderId, ...traverseFolders([folderMap.get(folderId).__ref.folderId])] : [] ); - return traverseFolders(collection.__meta.fOrders); - } - /** - * prepare an Set of request execution order - */ - prepareRequestExecutionOrder() { - const { collection, folders } = this.collection; - const { __meta: { fOrders: rootFolderIds = [], rOrders: rootRequestIds = [] } } = collection; - const extractRequestIdsFromFolder = (fId, requestIds = []) => { - const folder = folders.find((f) => f.__ref.id == fId); - if (!folder) - return requestIds; - if (folder.__meta.fOrders?.length) { - const rIds = folder.__meta.fOrders.map((fId2) => extractRequestIdsFromFolder(fId2, requestIds)); - requestIds = [...requestIds, ...rIds]; - } - if (folder.__meta.rOrders?.length) { - requestIds = [...requestIds, ...folder.__meta.rOrders]; - } - return requestIds; - }; - if (Array.isArray(rootFolderIds)) { - rootFolderIds.map((fId) => { - const requestIds = extractRequestIdsFromFolder(fId); - requestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); - }); - } - if (Array.isArray(rootRequestIds)) { - rootRequestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); - } + const ids = traverseFolders(collection.__meta.fOrders); + ids.forEach(this.folderRunSequence.add, this.folderRunSequence); } updateResult(response = {}) { const { testResult: { total, passed, failed } = { @@ -133,7 +104,7 @@ class Runner { if (Number.isInteger(failed)) this.result.fail += failed; } - async executeRequest(requestId) { + async runRequest(requestId) { const { folders, requests } = this.collection; const request = requests.find((r) => r.__ref.id == requestId); this.emitter.emit("beforeRequest" /* BeforeRequest */, { @@ -152,32 +123,41 @@ class Runner { }); return { request, response }; } - async start() { + async runFolder(folderId) { + const folder = this.collection.folders.find((f) => f.__ref.id == folderId); + this.emitter.emit("beforeFolder" /* BeforeFolder */, { + name: folder.name, + id: folder.__ref.id + }); try { - const { value: requestId, done } = this.requestOrdersForExecution.values().next(); - this.i = this.i + 1; - if (!done) { - this.currentRequestInExecution = requestId; - const res = await this.executeRequest(requestId); + const requestIds = folder.__meta.rOrders || []; + for (let i = 0; i < requestIds.length; i++) { + const res = await this.runRequest(requestIds[i]); this.testResults.push(res); - this.executedRequestQueue.add(requestId); - this.requestOrdersForExecution.delete(requestId); - await this.start(); } - } catch (error) { - console.error(`Error while running the collection:`, error); + } catch (e) { + console.error(`Error while running the collection:`, e); } + this.emitter.emit("folder" /* Folder */, { + id: folder.__ref.id + }); } - exposeOnlyOn() { - return { - on: (evt, fn) => { - this.emitter.on(evt, fn); - return this.exposeOnlyOn(); - } - }; + async runIteration() { + try { + const folderSet = this.folderRunSequence.values(); + const next = async () => { + const { value: folderId, done } = folderSet.next(); + if (!done) { + await this.runFolder(folderId); + await next(); + } + }; + await next(); + } catch (e) { + console.error(`Error while running the collection:`, e); + } } run() { - this.prepareRequestExecutionOrder(); setTimeout(async () => { const { collection } = this.collection; const startTs = (/* @__PURE__ */ new Date()).valueOf(); @@ -186,8 +166,15 @@ class Runner { id: collection.__ref.id }); for (let i = 0; i < this.options.iterationCount; i++) { - await this.start(); - console.log(i, "----"); + this.emitter.emit("beforeIteration" /* BeforeIteration */, { + current: i + 1, + total: this.options.iterationCount + }); + await this.runIteration(); + this.emitter.emit("iteration" /* Iteration */, { + current: i + 1, + total: this.options.iterationCount + }); } this.result.duration = (/* @__PURE__ */ new Date()).valueOf() - startTs; this.emitter.emit("done" /* Done */, { @@ -198,6 +185,14 @@ class Runner { }); return this.exposeOnlyOn(); } + exposeOnlyOn() { + return { + on: (evt, fn) => { + this.emitter.on(evt, fn); + return this.exposeOnlyOn(); + } + }; + } } const fetchRequestPath = (folders, request) => { const requestPath = []; diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index 3af28dfc7..86c1836e4 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -13,6 +13,10 @@ export enum ERunnerEvents { Start = 'start', BeforeRequest = 'beforeRequest', Request = 'request', + BeforeFolder = 'beforeFolder', + Folder = 'folder', + BeforeIteration = 'beforeIteration', + Iteration = 'iteration', Done = 'done' } @@ -31,9 +35,7 @@ export default class Runner { private collection: any; private options: IRunnerOptions; - private requestOrdersForExecution: Set; - private executedRequestQueue: Set; - private currentRequestInExecution: TId; + private folderRunSequence: Set; private testResults: any = []; private emitter: EventEmitter; private result = { @@ -47,16 +49,15 @@ export default class Runner { constructor(collection, options: IRunnerOptions) { this.collection = collection; this.options = options; - this.requestOrdersForExecution = new Set(); - this.executedRequestQueue = new Set(); - this.currentRequestInExecution = ''; + this.folderRunSequence = new Set(); this.emitter = new EventEmitter(); this.validate(); this.assignDefaultOptions(); + this.prepareFolderRunSequence(); } private assignDefaultOptions() { - if (!this.options.hasOwnProperty('iterationCount')) this.options.iterationCount = 2; + if (!this.options.hasOwnProperty('iterationCount')) this.options.iterationCount = 1; if (!this.options.hasOwnProperty('delayRequest')) this.options.delayRequest = 0; if (!this.options.hasOwnProperty('timeout')) this.options.timeout = 0; if (!this.options.hasOwnProperty('timeoutRequest')) this.options.timeoutRequest = 0; @@ -89,9 +90,8 @@ export default class Runner { return true; } - getFolderIds() { + private prepareFolderRunSequence() { const { collection, folders } = this.collection - console.log(folders.length) const folderMap = new Map(folders.map(folder => [folder.__ref.id, folder])); const traverseFolders = (order) => order.flatMap(folderId => @@ -100,40 +100,8 @@ export default class Runner { ? [folderId, ...traverseFolders([folderMap.get(folderId).__ref.folderId])] : [] ); - return traverseFolders(collection.__meta.fOrders); - } - - - /** - * prepare an Set of request execution order - */ - private prepareRequestExecutionOrder() { - const { collection, folders } = this.collection - const { __meta: { fOrders: rootFolderIds = [], rOrders: rootRequestIds = [] } } = collection - - const extractRequestIdsFromFolder = (fId: TId, requestIds: TId[] = []) => { - const folder = folders.find(f => f.__ref.id == fId); - if (!folder) return requestIds; - if (folder.__meta.fOrders?.length) { - const rIds = folder.__meta.fOrders.map(fId => extractRequestIdsFromFolder(fId, requestIds)) - requestIds = [...requestIds, ...rIds] - } - if (folder.__meta.rOrders?.length) { - requestIds = [...requestIds, ...folder.__meta.rOrders] - } - return requestIds; - } - - if (Array.isArray(rootFolderIds)) { - rootFolderIds.map(fId => { - const requestIds = extractRequestIdsFromFolder(fId) - // console.log(requestIds, fId) - requestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); - }); - } - if (Array.isArray(rootRequestIds)) { - rootRequestIds.forEach(this.requestOrdersForExecution.add, this.requestOrdersForExecution); - } + const ids = traverseFolders(collection.__meta.fOrders); + ids.forEach(this.folderRunSequence.add, this.folderRunSequence); } private updateResult(response: any = {}) { @@ -145,7 +113,7 @@ export default class Runner { if (Number.isInteger(failed)) this.result.fail += failed; } - private async executeRequest(requestId: TId) { + private async runRequest(requestId: TId) { const { folders, requests } = this.collection; const request = requests.find(r => r.__ref.id == requestId); @@ -169,46 +137,56 @@ export default class Runner { return { request, response }; } - i = 0; - private async start() { + private async runFolder(folderId: TId) { + const folder = this.collection.folders.find(f => f.__ref.id == folderId); + + /** emit 'beforeFolder' event just before folder execution start */ + this.emitter.emit(ERunnerEvents.BeforeFolder, { + name: folder.name, + id: folder.__ref.id + }); + try { - const { value: requestId, done } = this.requestOrdersForExecution.values().next(); - // if (this.i > 0) return - this.i = this.i + 1 - if (!done) { - this.currentRequestInExecution = requestId; - const res = await this.executeRequest(requestId); + const requestIds = folder.__meta.rOrders || []; + for (let i = 0; i < requestIds.length; i++) { + const res = await this.runRequest(requestIds[i]); this.testResults.push(res); - this.executedRequestQueue.add(requestId); - this.requestOrdersForExecution.delete(requestId); - await this.start(); } - } - catch (error) { - console.error(`Error while running the collection:`, error); - // await this.start(); // Retry fetching info for the remaining IDs even if an error occurred + catch (e) { + console.error(`Error while running the collection:`, e); + // await this.runIteration(); // Retry fetching info for the remaining IDs even if an error occurred } + /** emit 'folder' event on folder run completion */ + this.emitter.emit(ERunnerEvents.Folder, { + id: folder.__ref.id + }); } - private exposeOnlyOn() { - return { - on: (evt: string, fn: (...a) => void) => { - this.emitter.on(evt, fn) - return this.exposeOnlyOn() + private async runIteration() { + + try { + const folderSet = this.folderRunSequence.values(); + const next = async () => { + const { value: folderId, done } = folderSet.next(); + if (!done) { + await this.runFolder(folderId); + await next(); + } } + await next(); + } + catch (e) { + console.error(`Error while running the collection:`, e); } } run() { - this.prepareRequestExecutionOrder(); - setTimeout(async () => { const { collection } = this.collection; - const startTs: number = new Date().valueOf(); /** emit 'start' event on runner start */ this.emitter.emit(ERunnerEvents.Start, { @@ -217,8 +195,19 @@ export default class Runner { }); for (let i = 0; i < this.options.iterationCount; i++) { - await this.start(); - console.log(i, '----') + /** emit 'beforeIteration' event just before iteration start */ + this.emitter.emit(ERunnerEvents.BeforeIteration, { + current: i + 1, + total: this.options.iterationCount + }); + + await this.runIteration(); + + /** emit 'iteration' event just after the iteration complete */ + this.emitter.emit(ERunnerEvents.Iteration, { + current: i + 1, + total: this.options.iterationCount + }); } /** emit 'done' event once runner iterations are completed */ @@ -230,9 +219,17 @@ export default class Runner { }); }); - // return this.testResults; return this.exposeOnlyOn() } + + private exposeOnlyOn() { + return { + on: (evt: string, fn: (...a) => void) => { + this.emitter.on(evt, fn) + return this.exposeOnlyOn() + } + } + } } From 3f684b081b9493c2fae323a4f0dc57f747cb1727 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Mon, 19 Jun 2023 13:26:36 +0530 Subject: [PATCH 12/22] chore: comments removed --- packages/firecamp-cli/src/commands/collection/run.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/firecamp-cli/src/commands/collection/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts index 1092db458..168357426 100644 --- a/packages/firecamp-cli/src/commands/collection/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -39,10 +39,6 @@ export default class Run extends Command { } this.log(c.gray(figlet.textSync("Firecamp"))) - - // tasks.run() - // return - const _filepath = new URL(`../../../${file}`, import.meta.url).pathname loadJsonFile(_filepath) .then(collection => { @@ -54,7 +50,6 @@ export default class Run extends Command { } }) - const emitter = runner.run() // console.log(emitter) new CliReporter(emitter); From 4097c03fd6773eb4fbf0b255e71575b2471f3066 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Mon, 19 Jun 2023 16:24:52 +0530 Subject: [PATCH 13/22] feat: cli options are imeplemented with metadata and description --- .../src/commands/collection/run.ts | 46 +++++++++++-------- packages/firecamp-cli/src/reporters/cli.ts | 2 +- .../firecamp-collection-runner/src/index.ts | 2 +- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/packages/firecamp-cli/src/commands/collection/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts index 168357426..1f9eef7ac 100644 --- a/packages/firecamp-cli/src/commands/collection/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -3,7 +3,7 @@ import { loadJsonFile } from 'load-json-file'; import c from 'kleur'; import figlet from 'figlet' //@ts-ignore https://github.com/egoist/tsup/issues/760 -import Runner, { ERunnerEvents } from '@firecamp/collection-runner' +import Runner, { ERunnerEvents, IRunnerOptions } from '@firecamp/collection-runner' import _RestExecutor from '@firecamp/rest-executor'; //@ts-ignore //TODO: rest-executor is commonjs lib while runner is esm. we'll move all lib in esm in future const RestExecutor = _RestExecutor.default @@ -16,48 +16,58 @@ export default class Run extends Command { static description = 'Run Firecamp Collection' static examples = [ - '<%= config.bin %> <%= command.id %>', + '<%= config.bin %> <%= command.id %> ./echo.firecamp_collection.json', ] static flags = { - // flag with a value (-n, --name=VALUE) - // name: Flags.string({ char: 'n', description: 'name to print' }), - // flag with no value (-f, --force) - // force: Flags.boolean({ char: 'f' }), + 'iteration-count': Flags.string({ char: 'n', description: 'Set the number of iterations for the collection run' }), + 'iteration-data': Flags.string({ char: 'd', description: 'Provide the data file to be used for iterations. (should be JSON or CSV) file to use for iterations JSON or CSV' }), + // 'delay-request': Flags.integer({ description: 'Set the extent of delay between requests in milliseconds (default: 0)' }), + // timeout: Flags.integer({ description: 'Set a timeout for collection run in milliseconds (default: 0)' }), + // 'timeout-request': Flags.integer({ description: 'Set a timeout for requests in milliseconds (default: 0)' }), } static args = { - file: Args.string({ description: 'firecamp collection path' }), + path: Args.string({ description: 'provide the collection path' }), } public async run(): Promise { - const { args } = await this.parse(Run) - const { file } = args - if (!file) { + const { args, flags } = await this.parse(Run) + const { path } = args + if (!path) { this.logToStderr('error: The collection path is missing') return } + const { + "iteration-count": iterationCount, + "iteration-data": iterationData, + timeout, + "delay-request": delayRequest, + "timeout-request": timeoutRequest, + } = flags; + this.log(c.gray(figlet.textSync("Firecamp"))) - const _filepath = new URL(`../../../${file}`, import.meta.url).pathname + const _filepath = new URL(`../../../${path}`, import.meta.url).pathname loadJsonFile(_filepath) .then(collection => { // this.logJson(collection); - const runner = new Runner(collection, { + const options: IRunnerOptions = { executeRequest: (request: any) => { const executor = new RestExecutor(); return executor.send(request, { collectionVariables: [], environment: [], globals: [] }); } - }) + } + if (iterationCount) options.iterationCount = +iterationCount; + if (iterationData) options.iterationData = iterationData; + if (timeout) options.timeout = +timeout; + if (delayRequest) options.delayRequest = +delayRequest; + if (timeoutRequest) options.timeoutRequest = +timeoutRequest; + const runner = new Runner(collection, options); const emitter = runner.run() - // console.log(emitter) new CliReporter(emitter); }) - .then(testResults => { - // console.log(testResults) - // this.logJson(testResults) - }) .catch(e => { console.error(e) if (e.code == 'ENOENT') this.logToStderr(`error: file not exist at ${_filepath}`) diff --git a/packages/firecamp-cli/src/reporters/cli.ts b/packages/firecamp-cli/src/reporters/cli.ts index 586008d08..98bea24ea 100644 --- a/packages/firecamp-cli/src/reporters/cli.ts +++ b/packages/firecamp-cli/src/reporters/cli.ts @@ -19,7 +19,7 @@ export default class Reporter { }) .on(ERunnerEvents.BeforeIteration, (it: any) => { if (it.total > 1) { - this.log(c.gray().dim(`Iteration ${it.current}`)); + this.log(c.gray().dim().underline(`Iteration ${it.current}/${it.total}`)); this.newLine(); } }) diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index 86c1836e4..fda28082c 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -20,7 +20,7 @@ export enum ERunnerEvents { Done = 'done' } -interface IRunnerOptions { +export interface IRunnerOptions { executeRequest: (request: any) => Promise; environment?: TId | string; globals?: TId | string; From 89e8c7d237a0b6b79a5012d758cb6145faccce34 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Mon, 19 Jun 2023 17:05:35 +0530 Subject: [PATCH 14/22] chore: small fixes --- .../src/commands/collection/run.ts | 4 +-- .../firecamp-collection-runner/dist/index.cjs | 26 +++++++++++++++- .../dist/index.d.ts | 3 +- .../firecamp-collection-runner/dist/index.js | 26 +++++++++++++++- .../firecamp-collection-runner/src/index.ts | 30 ++++++++++++++++++- 5 files changed, 83 insertions(+), 6 deletions(-) diff --git a/packages/firecamp-cli/src/commands/collection/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts index 1f9eef7ac..78f7bcd8e 100644 --- a/packages/firecamp-cli/src/commands/collection/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -21,8 +21,8 @@ export default class Run extends Command { static flags = { 'iteration-count': Flags.string({ char: 'n', description: 'Set the number of iterations for the collection run' }), - 'iteration-data': Flags.string({ char: 'd', description: 'Provide the data file to be used for iterations. (should be JSON or CSV) file to use for iterations JSON or CSV' }), - // 'delay-request': Flags.integer({ description: 'Set the extent of delay between requests in milliseconds (default: 0)' }), + // 'iteration-data': Flags.string({ char: 'd', description: 'Provide the data file to be used for iterations. (should be JSON or CSV) file to use for iterations JSON or CSV' }), + 'delay-request': Flags.integer({ description: 'Set the extent of delay between requests in milliseconds (default: 0)' }), // timeout: Flags.integer({ description: 'Set a timeout for collection run in milliseconds (default: 0)' }), // 'timeout-request': Flags.integer({ description: 'Set a timeout for requests in milliseconds (default: 0)' }), } diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index c68de2055..60ab1b98a 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -125,12 +125,14 @@ class Runner { } async runFolder(folderId) { const folder = this.collection.folders.find((f) => f.__ref.id == folderId); + const requestIds = folder.__meta.rOrders || []; + if (!requestIds.length) + return; this.emitter.emit("beforeFolder" /* BeforeFolder */, { name: folder.name, id: folder.__ref.id }); try { - const requestIds = folder.__meta.rOrders || []; for (let i = 0; i < requestIds.length; i++) { const res = await this.runRequest(requestIds[i]); this.testResults.push(res); @@ -142,6 +144,27 @@ class Runner { id: folder.__ref.id }); } + async runRootRequests() { + const { collection } = this.collection; + const requestIds = collection.__meta.rOrders || []; + if (!requestIds.length) + return; + this.emitter.emit("beforeFolder" /* BeforeFolder */, { + name: "./", + id: collection.__ref.id + }); + try { + for (let i = 0; i < requestIds.length; i++) { + const res = await this.runRequest(requestIds[i]); + this.testResults.push(res); + } + } catch (e) { + console.error(`Error while running the collection:`, e); + } + this.emitter.emit("folder" /* Folder */, { + id: collection.__ref.id + }); + } async runIteration() { try { const folderSet = this.folderRunSequence.values(); @@ -153,6 +176,7 @@ class Runner { } }; await next(); + await this.runRootRequests(); } catch (e) { console.error(`Error while running the collection:`, e); } diff --git a/packages/firecamp-collection-runner/dist/index.d.ts b/packages/firecamp-collection-runner/dist/index.d.ts index 676457641..33f45b223 100644 --- a/packages/firecamp-collection-runner/dist/index.d.ts +++ b/packages/firecamp-collection-runner/dist/index.d.ts @@ -41,6 +41,7 @@ declare class Runner { private updateResult; private runRequest; private runFolder; + private runRootRequests; private runIteration; run(): { on: (evt: string, fn: (...a: any[]) => void) => any; @@ -48,4 +49,4 @@ declare class Runner { private exposeOnlyOn; } -export { ERunnerEvents, Runner as default }; +export { ERunnerEvents, IRunnerOptions, Runner as default }; diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index 9718d7413..725f109d4 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -125,12 +125,14 @@ class Runner { } async runFolder(folderId) { const folder = this.collection.folders.find((f) => f.__ref.id == folderId); + const requestIds = folder.__meta.rOrders || []; + if (!requestIds.length) + return; this.emitter.emit("beforeFolder" /* BeforeFolder */, { name: folder.name, id: folder.__ref.id }); try { - const requestIds = folder.__meta.rOrders || []; for (let i = 0; i < requestIds.length; i++) { const res = await this.runRequest(requestIds[i]); this.testResults.push(res); @@ -142,6 +144,27 @@ class Runner { id: folder.__ref.id }); } + async runRootRequests() { + const { collection } = this.collection; + const requestIds = collection.__meta.rOrders || []; + if (!requestIds.length) + return; + this.emitter.emit("beforeFolder" /* BeforeFolder */, { + name: "./", + id: collection.__ref.id + }); + try { + for (let i = 0; i < requestIds.length; i++) { + const res = await this.runRequest(requestIds[i]); + this.testResults.push(res); + } + } catch (e) { + console.error(`Error while running the collection:`, e); + } + this.emitter.emit("folder" /* Folder */, { + id: collection.__ref.id + }); + } async runIteration() { try { const folderSet = this.folderRunSequence.values(); @@ -153,6 +176,7 @@ class Runner { } }; await next(); + await this.runRootRequests(); } catch (e) { console.error(`Error while running the collection:`, e); } diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index fda28082c..baa4246b4 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -139,6 +139,8 @@ export default class Runner { private async runFolder(folderId: TId) { const folder = this.collection.folders.find(f => f.__ref.id == folderId); + const requestIds = folder.__meta.rOrders || []; + if (!requestIds.length) return; /** emit 'beforeFolder' event just before folder execution start */ this.emitter.emit(ERunnerEvents.BeforeFolder, { @@ -147,7 +149,6 @@ export default class Runner { }); try { - const requestIds = folder.__meta.rOrders || []; for (let i = 0; i < requestIds.length; i++) { const res = await this.runRequest(requestIds[i]); this.testResults.push(res); @@ -164,6 +165,32 @@ export default class Runner { }); } + private async runRootRequests() { + + const { collection } = this.collection; + const requestIds = collection.__meta.rOrders || []; + if (!requestIds.length) return; + this.emitter.emit(ERunnerEvents.BeforeFolder, { + name: './', + id: collection.__ref.id + }); + + try { + for (let i = 0; i < requestIds.length; i++) { + const res = await this.runRequest(requestIds[i]); + this.testResults.push(res); + } + } + catch (e) { + console.error(`Error while running the collection:`, e); + // await this.runIteration(); // Retry fetching info for the remaining IDs even if an error occurred + } + + this.emitter.emit(ERunnerEvents.Folder, { + id: collection.__ref.id + }); + } + private async runIteration() { try { @@ -176,6 +203,7 @@ export default class Runner { } } await next(); + await this.runRootRequests(); } catch (e) { console.error(`Error while running the collection:`, e); From 6bf885f4f58ce614466377c96f339d17bff7abac Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Tue, 20 Jun 2023 17:31:49 +0530 Subject: [PATCH 15/22] feat: run statistics and types are introduced --- .../dist/chunk-3OSFNS7Z.cjs | 10 ++ .../dist/chunk-XXPGZHWZ.js | 10 ++ .../firecamp-collection-runner/dist/index.cjs | 107 +++++++++--------- .../dist/index.d.ts | 29 +---- .../firecamp-collection-runner/dist/index.js | 95 ++++++++-------- .../firecamp-collection-runner/dist/types.cjs | 15 +++ .../dist/types.d.ts | 50 ++++++++ .../firecamp-collection-runner/dist/types.js | 15 +++ .../firecamp-collection-runner/src/index.ts | 73 +++++------- .../firecamp-collection-runner/src/types.ts | 81 +++++++++++++ pnpm-lock.yaml | 38 ++++--- 11 files changed, 338 insertions(+), 185 deletions(-) create mode 100644 packages/firecamp-collection-runner/dist/chunk-3OSFNS7Z.cjs create mode 100644 packages/firecamp-collection-runner/dist/chunk-XXPGZHWZ.js create mode 100644 packages/firecamp-collection-runner/dist/types.cjs create mode 100644 packages/firecamp-collection-runner/dist/types.d.ts create mode 100644 packages/firecamp-collection-runner/dist/types.js create mode 100644 packages/firecamp-collection-runner/src/types.ts diff --git a/packages/firecamp-collection-runner/dist/chunk-3OSFNS7Z.cjs b/packages/firecamp-collection-runner/dist/chunk-3OSFNS7Z.cjs new file mode 100644 index 000000000..1f3dc6f7b --- /dev/null +++ b/packages/firecamp-collection-runner/dist/chunk-3OSFNS7Z.cjs @@ -0,0 +1,10 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});var __defProp = Object.defineProperty; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; + + + +exports.__publicField = __publicField; diff --git a/packages/firecamp-collection-runner/dist/chunk-XXPGZHWZ.js b/packages/firecamp-collection-runner/dist/chunk-XXPGZHWZ.js new file mode 100644 index 000000000..782cce266 --- /dev/null +++ b/packages/firecamp-collection-runner/dist/chunk-XXPGZHWZ.js @@ -0,0 +1,10 @@ +var __defProp = Object.defineProperty; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; + +export { + __publicField +}; diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index 60ab1b98a..c246b3854 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -1,10 +1,8 @@ -"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var __defProp = Object.defineProperty; -var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; -var __publicField = (obj, key, value) => { - __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); - return value; -}; +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } + +var _chunk3OSFNS7Zcjs = require('./chunk-3OSFNS7Z.cjs'); var _eventemitter3 = require('eventemitter3'); var _eventemitter32 = _interopRequireDefault(_eventemitter3); +var _types = require('./types'); const delay = async (ts) => { return new Promise((rs) => { setTimeout(() => { @@ -12,30 +10,28 @@ const delay = async (ts) => { }, ts); }); }; -var ERunnerEvents = /* @__PURE__ */ ((ERunnerEvents2) => { - ERunnerEvents2["Start"] = "start"; - ERunnerEvents2["BeforeRequest"] = "beforeRequest"; - ERunnerEvents2["Request"] = "request"; - ERunnerEvents2["BeforeFolder"] = "beforeFolder"; - ERunnerEvents2["Folder"] = "folder"; - ERunnerEvents2["BeforeIteration"] = "beforeIteration"; - ERunnerEvents2["Iteration"] = "iteration"; - ERunnerEvents2["Done"] = "done"; - return ERunnerEvents2; -})(ERunnerEvents || {}); class Runner { constructor(collection, options) { - __publicField(this, "collection"); - __publicField(this, "options"); - __publicField(this, "folderRunSequence"); - __publicField(this, "testResults", []); - __publicField(this, "emitter"); - __publicField(this, "result", { - total: 0, - pass: 0, - fail: 0, - skip: 0, - duration: 0 + _chunk3OSFNS7Zcjs.__publicField.call(void 0, this, "collection"); + _chunk3OSFNS7Zcjs.__publicField.call(void 0, this, "options"); + _chunk3OSFNS7Zcjs.__publicField.call(void 0, this, "folderRunSequence"); + _chunk3OSFNS7Zcjs.__publicField.call(void 0, this, "testResults", []); + _chunk3OSFNS7Zcjs.__publicField.call(void 0, this, "emitter"); + _chunk3OSFNS7Zcjs.__publicField.call(void 0, this, "runStatistics", { + stats: { + iteration: { failed: 0, total: 0 }, + requests: { failed: 0, total: 0 }, + tests: { failed: 0, total: 0 } + }, + timings: { + runDuration: 0, + responseAverage: 0, + responseMax: 0, + responseMin: 0 + }, + transfers: { + responseTotal: 0 + } }); this.collection = collection; this.options = options; @@ -91,23 +87,25 @@ class Runner { const ids = traverseFolders(collection.__meta.fOrders); ids.forEach(this.folderRunSequence.add, this.folderRunSequence); } - updateResult(response = {}) { - const { testResult: { total, passed, failed } = { - total: 0, - passed: 0, - failed: 0 - } } = response; + updateResponseStatistics(response) { + const { + testResult: { total, passed, failed } = { total: 0, passed: 0, failed: 0 }, + code, + status, + responseSize, + responseTime + } = response; if (Number.isInteger(total)) - this.result.total += total; - if (Number.isInteger(passed)) - this.result.pass += passed; + this.runStatistics.stats.tests.total += total; if (Number.isInteger(failed)) - this.result.fail += failed; + this.runStatistics.stats.tests.failed += failed; + if (Number.isInteger(responseSize)) + this.runStatistics.transfers.responseTotal += responseSize; } async runRequest(requestId) { const { folders, requests } = this.collection; const request = requests.find((r) => r.__ref.id == requestId); - this.emitter.emit("beforeRequest" /* BeforeRequest */, { + this.emitter.emit(_types.ERunnerEvents.BeforeRequest, { name: request.__meta.name, url: request.url.raw, method: request.method.toUpperCase(), @@ -116,11 +114,12 @@ class Runner { }); await delay(this.options.delayRequest); const response = await this.options.executeRequest(request); - this.updateResult(response); - this.emitter.emit("request" /* Request */, { + this.updateResponseStatistics(response); + this.emitter.emit(_types.ERunnerEvents.Request, { id: request.__ref.id, response }); + this.runStatistics.stats.requests.total += 1; return { request, response }; } async runFolder(folderId) { @@ -128,7 +127,7 @@ class Runner { const requestIds = folder.__meta.rOrders || []; if (!requestIds.length) return; - this.emitter.emit("beforeFolder" /* BeforeFolder */, { + this.emitter.emit(_types.ERunnerEvents.BeforeFolder, { name: folder.name, id: folder.__ref.id }); @@ -140,7 +139,7 @@ class Runner { } catch (e) { console.error(`Error while running the collection:`, e); } - this.emitter.emit("folder" /* Folder */, { + this.emitter.emit(_types.ERunnerEvents.Folder, { id: folder.__ref.id }); } @@ -149,7 +148,7 @@ class Runner { const requestIds = collection.__meta.rOrders || []; if (!requestIds.length) return; - this.emitter.emit("beforeFolder" /* BeforeFolder */, { + this.emitter.emit(_types.ERunnerEvents.BeforeFolder, { name: "./", id: collection.__ref.id }); @@ -161,7 +160,7 @@ class Runner { } catch (e) { console.error(`Error while running the collection:`, e); } - this.emitter.emit("folder" /* Folder */, { + this.emitter.emit(_types.ERunnerEvents.Folder, { id: collection.__ref.id }); } @@ -185,27 +184,24 @@ class Runner { setTimeout(async () => { const { collection } = this.collection; const startTs = (/* @__PURE__ */ new Date()).valueOf(); - this.emitter.emit("start" /* Start */, { + this.emitter.emit(_types.ERunnerEvents.Start, { name: collection.name, id: collection.__ref.id }); for (let i = 0; i < this.options.iterationCount; i++) { - this.emitter.emit("beforeIteration" /* BeforeIteration */, { + this.emitter.emit(_types.ERunnerEvents.BeforeIteration, { current: i + 1, total: this.options.iterationCount }); await this.runIteration(); - this.emitter.emit("iteration" /* Iteration */, { + this.emitter.emit(_types.ERunnerEvents.Iteration, { current: i + 1, total: this.options.iterationCount }); + this.runStatistics.stats.iteration.total += 1; } - this.result.duration = (/* @__PURE__ */ new Date()).valueOf() - startTs; - this.emitter.emit("done" /* Done */, { - result: { - ...this.result - } - }); + this.runStatistics.timings.runDuration = (/* @__PURE__ */ new Date()).valueOf() - startTs; + this.emitter.emit(_types.ERunnerEvents.Done, this.runStatistics); }); return this.exposeOnlyOn(); } @@ -231,5 +227,4 @@ const fetchRequestPath = (folders, request) => { }; - -exports.ERunnerEvents = ERunnerEvents; exports.default = Runner; +exports.default = Runner; diff --git a/packages/firecamp-collection-runner/dist/index.d.ts b/packages/firecamp-collection-runner/dist/index.d.ts index 33f45b223..94f4b88b2 100644 --- a/packages/firecamp-collection-runner/dist/index.d.ts +++ b/packages/firecamp-collection-runner/dist/index.d.ts @@ -1,32 +1,13 @@ -import { TId } from '@firecamp/types'; +import { IRunnerOptions } from './types.js'; +import '@firecamp/types'; -declare enum ERunnerEvents { - Start = "start", - BeforeRequest = "beforeRequest", - Request = "request", - BeforeFolder = "beforeFolder", - Folder = "folder", - BeforeIteration = "beforeIteration", - Iteration = "iteration", - Done = "done" -} -interface IRunnerOptions { - executeRequest: (request: any) => Promise; - environment?: TId | string; - globals?: TId | string; - iterationCount?: number; - iterationData?: string; - delayRequest?: number; - timeout?: number; - timeoutRequest?: number; -} declare class Runner { private collection; private options; private folderRunSequence; private testResults; private emitter; - private result; + private runStatistics; constructor(collection: any, options: IRunnerOptions); private assignDefaultOptions; /** @@ -38,7 +19,7 @@ declare class Runner { */ private validate; private prepareFolderRunSequence; - private updateResult; + private updateResponseStatistics; private runRequest; private runFolder; private runRootRequests; @@ -49,4 +30,4 @@ declare class Runner { private exposeOnlyOn; } -export { ERunnerEvents, IRunnerOptions, Runner as default }; +export { Runner as default }; diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index 725f109d4..fd0863ce3 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -1,10 +1,8 @@ -var __defProp = Object.defineProperty; -var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; -var __publicField = (obj, key, value) => { - __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); - return value; -}; +import { + __publicField +} from "./chunk-XXPGZHWZ.js"; import EventEmitter from "eventemitter3"; +import { ERunnerEvents } from "./types"; const delay = async (ts) => { return new Promise((rs) => { setTimeout(() => { @@ -12,17 +10,6 @@ const delay = async (ts) => { }, ts); }); }; -var ERunnerEvents = /* @__PURE__ */ ((ERunnerEvents2) => { - ERunnerEvents2["Start"] = "start"; - ERunnerEvents2["BeforeRequest"] = "beforeRequest"; - ERunnerEvents2["Request"] = "request"; - ERunnerEvents2["BeforeFolder"] = "beforeFolder"; - ERunnerEvents2["Folder"] = "folder"; - ERunnerEvents2["BeforeIteration"] = "beforeIteration"; - ERunnerEvents2["Iteration"] = "iteration"; - ERunnerEvents2["Done"] = "done"; - return ERunnerEvents2; -})(ERunnerEvents || {}); class Runner { constructor(collection, options) { __publicField(this, "collection"); @@ -30,12 +17,21 @@ class Runner { __publicField(this, "folderRunSequence"); __publicField(this, "testResults", []); __publicField(this, "emitter"); - __publicField(this, "result", { - total: 0, - pass: 0, - fail: 0, - skip: 0, - duration: 0 + __publicField(this, "runStatistics", { + stats: { + iteration: { failed: 0, total: 0 }, + requests: { failed: 0, total: 0 }, + tests: { failed: 0, total: 0 } + }, + timings: { + runDuration: 0, + responseAverage: 0, + responseMax: 0, + responseMin: 0 + }, + transfers: { + responseTotal: 0 + } }); this.collection = collection; this.options = options; @@ -91,23 +87,25 @@ class Runner { const ids = traverseFolders(collection.__meta.fOrders); ids.forEach(this.folderRunSequence.add, this.folderRunSequence); } - updateResult(response = {}) { - const { testResult: { total, passed, failed } = { - total: 0, - passed: 0, - failed: 0 - } } = response; + updateResponseStatistics(response) { + const { + testResult: { total, passed, failed } = { total: 0, passed: 0, failed: 0 }, + code, + status, + responseSize, + responseTime + } = response; if (Number.isInteger(total)) - this.result.total += total; - if (Number.isInteger(passed)) - this.result.pass += passed; + this.runStatistics.stats.tests.total += total; if (Number.isInteger(failed)) - this.result.fail += failed; + this.runStatistics.stats.tests.failed += failed; + if (Number.isInteger(responseSize)) + this.runStatistics.transfers.responseTotal += responseSize; } async runRequest(requestId) { const { folders, requests } = this.collection; const request = requests.find((r) => r.__ref.id == requestId); - this.emitter.emit("beforeRequest" /* BeforeRequest */, { + this.emitter.emit(ERunnerEvents.BeforeRequest, { name: request.__meta.name, url: request.url.raw, method: request.method.toUpperCase(), @@ -116,11 +114,12 @@ class Runner { }); await delay(this.options.delayRequest); const response = await this.options.executeRequest(request); - this.updateResult(response); - this.emitter.emit("request" /* Request */, { + this.updateResponseStatistics(response); + this.emitter.emit(ERunnerEvents.Request, { id: request.__ref.id, response }); + this.runStatistics.stats.requests.total += 1; return { request, response }; } async runFolder(folderId) { @@ -128,7 +127,7 @@ class Runner { const requestIds = folder.__meta.rOrders || []; if (!requestIds.length) return; - this.emitter.emit("beforeFolder" /* BeforeFolder */, { + this.emitter.emit(ERunnerEvents.BeforeFolder, { name: folder.name, id: folder.__ref.id }); @@ -140,7 +139,7 @@ class Runner { } catch (e) { console.error(`Error while running the collection:`, e); } - this.emitter.emit("folder" /* Folder */, { + this.emitter.emit(ERunnerEvents.Folder, { id: folder.__ref.id }); } @@ -149,7 +148,7 @@ class Runner { const requestIds = collection.__meta.rOrders || []; if (!requestIds.length) return; - this.emitter.emit("beforeFolder" /* BeforeFolder */, { + this.emitter.emit(ERunnerEvents.BeforeFolder, { name: "./", id: collection.__ref.id }); @@ -161,7 +160,7 @@ class Runner { } catch (e) { console.error(`Error while running the collection:`, e); } - this.emitter.emit("folder" /* Folder */, { + this.emitter.emit(ERunnerEvents.Folder, { id: collection.__ref.id }); } @@ -185,27 +184,24 @@ class Runner { setTimeout(async () => { const { collection } = this.collection; const startTs = (/* @__PURE__ */ new Date()).valueOf(); - this.emitter.emit("start" /* Start */, { + this.emitter.emit(ERunnerEvents.Start, { name: collection.name, id: collection.__ref.id }); for (let i = 0; i < this.options.iterationCount; i++) { - this.emitter.emit("beforeIteration" /* BeforeIteration */, { + this.emitter.emit(ERunnerEvents.BeforeIteration, { current: i + 1, total: this.options.iterationCount }); await this.runIteration(); - this.emitter.emit("iteration" /* Iteration */, { + this.emitter.emit(ERunnerEvents.Iteration, { current: i + 1, total: this.options.iterationCount }); + this.runStatistics.stats.iteration.total += 1; } - this.result.duration = (/* @__PURE__ */ new Date()).valueOf() - startTs; - this.emitter.emit("done" /* Done */, { - result: { - ...this.result - } - }); + this.runStatistics.timings.runDuration = (/* @__PURE__ */ new Date()).valueOf() - startTs; + this.emitter.emit(ERunnerEvents.Done, this.runStatistics); }); return this.exposeOnlyOn(); } @@ -230,6 +226,5 @@ const fetchRequestPath = (folders, request) => { return `./${requestPath.join("/")}`; }; export { - ERunnerEvents, Runner as default }; diff --git a/packages/firecamp-collection-runner/dist/types.cjs b/packages/firecamp-collection-runner/dist/types.cjs new file mode 100644 index 000000000..e46c40e1d --- /dev/null +++ b/packages/firecamp-collection-runner/dist/types.cjs @@ -0,0 +1,15 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});require('./chunk-3OSFNS7Z.cjs'); +var ERunnerEvents = /* @__PURE__ */ ((ERunnerEvents2) => { + ERunnerEvents2["Start"] = "start"; + ERunnerEvents2["BeforeRequest"] = "beforeRequest"; + ERunnerEvents2["Request"] = "request"; + ERunnerEvents2["BeforeFolder"] = "beforeFolder"; + ERunnerEvents2["Folder"] = "folder"; + ERunnerEvents2["BeforeIteration"] = "beforeIteration"; + ERunnerEvents2["Iteration"] = "iteration"; + ERunnerEvents2["Done"] = "done"; + return ERunnerEvents2; +})(ERunnerEvents || {}); + + +exports.ERunnerEvents = ERunnerEvents; diff --git a/packages/firecamp-collection-runner/dist/types.d.ts b/packages/firecamp-collection-runner/dist/types.d.ts new file mode 100644 index 000000000..e57085587 --- /dev/null +++ b/packages/firecamp-collection-runner/dist/types.d.ts @@ -0,0 +1,50 @@ +import { TId } from '@firecamp/types'; + +declare enum ERunnerEvents { + Start = "start", + BeforeRequest = "beforeRequest", + Request = "request", + BeforeFolder = "beforeFolder", + Folder = "folder", + BeforeIteration = "beforeIteration", + Iteration = "iteration", + Done = "done" +} +interface IRunnerOptions { + executeRequest: (request: any) => Promise; + environment?: TId | string; + globals?: TId | string; + iterationCount?: number; + iterationData?: string; + delayRequest?: number; + timeout?: number; + timeoutRequest?: number; +} +type TStats = { + total: number; + failed: number; +}; +interface IRunStatistics { + /** stats contains the meta information of every components of run, every component will have 'total' and 'failed' count refs */ + stats: { + iteration: TStats; + requests: TStats; + tests: TStats; + }; + timings: { + /** total time of the run */ + runDuration: number; + /** average response time of the run */ + responseAverage: number; + /** miminum response time of the run */ + responseMin: number; + /** maximum response time of the run */ + responseMax: number; + }; + transfers: { + /** total response data received in run */ + responseTotal: 0; + }; +} + +export { ERunnerEvents, IRunStatistics, IRunnerOptions }; diff --git a/packages/firecamp-collection-runner/dist/types.js b/packages/firecamp-collection-runner/dist/types.js new file mode 100644 index 000000000..186fd9f4d --- /dev/null +++ b/packages/firecamp-collection-runner/dist/types.js @@ -0,0 +1,15 @@ +import "./chunk-XXPGZHWZ.js"; +var ERunnerEvents = /* @__PURE__ */ ((ERunnerEvents2) => { + ERunnerEvents2["Start"] = "start"; + ERunnerEvents2["BeforeRequest"] = "beforeRequest"; + ERunnerEvents2["Request"] = "request"; + ERunnerEvents2["BeforeFolder"] = "beforeFolder"; + ERunnerEvents2["Folder"] = "folder"; + ERunnerEvents2["BeforeIteration"] = "beforeIteration"; + ERunnerEvents2["Iteration"] = "iteration"; + ERunnerEvents2["Done"] = "done"; + return ERunnerEvents2; +})(ERunnerEvents || {}); +export { + ERunnerEvents +}; diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index baa4246b4..bd2fd656e 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -1,5 +1,6 @@ import EventEmitter from 'eventemitter3'; import { TId } from "@firecamp/types"; +import { ERunnerEvents, IRunStatistics, IRunnerOptions } from './types'; const delay = async (ts: number): Promise => { return new Promise((rs) => { @@ -9,28 +10,6 @@ const delay = async (ts: number): Promise => { }) } -export enum ERunnerEvents { - Start = 'start', - BeforeRequest = 'beforeRequest', - Request = 'request', - BeforeFolder = 'beforeFolder', - Folder = 'folder', - BeforeIteration = 'beforeIteration', - Iteration = 'iteration', - Done = 'done' -} - -export interface IRunnerOptions { - executeRequest: (request: any) => Promise; - environment?: TId | string; - globals?: TId | string; - iterationCount?: number; - iterationData?: string; - delayRequest?: number; - timeout?: number; - timeoutRequest?: number; -} - export default class Runner { private collection: any; @@ -38,12 +17,21 @@ export default class Runner { private folderRunSequence: Set; private testResults: any = []; private emitter: EventEmitter; - private result = { - total: 0, - pass: 0, - fail: 0, - skip: 0, - duration: 0 + private runStatistics: IRunStatistics = { + stats: { + iteration: { failed: 0, total: 0 }, + requests: { failed: 0, total: 0 }, + tests: { failed: 0, total: 0 }, + }, + timings: { + runDuration: 0, + responseAverage: 0, + responseMax: 0, + responseMin: 0, + }, + transfers: { + responseTotal: 0 + } } constructor(collection, options: IRunnerOptions) { @@ -104,13 +92,15 @@ export default class Runner { ids.forEach(this.folderRunSequence.add, this.folderRunSequence); } - private updateResult(response: any = {}) { - const { testResult: { total, passed, failed } = { - total: 0, passed: 0, failed: 0 - } } = response - if (Number.isInteger(total)) this.result.total += total; - if (Number.isInteger(passed)) this.result.pass += passed; - if (Number.isInteger(failed)) this.result.fail += failed; + private updateResponseStatistics(response: any) { + const { + testResult: { total, passed, failed } = { total: 0, passed: 0, failed: 0 }, + code, status, responseSize, responseTime } = response; + + if (Number.isInteger(total)) this.runStatistics.stats.tests.total += total; + // if (Number.isInteger(passed)) this.runStatistics.stats.tests.pass += passed; + if (Number.isInteger(failed)) this.runStatistics.stats.tests.failed += failed; + if (Number.isInteger(responseSize)) this.runStatistics.transfers.responseTotal += responseSize } private async runRequest(requestId: TId) { @@ -128,12 +118,14 @@ export default class Runner { await delay(this.options.delayRequest); const response = await this.options.executeRequest(request); - this.updateResult(response) + this.updateResponseStatistics(response); + /** emit 'request' event on request execution completion */ this.emitter.emit(ERunnerEvents.Request, { id: request.__ref.id, response }); + this.runStatistics.stats.requests.total += 1 return { request, response }; } @@ -236,15 +228,12 @@ export default class Runner { current: i + 1, total: this.options.iterationCount }); + this.runStatistics.stats.iteration.total += 1; } /** emit 'done' event once runner iterations are completed */ - this.result.duration = new Date().valueOf() - startTs; - this.emitter.emit(ERunnerEvents.Done, { - result: { - ...this.result, - } - }); + this.runStatistics.timings.runDuration = new Date().valueOf() - startTs; + this.emitter.emit(ERunnerEvents.Done, this.runStatistics); }); return this.exposeOnlyOn() diff --git a/packages/firecamp-collection-runner/src/types.ts b/packages/firecamp-collection-runner/src/types.ts new file mode 100644 index 000000000..391d1bb76 --- /dev/null +++ b/packages/firecamp-collection-runner/src/types.ts @@ -0,0 +1,81 @@ +import { TId } from "@firecamp/types"; + +export enum ERunnerEvents { + Start = 'start', + BeforeRequest = 'beforeRequest', + Request = 'request', + BeforeFolder = 'beforeFolder', + Folder = 'folder', + BeforeIteration = 'beforeIteration', + Iteration = 'iteration', + Done = 'done' +} + +export interface IRunnerOptions { + executeRequest: (request: any) => Promise; + environment?: TId | string; + globals?: TId | string; + iterationCount?: number; + iterationData?: string; + delayRequest?: number; + timeout?: number; + timeoutRequest?: number; +} + +type TStats = { + total: number, + failed: number +} +export interface IRunStatistics { + /** stats contains the meta information of every components of run, every component will have 'total' and 'failed' count refs */ + stats: { + iteration: TStats, + requests: TStats, + tests: TStats + }, + timings: { + + /** total time of the run */ + runDuration: number, + + /** average response time of the run */ + responseAverage: number, + + /** miminum response time of the run */ + responseMin: number, + + /** maximum response time of the run */ + responseMax: number, + + /** standard deviation of response time of the run */ + // responseSd: number, + + /** average DNS lookup time of the run */ + // dnsAverage: number, + + /** minimum DNS lookup time of the run */ + // dnsMin: number, + + /** maximum DNS lookup time of the run */ + // dnsMax: number, + + /** standard deviation of DNS lookup time of the run */ + // dnsSd: number, + + /** average first byte time of the run */ + // firstByteAverage: number, + + /** minimum first byte time of the run */ + // firstByteMin: number, + + /** maximum first byte time of the run */ + // firstByteMax: number, + + /** standard deviation of first byte time of the run */ + // firstByteSd: 0 + }, + transfers: { + /** total response data received in run */ + responseTotal: 0 + }, +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9da8405e2..16c0f6d4a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -228,7 +228,7 @@ packages: '@babel/traverse': 7.22.5 '@babel/types': 7.22.5 convert-source-map: 1.9.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.0 @@ -526,7 +526,7 @@ packages: '@babel/helper-split-export-declaration': 7.22.5 '@babel/parser': 7.22.5 '@babel/types': 7.22.5 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -920,7 +920,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 espree: 9.5.2 globals: 13.20.0 ignore: 5.2.4 @@ -1087,7 +1087,7 @@ packages: engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -2265,7 +2265,7 @@ packages: '@typescript-eslint/scope-manager': 5.35.1 '@typescript-eslint/type-utils': 5.35.1(eslint@8.29.0)(typescript@4.9.5) '@typescript-eslint/utils': 5.35.1(eslint@8.29.0)(typescript@4.9.5) - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 eslint: 8.29.0 functional-red-black-tree: 1.0.1 ignore: 5.2.4 @@ -2328,7 +2328,7 @@ packages: '@typescript-eslint/scope-manager': 5.29.0 '@typescript-eslint/types': 5.29.0 '@typescript-eslint/typescript-estree': 5.29.0(typescript@4.9.5) - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 eslint: 8.29.0 typescript: 4.9.5 transitivePeerDependencies: @@ -2378,7 +2378,7 @@ packages: optional: true dependencies: '@typescript-eslint/utils': 5.35.1(eslint@8.29.0)(typescript@4.9.5) - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 eslint: 8.29.0 tsutils: 3.21.0(typescript@4.9.5) typescript: 4.9.5 @@ -2438,7 +2438,7 @@ packages: dependencies: '@typescript-eslint/types': 5.29.0 '@typescript-eslint/visitor-keys': 5.29.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.1 @@ -2459,7 +2459,7 @@ packages: dependencies: '@typescript-eslint/types': 5.35.1 '@typescript-eslint/visitor-keys': 5.35.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.1 @@ -2480,7 +2480,7 @@ packages: dependencies: '@typescript-eslint/types': 5.59.9 '@typescript-eslint/visitor-keys': 5.59.9 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.1 @@ -4028,6 +4028,18 @@ packages: supports-color: 8.1.1 dev: true + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + /debug@4.3.4(supports-color@8.1.1): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -4770,7 +4782,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.0 @@ -6168,7 +6180,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 istanbul-lib-coverage: 3.2.0 source-map: 0.6.1 transitivePeerDependencies: @@ -9670,7 +9682,7 @@ packages: bundle-require: 4.0.1(esbuild@0.17.19) cac: 6.7.14 chokidar: 3.5.3 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 esbuild: 0.17.19 execa: 5.1.1 globby: 11.1.0 From bee763fa04ae27be117ae2cd4ccbbd624be93adf Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Tue, 20 Jun 2023 18:16:13 +0530 Subject: [PATCH 16/22] feat(runner): response min, max, avg, total and stats like started, duration an etc implemented --- .../firecamp-collection-runner/dist/index.cjs | 26 +++++++++++++++--- .../firecamp-collection-runner/dist/index.js | 26 +++++++++++++++--- .../dist/types.d.ts | 8 ++++-- .../firecamp-collection-runner/src/index.ts | 27 ++++++++++++++++--- .../firecamp-collection-runner/src/types.ts | 10 +++++-- 5 files changed, 81 insertions(+), 16 deletions(-) diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index c246b3854..64d2e385d 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -24,10 +24,12 @@ class Runner { tests: { failed: 0, total: 0 } }, timings: { + started: 0, runDuration: 0, - responseAverage: 0, + responseMin: 0, responseMax: 0, - responseMin: 0 + responseAvg: 0, + responseTotal: 0 }, transfers: { responseTotal: 0 @@ -101,6 +103,22 @@ class Runner { this.runStatistics.stats.tests.failed += failed; if (Number.isInteger(responseSize)) this.runStatistics.transfers.responseTotal += responseSize; + if (Number.isInteger(responseTime)) { + const { + stats: { requests }, + timings: { responseMin, responseMax } + } = this.runStatistics; + if (responseMin == 0) + this.runStatistics.timings.responseMin = responseTime; + else if (responseTime < responseMin) + this.runStatistics.timings.responseMin = responseTime; + if (responseMax == 0) + this.runStatistics.timings.responseMax = responseTime; + else if (responseTime > responseMax) + this.runStatistics.timings.responseMax = responseTime; + this.runStatistics.timings.responseTotal += responseTime; + this.runStatistics.timings.responseAvg = this.runStatistics.timings.responseTotal / requests.total; + } } async runRequest(requestId) { const { folders, requests } = this.collection; @@ -183,7 +201,7 @@ class Runner { run() { setTimeout(async () => { const { collection } = this.collection; - const startTs = (/* @__PURE__ */ new Date()).valueOf(); + this.runStatistics.timings.started = (/* @__PURE__ */ new Date()).valueOf(); this.emitter.emit(_types.ERunnerEvents.Start, { name: collection.name, id: collection.__ref.id @@ -200,7 +218,7 @@ class Runner { }); this.runStatistics.stats.iteration.total += 1; } - this.runStatistics.timings.runDuration = (/* @__PURE__ */ new Date()).valueOf() - startTs; + this.runStatistics.timings.runDuration = (/* @__PURE__ */ new Date()).valueOf() - this.runStatistics.timings.started; this.emitter.emit(_types.ERunnerEvents.Done, this.runStatistics); }); return this.exposeOnlyOn(); diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index fd0863ce3..0918e0b95 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -24,10 +24,12 @@ class Runner { tests: { failed: 0, total: 0 } }, timings: { + started: 0, runDuration: 0, - responseAverage: 0, + responseMin: 0, responseMax: 0, - responseMin: 0 + responseAvg: 0, + responseTotal: 0 }, transfers: { responseTotal: 0 @@ -101,6 +103,22 @@ class Runner { this.runStatistics.stats.tests.failed += failed; if (Number.isInteger(responseSize)) this.runStatistics.transfers.responseTotal += responseSize; + if (Number.isInteger(responseTime)) { + const { + stats: { requests }, + timings: { responseMin, responseMax } + } = this.runStatistics; + if (responseMin == 0) + this.runStatistics.timings.responseMin = responseTime; + else if (responseTime < responseMin) + this.runStatistics.timings.responseMin = responseTime; + if (responseMax == 0) + this.runStatistics.timings.responseMax = responseTime; + else if (responseTime > responseMax) + this.runStatistics.timings.responseMax = responseTime; + this.runStatistics.timings.responseTotal += responseTime; + this.runStatistics.timings.responseAvg = this.runStatistics.timings.responseTotal / requests.total; + } } async runRequest(requestId) { const { folders, requests } = this.collection; @@ -183,7 +201,7 @@ class Runner { run() { setTimeout(async () => { const { collection } = this.collection; - const startTs = (/* @__PURE__ */ new Date()).valueOf(); + this.runStatistics.timings.started = (/* @__PURE__ */ new Date()).valueOf(); this.emitter.emit(ERunnerEvents.Start, { name: collection.name, id: collection.__ref.id @@ -200,7 +218,7 @@ class Runner { }); this.runStatistics.stats.iteration.total += 1; } - this.runStatistics.timings.runDuration = (/* @__PURE__ */ new Date()).valueOf() - startTs; + this.runStatistics.timings.runDuration = (/* @__PURE__ */ new Date()).valueOf() - this.runStatistics.timings.started; this.emitter.emit(ERunnerEvents.Done, this.runStatistics); }); return this.exposeOnlyOn(); diff --git a/packages/firecamp-collection-runner/dist/types.d.ts b/packages/firecamp-collection-runner/dist/types.d.ts index e57085587..2e69dbce8 100644 --- a/packages/firecamp-collection-runner/dist/types.d.ts +++ b/packages/firecamp-collection-runner/dist/types.d.ts @@ -32,14 +32,18 @@ interface IRunStatistics { tests: TStats; }; timings: { + /** run start time */ + started: number; /** total time of the run */ runDuration: number; /** average response time of the run */ - responseAverage: number; - /** miminum response time of the run */ + responseAvg: number; + /** minimum response time of the run */ responseMin: number; /** maximum response time of the run */ responseMax: number; + /** total response time of all requests */ + responseTotal: number; }; transfers: { /** total response data received in run */ diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index bd2fd656e..1cb0b626b 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -24,10 +24,12 @@ export default class Runner { tests: { failed: 0, total: 0 }, }, timings: { + started: 0, runDuration: 0, - responseAverage: 0, - responseMax: 0, responseMin: 0, + responseMax: 0, + responseAvg: 0, + responseTotal: 0, }, transfers: { responseTotal: 0 @@ -101,6 +103,23 @@ export default class Runner { // if (Number.isInteger(passed)) this.runStatistics.stats.tests.pass += passed; if (Number.isInteger(failed)) this.runStatistics.stats.tests.failed += failed; if (Number.isInteger(responseSize)) this.runStatistics.transfers.responseTotal += responseSize + + if (Number.isInteger(responseTime)) { + const { + stats: { requests }, + timings: { responseMin, responseMax } + } = this.runStatistics + if (responseMin == 0) this.runStatistics.timings.responseMin = responseTime; + else if (responseTime < responseMin) this.runStatistics.timings.responseMin = responseTime; + + if (responseMax == 0) this.runStatistics.timings.responseMax = responseTime; + else if (responseTime > responseMax) this.runStatistics.timings.responseMax = responseTime; + + this.runStatistics.timings.responseTotal += responseTime; + this.runStatistics.timings.responseAvg = ( + this.runStatistics.timings.responseTotal / requests.total + ) + } } private async runRequest(requestId: TId) { @@ -207,7 +226,7 @@ export default class Runner { setTimeout(async () => { const { collection } = this.collection; - const startTs: number = new Date().valueOf(); + this.runStatistics.timings.started = new Date().valueOf(); /** emit 'start' event on runner start */ this.emitter.emit(ERunnerEvents.Start, { name: collection.name, @@ -232,7 +251,7 @@ export default class Runner { } /** emit 'done' event once runner iterations are completed */ - this.runStatistics.timings.runDuration = new Date().valueOf() - startTs; + this.runStatistics.timings.runDuration = new Date().valueOf() - this.runStatistics.timings.started; this.emitter.emit(ERunnerEvents.Done, this.runStatistics); }); diff --git a/packages/firecamp-collection-runner/src/types.ts b/packages/firecamp-collection-runner/src/types.ts index 391d1bb76..26d8d598d 100644 --- a/packages/firecamp-collection-runner/src/types.ts +++ b/packages/firecamp-collection-runner/src/types.ts @@ -35,18 +35,24 @@ export interface IRunStatistics { }, timings: { + /** run start time */ + started: number; + /** total time of the run */ runDuration: number, /** average response time of the run */ - responseAverage: number, + responseAvg: number, - /** miminum response time of the run */ + /** minimum response time of the run */ responseMin: number, /** maximum response time of the run */ responseMax: number, + /** total response time of all requests */ + responseTotal: number; + /** standard deviation of response time of the run */ // responseSd: number, From 4e293e8798ba232240a359ed659b10e0d376275a Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Tue, 20 Jun 2023 18:41:00 +0530 Subject: [PATCH 17/22] feat: cli runner result set and type import issue fixed --- packages/firecamp-cli/src/reporters/cli.ts | 12 ++++----- .../firecamp-collection-runner/dist/index.cjs | 25 ++++++++++--------- .../dist/index.d.ts | 3 ++- .../firecamp-collection-runner/dist/index.js | 3 ++- .../firecamp-collection-runner/src/index.ts | 6 +++-- 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/packages/firecamp-cli/src/reporters/cli.ts b/packages/firecamp-cli/src/reporters/cli.ts index 98bea24ea..d8b9793f8 100644 --- a/packages/firecamp-cli/src/reporters/cli.ts +++ b/packages/firecamp-cli/src/reporters/cli.ts @@ -115,7 +115,7 @@ export default class Reporter { } logResult(summary: any) { - const { result: { total, pass, fail, duration } } = summary + const { stats, timings } = summary // const _header = (h: string) => c.magenta(h); var table = new Table({ @@ -133,11 +133,11 @@ export default class Reporter { }); table.push( - [c.dim('Total Requests'), 28], - [c.dim('Total run duration'), prettyMs(duration)], - [c.dim('Tests'), total], - [c.green('Pass Tests'), pass], - [c.red('Fail Tests'), fail] + [c.dim('Total Requests'), stats.requests.total], + [c.dim('Total run duration'), prettyMs(timings.runDuration)], + [c.dim('Tests'), stats.tests.total], + [c.green('Pass Tests'), stats.tests.total - stats.tests.total], + [c.red('Fail Tests'), stats.tests.total] ); this.log(table.toString()); diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index 64d2e385d..059b4df2a 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -1,8 +1,8 @@ -"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _createStarExport(obj) { Object.keys(obj) .filter((key) => key !== "default" && key !== "__esModule") .forEach((key) => { if (exports.hasOwnProperty(key)) { return; } Object.defineProperty(exports, key, {enumerable: true, configurable: true, get: () => obj[key]}); }); } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _chunk3OSFNS7Zcjs = require('./chunk-3OSFNS7Z.cjs'); var _eventemitter3 = require('eventemitter3'); var _eventemitter32 = _interopRequireDefault(_eventemitter3); -var _types = require('./types'); +var _typesjs = require('./types.js'); _createStarExport(_typesjs); const delay = async (ts) => { return new Promise((rs) => { setTimeout(() => { @@ -123,7 +123,7 @@ class Runner { async runRequest(requestId) { const { folders, requests } = this.collection; const request = requests.find((r) => r.__ref.id == requestId); - this.emitter.emit(_types.ERunnerEvents.BeforeRequest, { + this.emitter.emit(_typesjs.ERunnerEvents.BeforeRequest, { name: request.__meta.name, url: request.url.raw, method: request.method.toUpperCase(), @@ -133,7 +133,7 @@ class Runner { await delay(this.options.delayRequest); const response = await this.options.executeRequest(request); this.updateResponseStatistics(response); - this.emitter.emit(_types.ERunnerEvents.Request, { + this.emitter.emit(_typesjs.ERunnerEvents.Request, { id: request.__ref.id, response }); @@ -145,7 +145,7 @@ class Runner { const requestIds = folder.__meta.rOrders || []; if (!requestIds.length) return; - this.emitter.emit(_types.ERunnerEvents.BeforeFolder, { + this.emitter.emit(_typesjs.ERunnerEvents.BeforeFolder, { name: folder.name, id: folder.__ref.id }); @@ -157,7 +157,7 @@ class Runner { } catch (e) { console.error(`Error while running the collection:`, e); } - this.emitter.emit(_types.ERunnerEvents.Folder, { + this.emitter.emit(_typesjs.ERunnerEvents.Folder, { id: folder.__ref.id }); } @@ -166,7 +166,7 @@ class Runner { const requestIds = collection.__meta.rOrders || []; if (!requestIds.length) return; - this.emitter.emit(_types.ERunnerEvents.BeforeFolder, { + this.emitter.emit(_typesjs.ERunnerEvents.BeforeFolder, { name: "./", id: collection.__ref.id }); @@ -178,7 +178,7 @@ class Runner { } catch (e) { console.error(`Error while running the collection:`, e); } - this.emitter.emit(_types.ERunnerEvents.Folder, { + this.emitter.emit(_typesjs.ERunnerEvents.Folder, { id: collection.__ref.id }); } @@ -202,24 +202,24 @@ class Runner { setTimeout(async () => { const { collection } = this.collection; this.runStatistics.timings.started = (/* @__PURE__ */ new Date()).valueOf(); - this.emitter.emit(_types.ERunnerEvents.Start, { + this.emitter.emit(_typesjs.ERunnerEvents.Start, { name: collection.name, id: collection.__ref.id }); for (let i = 0; i < this.options.iterationCount; i++) { - this.emitter.emit(_types.ERunnerEvents.BeforeIteration, { + this.emitter.emit(_typesjs.ERunnerEvents.BeforeIteration, { current: i + 1, total: this.options.iterationCount }); await this.runIteration(); - this.emitter.emit(_types.ERunnerEvents.Iteration, { + this.emitter.emit(_typesjs.ERunnerEvents.Iteration, { current: i + 1, total: this.options.iterationCount }); this.runStatistics.stats.iteration.total += 1; } this.runStatistics.timings.runDuration = (/* @__PURE__ */ new Date()).valueOf() - this.runStatistics.timings.started; - this.emitter.emit(_types.ERunnerEvents.Done, this.runStatistics); + this.emitter.emit(_typesjs.ERunnerEvents.Done, this.runStatistics); }); return this.exposeOnlyOn(); } @@ -245,4 +245,5 @@ const fetchRequestPath = (folders, request) => { }; + exports.default = Runner; diff --git a/packages/firecamp-collection-runner/dist/index.d.ts b/packages/firecamp-collection-runner/dist/index.d.ts index 94f4b88b2..34de1dbae 100644 --- a/packages/firecamp-collection-runner/dist/index.d.ts +++ b/packages/firecamp-collection-runner/dist/index.d.ts @@ -1,4 +1,5 @@ import { IRunnerOptions } from './types.js'; +export { ERunnerEvents, IRunStatistics } from './types.js'; import '@firecamp/types'; declare class Runner { @@ -30,4 +31,4 @@ declare class Runner { private exposeOnlyOn; } -export { Runner as default }; +export { IRunnerOptions, Runner as default }; diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index 0918e0b95..976643200 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -2,7 +2,7 @@ import { __publicField } from "./chunk-XXPGZHWZ.js"; import EventEmitter from "eventemitter3"; -import { ERunnerEvents } from "./types"; +import { ERunnerEvents } from "./types.js"; const delay = async (ts) => { return new Promise((rs) => { setTimeout(() => { @@ -243,6 +243,7 @@ const fetchRequestPath = (folders, request) => { } return `./${requestPath.join("/")}`; }; +export * from "./types.js"; export { Runner as default }; diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index 1cb0b626b..0bc5cd2cb 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -1,6 +1,6 @@ import EventEmitter from 'eventemitter3'; import { TId } from "@firecamp/types"; -import { ERunnerEvents, IRunStatistics, IRunnerOptions } from './types'; +import { ERunnerEvents, IRunStatistics, IRunnerOptions } from './types.js'; const delay = async (ts: number): Promise => { return new Promise((rs) => { @@ -279,4 +279,6 @@ const fetchRequestPath = (folders, request) => { currentFolder = folders.find(folder => folder.__ref.id === parentFolderId); } return `./${requestPath.join('/')}`; -} \ No newline at end of file +} + +export * from './types.js' \ No newline at end of file From 353a6fad0a3a6dddeac644b8f668240981583731 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Tue, 20 Jun 2023 19:47:13 +0530 Subject: [PATCH 18/22] feat(cli): cli result table designed --- packages/firecamp-cli/package.json | 1 + packages/firecamp-cli/src/reporters/cli.ts | 50 +++++++++---------- .../firecamp-collection-runner/dist/index.cjs | 19 +++---- .../firecamp-collection-runner/dist/index.js | 19 +++---- .../dist/types.d.ts | 2 +- .../firecamp-collection-runner/src/index.ts | 13 ++--- .../firecamp-collection-runner/src/types.ts | 2 +- pnpm-lock.yaml | 46 ++++++++--------- 8 files changed, 71 insertions(+), 81 deletions(-) diff --git a/packages/firecamp-cli/package.json b/packages/firecamp-cli/package.json index a6ca0ca0e..b75e15548 100644 --- a/packages/firecamp-cli/package.json +++ b/packages/firecamp-cli/package.json @@ -30,6 +30,7 @@ "kleur": "^4.1.5", "load-json-file": "^7.0.1", "ora": "^6.3.1", + "pretty-bytes": "^6.1.0", "pretty-ms": "^8.0.0", "react-fast-compare": "^3.2.2" }, diff --git a/packages/firecamp-cli/src/reporters/cli.ts b/packages/firecamp-cli/src/reporters/cli.ts index d8b9793f8..c2bdda012 100644 --- a/packages/firecamp-cli/src/reporters/cli.ts +++ b/packages/firecamp-cli/src/reporters/cli.ts @@ -1,9 +1,10 @@ -import { ERunnerEvents } from '@firecamp/collection-runner'; import ora, { Ora } from 'ora'; import c from 'kleur'; import figures from 'figures'; import Table from 'cli-table3'; import prettyMs from 'pretty-ms'; +import prettyBytes from 'pretty-bytes'; +import { ERunnerEvents } from '@firecamp/collection-runner'; export default class Reporter { @@ -73,7 +74,6 @@ export default class Reporter { } onDone(result: any) { - this.newLine(); this.logResult(result) } @@ -98,7 +98,7 @@ export default class Reporter { _responseMeta() { const { code, status, responseTime, responseSize } = this.response - const line = `[${code + ' ' + status}, ${responseSize}B, ${prettyMs(responseTime)}]`; + const line = `[${code + ' ' + status}, ${prettyBytes(responseSize)}, ${prettyMs(responseTime)}]`; return c.dim(line) } @@ -115,31 +115,29 @@ export default class Reporter { } logResult(summary: any) { - const { stats, timings } = summary - - // const _header = (h: string) => c.magenta(h); - var table = new Table({ - // head: [ - // _header('method'), - // _header('api'), - // _header('status'), - // _header('pass'), - // _header('fail') - // ], - // colWidths: [100, 400, 200, 150, 150 ], - // wordWrap: true, - // chars: { 'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': '' } - - }); - + const { stats: { iterations, requests, tests }, timings, transfers } = summary; + const _header = (h: string) => c.magenta(h); + var table = new Table(); table.push( - [c.dim('Total Requests'), stats.requests.total], - [c.dim('Total run duration'), prettyMs(timings.runDuration)], - [c.dim('Tests'), stats.tests.total], - [c.green('Pass Tests'), stats.tests.total - stats.tests.total], - [c.red('Fail Tests'), stats.tests.total] + ['', { hAlign: 'right', content: _header('executed') }, { hAlign: 'right', content: _header('failed') }], + [ + { hAlign: 'right', content: c[iterations.failed ? 'red' : 'gray']('iterations') }, + { hAlign: 'right', content: iterations.total }, + { hAlign: 'right', content: c[iterations.failed ? 'red' : 'gray'](iterations.failed) }], + [ + { hAlign: 'right', content: c[requests.failed ? 'red' : 'gray']('requests') }, + { hAlign: 'right', content: requests.total }, + { hAlign: 'right', content: c[requests.failed ? 'red' : 'gray'](requests.failed) } + ], + [ + { hAlign: 'right', content: c[tests.failed ? 'red' : 'gray']('tests') }, + { hAlign: 'right', content: tests.total }, + { hAlign: 'right', content: c[tests.failed ? 'red' : 'gray'](tests.failed) } + ], + [{ colSpan: 3, content: `total run duration: ${prettyMs(timings.runDuration)}` }], + [{ colSpan: 3, content: `total data received: ${prettyBytes(transfers.responseTotal)} (approx)` }], + [{ colSpan: 3, content: `average response time: ${prettyMs(timings.responseAvg)} [min: ${prettyMs(timings.responseMin)}, max: ${prettyMs(timings.responseMax)}]` }], ); - this.log(table.toString()); } diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index 059b4df2a..efe22fe22 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -19,7 +19,7 @@ class Runner { _chunk3OSFNS7Zcjs.__publicField.call(void 0, this, "emitter"); _chunk3OSFNS7Zcjs.__publicField.call(void 0, this, "runStatistics", { stats: { - iteration: { failed: 0, total: 0 }, + iterations: { failed: 0, total: 0 }, requests: { failed: 0, total: 0 }, tests: { failed: 0, total: 0 } }, @@ -91,16 +91,13 @@ class Runner { } updateResponseStatistics(response) { const { - testResult: { total, passed, failed } = { total: 0, passed: 0, failed: 0 }, - code, - status, - responseSize, - responseTime + testResult, + response: { code, status, responseSize, responseTime } } = response; - if (Number.isInteger(total)) - this.runStatistics.stats.tests.total += total; - if (Number.isInteger(failed)) - this.runStatistics.stats.tests.failed += failed; + if (Number.isInteger(testResult.total)) + this.runStatistics.stats.tests.total += testResult.total; + if (Number.isInteger(testResult.failed)) + this.runStatistics.stats.tests.failed += testResult.failed; if (Number.isInteger(responseSize)) this.runStatistics.transfers.responseTotal += responseSize; if (Number.isInteger(responseTime)) { @@ -216,7 +213,7 @@ class Runner { current: i + 1, total: this.options.iterationCount }); - this.runStatistics.stats.iteration.total += 1; + this.runStatistics.stats.iterations.total += 1; } this.runStatistics.timings.runDuration = (/* @__PURE__ */ new Date()).valueOf() - this.runStatistics.timings.started; this.emitter.emit(_typesjs.ERunnerEvents.Done, this.runStatistics); diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index 976643200..eae2f721d 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -19,7 +19,7 @@ class Runner { __publicField(this, "emitter"); __publicField(this, "runStatistics", { stats: { - iteration: { failed: 0, total: 0 }, + iterations: { failed: 0, total: 0 }, requests: { failed: 0, total: 0 }, tests: { failed: 0, total: 0 } }, @@ -91,16 +91,13 @@ class Runner { } updateResponseStatistics(response) { const { - testResult: { total, passed, failed } = { total: 0, passed: 0, failed: 0 }, - code, - status, - responseSize, - responseTime + testResult, + response: { code, status, responseSize, responseTime } } = response; - if (Number.isInteger(total)) - this.runStatistics.stats.tests.total += total; - if (Number.isInteger(failed)) - this.runStatistics.stats.tests.failed += failed; + if (Number.isInteger(testResult.total)) + this.runStatistics.stats.tests.total += testResult.total; + if (Number.isInteger(testResult.failed)) + this.runStatistics.stats.tests.failed += testResult.failed; if (Number.isInteger(responseSize)) this.runStatistics.transfers.responseTotal += responseSize; if (Number.isInteger(responseTime)) { @@ -216,7 +213,7 @@ class Runner { current: i + 1, total: this.options.iterationCount }); - this.runStatistics.stats.iteration.total += 1; + this.runStatistics.stats.iterations.total += 1; } this.runStatistics.timings.runDuration = (/* @__PURE__ */ new Date()).valueOf() - this.runStatistics.timings.started; this.emitter.emit(ERunnerEvents.Done, this.runStatistics); diff --git a/packages/firecamp-collection-runner/dist/types.d.ts b/packages/firecamp-collection-runner/dist/types.d.ts index 2e69dbce8..02b5c37a0 100644 --- a/packages/firecamp-collection-runner/dist/types.d.ts +++ b/packages/firecamp-collection-runner/dist/types.d.ts @@ -27,7 +27,7 @@ type TStats = { interface IRunStatistics { /** stats contains the meta information of every components of run, every component will have 'total' and 'failed' count refs */ stats: { - iteration: TStats; + iterations: TStats; requests: TStats; tests: TStats; }; diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index 0bc5cd2cb..a9ea28ddc 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -19,7 +19,7 @@ export default class Runner { private emitter: EventEmitter; private runStatistics: IRunStatistics = { stats: { - iteration: { failed: 0, total: 0 }, + iterations: { failed: 0, total: 0 }, requests: { failed: 0, total: 0 }, tests: { failed: 0, total: 0 }, }, @@ -96,12 +96,13 @@ export default class Runner { private updateResponseStatistics(response: any) { const { - testResult: { total, passed, failed } = { total: 0, passed: 0, failed: 0 }, - code, status, responseSize, responseTime } = response; + testResult, + response: { code, status, responseSize, responseTime } + } = response; - if (Number.isInteger(total)) this.runStatistics.stats.tests.total += total; + if (Number.isInteger(testResult.total)) this.runStatistics.stats.tests.total += testResult.total; // if (Number.isInteger(passed)) this.runStatistics.stats.tests.pass += passed; - if (Number.isInteger(failed)) this.runStatistics.stats.tests.failed += failed; + if (Number.isInteger(testResult.failed)) this.runStatistics.stats.tests.failed += testResult.failed; if (Number.isInteger(responseSize)) this.runStatistics.transfers.responseTotal += responseSize if (Number.isInteger(responseTime)) { @@ -247,7 +248,7 @@ export default class Runner { current: i + 1, total: this.options.iterationCount }); - this.runStatistics.stats.iteration.total += 1; + this.runStatistics.stats.iterations.total += 1; } /** emit 'done' event once runner iterations are completed */ diff --git a/packages/firecamp-collection-runner/src/types.ts b/packages/firecamp-collection-runner/src/types.ts index 26d8d598d..5645644f6 100644 --- a/packages/firecamp-collection-runner/src/types.ts +++ b/packages/firecamp-collection-runner/src/types.ts @@ -29,7 +29,7 @@ type TStats = { export interface IRunStatistics { /** stats contains the meta information of every components of run, every component will have 'total' and 'failed' count refs */ stats: { - iteration: TStats, + iterations: TStats, requests: TStats, tests: TStats }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 16c0f6d4a..a1a139f98 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: ora: specifier: ^6.3.1 version: 6.3.1 + pretty-bytes: + specifier: ^6.1.0 + version: 6.1.0 pretty-ms: specifier: ^8.0.0 version: 8.0.0 @@ -228,7 +231,7 @@ packages: '@babel/traverse': 7.22.5 '@babel/types': 7.22.5 convert-source-map: 1.9.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.0 @@ -526,7 +529,7 @@ packages: '@babel/helper-split-export-declaration': 7.22.5 '@babel/parser': 7.22.5 '@babel/types': 7.22.5 - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -920,7 +923,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) espree: 9.5.2 globals: 13.20.0 ignore: 5.2.4 @@ -1087,7 +1090,7 @@ packages: engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -2265,7 +2268,7 @@ packages: '@typescript-eslint/scope-manager': 5.35.1 '@typescript-eslint/type-utils': 5.35.1(eslint@8.29.0)(typescript@4.9.5) '@typescript-eslint/utils': 5.35.1(eslint@8.29.0)(typescript@4.9.5) - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) eslint: 8.29.0 functional-red-black-tree: 1.0.1 ignore: 5.2.4 @@ -2328,7 +2331,7 @@ packages: '@typescript-eslint/scope-manager': 5.29.0 '@typescript-eslint/types': 5.29.0 '@typescript-eslint/typescript-estree': 5.29.0(typescript@4.9.5) - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) eslint: 8.29.0 typescript: 4.9.5 transitivePeerDependencies: @@ -2378,7 +2381,7 @@ packages: optional: true dependencies: '@typescript-eslint/utils': 5.35.1(eslint@8.29.0)(typescript@4.9.5) - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) eslint: 8.29.0 tsutils: 3.21.0(typescript@4.9.5) typescript: 4.9.5 @@ -2438,7 +2441,7 @@ packages: dependencies: '@typescript-eslint/types': 5.29.0 '@typescript-eslint/visitor-keys': 5.29.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.1 @@ -2459,7 +2462,7 @@ packages: dependencies: '@typescript-eslint/types': 5.35.1 '@typescript-eslint/visitor-keys': 5.35.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.1 @@ -2480,7 +2483,7 @@ packages: dependencies: '@typescript-eslint/types': 5.59.9 '@typescript-eslint/visitor-keys': 5.59.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.1 @@ -4028,18 +4031,6 @@ packages: supports-color: 8.1.1 dev: true - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - /debug@4.3.4(supports-color@8.1.1): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -4782,7 +4773,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.0 @@ -6180,7 +6171,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) istanbul-lib-coverage: 3.2.0 source-map: 0.6.1 transitivePeerDependencies: @@ -8365,6 +8356,11 @@ packages: engines: {node: '>=6'} dev: true + /pretty-bytes@6.1.0: + resolution: {integrity: sha512-Rk753HI8f4uivXi4ZCIYdhmG1V+WKzvRMg/X+M42a6t7D07RcmopXJMDNk6N++7Bl75URRGsb40ruvg7Hcp2wQ==} + engines: {node: ^14.13.1 || >=16.0.0} + dev: false + /pretty-format@28.1.3: resolution: {integrity: sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -9682,7 +9678,7 @@ packages: bundle-require: 4.0.1(esbuild@0.17.19) cac: 6.7.14 chokidar: 3.5.3 - debug: 4.3.4 + debug: 4.3.4(supports-color@8.1.1) esbuild: 0.17.19 execa: 5.1.1 globby: 11.1.0 From 13d2dfe51195f8c9f5c2cc49f536eb99a974a0fa Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Wed, 21 Jun 2023 17:29:33 +0530 Subject: [PATCH 19/22] feat: -e and -g commands are added --- .../src/commands/collection/run.ts | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/packages/firecamp-cli/src/commands/collection/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts index 78f7bcd8e..05aa61351 100644 --- a/packages/firecamp-cli/src/commands/collection/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -20,6 +20,8 @@ export default class Run extends Command { ] static flags = { + 'environment': Flags.string({ char: 'e', description: 'Provide a path to a Firecamp Environment file' }), + 'globals': Flags.string({ char: 'g', description: 'Provide a path to a Firecamp Globals file' }), 'iteration-count': Flags.string({ char: 'n', description: 'Set the number of iterations for the collection run' }), // 'iteration-data': Flags.string({ char: 'd', description: 'Provide the data file to be used for iterations. (should be JSON or CSV) file to use for iterations JSON or CSV' }), 'delay-request': Flags.integer({ description: 'Set the extent of delay between requests in milliseconds (default: 0)' }), @@ -39,6 +41,8 @@ export default class Run extends Command { return } const { + environment, + globals, "iteration-count": iterationCount, "iteration-data": iterationData, timeout, @@ -48,15 +52,40 @@ export default class Run extends Command { this.log(c.gray(figlet.textSync("Firecamp"))) - const _filepath = new URL(`../../../${path}`, import.meta.url).pathname - loadJsonFile(_filepath) + // const _filepath = new URL(`../../../${path}`, import.meta.url).pathname + loadJsonFile(path) .then(collection => { + + let envObj = { value: [] }; + let globalObj = { value: [] }; + if (environment) { + try { + envObj = await loadJsonFile(environment) + } catch (e) { + this.logToStderr('Error: could not load environment') + this.logToStderr(` `, e.message) + process.exit(1); + } + } + + if (globals) { + try { + globalObj = await loadJsonFile(globals) + } catch (e) { + this.logToStderr('Error: could not load globals') + this.logToStderr(` `, e.message) + process.exit(1); + } + } + // this.logJson(collection); const options: IRunnerOptions = { executeRequest: (request: any) => { const executor = new RestExecutor(); return executor.send(request, { collectionVariables: [], environment: [], globals: [] }); - } + }, + environment: envObj, + globals: globalObj } if (iterationCount) options.iterationCount = +iterationCount; if (iterationData) options.iterationData = iterationData; @@ -69,9 +98,13 @@ export default class Run extends Command { new CliReporter(emitter); }) .catch(e => { - console.error(e) - if (e.code == 'ENOENT') this.logToStderr(`error: file not exist at ${_filepath}`) - else this.logToStderr('error: The collection file is not valid') + // console.error(e) + if (e.code == 'ENOENT') { + this.logToStderr(`Error: could not load collection file`) + this.logToStderr(` `, e.message) + } + else this.logToStderr('Error: The collection file is not valid'); + process.exit(1); }) } } From 3b687b1268938dd3acf7b2d69867c73c1339b0d5 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Wed, 21 Jun 2023 17:48:18 +0530 Subject: [PATCH 20/22] feat: error log common logic implemented --- .../src/commands/collection/run.ts | 34 +++++++++---------- .../dist/types.d.ts | 4 +-- .../firecamp-collection-runner/src/types.ts | 4 +-- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/packages/firecamp-cli/src/commands/collection/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts index 05aa61351..8d023fbaa 100644 --- a/packages/firecamp-cli/src/commands/collection/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -37,7 +37,7 @@ export default class Run extends Command { const { args, flags } = await this.parse(Run) const { path } = args if (!path) { - this.logToStderr('error: The collection path is missing') + this.logError('The collection path is missing') return } const { @@ -50,31 +50,25 @@ export default class Run extends Command { "timeout-request": timeoutRequest, } = flags; - this.log(c.gray(figlet.textSync("Firecamp"))) - // const _filepath = new URL(`../../../${path}`, import.meta.url).pathname loadJsonFile(path) - .then(collection => { + .then(async (collection) => { let envObj = { value: [] }; let globalObj = { value: [] }; if (environment) { try { envObj = await loadJsonFile(environment) - } catch (e) { - this.logToStderr('Error: could not load environment') - this.logToStderr(` `, e.message) - process.exit(1); + } catch (e: any) { + this.logError('could not load environment', e, 1) } } if (globals) { try { globalObj = await loadJsonFile(globals) - } catch (e) { - this.logToStderr('Error: could not load globals') - this.logToStderr(` `, e.message) - process.exit(1); + } catch (e: any) { + this.logError('could not load globals', e); } } @@ -93,18 +87,22 @@ export default class Run extends Command { if (delayRequest) options.delayRequest = +delayRequest; if (timeoutRequest) options.timeoutRequest = +timeoutRequest; + this.log(c.gray(figlet.textSync("Firecamp"))); + const runner = new Runner(collection, options); const emitter = runner.run() new CliReporter(emitter); }) .catch(e => { // console.error(e) - if (e.code == 'ENOENT') { - this.logToStderr(`Error: could not load collection file`) - this.logToStderr(` `, e.message) - } - else this.logToStderr('Error: The collection file is not valid'); - process.exit(1); + if (e.code == 'ENOENT') this.logError(`Error: could not load collection file`, e, 1); + else this.logError('The collection file is not valid', null, 1); }) } + + logError(title: string, e?: any, exitCode?: number) { + if (title) this.logToStderr(`${c.red('Error')}: ${title}`); + if (e?.message) this.logToStderr(` `, e.message); + if (Number.isInteger(exitCode)) process.exit(exitCode); + } } diff --git a/packages/firecamp-collection-runner/dist/types.d.ts b/packages/firecamp-collection-runner/dist/types.d.ts index 02b5c37a0..e4b143366 100644 --- a/packages/firecamp-collection-runner/dist/types.d.ts +++ b/packages/firecamp-collection-runner/dist/types.d.ts @@ -12,8 +12,8 @@ declare enum ERunnerEvents { } interface IRunnerOptions { executeRequest: (request: any) => Promise; - environment?: TId | string; - globals?: TId | string; + environment?: TId | any; + globals?: TId | any; iterationCount?: number; iterationData?: string; delayRequest?: number; diff --git a/packages/firecamp-collection-runner/src/types.ts b/packages/firecamp-collection-runner/src/types.ts index 5645644f6..f2da0abc2 100644 --- a/packages/firecamp-collection-runner/src/types.ts +++ b/packages/firecamp-collection-runner/src/types.ts @@ -13,8 +13,8 @@ export enum ERunnerEvents { export interface IRunnerOptions { executeRequest: (request: any) => Promise; - environment?: TId | string; - globals?: TId | string; + environment?: TId | any; + globals?: TId | any; iterationCount?: number; iterationData?: string; delayRequest?: number; From d1b57879d729b29f6d25c67f74b7e9632c720872 Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Thu, 22 Jun 2023 13:35:33 +0530 Subject: [PATCH 21/22] feat: env and globals vars execution logic implemented types changes echo.env.json env file added --- packages/firecamp-cli/src/commands/collection/run.ts | 11 +++++------ packages/firecamp-cli/test/data/echo.env.json | 10 ++++++++++ ...n.json => restEchoServer.firecamp_collection.json} | 6 +++--- packages/firecamp-collection-runner/dist/types.d.ts | 6 +++--- packages/firecamp-collection-runner/src/types.ts | 6 +++--- 5 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 packages/firecamp-cli/test/data/echo.env.json rename packages/firecamp-cli/test/data/{FirecampRestEchoServer.firecamp_collection.json => restEchoServer.firecamp_collection.json} (99%) diff --git a/packages/firecamp-cli/src/commands/collection/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts index 8d023fbaa..e39913f22 100644 --- a/packages/firecamp-cli/src/commands/collection/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -54,8 +54,8 @@ export default class Run extends Command { loadJsonFile(path) .then(async (collection) => { - let envObj = { value: [] }; - let globalObj = { value: [] }; + let envObj = { values: [] }; + let globalObj = { values: [] }; if (environment) { try { envObj = await loadJsonFile(environment) @@ -71,15 +71,14 @@ export default class Run extends Command { this.logError('could not load globals', e); } } - // this.logJson(collection); const options: IRunnerOptions = { executeRequest: (request: any) => { const executor = new RestExecutor(); - return executor.send(request, { collectionVariables: [], environment: [], globals: [] }); + return executor.send(request, { collectionVariables: [], environment: envObj.values, globals: globalObj.values }); }, - environment: envObj, - globals: globalObj + environment: envObj.values, + globals: globalObj.values } if (iterationCount) options.iterationCount = +iterationCount; if (iterationData) options.iterationData = iterationData; diff --git a/packages/firecamp-cli/test/data/echo.env.json b/packages/firecamp-cli/test/data/echo.env.json new file mode 100644 index 000000000..754be506a --- /dev/null +++ b/packages/firecamp-cli/test/data/echo.env.json @@ -0,0 +1,10 @@ +{ + "id": "678efsdf6X3r4i3", + "name": "RestEchoServer", + "values": [ + { + "key": "host", + "value": "http://localhost:3000" + } + ] +} \ No newline at end of file diff --git a/packages/firecamp-cli/test/data/FirecampRestEchoServer.firecamp_collection.json b/packages/firecamp-cli/test/data/restEchoServer.firecamp_collection.json similarity index 99% rename from packages/firecamp-cli/test/data/FirecampRestEchoServer.firecamp_collection.json rename to packages/firecamp-cli/test/data/restEchoServer.firecamp_collection.json index 7d954552c..a455eccb1 100644 --- a/packages/firecamp-cli/test/data/FirecampRestEchoServer.firecamp_collection.json +++ b/packages/firecamp-cli/test/data/restEchoServer.firecamp_collection.json @@ -123,7 +123,7 @@ "requests": [ { "url": { - "raw": "http://localhost:3000/get?foo1=bar1&foo2=bar2", + "raw": "{{host}}/get?foo1=bar1&foo2=bar2", "queryParams": [ { "id": "RRMgDmGWwOa9ZwpijZiWj", @@ -190,7 +190,7 @@ }, { "url": { - "raw": "http://localhost:3000/post", + "raw": "{{host}}/post", "queryParams": [], "pathParams": [] }, @@ -253,7 +253,7 @@ }, { "url": { - "raw": "http://localhost:3000/post", + "raw": "{{host}}/post", "queryParams": [], "pathParams": [] }, diff --git a/packages/firecamp-collection-runner/dist/types.d.ts b/packages/firecamp-collection-runner/dist/types.d.ts index e4b143366..e24a3be28 100644 --- a/packages/firecamp-collection-runner/dist/types.d.ts +++ b/packages/firecamp-collection-runner/dist/types.d.ts @@ -1,4 +1,4 @@ -import { TId } from '@firecamp/types'; +import { TId, TVariable } from '@firecamp/types'; declare enum ERunnerEvents { Start = "start", @@ -12,8 +12,8 @@ declare enum ERunnerEvents { } interface IRunnerOptions { executeRequest: (request: any) => Promise; - environment?: TId | any; - globals?: TId | any; + environment?: TId | TVariable[]; + globals?: TId | TVariable[]; iterationCount?: number; iterationData?: string; delayRequest?: number; diff --git a/packages/firecamp-collection-runner/src/types.ts b/packages/firecamp-collection-runner/src/types.ts index f2da0abc2..e10ae622b 100644 --- a/packages/firecamp-collection-runner/src/types.ts +++ b/packages/firecamp-collection-runner/src/types.ts @@ -1,4 +1,4 @@ -import { TId } from "@firecamp/types"; +import { TId, TVariable, IVariableGroup } from "@firecamp/types"; export enum ERunnerEvents { Start = 'start', @@ -13,8 +13,8 @@ export enum ERunnerEvents { export interface IRunnerOptions { executeRequest: (request: any) => Promise; - environment?: TId | any; - globals?: TId | any; + environment?: TId | TVariable[]; + globals?: TId | TVariable[]; iterationCount?: number; iterationData?: string; delayRequest?: number; From 66a05f4d1dbf282a9fb0656ccc611b19fcb96f0a Mon Sep 17 00:00:00 2001 From: Nishchit Dhanani Date: Thu, 22 Jun 2023 14:05:16 +0530 Subject: [PATCH 22/22] feat: execute request moved in runner from cli, also getExecutior method introduced to pass execcutor from cli to runner as an option --- packages/firecamp-cli/src/commands/collection/run.ts | 9 +++------ packages/firecamp-collection-runner/dist/index.cjs | 5 ++++- packages/firecamp-collection-runner/dist/index.js | 5 ++++- packages/firecamp-collection-runner/dist/types.d.ts | 2 +- packages/firecamp-collection-runner/src/index.ts | 5 ++++- packages/firecamp-collection-runner/src/types.ts | 4 ++-- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/firecamp-cli/src/commands/collection/run.ts b/packages/firecamp-cli/src/commands/collection/run.ts index e39913f22..9d7cfe785 100644 --- a/packages/firecamp-cli/src/commands/collection/run.ts +++ b/packages/firecamp-cli/src/commands/collection/run.ts @@ -73,12 +73,9 @@ export default class Run extends Command { } // this.logJson(collection); const options: IRunnerOptions = { - executeRequest: (request: any) => { - const executor = new RestExecutor(); - return executor.send(request, { collectionVariables: [], environment: envObj.values, globals: globalObj.values }); - }, - environment: envObj.values, - globals: globalObj.values + getExecutor: () => new RestExecutor(), + environment: envObj.values || [], + globals: globalObj.values || [] } if (iterationCount) options.iterationCount = +iterationCount; if (iterationData) options.iterationData = iterationData; diff --git a/packages/firecamp-collection-runner/dist/index.cjs b/packages/firecamp-collection-runner/dist/index.cjs index efe22fe22..f6833930d 100644 --- a/packages/firecamp-collection-runner/dist/index.cjs +++ b/packages/firecamp-collection-runner/dist/index.cjs @@ -128,7 +128,10 @@ class Runner { id: request.__ref.id }); await delay(this.options.delayRequest); - const response = await this.options.executeRequest(request); + const { globals, environment } = this.options; + const executor = this.options.getExecutor(); + const response = await executor.send(request, { collectionVariables: [], environment, globals }); + ; this.updateResponseStatistics(response); this.emitter.emit(_typesjs.ERunnerEvents.Request, { id: request.__ref.id, diff --git a/packages/firecamp-collection-runner/dist/index.js b/packages/firecamp-collection-runner/dist/index.js index eae2f721d..cf052d1be 100644 --- a/packages/firecamp-collection-runner/dist/index.js +++ b/packages/firecamp-collection-runner/dist/index.js @@ -128,7 +128,10 @@ class Runner { id: request.__ref.id }); await delay(this.options.delayRequest); - const response = await this.options.executeRequest(request); + const { globals, environment } = this.options; + const executor = this.options.getExecutor(); + const response = await executor.send(request, { collectionVariables: [], environment, globals }); + ; this.updateResponseStatistics(response); this.emitter.emit(ERunnerEvents.Request, { id: request.__ref.id, diff --git a/packages/firecamp-collection-runner/dist/types.d.ts b/packages/firecamp-collection-runner/dist/types.d.ts index e24a3be28..cb947a9db 100644 --- a/packages/firecamp-collection-runner/dist/types.d.ts +++ b/packages/firecamp-collection-runner/dist/types.d.ts @@ -11,7 +11,7 @@ declare enum ERunnerEvents { Done = "done" } interface IRunnerOptions { - executeRequest: (request: any) => Promise; + getExecutor: () => any; environment?: TId | TVariable[]; globals?: TId | TVariable[]; iterationCount?: number; diff --git a/packages/firecamp-collection-runner/src/index.ts b/packages/firecamp-collection-runner/src/index.ts index a9ea28ddc..64da7ae42 100644 --- a/packages/firecamp-collection-runner/src/index.ts +++ b/packages/firecamp-collection-runner/src/index.ts @@ -137,7 +137,10 @@ export default class Runner { }); await delay(this.options.delayRequest); - const response = await this.options.executeRequest(request); + const { globals, environment } = this.options; + const executor = this.options.getExecutor() + const response = await executor.send(request, { collectionVariables: [], environment, globals });; + this.updateResponseStatistics(response); /** emit 'request' event on request execution completion */ diff --git a/packages/firecamp-collection-runner/src/types.ts b/packages/firecamp-collection-runner/src/types.ts index e10ae622b..9691322bd 100644 --- a/packages/firecamp-collection-runner/src/types.ts +++ b/packages/firecamp-collection-runner/src/types.ts @@ -1,4 +1,4 @@ -import { TId, TVariable, IVariableGroup } from "@firecamp/types"; +import { TId, TVariable } from "@firecamp/types"; export enum ERunnerEvents { Start = 'start', @@ -12,7 +12,7 @@ export enum ERunnerEvents { } export interface IRunnerOptions { - executeRequest: (request: any) => Promise; + getExecutor: () => any; environment?: TId | TVariable[]; globals?: TId | TVariable[]; iterationCount?: number;