@dev-blinq/cucumber-js 1.0.133-dev → 1.0.133

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/bin/cucumber.ts +1 -0
  2. package/bin/download-install.js +22 -2
  3. package/lib/api/console_logger.js.map +1 -1
  4. package/lib/cli/run.js +1 -0
  5. package/lib/cli/run.js.map +1 -1
  6. package/lib/cli/validate_node_engine_version.js +3 -1
  7. package/lib/cli/validate_node_engine_version.js.map +1 -1
  8. package/lib/configuration/axios_client.js +1 -1
  9. package/lib/configuration/axios_client.js.map +1 -1
  10. package/lib/formatter/api.js +16 -5
  11. package/lib/formatter/api.js.map +1 -1
  12. package/lib/formatter/builder.js +1 -3
  13. package/lib/formatter/builder.js.map +1 -1
  14. package/lib/formatter/bvt_analysis_formatter.d.ts +14 -1
  15. package/lib/formatter/bvt_analysis_formatter.js +207 -57
  16. package/lib/formatter/bvt_analysis_formatter.js.map +1 -1
  17. package/lib/formatter/feature_data_format.js +22 -8
  18. package/lib/formatter/feature_data_format.js.map +1 -1
  19. package/lib/formatter/helpers/constants.d.ts +50 -0
  20. package/lib/formatter/helpers/constants.js +60 -0
  21. package/lib/formatter/helpers/constants.js.map +1 -0
  22. package/lib/formatter/helpers/report_generator.d.ts +20 -2
  23. package/lib/formatter/helpers/report_generator.js +279 -23
  24. package/lib/formatter/helpers/report_generator.js.map +1 -1
  25. package/lib/formatter/helpers/test_case_attempt_parser.js.map +1 -1
  26. package/lib/formatter/helpers/upload_serivce.d.ts +22 -2
  27. package/lib/formatter/helpers/upload_serivce.js +214 -34
  28. package/lib/formatter/helpers/upload_serivce.js.map +1 -1
  29. package/lib/formatter/helpers/uploader.js +6 -2
  30. package/lib/formatter/helpers/uploader.js.map +1 -1
  31. package/lib/formatter/progress_formatter.d.ts +2 -1
  32. package/lib/formatter/progress_formatter.js.map +1 -1
  33. package/lib/formatter/snippets_formatter.js.map +1 -1
  34. package/lib/formatter/summary_formatter.js +4 -0
  35. package/lib/formatter/summary_formatter.js.map +1 -1
  36. package/lib/formatter/usage_formatter.js.map +1 -1
  37. package/lib/formatter/usage_json_formatter.js.map +1 -1
  38. package/lib/pickle_filter.d.ts +3 -2
  39. package/lib/pickle_filter.js.map +1 -1
  40. package/lib/runtime/test_case_runner.d.ts +2 -0
  41. package/lib/runtime/test_case_runner.js +17 -1
  42. package/lib/runtime/test_case_runner.js.map +1 -1
  43. package/lib/uncaught_exception_manager.d.ts +1 -1
  44. package/lib/uncaught_exception_manager.js.map +1 -1
  45. package/lib/version.d.ts +1 -1
  46. package/lib/version.js +1 -1
  47. package/lib/version.js.map +1 -1
  48. package/package.json +7 -3
@@ -0,0 +1,50 @@
1
+ export declare const LOCAL: {
2
+ SSO: string;
3
+ WORKSPACE: string;
4
+ RUNS: string;
5
+ STORAGE: string;
6
+ };
7
+ export declare const DEV: {
8
+ SSO: string;
9
+ WORKSPACE: string;
10
+ RUNS: string;
11
+ STORAGE: string;
12
+ };
13
+ export declare const PROD: {
14
+ SSO: string;
15
+ WORKSPACE: string;
16
+ RUNS: string;
17
+ STORAGE: string;
18
+ };
19
+ export declare const STAGE: {
20
+ SSO: string;
21
+ WORKSPACE: string;
22
+ RUNS: string;
23
+ STORAGE: string;
24
+ };
25
+ export declare const CUSTOM: {
26
+ SSO: string;
27
+ WORKSPACE: string;
28
+ RUNS: string;
29
+ STORAGE: string;
30
+ };
31
+ export declare const SERVICES_URI: {
32
+ SSO: string;
33
+ WORKSPACE: string;
34
+ RUNS: string;
35
+ STORAGE: string;
36
+ };
37
+ export declare enum ActionEvents {
38
+ record_scenario = "record_scenario",
39
+ download_editor = "download_editor",
40
+ launch_editor = "launch_editor",
41
+ click_start_recording = "click_start_recording",
42
+ click_run_scenario = "click_run_scenario",
43
+ publish_scenario = "publish_scenario",
44
+ click_ai_generate = "click_ai_generate",
45
+ click_run_all = "click_run_all",
46
+ click_open_vscode = "click_open_vscode",
47
+ error_open_vscode = "error_open_vscode",
48
+ cli_run_tests = "cli_run_tests",
49
+ upload_report = "upload_report"
50
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ActionEvents = exports.SERVICES_URI = exports.CUSTOM = exports.STAGE = exports.PROD = exports.DEV = exports.LOCAL = void 0;
4
+ exports.LOCAL = {
5
+ SSO: 'http://localhost:5000/api/auth',
6
+ WORKSPACE: 'http://localhost:6000/api/workspace',
7
+ RUNS: 'http://localhost:5001/api/runs',
8
+ STORAGE: 'http://localhost:5050/api/storage',
9
+ };
10
+ exports.DEV = {
11
+ SSO: 'https://dev.api.blinq.io/api/auth',
12
+ WORKSPACE: 'https://dev.api.blinq.io/api/workspace',
13
+ RUNS: 'https://dev.api.blinq.io/api/runs',
14
+ STORAGE: 'https://dev.api.blinq.io/api/storage',
15
+ };
16
+ exports.PROD = {
17
+ SSO: 'https://api.blinq.io/api/auth',
18
+ WORKSPACE: 'https://api.blinq.io/api/workspace',
19
+ RUNS: 'https://api.blinq.io/api/runs',
20
+ STORAGE: 'https://api.blinq.io/api/storage',
21
+ };
22
+ exports.STAGE = {
23
+ SSO: 'https://stage.api.blinq.io/api/auth',
24
+ WORKSPACE: 'https://stage.api.blinq.io/api/workspace',
25
+ RUNS: 'https://stage.api.blinq.io/api/runs',
26
+ STORAGE: 'https://stage.api.blinq.io/api/storage',
27
+ };
28
+ exports.CUSTOM = {
29
+ SSO: `${process.env.NODE_ENV_BLINQ}/api/auth`,
30
+ WORKSPACE: `${process.env.NODE_ENV_BLINQ}/api/workspace`,
31
+ RUNS: `${process.env.NODE_ENV_BLINQ}/api/runs`,
32
+ STORAGE: `${process.env.NODE_ENV_BLINQ}/api/storage`,
33
+ };
34
+ exports.SERVICES_URI = process.env.NODE_ENV_BLINQ === 'local'
35
+ ? exports.LOCAL // eslint-disable-line
36
+ : process.env.NODE_ENV_BLINQ === 'dev'
37
+ ? exports.DEV // eslint-disable-line
38
+ : process.env.NODE_ENV_BLINQ === 'stage'
39
+ ? exports.STAGE // eslint-disable-line
40
+ : process.env.NODE_ENV_BLINQ === 'prod'
41
+ ? exports.PROD // eslint-disable-line
42
+ : !process.env.NODE_ENV_BLINQ
43
+ ? exports.PROD // eslint-disable-line
44
+ : exports.CUSTOM; // eslint-disable-line
45
+ var ActionEvents;
46
+ (function (ActionEvents) {
47
+ ActionEvents["record_scenario"] = "record_scenario";
48
+ ActionEvents["download_editor"] = "download_editor";
49
+ ActionEvents["launch_editor"] = "launch_editor";
50
+ ActionEvents["click_start_recording"] = "click_start_recording";
51
+ ActionEvents["click_run_scenario"] = "click_run_scenario";
52
+ ActionEvents["publish_scenario"] = "publish_scenario";
53
+ ActionEvents["click_ai_generate"] = "click_ai_generate";
54
+ ActionEvents["click_run_all"] = "click_run_all";
55
+ ActionEvents["click_open_vscode"] = "click_open_vscode";
56
+ ActionEvents["error_open_vscode"] = "error_open_vscode";
57
+ ActionEvents["cli_run_tests"] = "cli_run_tests";
58
+ ActionEvents["upload_report"] = "upload_report";
59
+ })(ActionEvents = exports.ActionEvents || (exports.ActionEvents = {}));
60
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/formatter/helpers/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,KAAK,GAAG;IACnB,GAAG,EAAE,gCAAgC;IACrC,SAAS,EAAE,qCAAqC;IAChD,IAAI,EAAE,gCAAgC;IACtC,OAAO,EAAE,mCAAmC;CAC7C,CAAA;AACY,QAAA,GAAG,GAAG;IACjB,GAAG,EAAE,mCAAmC;IACxC,SAAS,EAAE,wCAAwC;IACnD,IAAI,EAAE,mCAAmC;IACzC,OAAO,EAAE,sCAAsC;CAChD,CAAA;AACY,QAAA,IAAI,GAAG;IAClB,GAAG,EAAE,+BAA+B;IACpC,SAAS,EAAE,oCAAoC;IAC/C,IAAI,EAAE,+BAA+B;IACrC,OAAO,EAAE,kCAAkC;CAC5C,CAAA;AACY,QAAA,KAAK,GAAG;IACnB,GAAG,EAAE,qCAAqC;IAC1C,SAAS,EAAE,0CAA0C;IACrD,IAAI,EAAE,qCAAqC;IAC3C,OAAO,EAAE,wCAAwC;CAClD,CAAA;AAEY,QAAA,MAAM,GAAG;IACpB,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,WAAW;IAC7C,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,gBAAgB;IACxD,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,WAAW;IAC9C,OAAO,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,cAAc;CACrD,CAAA;AAEY,QAAA,YAAY,GACvB,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,OAAO;IACpC,CAAC,CAAC,aAAK,CAAC,sBAAsB;IAC9B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,KAAK;QACpC,CAAC,CAAC,WAAG,CAAC,sBAAsB;QAC5B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,OAAO;YACtC,CAAC,CAAC,aAAK,CAAC,sBAAsB;YAC9B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,MAAM;gBACrC,CAAC,CAAC,YAAI,CAAC,sBAAsB;gBAC7B,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc;oBAC3B,CAAC,CAAC,YAAI,CAAC,sBAAsB;oBAC7B,CAAC,CAAC,cAAM,CAAA,CAAC,sBAAsB;AAE3C,IAAY,YAaX;AAbD,WAAY,YAAY;IACtB,mDAAmC,CAAA;IACnC,mDAAmC,CAAA;IACnC,+CAA+B,CAAA;IAC/B,+DAA+C,CAAA;IAC/C,yDAAyC,CAAA;IACzC,qDAAqC,CAAA;IACrC,uDAAuC,CAAA;IACvC,+CAA+B,CAAA;IAC/B,uDAAuC,CAAA;IACvC,uDAAuC,CAAA;IACvC,+CAA+B,CAAA;IAC/B,+CAA+B,CAAA;AACjC,CAAC,EAbW,YAAY,GAAZ,oBAAY,KAAZ,oBAAY,QAavB","sourcesContent":["export const LOCAL = {\n SSO: 'http://localhost:5000/api/auth',\n WORKSPACE: 'http://localhost:6000/api/workspace',\n RUNS: 'http://localhost:5001/api/runs',\n STORAGE: 'http://localhost:5050/api/storage',\n}\nexport const DEV = {\n SSO: 'https://dev.api.blinq.io/api/auth',\n WORKSPACE: 'https://dev.api.blinq.io/api/workspace',\n RUNS: 'https://dev.api.blinq.io/api/runs',\n STORAGE: 'https://dev.api.blinq.io/api/storage',\n}\nexport const PROD = {\n SSO: 'https://api.blinq.io/api/auth',\n WORKSPACE: 'https://api.blinq.io/api/workspace',\n RUNS: 'https://api.blinq.io/api/runs',\n STORAGE: 'https://api.blinq.io/api/storage',\n}\nexport const STAGE = {\n SSO: 'https://stage.api.blinq.io/api/auth',\n WORKSPACE: 'https://stage.api.blinq.io/api/workspace',\n RUNS: 'https://stage.api.blinq.io/api/runs',\n STORAGE: 'https://stage.api.blinq.io/api/storage',\n}\n\nexport const CUSTOM = {\n SSO: `${process.env.NODE_ENV_BLINQ}/api/auth`,\n WORKSPACE: `${process.env.NODE_ENV_BLINQ}/api/workspace`,\n RUNS: `${process.env.NODE_ENV_BLINQ}/api/runs`,\n STORAGE: `${process.env.NODE_ENV_BLINQ}/api/storage`,\n}\n\nexport const SERVICES_URI =\n process.env.NODE_ENV_BLINQ === 'local'\n ? LOCAL // eslint-disable-line\n : process.env.NODE_ENV_BLINQ === 'dev'\n ? DEV // eslint-disable-line\n : process.env.NODE_ENV_BLINQ === 'stage'\n ? STAGE // eslint-disable-line\n : process.env.NODE_ENV_BLINQ === 'prod'\n ? PROD // eslint-disable-line\n : !process.env.NODE_ENV_BLINQ\n ? PROD // eslint-disable-line\n : CUSTOM // eslint-disable-line\n\nexport enum ActionEvents {\n record_scenario = 'record_scenario',\n download_editor = 'download_editor',\n launch_editor = 'launch_editor',\n click_start_recording = 'click_start_recording',\n click_run_scenario = 'click_run_scenario',\n publish_scenario = 'publish_scenario',\n click_ai_generate = 'click_ai_generate',\n click_run_all = 'click_run_all',\n click_open_vscode = 'click_open_vscode',\n error_open_vscode = 'error_open_vscode',\n cli_run_tests = 'cli_run_tests',\n upload_report = 'upload_report',\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import * as messages from '@cucumber/messages';
2
2
  type JsonTimestamp = number;
3
- type JsonStepType = 'Unknown' | 'Context' | 'Action' | 'Outcome' | 'Conjunction';
3
+ type JsonStepType = 'Unknown' | 'Context' | 'Action' | 'Outcome' | 'Conjunction' | 'After' | 'Before';
4
4
  export type JsonResultUnknown = {
5
5
  status: 'UNKNOWN';
6
6
  };
@@ -63,7 +63,12 @@ export type JsonStep = {
63
63
  commands: JsonCommand[];
64
64
  result: JsonStepResult;
65
65
  webLog: webLog[];
66
+ networkData: any[];
66
67
  data?: any;
68
+ ariaSnapshot: string;
69
+ traceFilePath?: string;
70
+ brunoData?: any;
71
+ interceptResults?: any;
67
72
  };
68
73
  export type RetrainStats = {
69
74
  result: JsonTestResult;
@@ -80,12 +85,15 @@ export type JsonTestProgress = {
80
85
  steps: JsonStep[];
81
86
  result: JsonTestResult;
82
87
  retrainStats?: RetrainStats;
88
+ initialAriaSnapshot?: string;
83
89
  webLog: any;
84
90
  networkLog: any;
91
+ logFileId?: string;
85
92
  env: {
86
93
  name: string;
87
94
  baseUrl: string;
88
95
  };
96
+ traceFileId?: string;
89
97
  };
90
98
  export type JsonReport = {
91
99
  testCases: JsonTestProgress[];
@@ -114,10 +122,16 @@ export default class ReportGenerator {
114
122
  private logs;
115
123
  private networkLog;
116
124
  private stepLogs;
125
+ private stepNetworkLogs;
117
126
  private runName;
127
+ private ariaSnapshot;
128
+ private initialAriaSnapshot;
129
+ private testCaseLog;
130
+ private loggingOverridden;
118
131
  reportFolder: null | string;
119
132
  private uploadService;
120
- handleMessage(envelope: EnvelopeWithMetaMessage): Promise<void>;
133
+ private retryTestCaseId;
134
+ handleMessage(envelope: EnvelopeWithMetaMessage | messages.Envelope, reRunId?: string): Promise<any>;
121
135
  getReport(): JsonReport;
122
136
  private handleParseError;
123
137
  private onGherkinDocument;
@@ -130,11 +144,15 @@ export default class ReportGenerator {
130
144
  private onTestCaseStarted;
131
145
  private onTestStepStarted;
132
146
  private onAttachment;
147
+ private getFailedTestStepResult;
133
148
  private onTestStepFinished;
134
149
  getLogFileContent(): any;
135
150
  private getTestCaseResult;
136
151
  private onTestCaseFinished;
152
+ private readonly retryCount;
137
153
  private uploadTestCase;
154
+ private tryUpload;
155
+ private writeTestCaseReportToDisk;
138
156
  private onTestRunFinished;
139
157
  }
140
158
  export {};
@@ -31,13 +31,20 @@ const messages = __importStar(require("@cucumber/messages"));
31
31
  const fs_1 = __importDefault(require("fs"));
32
32
  const path_1 = __importDefault(require("path"));
33
33
  const upload_serivce_1 = require("./upload_serivce");
34
+ const fs_extra_1 = require("fs-extra");
35
+ // type JsonException = messages.Exception
36
+ const object_path_1 = __importDefault(require("object-path"));
34
37
  const URL = process.env.NODE_ENV_BLINQ === 'dev'
35
38
  ? 'https://dev.api.blinq.io/api/runs'
36
39
  : process.env.NODE_ENV_BLINQ === 'local'
37
40
  ? 'http://localhost:5001/api/runs'
38
41
  : process.env.NODE_ENV_BLINQ === 'stage'
39
42
  ? 'https://stage.api.blinq.io/api/runs'
40
- : 'https://api.blinq.io/api/runs';
43
+ : process.env.NODE_ENV_BLINQ === 'prod'
44
+ ? 'https://api.blinq.io/api/runs'
45
+ : !process.env.NODE_ENV_BLINQ
46
+ ? 'https://api.blinq.io/api/runs'
47
+ : `${process.env.NODE_ENV_BLINQ}/api/runs`;
41
48
  const REPORT_SERVICE_URL = (_a = process.env.REPORT_SERVICE_URL) !== null && _a !== void 0 ? _a : URL;
42
49
  const BATCH_SIZE = 10;
43
50
  const MAX_RETRIES = 3;
@@ -65,12 +72,19 @@ class ReportGenerator {
65
72
  this.logs = [];
66
73
  this.networkLog = [];
67
74
  this.stepLogs = [];
75
+ this.stepNetworkLogs = [];
68
76
  this.runName = '';
77
+ this.ariaSnapshot = '';
78
+ this.initialAriaSnapshot = '';
79
+ this.testCaseLog = [];
80
+ this.loggingOverridden = false; // Flag to track if logging is overridden
69
81
  this.reportFolder = null;
70
82
  this.uploadService = new upload_serivce_1.RunUploadService(REPORT_SERVICE_URL, REPORT_SERVICE_TOKEN);
83
+ this.retryTestCaseId = null;
84
+ this.retryCount = 3;
71
85
  }
72
- async handleMessage(envelope) {
73
- if (envelope.meta && envelope.meta.runName) {
86
+ async handleMessage(envelope, reRunId) {
87
+ if (envelope.meta && 'runName' in envelope.meta) {
74
88
  this.runName = envelope.meta.runName;
75
89
  }
76
90
  const type = Object.keys(envelope)[0];
@@ -97,14 +111,35 @@ class ReportGenerator {
97
111
  case 'testRunStarted': {
98
112
  const testRunStarted = envelope[type];
99
113
  this.onTestRunStarted(testRunStarted);
114
+ await this.uploadService.createStatus('running');
100
115
  break;
101
116
  }
102
117
  case 'testCase': {
103
118
  const testCase = envelope[type];
119
+ // Initialize the log storage
120
+ this.testCaseLog = [];
121
+ if (!this.loggingOverridden) {
122
+ this.loggingOverridden = true;
123
+ // Store the original process.stdout.write, and process.stderr.write
124
+ const originalStdoutWrite = process.stdout.write;
125
+ const originalStderrWrite = process.stderr.write;
126
+ // Override process.stdout.write
127
+ process.stdout.write = (chunk, ...args) => {
128
+ this.testCaseLog.push(chunk.toString());
129
+ return originalStdoutWrite.call(process.stdout, chunk, ...args);
130
+ };
131
+ // Override process.stderr.write
132
+ process.stderr.write = (chunk, ...args) => {
133
+ this.testCaseLog.push(chunk.toString());
134
+ return originalStderrWrite.call(process.stderr, chunk, ...args);
135
+ };
136
+ }
137
+ // Call the onTestCase method
104
138
  this.onTestCase(testCase);
105
139
  break;
106
140
  }
107
141
  case 'testCaseStarted': {
142
+ this.retryTestCaseId = envelope[type].retryTestCaseId;
108
143
  const testCaseStarted = envelope[type];
109
144
  this.onTestCaseStarted(testCaseStarted);
110
145
  break;
@@ -126,13 +161,18 @@ class ReportGenerator {
126
161
  }
127
162
  case 'testCaseFinished': {
128
163
  const testCaseFinished = envelope[type];
129
- await this.onTestCaseFinished(testCaseFinished);
130
- break;
164
+ let reRunIdFinal = this.retryTestCaseId;
165
+ if (reRunId) {
166
+ reRunIdFinal = reRunId;
167
+ }
168
+ // Call the onTestCaseFinished method
169
+ const result = await this.onTestCaseFinished(testCaseFinished, reRunIdFinal);
170
+ return result;
131
171
  }
132
172
  // case "hook": { break} // After Hook
133
173
  case 'testRunFinished': {
134
174
  const testRunFinished = envelope[type];
135
- this.onTestRunFinished(testRunFinished);
175
+ await this.onTestRunFinished(testRunFinished);
136
176
  break;
137
177
  }
138
178
  // case "parameterType" : { break}
@@ -263,7 +303,10 @@ class ReportGenerator {
263
303
  result: {
264
304
  status: 'UNKNOWN',
265
305
  },
306
+ networkData: [],
266
307
  webLog: [],
308
+ data: {},
309
+ ariaSnapshot: this.ariaSnapshot,
267
310
  });
268
311
  return this.stepReportMap.get(pickleStep.id);
269
312
  });
@@ -306,6 +349,14 @@ class ReportGenerator {
306
349
  this.reportFolder = body.replaceAll('\\', '/');
307
350
  return;
308
351
  }
352
+ if (mediaType === 'application/json+snapshot-before') {
353
+ this.initialAriaSnapshot = body;
354
+ return;
355
+ }
356
+ if (mediaType === 'application/json+snapshot-after') {
357
+ this.ariaSnapshot = body;
358
+ return;
359
+ }
309
360
  if (mediaType === 'application/json+env') {
310
361
  const data = JSON.parse(body);
311
362
  this.report.env = data;
@@ -325,6 +376,7 @@ class ReportGenerator {
325
376
  const networkLog = JSON.parse(body);
326
377
  if (this.networkLog.length < 1000)
327
378
  this.networkLog.push(networkLog);
379
+ this.stepNetworkLogs.push(networkLog);
328
380
  }
329
381
  const testStep = this.testStepMap.get(testStepId);
330
382
  if (testStep.pickleStepId === undefined)
@@ -334,12 +386,77 @@ class ReportGenerator {
334
386
  const command = JSON.parse(body);
335
387
  stepProgess.commands.push(command);
336
388
  }
389
+ else if (mediaType === 'application/json+trace') {
390
+ const data = JSON.parse(body);
391
+ stepProgess.traceFilePath = data.traceFilePath;
392
+ }
393
+ if (mediaType === 'application/json+bruno') {
394
+ try {
395
+ const data = JSON.parse(body);
396
+ stepProgess.brunoData = data;
397
+ }
398
+ catch (error) {
399
+ console.error('Error parsing bruno data:', error);
400
+ }
401
+ }
402
+ if (mediaType === 'application/json+intercept-results') {
403
+ try {
404
+ const data = JSON.parse(body);
405
+ stepProgess.interceptResults = data;
406
+ }
407
+ catch (error) {
408
+ console.error('Error parsing intercept results:', error);
409
+ }
410
+ }
411
+ }
412
+ getFailedTestStepResult({ commands, startTime, endTime, result, }) {
413
+ for (const command of commands) {
414
+ if (command.result.status === 'FAILED') {
415
+ return {
416
+ status: 'FAILED',
417
+ message: command.result.message,
418
+ startTime,
419
+ endTime,
420
+ };
421
+ }
422
+ }
423
+ return {
424
+ status: 'FAILED',
425
+ startTime,
426
+ endTime,
427
+ message: result.message,
428
+ };
337
429
  }
338
430
  onTestStepFinished(testStepFinished) {
339
431
  const { testStepId, testStepResult, timestamp } = testStepFinished;
340
432
  const testStep = this.testStepMap.get(testStepId);
341
433
  if (testStep.pickleStepId === undefined) {
342
434
  if (testStepResult.status === 'FAILED') {
435
+ const testCase = this.testCaseReportMap.get(testStepFinished.testCaseStartedId);
436
+ const type = testCase.steps[0].result.status === 'UNKNOWN' ? 'Before' : 'After';
437
+ const hookStep = {
438
+ ariaSnapshot: null,
439
+ commands: [],
440
+ keyword: type,
441
+ data: {},
442
+ networkData: [],
443
+ result: {
444
+ status: 'FAILED',
445
+ message: testStepResult.message,
446
+ startTime: this.getTimeStamp(timestamp),
447
+ endTime: this.getTimeStamp(timestamp),
448
+ },
449
+ text: 'Failed hook',
450
+ type,
451
+ webLog: [],
452
+ };
453
+ if (type === 'Before') {
454
+ testCase.steps = [hookStep, ...testCase.steps];
455
+ }
456
+ else {
457
+ testCase.steps = [...testCase.steps, hookStep];
458
+ }
459
+ this.testCaseReportMap.set(testStepFinished.testCaseStartedId, testCase);
343
460
  console.error(`Before/After hook failed with message: ${testStepResult.message}`);
344
461
  }
345
462
  return;
@@ -378,18 +495,73 @@ class ReportGenerator {
378
495
  catch (error) {
379
496
  console.log('Error reading data.json');
380
497
  }
381
- stepProgess.result = {
382
- status: testStepResult.status,
383
- startTime: prevStepResult.startTime,
384
- endTime: this.getTimeStamp(timestamp),
385
- message: testStepResult.message,
386
- // exception: testStepResult.exception,
387
- };
498
+ if (testStepResult.status === 'FAILED') {
499
+ stepProgess.result = this.getFailedTestStepResult({
500
+ commands: stepProgess.commands,
501
+ startTime: prevStepResult.startTime,
502
+ endTime: this.getTimeStamp(timestamp),
503
+ result: testStepResult,
504
+ });
505
+ }
506
+ else {
507
+ stepProgess.result = {
508
+ status: testStepResult.status,
509
+ startTime: prevStepResult.startTime,
510
+ endTime: this.getTimeStamp(timestamp),
511
+ };
512
+ }
388
513
  stepProgess.webLog = this.stepLogs;
514
+ stepProgess.networkData = this.stepNetworkLogs;
515
+ stepProgess.ariaSnapshot = this.ariaSnapshot;
516
+ this.ariaSnapshot = '';
517
+ this.stepNetworkLogs = [];
389
518
  this.stepLogs = [];
390
519
  if (Object.keys(data).length > 0) {
391
520
  stepProgess.data = data;
521
+ const id = testStepFinished.testCaseStartedId;
522
+ const parameters = this.testCaseReportMap.get(id).parameters;
523
+ const _parameters = {};
524
+ Object.keys(parameters).map((key) => {
525
+ var _a;
526
+ const valueParam = parameters[key].toString();
527
+ if (valueParam.startsWith('{{') && valueParam.endsWith('}}')) {
528
+ const path = valueParam.slice(2, -2).split('.');
529
+ let value = String((_a = object_path_1.default.get(data, path)) !== null && _a !== void 0 ? _a : valueParam);
530
+ if (value) {
531
+ if (value.startsWith('secret:')) {
532
+ value = 'secret:****';
533
+ }
534
+ else if (value.startsWith('totp:')) {
535
+ value = 'totp:****';
536
+ }
537
+ else if (value.startsWith('mask:')) {
538
+ value = 'mask:****';
539
+ }
540
+ _parameters[key] = value;
541
+ }
542
+ }
543
+ else {
544
+ _parameters[key] = parameters[key];
545
+ }
546
+ });
547
+ this.report.testCases.find((testCase) => {
548
+ return testCase.id === id;
549
+ }).parameters = _parameters;
392
550
  }
551
+ // if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
552
+ // this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH
553
+ // if (!fs.existsSync(this.reportFolder)) {
554
+ // fs.mkdirSync(this.reportFolder)
555
+ // }
556
+ // const reportFilePath = path.join(
557
+ // this.reportFolder,
558
+ // `report.json`
559
+ // )
560
+ // writeFileSync(reportFilePath, JSON.stringify(this.report, null, 2))
561
+ // return undefined
562
+ // // } else {
563
+ // // return await this.uploadTestCase(testProgress, reRunId)
564
+ // }
393
565
  }
394
566
  getLogFileContent() {
395
567
  let projectPath = process.cwd();
@@ -416,6 +588,12 @@ class ReportGenerator {
416
588
  }
417
589
  }
418
590
  getTestCaseResult(steps) {
591
+ if (steps[0] && steps[0].result.status === 'SKIPPED') {
592
+ return {
593
+ status: 'FAILED',
594
+ message: 'Test skipped due to failure in before hooks',
595
+ };
596
+ }
419
597
  for (const step of steps) {
420
598
  switch (step.result.status) {
421
599
  case 'FAILED':
@@ -437,24 +615,79 @@ class ReportGenerator {
437
615
  status: 'PASSED',
438
616
  };
439
617
  }
440
- async onTestCaseFinished(testCaseFinished) {
618
+ async onTestCaseFinished(testCaseFinished, reRunId) {
441
619
  const { testCaseStartedId, timestamp } = testCaseFinished;
442
620
  const testProgress = this.testCaseReportMap.get(testCaseStartedId);
443
621
  const prevResult = testProgress.result;
444
622
  const steps = Object.values(testProgress.steps);
445
623
  const result = this.getTestCaseResult(steps);
624
+ if (result.status === 'PASSED' && reRunId) {
625
+ this.uploadService.updateProjectAnalytics(process.env.PROJECT_ID);
626
+ }
627
+ const endTime = this.getTimeStamp(timestamp);
446
628
  testProgress.result = {
447
629
  ...result,
448
630
  startTime: prevResult.startTime,
449
- endTime: this.getTimeStamp(timestamp),
631
+ endTime,
450
632
  };
451
633
  testProgress.webLog = this.logs;
452
634
  testProgress.networkLog = this.networkLog;
635
+ testProgress.initialAriaSnapshot = this.initialAriaSnapshot;
636
+ if (process.env.TRACE) {
637
+ testProgress.traceFileId = path_1.default.join(`trace-${testCaseStartedId}.zip`);
638
+ }
639
+ this.initialAriaSnapshot = '';
453
640
  this.networkLog = [];
454
641
  this.logs = [];
455
- await this.uploadTestCase(testProgress);
642
+ if (this.testCaseLog &&
643
+ this.testCaseLog.length > 0 &&
644
+ !testProgress.logFileId) {
645
+ // Create the logs directory
646
+ const logsDir = path_1.default.join(this.reportFolder, 'editorLogs');
647
+ const fileName = `testCaseLog_${testCaseStartedId}.log`;
648
+ const filePath = path_1.default.join(logsDir, fileName);
649
+ // Ensure the logs directory exists
650
+ fs_1.default.mkdirSync(logsDir, { recursive: true });
651
+ // Write the logs to the file
652
+ fs_1.default.writeFileSync(filePath, this.testCaseLog.join('\n'), 'utf8');
653
+ // Store this ID in the testProgress object so it can be accessed later
654
+ testProgress.logFileId = testCaseStartedId;
655
+ }
656
+ this.testCaseLog = [];
657
+ if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
658
+ this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH;
659
+ if (!fs_1.default.existsSync(this.reportFolder)) {
660
+ fs_1.default.mkdirSync(this.reportFolder);
661
+ }
662
+ const reportFilePath = path_1.default.join(this.reportFolder, `${endTime}_${testProgress.scenarioName}.json`);
663
+ (0, fs_extra_1.writeFileSync)(reportFilePath, JSON.stringify(testProgress, null, 2));
664
+ return undefined;
665
+ }
666
+ else {
667
+ return await this.uploadTestCase(testProgress, reRunId);
668
+ }
456
669
  }
457
- async uploadTestCase(testCase) {
670
+ async uploadTestCase(testCase, rerunId) {
671
+ let data = null;
672
+ for (let attempt = 1; attempt <= this.retryCount; attempt++) {
673
+ try {
674
+ data = await this.tryUpload(testCase, rerunId);
675
+ break;
676
+ }
677
+ catch (e) {
678
+ console.error(`Attempt ${attempt} to upload testcase failed:`, e);
679
+ if (attempt === this.retryCount) {
680
+ console.error('All retry attempts failed, failed to upload testcase.');
681
+ }
682
+ else {
683
+ const waitTime = 1000 * 2 ** (attempt - 1); //? exponential backoff: 1s, 2s, 4s...
684
+ await new Promise((r) => setTimeout(r, waitTime));
685
+ }
686
+ }
687
+ }
688
+ return data;
689
+ }
690
+ async tryUpload(testCase, rerunId) {
458
691
  let runId = '';
459
692
  let projectId = '';
460
693
  if (!process.env.UPLOADING_TEST_CASE) {
@@ -472,7 +705,7 @@ class ReportGenerator {
472
705
  projectId = process.env.PROJECT_ID;
473
706
  }
474
707
  else {
475
- const runDoc = await this.uploadService.createRunDocument(this.runName);
708
+ const runDoc = await this.uploadService.createRunDocument(this.runName, testCase.env);
476
709
  runId = runDoc._id;
477
710
  projectId = runDoc.project_id;
478
711
  if (!process.env.IGNORE_ENV_VARIABLES) {
@@ -480,10 +713,9 @@ class ReportGenerator {
480
713
  process.env.PROJECT_ID = projectId;
481
714
  }
482
715
  }
483
- await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder);
484
- }
485
- catch (e) {
486
- console.error('Error uploading test case:', e);
716
+ const data = await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder, rerunId);
717
+ this.writeTestCaseReportToDisk(testCase);
718
+ return data;
487
719
  }
488
720
  finally {
489
721
  const arrRem = JSON.parse(process.env.UPLOADING_TEST_CASE);
@@ -491,7 +723,30 @@ class ReportGenerator {
491
723
  process.env.UPLOADING_TEST_CASE = JSON.stringify(arrRem);
492
724
  }
493
725
  }
494
- onTestRunFinished(testRunFinished) {
726
+ writeTestCaseReportToDisk(testCase) {
727
+ var _a;
728
+ const reportFolder = (_a = this.reportFolder) !== null && _a !== void 0 ? _a : process.env.TESTCASE_REPORT_FOLDER_PATH;
729
+ if (!reportFolder) {
730
+ console.error('Report folder is not defined');
731
+ return;
732
+ }
733
+ try {
734
+ let i = 0;
735
+ while (fs_1.default.existsSync(path_1.default.join(reportFolder, `${i}`))) {
736
+ i++;
737
+ }
738
+ fs_1.default.mkdirSync(path_1.default.join(reportFolder, `${i}`));
739
+ //exclude network log from the saved report
740
+ const networkLog = testCase.networkLog;
741
+ delete testCase.networkLog;
742
+ fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `report.json`), JSON.stringify(testCase, null, 2));
743
+ fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `network.json`), JSON.stringify(networkLog, null, 2));
744
+ }
745
+ catch (error) {
746
+ console.error('Error writing test case report to disk:', error);
747
+ }
748
+ }
749
+ async onTestRunFinished(testRunFinished) {
495
750
  const { timestamp, success, message } = testRunFinished;
496
751
  const prevResult = this.report.result;
497
752
  this.report.result = {
@@ -501,6 +756,7 @@ class ReportGenerator {
501
756
  message,
502
757
  // exception,
503
758
  };
759
+ await this.uploadService.createStatus(success ? 'passed' : 'failed');
504
760
  }
505
761
  }
506
762
  exports.default = ReportGenerator;