@dev-blinq/cucumber-js 1.0.103 → 1.0.104-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.
- package/bin/cucumber.ts +1 -0
- package/lib/api/console_logger.js.map +1 -1
- package/lib/cli/run.js +1 -0
- package/lib/cli/run.js.map +1 -1
- package/lib/cli/validate_node_engine_version.js +3 -1
- package/lib/cli/validate_node_engine_version.js.map +1 -1
- package/lib/formatter/api.js +9 -4
- package/lib/formatter/api.js.map +1 -1
- package/lib/formatter/builder.js +1 -3
- package/lib/formatter/builder.js.map +1 -1
- package/lib/formatter/bvt_analysis_formatter.d.ts +3 -2
- package/lib/formatter/bvt_analysis_formatter.js +46 -18
- package/lib/formatter/bvt_analysis_formatter.js.map +1 -1
- package/lib/formatter/feature_data_format.js +9 -3
- package/lib/formatter/feature_data_format.js.map +1 -1
- package/lib/formatter/helpers/constants.js.map +1 -1
- package/lib/formatter/helpers/report_generator.d.ts +17 -11
- package/lib/formatter/helpers/report_generator.js +171 -93
- package/lib/formatter/helpers/report_generator.js.map +1 -1
- package/lib/formatter/helpers/test_case_attempt_parser.js.map +1 -1
- package/lib/formatter/helpers/upload_serivce.d.ts +4 -2
- package/lib/formatter/helpers/upload_serivce.js +100 -54
- package/lib/formatter/helpers/upload_serivce.js.map +1 -1
- package/lib/formatter/helpers/uploader.js.map +1 -1
- package/lib/formatter/summary_formatter.js +4 -0
- package/lib/formatter/summary_formatter.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +2 -1
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import * as messages from
|
|
1
|
+
import * as messages from '@cucumber/messages';
|
|
2
2
|
type JsonTimestamp = number;
|
|
3
|
-
type JsonStepType =
|
|
3
|
+
type JsonStepType = 'Unknown' | 'Context' | 'Action' | 'Outcome' | 'Conjunction';
|
|
4
4
|
export type JsonResultUnknown = {
|
|
5
|
-
status:
|
|
5
|
+
status: 'UNKNOWN';
|
|
6
6
|
};
|
|
7
7
|
type JsonResultSkipped = {
|
|
8
|
-
status:
|
|
8
|
+
status: 'SKIPPED';
|
|
9
9
|
};
|
|
10
10
|
type JsonResultUndefined = {
|
|
11
|
-
status:
|
|
11
|
+
status: 'UNDEFINED';
|
|
12
12
|
};
|
|
13
13
|
type JsonResultAmbiguous = {
|
|
14
|
-
status:
|
|
14
|
+
status: 'AMBIGUOUS';
|
|
15
15
|
};
|
|
16
16
|
export type JsonResultStarted = {
|
|
17
|
-
status:
|
|
17
|
+
status: 'STARTED';
|
|
18
18
|
startTime: JsonTimestamp;
|
|
19
19
|
};
|
|
20
20
|
type JsonResultPending = {
|
|
21
|
-
status:
|
|
21
|
+
status: 'PENDING';
|
|
22
22
|
startTime: JsonTimestamp;
|
|
23
23
|
endTime: JsonTimestamp;
|
|
24
24
|
};
|
|
25
25
|
export type JsonResultPassed = {
|
|
26
|
-
status:
|
|
26
|
+
status: 'PASSED';
|
|
27
27
|
startTime: JsonTimestamp;
|
|
28
28
|
endTime: JsonTimestamp;
|
|
29
29
|
};
|
|
30
30
|
export type JsonResultFailed = {
|
|
31
|
-
status:
|
|
31
|
+
status: 'FAILED';
|
|
32
32
|
startTime: JsonTimestamp;
|
|
33
33
|
endTime: JsonTimestamp;
|
|
34
34
|
message?: string;
|
|
35
35
|
};
|
|
36
36
|
export type JsonFixedByAi = {
|
|
37
|
-
status:
|
|
37
|
+
status: 'FIXED_BY_AI';
|
|
38
38
|
startTime: JsonTimestamp;
|
|
39
39
|
endTime: JsonTimestamp;
|
|
40
40
|
};
|
|
@@ -68,6 +68,7 @@ export type JsonStep = {
|
|
|
68
68
|
ariaSnapshot: string;
|
|
69
69
|
traceFilePath?: string;
|
|
70
70
|
brunoData?: any;
|
|
71
|
+
interceptResults?: any;
|
|
71
72
|
};
|
|
72
73
|
export type RetrainStats = {
|
|
73
74
|
result: JsonTestResult;
|
|
@@ -87,6 +88,7 @@ export type JsonTestProgress = {
|
|
|
87
88
|
initialAriaSnapshot?: string;
|
|
88
89
|
webLog: any;
|
|
89
90
|
networkLog: any;
|
|
91
|
+
logFileId?: string;
|
|
90
92
|
env: {
|
|
91
93
|
name: string;
|
|
92
94
|
baseUrl: string;
|
|
@@ -123,6 +125,8 @@ export default class ReportGenerator {
|
|
|
123
125
|
private runName;
|
|
124
126
|
private ariaSnapshot;
|
|
125
127
|
private initialAriaSnapshot;
|
|
128
|
+
private testCaseLog;
|
|
129
|
+
private loggingOverridden;
|
|
126
130
|
reportFolder: null | string;
|
|
127
131
|
private uploadService;
|
|
128
132
|
handleMessage(envelope: EnvelopeWithMetaMessage | messages.Envelope, reRunId?: string): Promise<any>;
|
|
@@ -143,7 +147,9 @@ export default class ReportGenerator {
|
|
|
143
147
|
getLogFileContent(): any;
|
|
144
148
|
private getTestCaseResult;
|
|
145
149
|
private onTestCaseFinished;
|
|
150
|
+
private readonly retryCount;
|
|
146
151
|
private uploadTestCase;
|
|
152
|
+
private tryUpload;
|
|
147
153
|
private writeTestCaseReportToDisk;
|
|
148
154
|
private onTestRunFinished;
|
|
149
155
|
}
|
|
@@ -34,16 +34,16 @@ const upload_serivce_1 = require("./upload_serivce");
|
|
|
34
34
|
const fs_extra_1 = require("fs-extra");
|
|
35
35
|
// type JsonException = messages.Exception
|
|
36
36
|
const object_path_1 = __importDefault(require("object-path"));
|
|
37
|
-
const URL = process.env.NODE_ENV_BLINQ ===
|
|
38
|
-
?
|
|
39
|
-
: process.env.NODE_ENV_BLINQ ===
|
|
40
|
-
?
|
|
41
|
-
: process.env.NODE_ENV_BLINQ ===
|
|
42
|
-
?
|
|
43
|
-
: process.env.NODE_ENV_BLINQ ===
|
|
44
|
-
?
|
|
37
|
+
const URL = process.env.NODE_ENV_BLINQ === 'dev'
|
|
38
|
+
? 'https://dev.api.blinq.io/api/runs'
|
|
39
|
+
: process.env.NODE_ENV_BLINQ === 'local'
|
|
40
|
+
? 'http://localhost:5001/api/runs'
|
|
41
|
+
: process.env.NODE_ENV_BLINQ === 'stage'
|
|
42
|
+
? 'https://stage.api.blinq.io/api/runs'
|
|
43
|
+
: process.env.NODE_ENV_BLINQ === 'prod'
|
|
44
|
+
? 'https://api.blinq.io/api/runs'
|
|
45
45
|
: !process.env.NODE_ENV_BLINQ
|
|
46
|
-
?
|
|
46
|
+
? 'https://api.blinq.io/api/runs'
|
|
47
47
|
: `${process.env.NODE_ENV_BLINQ}/api/runs`;
|
|
48
48
|
const REPORT_SERVICE_URL = (_a = process.env.REPORT_SERVICE_URL) !== null && _a !== void 0 ? _a : URL;
|
|
49
49
|
const BATCH_SIZE = 10;
|
|
@@ -53,12 +53,12 @@ class ReportGenerator {
|
|
|
53
53
|
constructor() {
|
|
54
54
|
this.report = {
|
|
55
55
|
result: {
|
|
56
|
-
status:
|
|
56
|
+
status: 'UNKNOWN',
|
|
57
57
|
},
|
|
58
58
|
testCases: [],
|
|
59
59
|
env: {
|
|
60
|
-
name:
|
|
61
|
-
baseUrl:
|
|
60
|
+
name: '',
|
|
61
|
+
baseUrl: '',
|
|
62
62
|
},
|
|
63
63
|
};
|
|
64
64
|
this.gherkinDocumentMap = new Map();
|
|
@@ -73,75 +73,100 @@ class ReportGenerator {
|
|
|
73
73
|
this.networkLog = [];
|
|
74
74
|
this.stepLogs = [];
|
|
75
75
|
this.stepNetworkLogs = [];
|
|
76
|
-
this.runName =
|
|
77
|
-
this.ariaSnapshot =
|
|
78
|
-
this.initialAriaSnapshot =
|
|
76
|
+
this.runName = '';
|
|
77
|
+
this.ariaSnapshot = '';
|
|
78
|
+
this.initialAriaSnapshot = '';
|
|
79
|
+
this.testCaseLog = [];
|
|
80
|
+
this.loggingOverridden = false; // Flag to track if logging is overridden
|
|
79
81
|
this.reportFolder = null;
|
|
80
82
|
this.uploadService = new upload_serivce_1.RunUploadService(REPORT_SERVICE_URL, REPORT_SERVICE_TOKEN);
|
|
83
|
+
this.retryCount = 3;
|
|
81
84
|
}
|
|
82
85
|
async handleMessage(envelope, reRunId) {
|
|
83
|
-
if (envelope.meta &&
|
|
86
|
+
if (envelope.meta && 'runName' in envelope.meta) {
|
|
84
87
|
this.runName = envelope.meta.runName;
|
|
85
88
|
}
|
|
86
89
|
const type = Object.keys(envelope)[0];
|
|
87
90
|
switch (type) {
|
|
88
91
|
// case "meta": { break}
|
|
89
92
|
// case "source": { break}
|
|
90
|
-
case
|
|
93
|
+
case 'parseError': {
|
|
91
94
|
const parseError = envelope[type];
|
|
92
95
|
this.handleParseError(parseError);
|
|
93
96
|
break;
|
|
94
97
|
}
|
|
95
|
-
case
|
|
98
|
+
case 'gherkinDocument': {
|
|
96
99
|
const doc = envelope[type];
|
|
97
100
|
this.onGherkinDocument(doc);
|
|
98
101
|
break;
|
|
99
102
|
}
|
|
100
|
-
case
|
|
103
|
+
case 'pickle': {
|
|
101
104
|
const pickle = envelope[type];
|
|
102
105
|
this.onPickle(pickle);
|
|
103
106
|
break;
|
|
104
107
|
}
|
|
105
108
|
// case "stepDefinition": { break}
|
|
106
109
|
// case "hook": { break} // Before Hook
|
|
107
|
-
case
|
|
110
|
+
case 'testRunStarted': {
|
|
108
111
|
const testRunStarted = envelope[type];
|
|
109
112
|
this.onTestRunStarted(testRunStarted);
|
|
113
|
+
await this.uploadService.createStatus('running');
|
|
110
114
|
break;
|
|
111
115
|
}
|
|
112
|
-
case
|
|
116
|
+
case 'testCase': {
|
|
113
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
|
|
114
137
|
this.onTestCase(testCase);
|
|
115
138
|
break;
|
|
116
139
|
}
|
|
117
|
-
case
|
|
140
|
+
case 'testCaseStarted': {
|
|
118
141
|
const testCaseStarted = envelope[type];
|
|
119
142
|
this.onTestCaseStarted(testCaseStarted);
|
|
120
143
|
break;
|
|
121
144
|
}
|
|
122
|
-
case
|
|
145
|
+
case 'testStepStarted': {
|
|
123
146
|
const testStepStarted = envelope[type];
|
|
124
147
|
this.onTestStepStarted(testStepStarted);
|
|
125
148
|
break;
|
|
126
149
|
}
|
|
127
|
-
case
|
|
150
|
+
case 'attachment': {
|
|
128
151
|
const attachment = envelope[type];
|
|
129
152
|
this.onAttachment(attachment);
|
|
130
153
|
break;
|
|
131
154
|
}
|
|
132
|
-
case
|
|
155
|
+
case 'testStepFinished': {
|
|
133
156
|
const testStepFinished = envelope[type];
|
|
134
157
|
this.onTestStepFinished(testStepFinished);
|
|
135
158
|
break;
|
|
136
159
|
}
|
|
137
|
-
case
|
|
160
|
+
case 'testCaseFinished': {
|
|
138
161
|
const testCaseFinished = envelope[type];
|
|
139
|
-
|
|
162
|
+
// Call the onTestCaseFinished method
|
|
163
|
+
const result = await this.onTestCaseFinished(testCaseFinished, reRunId);
|
|
164
|
+
return result;
|
|
140
165
|
}
|
|
141
166
|
// case "hook": { break} // After Hook
|
|
142
|
-
case
|
|
167
|
+
case 'testRunFinished': {
|
|
143
168
|
const testRunFinished = envelope[type];
|
|
144
|
-
this.onTestRunFinished(testRunFinished);
|
|
169
|
+
await this.onTestRunFinished(testRunFinished);
|
|
145
170
|
break;
|
|
146
171
|
}
|
|
147
172
|
// case "parameterType" : { break}
|
|
@@ -155,7 +180,7 @@ class ReportGenerator {
|
|
|
155
180
|
const { message } = parseError;
|
|
156
181
|
const timestamp = new Date().getTime();
|
|
157
182
|
this.report.result = {
|
|
158
|
-
status:
|
|
183
|
+
status: 'FAILED',
|
|
159
184
|
startTime: timestamp,
|
|
160
185
|
endTime: timestamp,
|
|
161
186
|
message: message,
|
|
@@ -198,7 +223,7 @@ class ReportGenerator {
|
|
|
198
223
|
}
|
|
199
224
|
onTestRunStarted(testRunStarted) {
|
|
200
225
|
this.report.result = {
|
|
201
|
-
status:
|
|
226
|
+
status: 'STARTED',
|
|
202
227
|
startTime: this.getTimeStamp(testRunStarted.timestamp),
|
|
203
228
|
};
|
|
204
229
|
}
|
|
@@ -231,7 +256,8 @@ class ReportGenerator {
|
|
|
231
256
|
for (const tableRow of examples.tableBody) {
|
|
232
257
|
if (tableRow.id === exampleId) {
|
|
233
258
|
for (let i = 0; i < examples.tableHeader.cells.length; i++) {
|
|
234
|
-
parameters[examples.tableHeader.cells[i].value] =
|
|
259
|
+
parameters[examples.tableHeader.cells[i].value] =
|
|
260
|
+
tableRow.cells[i].value;
|
|
235
261
|
}
|
|
236
262
|
}
|
|
237
263
|
}
|
|
@@ -269,7 +295,7 @@ class ReportGenerator {
|
|
|
269
295
|
text: step.text,
|
|
270
296
|
commands: [],
|
|
271
297
|
result: {
|
|
272
|
-
status:
|
|
298
|
+
status: 'UNKNOWN',
|
|
273
299
|
},
|
|
274
300
|
networkData: [],
|
|
275
301
|
webLog: [],
|
|
@@ -286,7 +312,7 @@ class ReportGenerator {
|
|
|
286
312
|
parameters,
|
|
287
313
|
steps,
|
|
288
314
|
result: {
|
|
289
|
-
status:
|
|
315
|
+
status: 'STARTED',
|
|
290
316
|
startTime: this.getTimeStamp(timestamp),
|
|
291
317
|
},
|
|
292
318
|
webLog: [],
|
|
@@ -307,25 +333,25 @@ class ReportGenerator {
|
|
|
307
333
|
return;
|
|
308
334
|
const stepProgess = this.stepReportMap.get(testStep.pickleStepId);
|
|
309
335
|
stepProgess.result = {
|
|
310
|
-
status:
|
|
336
|
+
status: 'STARTED',
|
|
311
337
|
startTime: this.getTimeStamp(timestamp),
|
|
312
338
|
};
|
|
313
339
|
}
|
|
314
340
|
onAttachment(attachment) {
|
|
315
341
|
const { testStepId, body, mediaType } = attachment;
|
|
316
|
-
if (mediaType ===
|
|
317
|
-
this.reportFolder = body.replaceAll(
|
|
342
|
+
if (mediaType === 'text/plain') {
|
|
343
|
+
this.reportFolder = body.replaceAll('\\', '/');
|
|
318
344
|
return;
|
|
319
345
|
}
|
|
320
|
-
if (mediaType ===
|
|
346
|
+
if (mediaType === 'application/json+snapshot-before') {
|
|
321
347
|
this.initialAriaSnapshot = body;
|
|
322
348
|
return;
|
|
323
349
|
}
|
|
324
|
-
if (mediaType ===
|
|
350
|
+
if (mediaType === 'application/json+snapshot-after') {
|
|
325
351
|
this.ariaSnapshot = body;
|
|
326
352
|
return;
|
|
327
353
|
}
|
|
328
|
-
if (mediaType ===
|
|
354
|
+
if (mediaType === 'application/json+env') {
|
|
329
355
|
const data = JSON.parse(body);
|
|
330
356
|
this.report.env = data;
|
|
331
357
|
this.report.testCases.map((testCase) => {
|
|
@@ -333,14 +359,14 @@ class ReportGenerator {
|
|
|
333
359
|
return testCase;
|
|
334
360
|
});
|
|
335
361
|
}
|
|
336
|
-
if (mediaType ===
|
|
362
|
+
if (mediaType === 'application/json+log') {
|
|
337
363
|
const log = JSON.parse(body);
|
|
338
364
|
if (this.logs.length < 1000) {
|
|
339
365
|
this.logs.push(log);
|
|
340
366
|
this.stepLogs.push(log);
|
|
341
367
|
}
|
|
342
368
|
}
|
|
343
|
-
if (mediaType ===
|
|
369
|
+
if (mediaType === 'application/json+network') {
|
|
344
370
|
const networkLog = JSON.parse(body);
|
|
345
371
|
if (this.networkLog.length < 1000)
|
|
346
372
|
this.networkLog.push(networkLog);
|
|
@@ -350,29 +376,38 @@ class ReportGenerator {
|
|
|
350
376
|
if (testStep.pickleStepId === undefined)
|
|
351
377
|
return;
|
|
352
378
|
const stepProgess = this.stepReportMap.get(testStep.pickleStepId);
|
|
353
|
-
if (mediaType ===
|
|
379
|
+
if (mediaType === 'application/json') {
|
|
354
380
|
const command = JSON.parse(body);
|
|
355
381
|
stepProgess.commands.push(command);
|
|
356
382
|
}
|
|
357
|
-
else if (mediaType ===
|
|
383
|
+
else if (mediaType === 'application/json+trace') {
|
|
358
384
|
const data = JSON.parse(body);
|
|
359
385
|
stepProgess.traceFilePath = data.traceFilePath;
|
|
360
386
|
}
|
|
361
|
-
if (mediaType ===
|
|
387
|
+
if (mediaType === 'application/json+bruno') {
|
|
362
388
|
try {
|
|
363
389
|
const data = JSON.parse(body);
|
|
364
390
|
stepProgess.brunoData = data;
|
|
365
391
|
}
|
|
366
392
|
catch (error) {
|
|
367
|
-
console.error(
|
|
393
|
+
console.error('Error parsing bruno data:', error);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (mediaType === 'application/json+intercept-results') {
|
|
397
|
+
try {
|
|
398
|
+
const data = JSON.parse(body);
|
|
399
|
+
stepProgess.interceptResults = data;
|
|
400
|
+
}
|
|
401
|
+
catch (error) {
|
|
402
|
+
console.error('Error parsing intercept results:', error);
|
|
368
403
|
}
|
|
369
404
|
}
|
|
370
405
|
}
|
|
371
406
|
getFailedTestStepResult({ commands, startTime, endTime, result, }) {
|
|
372
407
|
for (const command of commands) {
|
|
373
|
-
if (command.result.status ===
|
|
408
|
+
if (command.result.status === 'FAILED') {
|
|
374
409
|
return {
|
|
375
|
-
status:
|
|
410
|
+
status: 'FAILED',
|
|
376
411
|
message: command.result.message,
|
|
377
412
|
startTime,
|
|
378
413
|
endTime,
|
|
@@ -380,7 +415,7 @@ class ReportGenerator {
|
|
|
380
415
|
}
|
|
381
416
|
}
|
|
382
417
|
return {
|
|
383
|
-
status:
|
|
418
|
+
status: 'FAILED',
|
|
384
419
|
startTime,
|
|
385
420
|
endTime,
|
|
386
421
|
message: result.message,
|
|
@@ -390,26 +425,26 @@ class ReportGenerator {
|
|
|
390
425
|
const { testStepId, testStepResult, timestamp } = testStepFinished;
|
|
391
426
|
const testStep = this.testStepMap.get(testStepId);
|
|
392
427
|
if (testStep.pickleStepId === undefined) {
|
|
393
|
-
if (testStepResult.status ===
|
|
428
|
+
if (testStepResult.status === 'FAILED') {
|
|
394
429
|
console.error(`Before/After hook failed with message: ${testStepResult.message}`);
|
|
395
430
|
}
|
|
396
431
|
return;
|
|
397
432
|
}
|
|
398
|
-
if (testStepResult.status ===
|
|
433
|
+
if (testStepResult.status === 'UNDEFINED') {
|
|
399
434
|
const step = this.stepReportMap.get(testStep.pickleStepId);
|
|
400
|
-
const stepName = step ? step.keyword +
|
|
435
|
+
const stepName = step ? step.keyword + ' ' + step.text : 'Undefined step';
|
|
401
436
|
const undefinedCommand = {
|
|
402
437
|
testStepId: testStepId,
|
|
403
438
|
body: JSON.stringify({
|
|
404
|
-
type:
|
|
405
|
-
text:
|
|
439
|
+
type: 'error',
|
|
440
|
+
text: 'Undefined step: ' + stepName,
|
|
406
441
|
result: {
|
|
407
|
-
status:
|
|
442
|
+
status: 'FAILED',
|
|
408
443
|
startTime: this.getTimeStamp(timestamp),
|
|
409
444
|
endTime: this.getTimeStamp(timestamp),
|
|
410
445
|
},
|
|
411
446
|
}),
|
|
412
|
-
mediaType:
|
|
447
|
+
mediaType: 'application/json',
|
|
413
448
|
contentEncoding: messages.AttachmentContentEncoding.IDENTITY,
|
|
414
449
|
};
|
|
415
450
|
this.onAttachment(undefinedCommand);
|
|
@@ -422,14 +457,14 @@ class ReportGenerator {
|
|
|
422
457
|
if (reportFolder === null) {
|
|
423
458
|
throw new Error('"reportFolder" is "null". Failed to run BVT hooks. Please retry after running "Generate All" or "Record Scenario" ');
|
|
424
459
|
}
|
|
425
|
-
if (fs_1.default.existsSync(path_1.default.join(reportFolder,
|
|
426
|
-
data = JSON.parse(fs_1.default.readFileSync(path_1.default.join(reportFolder,
|
|
460
|
+
if (fs_1.default.existsSync(path_1.default.join(reportFolder, 'data.json'))) {
|
|
461
|
+
data = JSON.parse(fs_1.default.readFileSync(path_1.default.join(reportFolder, 'data.json'), 'utf8'));
|
|
427
462
|
}
|
|
428
463
|
}
|
|
429
464
|
catch (error) {
|
|
430
|
-
console.log(
|
|
465
|
+
console.log('Error reading data.json');
|
|
431
466
|
}
|
|
432
|
-
if (testStepResult.status ===
|
|
467
|
+
if (testStepResult.status === 'FAILED') {
|
|
433
468
|
stepProgess.result = this.getFailedTestStepResult({
|
|
434
469
|
commands: stepProgess.commands,
|
|
435
470
|
startTime: prevStepResult.startTime,
|
|
@@ -447,7 +482,7 @@ class ReportGenerator {
|
|
|
447
482
|
stepProgess.webLog = this.stepLogs;
|
|
448
483
|
stepProgess.networkData = this.stepNetworkLogs;
|
|
449
484
|
stepProgess.ariaSnapshot = this.ariaSnapshot;
|
|
450
|
-
this.ariaSnapshot =
|
|
485
|
+
this.ariaSnapshot = '';
|
|
451
486
|
this.stepNetworkLogs = [];
|
|
452
487
|
this.stepLogs = [];
|
|
453
488
|
if (Object.keys(data).length > 0) {
|
|
@@ -456,18 +491,20 @@ class ReportGenerator {
|
|
|
456
491
|
const parameters = this.testCaseReportMap.get(id).parameters;
|
|
457
492
|
const _parameters = {};
|
|
458
493
|
Object.keys(parameters).map((key) => {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
494
|
+
var _a;
|
|
495
|
+
if (parameters[key].startsWith('{{') &&
|
|
496
|
+
parameters[key].endsWith('}}')) {
|
|
497
|
+
const path = parameters[key].slice(2, -2).split('.');
|
|
498
|
+
let value = String((_a = object_path_1.default.get(data, path)) !== null && _a !== void 0 ? _a : parameters[key]);
|
|
462
499
|
if (value) {
|
|
463
|
-
if (value.startsWith(
|
|
464
|
-
value =
|
|
500
|
+
if (value.startsWith('secret:')) {
|
|
501
|
+
value = 'secret:****';
|
|
465
502
|
}
|
|
466
|
-
else if (value.startsWith(
|
|
467
|
-
value =
|
|
503
|
+
else if (value.startsWith('totp:')) {
|
|
504
|
+
value = 'totp:****';
|
|
468
505
|
}
|
|
469
|
-
else if (value.startsWith(
|
|
470
|
-
value =
|
|
506
|
+
else if (value.startsWith('mask:')) {
|
|
507
|
+
value = 'mask:****';
|
|
471
508
|
}
|
|
472
509
|
_parameters[key] = value;
|
|
473
510
|
}
|
|
@@ -500,7 +537,7 @@ class ReportGenerator {
|
|
|
500
537
|
if (process.env.PROJECT_PATH) {
|
|
501
538
|
projectPath = process.env.PROJECT_PATH;
|
|
502
539
|
}
|
|
503
|
-
const logFolder = path_1.default.join(projectPath,
|
|
540
|
+
const logFolder = path_1.default.join(projectPath, 'logs', 'web');
|
|
504
541
|
if (!fs_1.default.existsSync(logFolder)) {
|
|
505
542
|
return [];
|
|
506
543
|
}
|
|
@@ -512,7 +549,7 @@ class ReportGenerator {
|
|
|
512
549
|
return [];
|
|
513
550
|
}
|
|
514
551
|
try {
|
|
515
|
-
const logFileContent = fs_1.default.readFileSync(path_1.default.join(logFolder, `${nextId - 1}.json`),
|
|
552
|
+
const logFileContent = fs_1.default.readFileSync(path_1.default.join(logFolder, `${nextId - 1}.json`), 'utf8');
|
|
516
553
|
return JSON.parse(logFileContent);
|
|
517
554
|
}
|
|
518
555
|
catch (error) {
|
|
@@ -520,25 +557,31 @@ class ReportGenerator {
|
|
|
520
557
|
}
|
|
521
558
|
}
|
|
522
559
|
getTestCaseResult(steps) {
|
|
560
|
+
if (steps[0] && steps[0].result.status === 'SKIPPED') {
|
|
561
|
+
return {
|
|
562
|
+
status: 'FAILED',
|
|
563
|
+
message: 'Test skipped due to failure in before hooks',
|
|
564
|
+
};
|
|
565
|
+
}
|
|
523
566
|
for (const step of steps) {
|
|
524
567
|
switch (step.result.status) {
|
|
525
|
-
case
|
|
568
|
+
case 'FAILED':
|
|
526
569
|
return {
|
|
527
570
|
status: step.result.status,
|
|
528
571
|
message: step.result.message,
|
|
529
572
|
// exception: step.result.exception,
|
|
530
573
|
};
|
|
531
|
-
case
|
|
532
|
-
case
|
|
533
|
-
case
|
|
574
|
+
case 'AMBIGUOUS':
|
|
575
|
+
case 'UNDEFINED':
|
|
576
|
+
case 'PENDING':
|
|
534
577
|
return {
|
|
535
|
-
status:
|
|
578
|
+
status: 'FAILED',
|
|
536
579
|
message: `step "${step.text}" is ${step.result.status}`,
|
|
537
580
|
};
|
|
538
581
|
}
|
|
539
582
|
}
|
|
540
583
|
return {
|
|
541
|
-
status:
|
|
584
|
+
status: 'PASSED',
|
|
542
585
|
};
|
|
543
586
|
}
|
|
544
587
|
async onTestCaseFinished(testCaseFinished, reRunId) {
|
|
@@ -547,6 +590,9 @@ class ReportGenerator {
|
|
|
547
590
|
const prevResult = testProgress.result;
|
|
548
591
|
const steps = Object.values(testProgress.steps);
|
|
549
592
|
const result = this.getTestCaseResult(steps);
|
|
593
|
+
if (result.status === 'PASSED' && reRunId) {
|
|
594
|
+
this.uploadService.updateProjectAnalytics(process.env.PROJECT_ID);
|
|
595
|
+
}
|
|
550
596
|
const endTime = this.getTimeStamp(timestamp);
|
|
551
597
|
testProgress.result = {
|
|
552
598
|
...result,
|
|
@@ -556,9 +602,22 @@ class ReportGenerator {
|
|
|
556
602
|
testProgress.webLog = this.logs;
|
|
557
603
|
testProgress.networkLog = this.networkLog;
|
|
558
604
|
testProgress.initialAriaSnapshot = this.initialAriaSnapshot;
|
|
559
|
-
this.initialAriaSnapshot =
|
|
605
|
+
this.initialAriaSnapshot = '';
|
|
560
606
|
this.networkLog = [];
|
|
561
607
|
this.logs = [];
|
|
608
|
+
if (this.testCaseLog && this.testCaseLog.length > 0) {
|
|
609
|
+
// Create the logs directory
|
|
610
|
+
const logsDir = path_1.default.join(this.reportFolder, 'editorLogs');
|
|
611
|
+
const fileName = `testCaseLog_${testCaseStartedId}.log`;
|
|
612
|
+
const filePath = path_1.default.join(logsDir, fileName);
|
|
613
|
+
// Ensure the logs directory exists
|
|
614
|
+
fs_1.default.mkdirSync(logsDir, { recursive: true });
|
|
615
|
+
// Write the logs to the file
|
|
616
|
+
fs_1.default.writeFileSync(filePath, this.testCaseLog.join('\n'), 'utf8');
|
|
617
|
+
// Store this ID in the testProgress object so it can be accessed later
|
|
618
|
+
testProgress.logFileId = testCaseStartedId;
|
|
619
|
+
}
|
|
620
|
+
this.testCaseLog = [];
|
|
562
621
|
if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
|
|
563
622
|
this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH;
|
|
564
623
|
if (!fs_1.default.existsSync(this.reportFolder)) {
|
|
@@ -573,18 +632,39 @@ class ReportGenerator {
|
|
|
573
632
|
}
|
|
574
633
|
}
|
|
575
634
|
async uploadTestCase(testCase, rerunId) {
|
|
576
|
-
let
|
|
577
|
-
let
|
|
635
|
+
let data = null;
|
|
636
|
+
for (let attempt = 1; attempt <= this.retryCount; attempt++) {
|
|
637
|
+
try {
|
|
638
|
+
data = await this.tryUpload(testCase, rerunId);
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
catch (e) {
|
|
642
|
+
console.error(`Attempt ${attempt} to upload testcase failed:`, e);
|
|
643
|
+
if (attempt === this.retryCount) {
|
|
644
|
+
console.error('All retry attempts failed, failed to upload testcase.');
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
const waitTime = 1000 * 2 ** (attempt - 1); //? exponential backoff: 1s, 2s, 4s...
|
|
648
|
+
await new Promise((r) => setTimeout(r, waitTime));
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return data;
|
|
653
|
+
}
|
|
654
|
+
async tryUpload(testCase, rerunId) {
|
|
655
|
+
let runId = '';
|
|
656
|
+
let projectId = '';
|
|
578
657
|
if (!process.env.UPLOADING_TEST_CASE) {
|
|
579
|
-
process.env.UPLOADING_TEST_CASE =
|
|
658
|
+
process.env.UPLOADING_TEST_CASE = '[]';
|
|
580
659
|
}
|
|
581
660
|
const anyRemArr = JSON.parse(process.env.UPLOADING_TEST_CASE);
|
|
582
661
|
const randomID = Math.random().toString(36).substring(7);
|
|
583
662
|
anyRemArr.push(randomID);
|
|
584
|
-
let data;
|
|
585
663
|
process.env.UPLOADING_TEST_CASE = JSON.stringify(anyRemArr);
|
|
586
664
|
try {
|
|
587
|
-
if (process.env.RUN_ID &&
|
|
665
|
+
if (process.env.RUN_ID &&
|
|
666
|
+
process.env.PROJECT_ID &&
|
|
667
|
+
!process.env.IGNORE_ENV_VARIABLES) {
|
|
588
668
|
runId = process.env.RUN_ID;
|
|
589
669
|
projectId = process.env.PROJECT_ID;
|
|
590
670
|
}
|
|
@@ -597,24 +677,21 @@ class ReportGenerator {
|
|
|
597
677
|
process.env.PROJECT_ID = projectId;
|
|
598
678
|
}
|
|
599
679
|
}
|
|
600
|
-
data = await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder, rerunId);
|
|
680
|
+
const data = await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder, rerunId);
|
|
601
681
|
this.writeTestCaseReportToDisk(testCase);
|
|
602
|
-
|
|
603
|
-
catch (e) {
|
|
604
|
-
console.error("Error uploading test case:", e);
|
|
682
|
+
return data;
|
|
605
683
|
}
|
|
606
684
|
finally {
|
|
607
685
|
const arrRem = JSON.parse(process.env.UPLOADING_TEST_CASE);
|
|
608
686
|
arrRem.splice(arrRem.indexOf(randomID), 1);
|
|
609
687
|
process.env.UPLOADING_TEST_CASE = JSON.stringify(arrRem);
|
|
610
688
|
}
|
|
611
|
-
return data ? data : null;
|
|
612
689
|
}
|
|
613
690
|
writeTestCaseReportToDisk(testCase) {
|
|
614
691
|
var _a;
|
|
615
692
|
const reportFolder = (_a = this.reportFolder) !== null && _a !== void 0 ? _a : process.env.TESTCASE_REPORT_FOLDER_PATH;
|
|
616
693
|
if (!reportFolder) {
|
|
617
|
-
console.error(
|
|
694
|
+
console.error('Report folder is not defined');
|
|
618
695
|
return;
|
|
619
696
|
}
|
|
620
697
|
try {
|
|
@@ -630,19 +707,20 @@ class ReportGenerator {
|
|
|
630
707
|
fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `network.json`), JSON.stringify(networkLog, null, 2));
|
|
631
708
|
}
|
|
632
709
|
catch (error) {
|
|
633
|
-
console.error(
|
|
710
|
+
console.error('Error writing test case report to disk:', error);
|
|
634
711
|
}
|
|
635
712
|
}
|
|
636
|
-
onTestRunFinished(testRunFinished) {
|
|
713
|
+
async onTestRunFinished(testRunFinished) {
|
|
637
714
|
const { timestamp, success, message } = testRunFinished;
|
|
638
715
|
const prevResult = this.report.result;
|
|
639
716
|
this.report.result = {
|
|
640
|
-
status: success ?
|
|
717
|
+
status: success ? 'PASSED' : 'FAILED',
|
|
641
718
|
startTime: prevResult.startTime,
|
|
642
719
|
endTime: this.getTimeStamp(timestamp),
|
|
643
720
|
message,
|
|
644
721
|
// exception,
|
|
645
722
|
};
|
|
723
|
+
await this.uploadService.createStatus(success ? 'passed' : 'failed');
|
|
646
724
|
}
|
|
647
725
|
}
|
|
648
726
|
exports.default = ReportGenerator;
|