@dev-blinq/cucumber-js 1.0.117-dev → 1.0.117-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/bin/download-install.js +22 -2
- 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/configuration/axios_client.js +1 -1
- package/lib/configuration/axios_client.js.map +1 -1
- package/lib/formatter/api.js +16 -5
- 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 +13 -1
- package/lib/formatter/bvt_analysis_formatter.js +163 -55
- package/lib/formatter/bvt_analysis_formatter.js.map +1 -1
- package/lib/formatter/feature_data_format.js +22 -8
- package/lib/formatter/feature_data_format.js.map +1 -1
- package/lib/formatter/helpers/constants.d.ts +50 -0
- package/lib/formatter/helpers/constants.js +60 -0
- package/lib/formatter/helpers/constants.js.map +1 -0
- package/lib/formatter/helpers/report_generator.d.ts +23 -3
- package/lib/formatter/helpers/report_generator.js +339 -27
- package/lib/formatter/helpers/report_generator.js.map +1 -1
- package/lib/formatter/helpers/test_case_attempt_formatter.js +1 -1
- package/lib/formatter/helpers/test_case_attempt_formatter.js.map +1 -1
- package/lib/formatter/helpers/test_case_attempt_parser.js.map +1 -1
- package/lib/formatter/helpers/upload_serivce.d.ts +15 -2
- package/lib/formatter/helpers/upload_serivce.js +156 -7
- package/lib/formatter/helpers/upload_serivce.js.map +1 -1
- package/lib/formatter/helpers/uploader.js +6 -2
- 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/runtime/test_case_runner.d.ts +2 -0
- package/lib/runtime/test_case_runner.js +17 -1
- package/lib/runtime/test_case_runner.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 +6 -3
|
@@ -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
|
-
:
|
|
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,20 @@ 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.retryTestCaseId = null;
|
|
84
|
+
this.retryCount = 3;
|
|
46
85
|
}
|
|
47
|
-
async handleMessage(envelope) {
|
|
48
|
-
if (envelope.meta && envelope.meta
|
|
86
|
+
async handleMessage(envelope, reRunId) {
|
|
87
|
+
if (envelope.meta && 'runName' in envelope.meta) {
|
|
49
88
|
this.runName = envelope.meta.runName;
|
|
50
89
|
}
|
|
51
90
|
const type = Object.keys(envelope)[0];
|
|
@@ -72,14 +111,35 @@ class ReportGenerator {
|
|
|
72
111
|
case 'testRunStarted': {
|
|
73
112
|
const testRunStarted = envelope[type];
|
|
74
113
|
this.onTestRunStarted(testRunStarted);
|
|
114
|
+
await this.uploadService.createStatus('running');
|
|
75
115
|
break;
|
|
76
116
|
}
|
|
77
117
|
case 'testCase': {
|
|
78
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
|
|
79
138
|
this.onTestCase(testCase);
|
|
80
139
|
break;
|
|
81
140
|
}
|
|
82
141
|
case 'testCaseStarted': {
|
|
142
|
+
this.retryTestCaseId = envelope[type].retryTestCaseId;
|
|
83
143
|
const testCaseStarted = envelope[type];
|
|
84
144
|
this.onTestCaseStarted(testCaseStarted);
|
|
85
145
|
break;
|
|
@@ -101,13 +161,18 @@ class ReportGenerator {
|
|
|
101
161
|
}
|
|
102
162
|
case 'testCaseFinished': {
|
|
103
163
|
const testCaseFinished = envelope[type];
|
|
104
|
-
|
|
105
|
-
|
|
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;
|
|
106
171
|
}
|
|
107
172
|
// case "hook": { break} // After Hook
|
|
108
173
|
case 'testRunFinished': {
|
|
109
174
|
const testRunFinished = envelope[type];
|
|
110
|
-
this.onTestRunFinished(testRunFinished);
|
|
175
|
+
await this.onTestRunFinished(testRunFinished);
|
|
111
176
|
break;
|
|
112
177
|
}
|
|
113
178
|
// case "parameterType" : { break}
|
|
@@ -238,6 +303,10 @@ class ReportGenerator {
|
|
|
238
303
|
result: {
|
|
239
304
|
status: 'UNKNOWN',
|
|
240
305
|
},
|
|
306
|
+
networkData: [],
|
|
307
|
+
webLog: [],
|
|
308
|
+
data: {},
|
|
309
|
+
ariaSnapshot: this.ariaSnapshot,
|
|
241
310
|
});
|
|
242
311
|
return this.stepReportMap.get(pickleStep.id);
|
|
243
312
|
});
|
|
@@ -280,6 +349,14 @@ class ReportGenerator {
|
|
|
280
349
|
this.reportFolder = body.replaceAll('\\', '/');
|
|
281
350
|
return;
|
|
282
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
|
+
}
|
|
283
360
|
if (mediaType === 'application/json+env') {
|
|
284
361
|
const data = JSON.parse(body);
|
|
285
362
|
this.report.env = data;
|
|
@@ -290,13 +367,16 @@ class ReportGenerator {
|
|
|
290
367
|
}
|
|
291
368
|
if (mediaType === 'application/json+log') {
|
|
292
369
|
const log = JSON.parse(body);
|
|
293
|
-
if (this.logs.length < 1000)
|
|
370
|
+
if (this.logs.length < 1000) {
|
|
294
371
|
this.logs.push(log);
|
|
372
|
+
this.stepLogs.push(log);
|
|
373
|
+
}
|
|
295
374
|
}
|
|
296
375
|
if (mediaType === 'application/json+network') {
|
|
297
376
|
const networkLog = JSON.parse(body);
|
|
298
377
|
if (this.networkLog.length < 1000)
|
|
299
378
|
this.networkLog.push(networkLog);
|
|
379
|
+
this.stepNetworkLogs.push(networkLog);
|
|
300
380
|
}
|
|
301
381
|
const testStep = this.testStepMap.get(testStepId);
|
|
302
382
|
if (testStep.pickleStepId === undefined)
|
|
@@ -306,16 +386,102 @@ class ReportGenerator {
|
|
|
306
386
|
const command = JSON.parse(body);
|
|
307
387
|
stepProgess.commands.push(command);
|
|
308
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
|
+
};
|
|
309
431
|
}
|
|
310
432
|
onTestStepFinished(testStepFinished) {
|
|
311
433
|
const { testStepId, testStepResult, timestamp } = testStepFinished;
|
|
312
434
|
const testStep = this.testStepMap.get(testStepId);
|
|
313
435
|
if (testStep.pickleStepId === undefined) {
|
|
314
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);
|
|
315
462
|
console.error(`Before/After hook failed with message: ${testStepResult.message}`);
|
|
316
463
|
}
|
|
317
464
|
return;
|
|
318
465
|
}
|
|
466
|
+
if (testStepResult.status === 'UNDEFINED') {
|
|
467
|
+
const step = this.stepReportMap.get(testStep.pickleStepId);
|
|
468
|
+
const stepName = step ? step.keyword + ' ' + step.text : 'Undefined step';
|
|
469
|
+
const undefinedCommand = {
|
|
470
|
+
testStepId: testStepId,
|
|
471
|
+
body: JSON.stringify({
|
|
472
|
+
type: 'error',
|
|
473
|
+
text: 'Undefined step: ' + stepName,
|
|
474
|
+
result: {
|
|
475
|
+
status: 'FAILED',
|
|
476
|
+
startTime: this.getTimeStamp(timestamp),
|
|
477
|
+
endTime: this.getTimeStamp(timestamp),
|
|
478
|
+
},
|
|
479
|
+
}),
|
|
480
|
+
mediaType: 'application/json',
|
|
481
|
+
contentEncoding: messages.AttachmentContentEncoding.IDENTITY,
|
|
482
|
+
};
|
|
483
|
+
this.onAttachment(undefinedCommand);
|
|
484
|
+
}
|
|
319
485
|
const stepProgess = this.stepReportMap.get(testStep.pickleStepId);
|
|
320
486
|
const prevStepResult = stepProgess.result;
|
|
321
487
|
let data = {};
|
|
@@ -331,16 +497,74 @@ class ReportGenerator {
|
|
|
331
497
|
catch (error) {
|
|
332
498
|
console.log('Error reading data.json');
|
|
333
499
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
+
}
|
|
516
|
+
stepProgess.webLog = this.stepLogs;
|
|
517
|
+
stepProgess.networkData = this.stepNetworkLogs;
|
|
518
|
+
stepProgess.ariaSnapshot = this.ariaSnapshot;
|
|
519
|
+
this.ariaSnapshot = '';
|
|
520
|
+
this.stepNetworkLogs = [];
|
|
521
|
+
this.stepLogs = [];
|
|
341
522
|
if (Object.keys(data).length > 0) {
|
|
342
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;
|
|
343
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
|
+
// }
|
|
344
568
|
}
|
|
345
569
|
getLogFileContent() {
|
|
346
570
|
let projectPath = process.cwd();
|
|
@@ -367,6 +591,12 @@ class ReportGenerator {
|
|
|
367
591
|
}
|
|
368
592
|
}
|
|
369
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
|
+
}
|
|
370
600
|
for (const step of steps) {
|
|
371
601
|
switch (step.result.status) {
|
|
372
602
|
case 'FAILED':
|
|
@@ -388,24 +618,79 @@ class ReportGenerator {
|
|
|
388
618
|
status: 'PASSED',
|
|
389
619
|
};
|
|
390
620
|
}
|
|
391
|
-
async onTestCaseFinished(testCaseFinished) {
|
|
621
|
+
async onTestCaseFinished(testCaseFinished, reRunId) {
|
|
392
622
|
const { testCaseStartedId, timestamp } = testCaseFinished;
|
|
393
623
|
const testProgress = this.testCaseReportMap.get(testCaseStartedId);
|
|
394
624
|
const prevResult = testProgress.result;
|
|
395
625
|
const steps = Object.values(testProgress.steps);
|
|
396
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);
|
|
397
631
|
testProgress.result = {
|
|
398
632
|
...result,
|
|
399
633
|
startTime: prevResult.startTime,
|
|
400
|
-
endTime
|
|
634
|
+
endTime,
|
|
401
635
|
};
|
|
402
636
|
testProgress.webLog = this.logs;
|
|
403
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 = '';
|
|
404
643
|
this.networkLog = [];
|
|
405
644
|
this.logs = [];
|
|
406
|
-
|
|
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
|
+
}
|
|
407
672
|
}
|
|
408
|
-
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) {
|
|
409
694
|
let runId = '';
|
|
410
695
|
let projectId = '';
|
|
411
696
|
if (!process.env.UPLOADING_TEST_CASE) {
|
|
@@ -416,21 +701,24 @@ class ReportGenerator {
|
|
|
416
701
|
anyRemArr.push(randomID);
|
|
417
702
|
process.env.UPLOADING_TEST_CASE = JSON.stringify(anyRemArr);
|
|
418
703
|
try {
|
|
419
|
-
if (process.env.RUN_ID &&
|
|
704
|
+
if (process.env.RUN_ID &&
|
|
705
|
+
process.env.PROJECT_ID &&
|
|
706
|
+
!process.env.IGNORE_ENV_VARIABLES) {
|
|
420
707
|
runId = process.env.RUN_ID;
|
|
421
708
|
projectId = process.env.PROJECT_ID;
|
|
422
709
|
}
|
|
423
710
|
else {
|
|
424
|
-
const runDoc = await this.uploadService.createRunDocument(this.runName);
|
|
711
|
+
const runDoc = await this.uploadService.createRunDocument(this.runName, testCase.env);
|
|
425
712
|
runId = runDoc._id;
|
|
426
713
|
projectId = runDoc.project_id;
|
|
427
|
-
process.env.
|
|
428
|
-
|
|
714
|
+
if (!process.env.IGNORE_ENV_VARIABLES) {
|
|
715
|
+
process.env.RUN_ID = runId;
|
|
716
|
+
process.env.PROJECT_ID = projectId;
|
|
717
|
+
}
|
|
429
718
|
}
|
|
430
|
-
await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder);
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
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;
|
|
434
722
|
}
|
|
435
723
|
finally {
|
|
436
724
|
const arrRem = JSON.parse(process.env.UPLOADING_TEST_CASE);
|
|
@@ -438,7 +726,30 @@ class ReportGenerator {
|
|
|
438
726
|
process.env.UPLOADING_TEST_CASE = JSON.stringify(arrRem);
|
|
439
727
|
}
|
|
440
728
|
}
|
|
441
|
-
|
|
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) {
|
|
442
753
|
const { timestamp, success, message } = testRunFinished;
|
|
443
754
|
const prevResult = this.report.result;
|
|
444
755
|
this.report.result = {
|
|
@@ -448,6 +759,7 @@ class ReportGenerator {
|
|
|
448
759
|
message,
|
|
449
760
|
// exception,
|
|
450
761
|
};
|
|
762
|
+
await this.uploadService.createStatus(success ? 'passed' : 'failed');
|
|
451
763
|
}
|
|
452
764
|
}
|
|
453
765
|
exports.default = ReportGenerator;
|