@dev-blinq/cucumber-js 1.0.90-main → 1.0.90-stage

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 (30) hide show
  1. package/bin/download-install.js +14 -2
  2. package/lib/formatter/api.js +7 -1
  3. package/lib/formatter/api.js.map +1 -1
  4. package/lib/formatter/bvt_analysis_formatter.d.ts +13 -1
  5. package/lib/formatter/bvt_analysis_formatter.js +139 -50
  6. package/lib/formatter/bvt_analysis_formatter.js.map +1 -1
  7. package/lib/formatter/feature_data_format.js +0 -1
  8. package/lib/formatter/feature_data_format.js.map +1 -1
  9. package/lib/formatter/helpers/constants.d.ts +50 -0
  10. package/lib/formatter/helpers/constants.js +60 -0
  11. package/lib/formatter/helpers/constants.js.map +1 -0
  12. package/lib/formatter/helpers/report_generator.d.ts +19 -2
  13. package/lib/formatter/helpers/report_generator.js +290 -26
  14. package/lib/formatter/helpers/report_generator.js.map +1 -1
  15. package/lib/formatter/helpers/test_case_attempt_formatter.js +1 -1
  16. package/lib/formatter/helpers/test_case_attempt_formatter.js.map +1 -1
  17. package/lib/formatter/helpers/upload_serivce.d.ts +13 -1
  18. package/lib/formatter/helpers/upload_serivce.js +71 -4
  19. package/lib/formatter/helpers/upload_serivce.js.map +1 -1
  20. package/lib/formatter/helpers/uploader.js +11 -14
  21. package/lib/formatter/helpers/uploader.js.map +1 -1
  22. package/lib/formatter/summary_formatter.js +4 -0
  23. package/lib/formatter/summary_formatter.js.map +1 -1
  24. package/lib/runtime/test_case_runner.d.ts +1 -0
  25. package/lib/runtime/test_case_runner.js +10 -1
  26. package/lib/runtime/test_case_runner.js.map +1 -1
  27. package/lib/version.d.ts +1 -1
  28. package/lib/version.js +1 -1
  29. package/lib/version.js.map +1 -1
  30. package/package.json +4 -2
@@ -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;QACtC,CAAC,CAAC,WAAG,CAAC,sBAAsB;QAC5B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,OAAO;YACxC,CAAC,CAAC,aAAK,CAAC,sBAAsB;YAC9B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,MAAM;gBACvC,CAAC,CAAC,YAAI,CAAC,sBAAsB;gBAC7B,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc;oBAC7B,CAAC,CAAC,YAAI,CAAC,sBAAsB;oBAC7B,CAAC,CAAC,cAAM,CAAA,CAAC,sBAAsB;AAEnC,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"]}
@@ -48,7 +48,6 @@ type JsonCommand = {
48
48
  text: string;
49
49
  screenshotId?: string;
50
50
  result: JsonCommandResult;
51
- webLog?: webLog[];
52
51
  netWorkLog?: any[];
53
52
  };
54
53
  type webLog = {
@@ -63,7 +62,13 @@ export type JsonStep = {
63
62
  text: string;
64
63
  commands: JsonCommand[];
65
64
  result: JsonStepResult;
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,8 +85,10 @@ 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;
@@ -113,10 +120,16 @@ export default class ReportGenerator {
113
120
  private scenarioIterationCountMap;
114
121
  private logs;
115
122
  private networkLog;
123
+ private stepLogs;
124
+ private stepNetworkLogs;
116
125
  private runName;
126
+ private ariaSnapshot;
127
+ private initialAriaSnapshot;
128
+ private testCaseLog;
129
+ private loggingOverridden;
117
130
  reportFolder: null | string;
118
131
  private uploadService;
119
- handleMessage(envelope: EnvelopeWithMetaMessage): Promise<void>;
132
+ handleMessage(envelope: EnvelopeWithMetaMessage | messages.Envelope, reRunId?: string): Promise<any>;
120
133
  getReport(): JsonReport;
121
134
  private handleParseError;
122
135
  private onGherkinDocument;
@@ -129,11 +142,15 @@ export default class ReportGenerator {
129
142
  private onTestCaseStarted;
130
143
  private onTestStepStarted;
131
144
  private onAttachment;
145
+ private getFailedTestStepResult;
132
146
  private onTestStepFinished;
133
147
  getLogFileContent(): any;
134
148
  private getTestCaseResult;
135
149
  private onTestCaseFinished;
150
+ private readonly retryCount;
136
151
  private uploadTestCase;
152
+ private tryUpload;
153
+ private writeTestCaseReportToDisk;
137
154
  private onTestRunFinished;
138
155
  }
139
156
  export {};
@@ -1,19 +1,50 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  var _a, _b;
6
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
+ const messages = __importStar(require("@cucumber/messages"));
7
31
  const fs_1 = __importDefault(require("fs"));
8
32
  const path_1 = __importDefault(require("path"));
9
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"));
10
37
  const URL = process.env.NODE_ENV_BLINQ === 'dev'
11
38
  ? 'https://dev.api.blinq.io/api/runs'
12
39
  : process.env.NODE_ENV_BLINQ === 'local'
13
40
  ? 'http://localhost:5001/api/runs'
14
41
  : process.env.NODE_ENV_BLINQ === 'stage'
15
42
  ? 'https://stage.api.blinq.io/api/runs'
16
- : '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`;
17
48
  const REPORT_SERVICE_URL = (_a = process.env.REPORT_SERVICE_URL) !== null && _a !== void 0 ? _a : URL;
18
49
  const BATCH_SIZE = 10;
19
50
  const MAX_RETRIES = 3;
@@ -40,12 +71,19 @@ class ReportGenerator {
40
71
  this.scenarioIterationCountMap = new Map();
41
72
  this.logs = [];
42
73
  this.networkLog = [];
74
+ this.stepLogs = [];
75
+ this.stepNetworkLogs = [];
43
76
  this.runName = '';
77
+ this.ariaSnapshot = '';
78
+ this.initialAriaSnapshot = '';
79
+ this.testCaseLog = [];
80
+ this.loggingOverridden = false; // Flag to track if logging is overridden
44
81
  this.reportFolder = null;
45
82
  this.uploadService = new upload_serivce_1.RunUploadService(REPORT_SERVICE_URL, REPORT_SERVICE_TOKEN);
83
+ this.retryCount = 3;
46
84
  }
47
- async handleMessage(envelope) {
48
- if (envelope.meta && envelope.meta.runName) {
85
+ async handleMessage(envelope, reRunId) {
86
+ if (envelope.meta && 'runName' in envelope.meta) {
49
87
  this.runName = envelope.meta.runName;
50
88
  }
51
89
  const type = Object.keys(envelope)[0];
@@ -72,10 +110,30 @@ class ReportGenerator {
72
110
  case 'testRunStarted': {
73
111
  const testRunStarted = envelope[type];
74
112
  this.onTestRunStarted(testRunStarted);
113
+ await this.uploadService.createStatus('running');
75
114
  break;
76
115
  }
77
116
  case 'testCase': {
78
117
  const testCase = envelope[type];
118
+ // Initialize the log storage
119
+ this.testCaseLog = [];
120
+ if (!this.loggingOverridden) {
121
+ this.loggingOverridden = true;
122
+ // Store the original process.stdout.write, and process.stderr.write
123
+ const originalStdoutWrite = process.stdout.write;
124
+ const originalStderrWrite = process.stderr.write;
125
+ // Override process.stdout.write
126
+ process.stdout.write = (chunk, ...args) => {
127
+ this.testCaseLog.push(chunk.toString());
128
+ return originalStdoutWrite.call(process.stdout, chunk, ...args);
129
+ };
130
+ // Override process.stderr.write
131
+ process.stderr.write = (chunk, ...args) => {
132
+ this.testCaseLog.push(chunk.toString());
133
+ return originalStderrWrite.call(process.stderr, chunk, ...args);
134
+ };
135
+ }
136
+ // Call the onTestCase method
79
137
  this.onTestCase(testCase);
80
138
  break;
81
139
  }
@@ -101,13 +159,14 @@ class ReportGenerator {
101
159
  }
102
160
  case 'testCaseFinished': {
103
161
  const testCaseFinished = envelope[type];
104
- await this.onTestCaseFinished(testCaseFinished);
105
- break;
162
+ // Call the onTestCaseFinished method
163
+ const result = await this.onTestCaseFinished(testCaseFinished, reRunId);
164
+ return result;
106
165
  }
107
166
  // case "hook": { break} // After Hook
108
167
  case 'testRunFinished': {
109
168
  const testRunFinished = envelope[type];
110
- this.onTestRunFinished(testRunFinished);
169
+ await this.onTestRunFinished(testRunFinished);
111
170
  break;
112
171
  }
113
172
  // case "parameterType" : { break}
@@ -238,6 +297,10 @@ class ReportGenerator {
238
297
  result: {
239
298
  status: 'UNKNOWN',
240
299
  },
300
+ networkData: [],
301
+ webLog: [],
302
+ data: {},
303
+ ariaSnapshot: this.ariaSnapshot,
241
304
  });
242
305
  return this.stepReportMap.get(pickleStep.id);
243
306
  });
@@ -280,6 +343,14 @@ class ReportGenerator {
280
343
  this.reportFolder = body.replaceAll('\\', '/');
281
344
  return;
282
345
  }
346
+ if (mediaType === 'application/json+snapshot-before') {
347
+ this.initialAriaSnapshot = body;
348
+ return;
349
+ }
350
+ if (mediaType === 'application/json+snapshot-after') {
351
+ this.ariaSnapshot = body;
352
+ return;
353
+ }
283
354
  if (mediaType === 'application/json+env') {
284
355
  const data = JSON.parse(body);
285
356
  this.report.env = data;
@@ -290,13 +361,16 @@ class ReportGenerator {
290
361
  }
291
362
  if (mediaType === 'application/json+log') {
292
363
  const log = JSON.parse(body);
293
- if (this.logs.length < 1000)
364
+ if (this.logs.length < 1000) {
294
365
  this.logs.push(log);
366
+ this.stepLogs.push(log);
367
+ }
295
368
  }
296
369
  if (mediaType === 'application/json+network') {
297
370
  const networkLog = JSON.parse(body);
298
371
  if (this.networkLog.length < 1000)
299
372
  this.networkLog.push(networkLog);
373
+ this.stepNetworkLogs.push(networkLog);
300
374
  }
301
375
  const testStep = this.testStepMap.get(testStepId);
302
376
  if (testStep.pickleStepId === undefined)
@@ -306,6 +380,47 @@ class ReportGenerator {
306
380
  const command = JSON.parse(body);
307
381
  stepProgess.commands.push(command);
308
382
  }
383
+ else if (mediaType === 'application/json+trace') {
384
+ const data = JSON.parse(body);
385
+ stepProgess.traceFilePath = data.traceFilePath;
386
+ }
387
+ if (mediaType === 'application/json+bruno') {
388
+ try {
389
+ const data = JSON.parse(body);
390
+ stepProgess.brunoData = data;
391
+ }
392
+ catch (error) {
393
+ console.error('Error parsing bruno data:', error);
394
+ }
395
+ }
396
+ if (mediaType === 'application/json+intercept-results') {
397
+ console.log('Intercept results received:', body);
398
+ try {
399
+ const data = JSON.parse(body);
400
+ stepProgess.interceptResults = data;
401
+ }
402
+ catch (error) {
403
+ console.error('Error parsing intercept results:', error);
404
+ }
405
+ }
406
+ }
407
+ getFailedTestStepResult({ commands, startTime, endTime, result, }) {
408
+ for (const command of commands) {
409
+ if (command.result.status === 'FAILED') {
410
+ return {
411
+ status: 'FAILED',
412
+ message: command.result.message,
413
+ startTime,
414
+ endTime,
415
+ };
416
+ }
417
+ }
418
+ return {
419
+ status: 'FAILED',
420
+ startTime,
421
+ endTime,
422
+ message: result.message,
423
+ };
309
424
  }
310
425
  onTestStepFinished(testStepFinished) {
311
426
  const { testStepId, testStepResult, timestamp } = testStepFinished;
@@ -316,6 +431,25 @@ class ReportGenerator {
316
431
  }
317
432
  return;
318
433
  }
434
+ if (testStepResult.status === 'UNDEFINED') {
435
+ const step = this.stepReportMap.get(testStep.pickleStepId);
436
+ const stepName = step ? step.keyword + ' ' + step.text : 'Undefined step';
437
+ const undefinedCommand = {
438
+ testStepId: testStepId,
439
+ body: JSON.stringify({
440
+ type: 'error',
441
+ text: 'Undefined step: ' + stepName,
442
+ result: {
443
+ status: 'FAILED',
444
+ startTime: this.getTimeStamp(timestamp),
445
+ endTime: this.getTimeStamp(timestamp),
446
+ },
447
+ }),
448
+ mediaType: 'application/json',
449
+ contentEncoding: messages.AttachmentContentEncoding.IDENTITY,
450
+ };
451
+ this.onAttachment(undefinedCommand);
452
+ }
319
453
  const stepProgess = this.stepReportMap.get(testStep.pickleStepId);
320
454
  const prevStepResult = stepProgess.result;
321
455
  let data = {};
@@ -331,16 +465,72 @@ class ReportGenerator {
331
465
  catch (error) {
332
466
  console.log('Error reading data.json');
333
467
  }
334
- stepProgess.result = {
335
- status: testStepResult.status,
336
- startTime: prevStepResult.startTime,
337
- endTime: this.getTimeStamp(timestamp),
338
- message: testStepResult.message,
339
- // exception: testStepResult.exception,
340
- };
468
+ if (testStepResult.status === 'FAILED') {
469
+ stepProgess.result = this.getFailedTestStepResult({
470
+ commands: stepProgess.commands,
471
+ startTime: prevStepResult.startTime,
472
+ endTime: this.getTimeStamp(timestamp),
473
+ result: testStepResult,
474
+ });
475
+ }
476
+ else {
477
+ stepProgess.result = {
478
+ status: testStepResult.status,
479
+ startTime: prevStepResult.startTime,
480
+ endTime: this.getTimeStamp(timestamp),
481
+ };
482
+ }
483
+ stepProgess.webLog = this.stepLogs;
484
+ stepProgess.networkData = this.stepNetworkLogs;
485
+ stepProgess.ariaSnapshot = this.ariaSnapshot;
486
+ this.ariaSnapshot = '';
487
+ this.stepNetworkLogs = [];
488
+ this.stepLogs = [];
341
489
  if (Object.keys(data).length > 0) {
342
490
  stepProgess.data = data;
491
+ const id = testStepFinished.testCaseStartedId;
492
+ const parameters = this.testCaseReportMap.get(id).parameters;
493
+ const _parameters = {};
494
+ Object.keys(parameters).map((key) => {
495
+ if (parameters[key].startsWith('{{') &&
496
+ parameters[key].endsWith('}}')) {
497
+ const path = parameters[key].slice(2, -2).split('.');
498
+ let value = String(object_path_1.default.get(data, path));
499
+ if (value) {
500
+ if (value.startsWith('secret:')) {
501
+ value = 'secret:****';
502
+ }
503
+ else if (value.startsWith('totp:')) {
504
+ value = 'totp:****';
505
+ }
506
+ else if (value.startsWith('mask:')) {
507
+ value = 'mask:****';
508
+ }
509
+ _parameters[key] = value;
510
+ }
511
+ }
512
+ else {
513
+ _parameters[key] = parameters[key];
514
+ }
515
+ });
516
+ this.report.testCases.find((testCase) => {
517
+ return testCase.id === id;
518
+ }).parameters = _parameters;
343
519
  }
520
+ // if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
521
+ // this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH
522
+ // if (!fs.existsSync(this.reportFolder)) {
523
+ // fs.mkdirSync(this.reportFolder)
524
+ // }
525
+ // const reportFilePath = path.join(
526
+ // this.reportFolder,
527
+ // `report.json`
528
+ // )
529
+ // writeFileSync(reportFilePath, JSON.stringify(this.report, null, 2))
530
+ // return undefined
531
+ // // } else {
532
+ // // return await this.uploadTestCase(testProgress, reRunId)
533
+ // }
344
534
  }
345
535
  getLogFileContent() {
346
536
  let projectPath = process.cwd();
@@ -388,24 +578,71 @@ class ReportGenerator {
388
578
  status: 'PASSED',
389
579
  };
390
580
  }
391
- async onTestCaseFinished(testCaseFinished) {
581
+ async onTestCaseFinished(testCaseFinished, reRunId) {
392
582
  const { testCaseStartedId, timestamp } = testCaseFinished;
393
583
  const testProgress = this.testCaseReportMap.get(testCaseStartedId);
394
584
  const prevResult = testProgress.result;
395
585
  const steps = Object.values(testProgress.steps);
396
586
  const result = this.getTestCaseResult(steps);
587
+ const endTime = this.getTimeStamp(timestamp);
397
588
  testProgress.result = {
398
589
  ...result,
399
590
  startTime: prevResult.startTime,
400
- endTime: this.getTimeStamp(timestamp),
591
+ endTime,
401
592
  };
402
593
  testProgress.webLog = this.logs;
403
594
  testProgress.networkLog = this.networkLog;
595
+ testProgress.initialAriaSnapshot = this.initialAriaSnapshot;
596
+ this.initialAriaSnapshot = '';
404
597
  this.networkLog = [];
405
598
  this.logs = [];
406
- await this.uploadTestCase(testProgress);
599
+ if (this.testCaseLog && this.testCaseLog.length > 0) {
600
+ // Create the logs directory
601
+ const logsDir = path_1.default.join(this.reportFolder, 'editorLogs');
602
+ const fileName = `testCaseLog_${testCaseStartedId}.log`;
603
+ const filePath = path_1.default.join(logsDir, fileName);
604
+ // Ensure the logs directory exists
605
+ fs_1.default.mkdirSync(logsDir, { recursive: true });
606
+ // Write the logs to the file
607
+ fs_1.default.writeFileSync(filePath, this.testCaseLog.join('\n'), 'utf8');
608
+ // Store this ID in the testProgress object so it can be accessed later
609
+ testProgress.logFileId = testCaseStartedId;
610
+ }
611
+ this.testCaseLog = [];
612
+ if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
613
+ this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH;
614
+ if (!fs_1.default.existsSync(this.reportFolder)) {
615
+ fs_1.default.mkdirSync(this.reportFolder);
616
+ }
617
+ const reportFilePath = path_1.default.join(this.reportFolder, `${endTime}_${testProgress.scenarioName}.json`);
618
+ (0, fs_extra_1.writeFileSync)(reportFilePath, JSON.stringify(testProgress, null, 2));
619
+ return undefined;
620
+ }
621
+ else {
622
+ return await this.uploadTestCase(testProgress, reRunId);
623
+ }
407
624
  }
408
- async uploadTestCase(testCase) {
625
+ async uploadTestCase(testCase, rerunId) {
626
+ let data = null;
627
+ for (let attempt = 1; attempt <= this.retryCount; attempt++) {
628
+ try {
629
+ data = await this.tryUpload(testCase, rerunId);
630
+ break;
631
+ }
632
+ catch (e) {
633
+ console.error(`Attempt ${attempt} to upload testcase failed:`, e);
634
+ if (attempt === this.retryCount) {
635
+ console.error('All retry attempts failed, failed to upload testcase.');
636
+ }
637
+ else {
638
+ const waitTime = 1000 * 2 ** (attempt - 1); //? exponential backoff: 1s, 2s, 4s...
639
+ await new Promise((r) => setTimeout(r, waitTime));
640
+ }
641
+ }
642
+ }
643
+ return data;
644
+ }
645
+ async tryUpload(testCase, rerunId) {
409
646
  let runId = '';
410
647
  let projectId = '';
411
648
  if (!process.env.UPLOADING_TEST_CASE) {
@@ -416,7 +653,9 @@ class ReportGenerator {
416
653
  anyRemArr.push(randomID);
417
654
  process.env.UPLOADING_TEST_CASE = JSON.stringify(anyRemArr);
418
655
  try {
419
- if (process.env.RUN_ID && process.env.PROJECT_ID) {
656
+ if (process.env.RUN_ID &&
657
+ process.env.PROJECT_ID &&
658
+ !process.env.IGNORE_ENV_VARIABLES) {
420
659
  runId = process.env.RUN_ID;
421
660
  projectId = process.env.PROJECT_ID;
422
661
  }
@@ -424,13 +663,14 @@ class ReportGenerator {
424
663
  const runDoc = await this.uploadService.createRunDocument(this.runName);
425
664
  runId = runDoc._id;
426
665
  projectId = runDoc.project_id;
427
- process.env.RUN_ID = runId;
428
- process.env.PROJECT_ID = projectId;
666
+ if (!process.env.IGNORE_ENV_VARIABLES) {
667
+ process.env.RUN_ID = runId;
668
+ process.env.PROJECT_ID = projectId;
669
+ }
429
670
  }
430
- await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder);
431
- }
432
- catch (e) {
433
- console.error('Error uploading test case:', e);
671
+ const data = await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder, rerunId);
672
+ this.writeTestCaseReportToDisk(testCase);
673
+ return data;
434
674
  }
435
675
  finally {
436
676
  const arrRem = JSON.parse(process.env.UPLOADING_TEST_CASE);
@@ -438,7 +678,30 @@ class ReportGenerator {
438
678
  process.env.UPLOADING_TEST_CASE = JSON.stringify(arrRem);
439
679
  }
440
680
  }
441
- onTestRunFinished(testRunFinished) {
681
+ writeTestCaseReportToDisk(testCase) {
682
+ var _a;
683
+ const reportFolder = (_a = this.reportFolder) !== null && _a !== void 0 ? _a : process.env.TESTCASE_REPORT_FOLDER_PATH;
684
+ if (!reportFolder) {
685
+ console.error('Report folder is not defined');
686
+ return;
687
+ }
688
+ try {
689
+ let i = 0;
690
+ while (fs_1.default.existsSync(path_1.default.join(reportFolder, `${i}`))) {
691
+ i++;
692
+ }
693
+ fs_1.default.mkdirSync(path_1.default.join(reportFolder, `${i}`));
694
+ //exclude network log from the saved report
695
+ const networkLog = testCase.networkLog;
696
+ delete testCase.networkLog;
697
+ fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `report.json`), JSON.stringify(testCase, null, 2));
698
+ fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `network.json`), JSON.stringify(networkLog, null, 2));
699
+ }
700
+ catch (error) {
701
+ console.error('Error writing test case report to disk:', error);
702
+ }
703
+ }
704
+ async onTestRunFinished(testRunFinished) {
442
705
  const { timestamp, success, message } = testRunFinished;
443
706
  const prevResult = this.report.result;
444
707
  this.report.result = {
@@ -448,6 +711,7 @@ class ReportGenerator {
448
711
  message,
449
712
  // exception,
450
713
  };
714
+ await this.uploadService.createStatus(success ? 'passed' : 'failed');
451
715
  }
452
716
  }
453
717
  exports.default = ReportGenerator;