@dev-blinq/cucumber-js 1.0.104 → 1.0.105-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 +2 -2
- package/lib/formatter/bvt_analysis_formatter.js +36 -16
- 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 +196 -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 -55
- 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 +3 -1
- 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
|
@@ -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,51 @@ 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') {
|
|
429
|
+
const testCase = this.testCaseReportMap.get(testStepFinished.testCaseStartedId);
|
|
430
|
+
const type = testCase.steps[0].result.status === 'UNKNOWN' ? 'Before' : 'After';
|
|
431
|
+
const hookStep = {
|
|
432
|
+
ariaSnapshot: null,
|
|
433
|
+
commands: [],
|
|
434
|
+
keyword: type,
|
|
435
|
+
data: {},
|
|
436
|
+
networkData: [],
|
|
437
|
+
result: {
|
|
438
|
+
status: 'FAILED',
|
|
439
|
+
message: testStepResult.message,
|
|
440
|
+
startTime: this.getTimeStamp(timestamp),
|
|
441
|
+
endTime: this.getTimeStamp(timestamp),
|
|
442
|
+
},
|
|
443
|
+
text: 'Failed hook',
|
|
444
|
+
type,
|
|
445
|
+
webLog: [],
|
|
446
|
+
};
|
|
447
|
+
if (type === 'Before') {
|
|
448
|
+
testCase.steps = [hookStep, ...testCase.steps];
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
testCase.steps = [...testCase.steps, hookStep];
|
|
452
|
+
}
|
|
453
|
+
this.testCaseReportMap.set(testStepFinished.testCaseStartedId, testCase);
|
|
394
454
|
console.error(`Before/After hook failed with message: ${testStepResult.message}`);
|
|
395
455
|
}
|
|
396
456
|
return;
|
|
397
457
|
}
|
|
398
|
-
if (testStepResult.status ===
|
|
458
|
+
if (testStepResult.status === 'UNDEFINED') {
|
|
399
459
|
const step = this.stepReportMap.get(testStep.pickleStepId);
|
|
400
|
-
const stepName = step ? step.keyword +
|
|
460
|
+
const stepName = step ? step.keyword + ' ' + step.text : 'Undefined step';
|
|
401
461
|
const undefinedCommand = {
|
|
402
462
|
testStepId: testStepId,
|
|
403
463
|
body: JSON.stringify({
|
|
404
|
-
type:
|
|
405
|
-
text:
|
|
464
|
+
type: 'error',
|
|
465
|
+
text: 'Undefined step: ' + stepName,
|
|
406
466
|
result: {
|
|
407
|
-
status:
|
|
467
|
+
status: 'FAILED',
|
|
408
468
|
startTime: this.getTimeStamp(timestamp),
|
|
409
469
|
endTime: this.getTimeStamp(timestamp),
|
|
410
470
|
},
|
|
411
471
|
}),
|
|
412
|
-
mediaType:
|
|
472
|
+
mediaType: 'application/json',
|
|
413
473
|
contentEncoding: messages.AttachmentContentEncoding.IDENTITY,
|
|
414
474
|
};
|
|
415
475
|
this.onAttachment(undefinedCommand);
|
|
@@ -422,14 +482,14 @@ class ReportGenerator {
|
|
|
422
482
|
if (reportFolder === null) {
|
|
423
483
|
throw new Error('"reportFolder" is "null". Failed to run BVT hooks. Please retry after running "Generate All" or "Record Scenario" ');
|
|
424
484
|
}
|
|
425
|
-
if (fs_1.default.existsSync(path_1.default.join(reportFolder,
|
|
426
|
-
data = JSON.parse(fs_1.default.readFileSync(path_1.default.join(reportFolder,
|
|
485
|
+
if (fs_1.default.existsSync(path_1.default.join(reportFolder, 'data.json'))) {
|
|
486
|
+
data = JSON.parse(fs_1.default.readFileSync(path_1.default.join(reportFolder, 'data.json'), 'utf8'));
|
|
427
487
|
}
|
|
428
488
|
}
|
|
429
489
|
catch (error) {
|
|
430
|
-
console.log(
|
|
490
|
+
console.log('Error reading data.json');
|
|
431
491
|
}
|
|
432
|
-
if (testStepResult.status ===
|
|
492
|
+
if (testStepResult.status === 'FAILED') {
|
|
433
493
|
stepProgess.result = this.getFailedTestStepResult({
|
|
434
494
|
commands: stepProgess.commands,
|
|
435
495
|
startTime: prevStepResult.startTime,
|
|
@@ -447,7 +507,7 @@ class ReportGenerator {
|
|
|
447
507
|
stepProgess.webLog = this.stepLogs;
|
|
448
508
|
stepProgess.networkData = this.stepNetworkLogs;
|
|
449
509
|
stepProgess.ariaSnapshot = this.ariaSnapshot;
|
|
450
|
-
this.ariaSnapshot =
|
|
510
|
+
this.ariaSnapshot = '';
|
|
451
511
|
this.stepNetworkLogs = [];
|
|
452
512
|
this.stepLogs = [];
|
|
453
513
|
if (Object.keys(data).length > 0) {
|
|
@@ -456,18 +516,20 @@ class ReportGenerator {
|
|
|
456
516
|
const parameters = this.testCaseReportMap.get(id).parameters;
|
|
457
517
|
const _parameters = {};
|
|
458
518
|
Object.keys(parameters).map((key) => {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
519
|
+
var _a;
|
|
520
|
+
if (parameters[key].startsWith('{{') &&
|
|
521
|
+
parameters[key].endsWith('}}')) {
|
|
522
|
+
const path = parameters[key].slice(2, -2).split('.');
|
|
523
|
+
let value = String((_a = object_path_1.default.get(data, path)) !== null && _a !== void 0 ? _a : parameters[key]);
|
|
462
524
|
if (value) {
|
|
463
|
-
if (value.startsWith(
|
|
464
|
-
value =
|
|
525
|
+
if (value.startsWith('secret:')) {
|
|
526
|
+
value = 'secret:****';
|
|
465
527
|
}
|
|
466
|
-
else if (value.startsWith(
|
|
467
|
-
value =
|
|
528
|
+
else if (value.startsWith('totp:')) {
|
|
529
|
+
value = 'totp:****';
|
|
468
530
|
}
|
|
469
|
-
else if (value.startsWith(
|
|
470
|
-
value =
|
|
531
|
+
else if (value.startsWith('mask:')) {
|
|
532
|
+
value = 'mask:****';
|
|
471
533
|
}
|
|
472
534
|
_parameters[key] = value;
|
|
473
535
|
}
|
|
@@ -500,7 +562,7 @@ class ReportGenerator {
|
|
|
500
562
|
if (process.env.PROJECT_PATH) {
|
|
501
563
|
projectPath = process.env.PROJECT_PATH;
|
|
502
564
|
}
|
|
503
|
-
const logFolder = path_1.default.join(projectPath,
|
|
565
|
+
const logFolder = path_1.default.join(projectPath, 'logs', 'web');
|
|
504
566
|
if (!fs_1.default.existsSync(logFolder)) {
|
|
505
567
|
return [];
|
|
506
568
|
}
|
|
@@ -512,7 +574,7 @@ class ReportGenerator {
|
|
|
512
574
|
return [];
|
|
513
575
|
}
|
|
514
576
|
try {
|
|
515
|
-
const logFileContent = fs_1.default.readFileSync(path_1.default.join(logFolder, `${nextId - 1}.json`),
|
|
577
|
+
const logFileContent = fs_1.default.readFileSync(path_1.default.join(logFolder, `${nextId - 1}.json`), 'utf8');
|
|
516
578
|
return JSON.parse(logFileContent);
|
|
517
579
|
}
|
|
518
580
|
catch (error) {
|
|
@@ -520,25 +582,31 @@ class ReportGenerator {
|
|
|
520
582
|
}
|
|
521
583
|
}
|
|
522
584
|
getTestCaseResult(steps) {
|
|
585
|
+
if (steps[0] && steps[0].result.status === 'SKIPPED') {
|
|
586
|
+
return {
|
|
587
|
+
status: 'FAILED',
|
|
588
|
+
message: 'Test skipped due to failure in before hooks',
|
|
589
|
+
};
|
|
590
|
+
}
|
|
523
591
|
for (const step of steps) {
|
|
524
592
|
switch (step.result.status) {
|
|
525
|
-
case
|
|
593
|
+
case 'FAILED':
|
|
526
594
|
return {
|
|
527
595
|
status: step.result.status,
|
|
528
596
|
message: step.result.message,
|
|
529
597
|
// exception: step.result.exception,
|
|
530
598
|
};
|
|
531
|
-
case
|
|
532
|
-
case
|
|
533
|
-
case
|
|
599
|
+
case 'AMBIGUOUS':
|
|
600
|
+
case 'UNDEFINED':
|
|
601
|
+
case 'PENDING':
|
|
534
602
|
return {
|
|
535
|
-
status:
|
|
603
|
+
status: 'FAILED',
|
|
536
604
|
message: `step "${step.text}" is ${step.result.status}`,
|
|
537
605
|
};
|
|
538
606
|
}
|
|
539
607
|
}
|
|
540
608
|
return {
|
|
541
|
-
status:
|
|
609
|
+
status: 'PASSED',
|
|
542
610
|
};
|
|
543
611
|
}
|
|
544
612
|
async onTestCaseFinished(testCaseFinished, reRunId) {
|
|
@@ -547,6 +615,9 @@ class ReportGenerator {
|
|
|
547
615
|
const prevResult = testProgress.result;
|
|
548
616
|
const steps = Object.values(testProgress.steps);
|
|
549
617
|
const result = this.getTestCaseResult(steps);
|
|
618
|
+
if (result.status === 'PASSED' && reRunId) {
|
|
619
|
+
this.uploadService.updateProjectAnalytics(process.env.PROJECT_ID);
|
|
620
|
+
}
|
|
550
621
|
const endTime = this.getTimeStamp(timestamp);
|
|
551
622
|
testProgress.result = {
|
|
552
623
|
...result,
|
|
@@ -556,9 +627,22 @@ class ReportGenerator {
|
|
|
556
627
|
testProgress.webLog = this.logs;
|
|
557
628
|
testProgress.networkLog = this.networkLog;
|
|
558
629
|
testProgress.initialAriaSnapshot = this.initialAriaSnapshot;
|
|
559
|
-
this.initialAriaSnapshot =
|
|
630
|
+
this.initialAriaSnapshot = '';
|
|
560
631
|
this.networkLog = [];
|
|
561
632
|
this.logs = [];
|
|
633
|
+
if (this.testCaseLog && this.testCaseLog.length > 0) {
|
|
634
|
+
// Create the logs directory
|
|
635
|
+
const logsDir = path_1.default.join(this.reportFolder, 'editorLogs');
|
|
636
|
+
const fileName = `testCaseLog_${testCaseStartedId}.log`;
|
|
637
|
+
const filePath = path_1.default.join(logsDir, fileName);
|
|
638
|
+
// Ensure the logs directory exists
|
|
639
|
+
fs_1.default.mkdirSync(logsDir, { recursive: true });
|
|
640
|
+
// Write the logs to the file
|
|
641
|
+
fs_1.default.writeFileSync(filePath, this.testCaseLog.join('\n'), 'utf8');
|
|
642
|
+
// Store this ID in the testProgress object so it can be accessed later
|
|
643
|
+
testProgress.logFileId = testCaseStartedId;
|
|
644
|
+
}
|
|
645
|
+
this.testCaseLog = [];
|
|
562
646
|
if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
|
|
563
647
|
this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH;
|
|
564
648
|
if (!fs_1.default.existsSync(this.reportFolder)) {
|
|
@@ -573,18 +657,39 @@ class ReportGenerator {
|
|
|
573
657
|
}
|
|
574
658
|
}
|
|
575
659
|
async uploadTestCase(testCase, rerunId) {
|
|
576
|
-
let
|
|
577
|
-
let
|
|
660
|
+
let data = null;
|
|
661
|
+
for (let attempt = 1; attempt <= this.retryCount; attempt++) {
|
|
662
|
+
try {
|
|
663
|
+
data = await this.tryUpload(testCase, rerunId);
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
catch (e) {
|
|
667
|
+
console.error(`Attempt ${attempt} to upload testcase failed:`, e);
|
|
668
|
+
if (attempt === this.retryCount) {
|
|
669
|
+
console.error('All retry attempts failed, failed to upload testcase.');
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
const waitTime = 1000 * 2 ** (attempt - 1); //? exponential backoff: 1s, 2s, 4s...
|
|
673
|
+
await new Promise((r) => setTimeout(r, waitTime));
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return data;
|
|
678
|
+
}
|
|
679
|
+
async tryUpload(testCase, rerunId) {
|
|
680
|
+
let runId = '';
|
|
681
|
+
let projectId = '';
|
|
578
682
|
if (!process.env.UPLOADING_TEST_CASE) {
|
|
579
|
-
process.env.UPLOADING_TEST_CASE =
|
|
683
|
+
process.env.UPLOADING_TEST_CASE = '[]';
|
|
580
684
|
}
|
|
581
685
|
const anyRemArr = JSON.parse(process.env.UPLOADING_TEST_CASE);
|
|
582
686
|
const randomID = Math.random().toString(36).substring(7);
|
|
583
687
|
anyRemArr.push(randomID);
|
|
584
|
-
let data;
|
|
585
688
|
process.env.UPLOADING_TEST_CASE = JSON.stringify(anyRemArr);
|
|
586
689
|
try {
|
|
587
|
-
if (process.env.RUN_ID &&
|
|
690
|
+
if (process.env.RUN_ID &&
|
|
691
|
+
process.env.PROJECT_ID &&
|
|
692
|
+
!process.env.IGNORE_ENV_VARIABLES) {
|
|
588
693
|
runId = process.env.RUN_ID;
|
|
589
694
|
projectId = process.env.PROJECT_ID;
|
|
590
695
|
}
|
|
@@ -597,24 +702,21 @@ class ReportGenerator {
|
|
|
597
702
|
process.env.PROJECT_ID = projectId;
|
|
598
703
|
}
|
|
599
704
|
}
|
|
600
|
-
data = await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder, rerunId);
|
|
705
|
+
const data = await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder, rerunId);
|
|
601
706
|
this.writeTestCaseReportToDisk(testCase);
|
|
602
|
-
|
|
603
|
-
catch (e) {
|
|
604
|
-
console.error("Error uploading test case:", e);
|
|
707
|
+
return data;
|
|
605
708
|
}
|
|
606
709
|
finally {
|
|
607
710
|
const arrRem = JSON.parse(process.env.UPLOADING_TEST_CASE);
|
|
608
711
|
arrRem.splice(arrRem.indexOf(randomID), 1);
|
|
609
712
|
process.env.UPLOADING_TEST_CASE = JSON.stringify(arrRem);
|
|
610
713
|
}
|
|
611
|
-
return data ? data : null;
|
|
612
714
|
}
|
|
613
715
|
writeTestCaseReportToDisk(testCase) {
|
|
614
716
|
var _a;
|
|
615
717
|
const reportFolder = (_a = this.reportFolder) !== null && _a !== void 0 ? _a : process.env.TESTCASE_REPORT_FOLDER_PATH;
|
|
616
718
|
if (!reportFolder) {
|
|
617
|
-
console.error(
|
|
719
|
+
console.error('Report folder is not defined');
|
|
618
720
|
return;
|
|
619
721
|
}
|
|
620
722
|
try {
|
|
@@ -630,19 +732,20 @@ class ReportGenerator {
|
|
|
630
732
|
fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `network.json`), JSON.stringify(networkLog, null, 2));
|
|
631
733
|
}
|
|
632
734
|
catch (error) {
|
|
633
|
-
console.error(
|
|
735
|
+
console.error('Error writing test case report to disk:', error);
|
|
634
736
|
}
|
|
635
737
|
}
|
|
636
|
-
onTestRunFinished(testRunFinished) {
|
|
738
|
+
async onTestRunFinished(testRunFinished) {
|
|
637
739
|
const { timestamp, success, message } = testRunFinished;
|
|
638
740
|
const prevResult = this.report.result;
|
|
639
741
|
this.report.result = {
|
|
640
|
-
status: success ?
|
|
742
|
+
status: success ? 'PASSED' : 'FAILED',
|
|
641
743
|
startTime: prevResult.startTime,
|
|
642
744
|
endTime: this.getTimeStamp(timestamp),
|
|
643
745
|
message,
|
|
644
746
|
// exception,
|
|
645
747
|
};
|
|
748
|
+
await this.uploadService.createStatus(success ? 'passed' : 'failed');
|
|
646
749
|
}
|
|
647
750
|
}
|
|
648
751
|
exports.default = ReportGenerator;
|