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

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 +13 -1
  15. package/lib/formatter/bvt_analysis_formatter.js +199 -58
  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 +6 -0
  20. package/lib/formatter/helpers/constants.js +14 -4
  21. package/lib/formatter/helpers/constants.js.map +1 -1
  22. package/lib/formatter/helpers/report_generator.d.ts +21 -2
  23. package/lib/formatter/helpers/report_generator.js +282 -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 +197 -46
  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
@@ -22,6 +22,12 @@ export declare const STAGE: {
22
22
  RUNS: string;
23
23
  STORAGE: string;
24
24
  };
25
+ export declare const CUSTOM: {
26
+ SSO: string;
27
+ WORKSPACE: string;
28
+ RUNS: string;
29
+ STORAGE: string;
30
+ };
25
31
  export declare const SERVICES_URI: {
26
32
  SSO: string;
27
33
  WORKSPACE: string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ActionEvents = exports.SERVICES_URI = exports.STAGE = exports.PROD = exports.DEV = exports.LOCAL = void 0;
3
+ exports.ActionEvents = exports.SERVICES_URI = exports.CUSTOM = exports.STAGE = exports.PROD = exports.DEV = exports.LOCAL = void 0;
4
4
  exports.LOCAL = {
5
5
  SSO: 'http://localhost:5000/api/auth',
6
6
  WORKSPACE: 'http://localhost:6000/api/workspace',
@@ -11,7 +11,7 @@ exports.DEV = {
11
11
  SSO: 'https://dev.api.blinq.io/api/auth',
12
12
  WORKSPACE: 'https://dev.api.blinq.io/api/workspace',
13
13
  RUNS: 'https://dev.api.blinq.io/api/runs',
14
- STORAGE: 'http://localhost:5050/api/storage',
14
+ STORAGE: 'https://dev.api.blinq.io/api/storage',
15
15
  };
16
16
  exports.PROD = {
17
17
  SSO: 'https://api.blinq.io/api/auth',
@@ -25,13 +25,23 @@ exports.STAGE = {
25
25
  RUNS: 'https://stage.api.blinq.io/api/runs',
26
26
  STORAGE: 'https://stage.api.blinq.io/api/storage',
27
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
+ };
28
34
  exports.SERVICES_URI = process.env.NODE_ENV_BLINQ === 'local'
29
35
  ? exports.LOCAL // eslint-disable-line
30
36
  : process.env.NODE_ENV_BLINQ === 'dev'
31
37
  ? exports.DEV // eslint-disable-line
32
38
  : process.env.NODE_ENV_BLINQ === 'stage'
33
- ? exports.STAGE
34
- : exports.PROD; // eslint-disable-line
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
35
45
  var ActionEvents;
36
46
  (function (ActionEvents) {
37
47
  ActionEvents["record_scenario"] = "record_scenario";
@@ -1 +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,mCAAmC;CAC7C,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,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;YACP,CAAC,CAAC,YAAI,CAAA,CAAC,sBAAsB;AAEjC,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: 'http://localhost:5050/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 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\n : PROD // 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
+ {"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
  };
@@ -32,6 +32,7 @@ export type JsonResultFailed = {
32
32
  startTime: JsonTimestamp;
33
33
  endTime: JsonTimestamp;
34
34
  message?: string;
35
+ name?: string;
35
36
  };
36
37
  export type JsonFixedByAi = {
37
38
  status: 'FIXED_BY_AI';
@@ -63,7 +64,12 @@ export type JsonStep = {
63
64
  commands: JsonCommand[];
64
65
  result: JsonStepResult;
65
66
  webLog: webLog[];
67
+ networkData: any[];
66
68
  data?: any;
69
+ ariaSnapshot: string;
70
+ traceFilePath?: string;
71
+ brunoData?: any;
72
+ interceptResults?: any;
67
73
  };
68
74
  export type RetrainStats = {
69
75
  result: JsonTestResult;
@@ -80,12 +86,15 @@ export type JsonTestProgress = {
80
86
  steps: JsonStep[];
81
87
  result: JsonTestResult;
82
88
  retrainStats?: RetrainStats;
89
+ initialAriaSnapshot?: string;
83
90
  webLog: any;
84
91
  networkLog: any;
92
+ logFileId?: string;
85
93
  env: {
86
94
  name: string;
87
95
  baseUrl: string;
88
96
  };
97
+ traceFileId?: string;
89
98
  };
90
99
  export type JsonReport = {
91
100
  testCases: JsonTestProgress[];
@@ -114,10 +123,16 @@ export default class ReportGenerator {
114
123
  private logs;
115
124
  private networkLog;
116
125
  private stepLogs;
126
+ private stepNetworkLogs;
117
127
  private runName;
128
+ private ariaSnapshot;
129
+ private initialAriaSnapshot;
130
+ private testCaseLog;
131
+ private loggingOverridden;
118
132
  reportFolder: null | string;
119
133
  private uploadService;
120
- handleMessage(envelope: EnvelopeWithMetaMessage): Promise<void>;
134
+ private retryTestCaseId;
135
+ handleMessage(envelope: EnvelopeWithMetaMessage | messages.Envelope, reRunId?: string): Promise<any>;
121
136
  getReport(): JsonReport;
122
137
  private handleParseError;
123
138
  private onGherkinDocument;
@@ -130,11 +145,15 @@ export default class ReportGenerator {
130
145
  private onTestCaseStarted;
131
146
  private onTestStepStarted;
132
147
  private onAttachment;
148
+ private getFailedTestStepResult;
133
149
  private onTestStepFinished;
134
150
  getLogFileContent(): any;
135
151
  private getTestCaseResult;
136
152
  private onTestCaseFinished;
153
+ private readonly retryCount;
137
154
  private uploadTestCase;
155
+ private tryUpload;
156
+ private writeTestCaseReportToDisk;
138
157
  private onTestRunFinished;
139
158
  }
140
159
  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,79 @@ 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, stepName, }) {
413
+ for (const command of commands) {
414
+ if (command.result.status === 'FAILED') {
415
+ return {
416
+ status: 'FAILED',
417
+ message: command.result.message,
418
+ name: stepName,
419
+ startTime,
420
+ endTime,
421
+ };
422
+ }
423
+ }
424
+ return {
425
+ status: 'FAILED',
426
+ startTime,
427
+ endTime,
428
+ message: result.message,
429
+ name: stepName,
430
+ };
337
431
  }
338
432
  onTestStepFinished(testStepFinished) {
339
433
  const { testStepId, testStepResult, timestamp } = testStepFinished;
340
434
  const testStep = this.testStepMap.get(testStepId);
341
435
  if (testStep.pickleStepId === undefined) {
342
436
  if (testStepResult.status === 'FAILED') {
437
+ const testCase = this.testCaseReportMap.get(testStepFinished.testCaseStartedId);
438
+ const type = testCase.steps[0].result.status === 'UNKNOWN' ? 'Before' : 'After';
439
+ const hookStep = {
440
+ ariaSnapshot: null,
441
+ commands: [],
442
+ keyword: type,
443
+ data: {},
444
+ networkData: [],
445
+ result: {
446
+ status: 'FAILED',
447
+ message: testStepResult.message,
448
+ startTime: this.getTimeStamp(timestamp),
449
+ endTime: this.getTimeStamp(timestamp),
450
+ },
451
+ text: 'Failed hook',
452
+ type,
453
+ webLog: [],
454
+ };
455
+ if (type === 'Before') {
456
+ testCase.steps = [hookStep, ...testCase.steps];
457
+ }
458
+ else {
459
+ testCase.steps = [...testCase.steps, hookStep];
460
+ }
461
+ this.testCaseReportMap.set(testStepFinished.testCaseStartedId, testCase);
343
462
  console.error(`Before/After hook failed with message: ${testStepResult.message}`);
344
463
  }
345
464
  return;
@@ -378,18 +497,74 @@ class ReportGenerator {
378
497
  catch (error) {
379
498
  console.log('Error reading data.json');
380
499
  }
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
- };
500
+ if (testStepResult.status === 'FAILED') {
501
+ stepProgess.result = this.getFailedTestStepResult({
502
+ commands: stepProgess.commands,
503
+ startTime: prevStepResult.startTime,
504
+ endTime: this.getTimeStamp(timestamp),
505
+ result: testStepResult,
506
+ stepName: stepProgess.text,
507
+ });
508
+ }
509
+ else {
510
+ stepProgess.result = {
511
+ status: testStepResult.status,
512
+ startTime: prevStepResult.startTime,
513
+ endTime: this.getTimeStamp(timestamp),
514
+ };
515
+ }
388
516
  stepProgess.webLog = this.stepLogs;
517
+ stepProgess.networkData = this.stepNetworkLogs;
518
+ stepProgess.ariaSnapshot = this.ariaSnapshot;
519
+ this.ariaSnapshot = '';
520
+ this.stepNetworkLogs = [];
389
521
  this.stepLogs = [];
390
522
  if (Object.keys(data).length > 0) {
391
523
  stepProgess.data = data;
524
+ const id = testStepFinished.testCaseStartedId;
525
+ const parameters = this.testCaseReportMap.get(id).parameters;
526
+ const _parameters = {};
527
+ Object.keys(parameters).map((key) => {
528
+ var _a;
529
+ const valueParam = parameters[key].toString();
530
+ if (valueParam.startsWith('{{') && valueParam.endsWith('}}')) {
531
+ const path = valueParam.slice(2, -2).split('.');
532
+ let value = String((_a = object_path_1.default.get(data, path)) !== null && _a !== void 0 ? _a : valueParam);
533
+ if (value) {
534
+ if (value.startsWith('secret:')) {
535
+ value = 'secret:****';
536
+ }
537
+ else if (value.startsWith('totp:')) {
538
+ value = 'totp:****';
539
+ }
540
+ else if (value.startsWith('mask:')) {
541
+ value = 'mask:****';
542
+ }
543
+ _parameters[key] = value;
544
+ }
545
+ }
546
+ else {
547
+ _parameters[key] = parameters[key];
548
+ }
549
+ });
550
+ this.report.testCases.find((testCase) => {
551
+ return testCase.id === id;
552
+ }).parameters = _parameters;
392
553
  }
554
+ // if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
555
+ // this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH
556
+ // if (!fs.existsSync(this.reportFolder)) {
557
+ // fs.mkdirSync(this.reportFolder)
558
+ // }
559
+ // const reportFilePath = path.join(
560
+ // this.reportFolder,
561
+ // `report.json`
562
+ // )
563
+ // writeFileSync(reportFilePath, JSON.stringify(this.report, null, 2))
564
+ // return undefined
565
+ // // } else {
566
+ // // return await this.uploadTestCase(testProgress, reRunId)
567
+ // }
393
568
  }
394
569
  getLogFileContent() {
395
570
  let projectPath = process.cwd();
@@ -416,6 +591,12 @@ class ReportGenerator {
416
591
  }
417
592
  }
418
593
  getTestCaseResult(steps) {
594
+ if (steps[0] && steps[0].result.status === 'SKIPPED') {
595
+ return {
596
+ status: 'FAILED',
597
+ message: 'Test skipped due to failure in before hooks',
598
+ };
599
+ }
419
600
  for (const step of steps) {
420
601
  switch (step.result.status) {
421
602
  case 'FAILED':
@@ -437,24 +618,79 @@ class ReportGenerator {
437
618
  status: 'PASSED',
438
619
  };
439
620
  }
440
- async onTestCaseFinished(testCaseFinished) {
621
+ async onTestCaseFinished(testCaseFinished, reRunId) {
441
622
  const { testCaseStartedId, timestamp } = testCaseFinished;
442
623
  const testProgress = this.testCaseReportMap.get(testCaseStartedId);
443
624
  const prevResult = testProgress.result;
444
625
  const steps = Object.values(testProgress.steps);
445
626
  const result = this.getTestCaseResult(steps);
627
+ if (result.status === 'PASSED' && reRunId) {
628
+ this.uploadService.updateProjectAnalytics(process.env.PROJECT_ID);
629
+ }
630
+ const endTime = this.getTimeStamp(timestamp);
446
631
  testProgress.result = {
447
632
  ...result,
448
633
  startTime: prevResult.startTime,
449
- endTime: this.getTimeStamp(timestamp),
634
+ endTime,
450
635
  };
451
636
  testProgress.webLog = this.logs;
452
637
  testProgress.networkLog = this.networkLog;
638
+ testProgress.initialAriaSnapshot = this.initialAriaSnapshot;
639
+ if (process.env.TRACE) {
640
+ testProgress.traceFileId = path_1.default.join(`trace-${testCaseStartedId}.zip`);
641
+ }
642
+ this.initialAriaSnapshot = '';
453
643
  this.networkLog = [];
454
644
  this.logs = [];
455
- await this.uploadTestCase(testProgress);
645
+ if (this.testCaseLog &&
646
+ this.testCaseLog.length > 0 &&
647
+ !testProgress.logFileId) {
648
+ // Create the logs directory
649
+ const logsDir = path_1.default.join(this.reportFolder, 'editorLogs');
650
+ const fileName = `testCaseLog_${testCaseStartedId}.log`;
651
+ const filePath = path_1.default.join(logsDir, fileName);
652
+ // Ensure the logs directory exists
653
+ fs_1.default.mkdirSync(logsDir, { recursive: true });
654
+ // Write the logs to the file
655
+ fs_1.default.writeFileSync(filePath, this.testCaseLog.join('\n'), 'utf8');
656
+ // Store this ID in the testProgress object so it can be accessed later
657
+ testProgress.logFileId = testCaseStartedId;
658
+ }
659
+ this.testCaseLog = [];
660
+ if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
661
+ this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH;
662
+ if (!fs_1.default.existsSync(this.reportFolder)) {
663
+ fs_1.default.mkdirSync(this.reportFolder);
664
+ }
665
+ const reportFilePath = path_1.default.join(this.reportFolder, `${endTime}_${testProgress.scenarioName}.json`);
666
+ (0, fs_extra_1.writeFileSync)(reportFilePath, JSON.stringify(testProgress, null, 2));
667
+ return undefined;
668
+ }
669
+ else {
670
+ return await this.uploadTestCase(testProgress, reRunId);
671
+ }
456
672
  }
457
- async uploadTestCase(testCase) {
673
+ async uploadTestCase(testCase, rerunId) {
674
+ let data = null;
675
+ for (let attempt = 1; attempt <= this.retryCount; attempt++) {
676
+ try {
677
+ data = await this.tryUpload(testCase, rerunId);
678
+ break;
679
+ }
680
+ catch (e) {
681
+ console.error(`Attempt ${attempt} to upload testcase failed:`, e);
682
+ if (attempt === this.retryCount) {
683
+ console.error('All retry attempts failed, failed to upload testcase.');
684
+ }
685
+ else {
686
+ const waitTime = 1000 * 2 ** (attempt - 1); //? exponential backoff: 1s, 2s, 4s...
687
+ await new Promise((r) => setTimeout(r, waitTime));
688
+ }
689
+ }
690
+ }
691
+ return data;
692
+ }
693
+ async tryUpload(testCase, rerunId) {
458
694
  let runId = '';
459
695
  let projectId = '';
460
696
  if (!process.env.UPLOADING_TEST_CASE) {
@@ -472,7 +708,7 @@ class ReportGenerator {
472
708
  projectId = process.env.PROJECT_ID;
473
709
  }
474
710
  else {
475
- const runDoc = await this.uploadService.createRunDocument(this.runName);
711
+ const runDoc = await this.uploadService.createRunDocument(this.runName, testCase.env);
476
712
  runId = runDoc._id;
477
713
  projectId = runDoc.project_id;
478
714
  if (!process.env.IGNORE_ENV_VARIABLES) {
@@ -480,10 +716,9 @@ class ReportGenerator {
480
716
  process.env.PROJECT_ID = projectId;
481
717
  }
482
718
  }
483
- await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder);
484
- }
485
- catch (e) {
486
- console.error('Error uploading test case:', e);
719
+ const data = await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder, rerunId);
720
+ this.writeTestCaseReportToDisk(testCase);
721
+ return data;
487
722
  }
488
723
  finally {
489
724
  const arrRem = JSON.parse(process.env.UPLOADING_TEST_CASE);
@@ -491,7 +726,30 @@ class ReportGenerator {
491
726
  process.env.UPLOADING_TEST_CASE = JSON.stringify(arrRem);
492
727
  }
493
728
  }
494
- onTestRunFinished(testRunFinished) {
729
+ writeTestCaseReportToDisk(testCase) {
730
+ var _a;
731
+ const reportFolder = (_a = this.reportFolder) !== null && _a !== void 0 ? _a : process.env.TESTCASE_REPORT_FOLDER_PATH;
732
+ if (!reportFolder) {
733
+ console.error('Report folder is not defined');
734
+ return;
735
+ }
736
+ try {
737
+ let i = 0;
738
+ while (fs_1.default.existsSync(path_1.default.join(reportFolder, `${i}`))) {
739
+ i++;
740
+ }
741
+ fs_1.default.mkdirSync(path_1.default.join(reportFolder, `${i}`));
742
+ //exclude network log from the saved report
743
+ const networkLog = testCase.networkLog;
744
+ delete testCase.networkLog;
745
+ fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `report.json`), JSON.stringify(testCase, null, 2));
746
+ fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `network.json`), JSON.stringify(networkLog, null, 2));
747
+ }
748
+ catch (error) {
749
+ console.error('Error writing test case report to disk:', error);
750
+ }
751
+ }
752
+ async onTestRunFinished(testRunFinished) {
495
753
  const { timestamp, success, message } = testRunFinished;
496
754
  const prevResult = this.report.result;
497
755
  this.report.result = {
@@ -501,6 +759,7 @@ class ReportGenerator {
501
759
  message,
502
760
  // exception,
503
761
  };
762
+ await this.uploadService.createStatus(success ? 'passed' : 'failed');
504
763
  }
505
764
  }
506
765
  exports.default = ReportGenerator;