@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.
- 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 +199 -58
- 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 +6 -0
- package/lib/formatter/helpers/constants.js +14 -4
- package/lib/formatter/helpers/constants.js.map +1 -1
- package/lib/formatter/helpers/report_generator.d.ts +21 -2
- package/lib/formatter/helpers/report_generator.js +282 -23
- 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 +22 -2
- package/lib/formatter/helpers/upload_serivce.js +197 -46
- 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/progress_formatter.d.ts +2 -1
- package/lib/formatter/progress_formatter.js.map +1 -1
- package/lib/formatter/snippets_formatter.js.map +1 -1
- package/lib/formatter/summary_formatter.js +4 -0
- package/lib/formatter/summary_formatter.js.map +1 -1
- package/lib/formatter/usage_formatter.js.map +1 -1
- package/lib/formatter/usage_json_formatter.js.map +1 -1
- package/lib/pickle_filter.d.ts +3 -2
- package/lib/pickle_filter.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/uncaught_exception_manager.d.ts +1 -1
- package/lib/uncaught_exception_manager.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 +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: '
|
|
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
|
-
:
|
|
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,
|
|
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
|
-
|
|
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
|
-
:
|
|
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
|
|
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
|
-
|
|
130
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|