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