@dev-blinq/cucumber-js 1.0.105-dev → 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/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 +185 -60
- package/lib/formatter/bvt_analysis_formatter.js.map +1 -1
- package/lib/formatter/feature_data_format.js +12 -3
- 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 +24 -3
- package/lib/formatter/helpers/report_generator.js +343 -25
- 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 -1
- package/lib/formatter/helpers/upload_serivce.js +124 -4
- package/lib/formatter/helpers/upload_serivce.js.map +1 -1
- package/lib/formatter/helpers/uploader.d.ts +2 -1
- package/lib/formatter/helpers/uploader.js +16 -1
- package/lib/formatter/helpers/uploader.js.map +1 -1
- package/lib/formatter/summary_formatter.js +4 -0
- package/lib/formatter/summary_formatter.js.map +1 -1
- package/lib/runtime/test_case_runner.d.ts +1 -0
- package/lib/runtime/test_case_runner.js +10 -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 +5 -2
|
@@ -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
|
};
|
|
@@ -48,7 +48,6 @@ type JsonCommand = {
|
|
|
48
48
|
text: string;
|
|
49
49
|
screenshotId?: string;
|
|
50
50
|
result: JsonCommandResult;
|
|
51
|
-
webLog?: webLog[];
|
|
52
51
|
netWorkLog?: any[];
|
|
53
52
|
};
|
|
54
53
|
type webLog = {
|
|
@@ -63,7 +62,13 @@ export type JsonStep = {
|
|
|
63
62
|
text: string;
|
|
64
63
|
commands: JsonCommand[];
|
|
65
64
|
result: JsonStepResult;
|
|
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,8 +85,14 @@ 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;
|
|
92
|
+
env: {
|
|
93
|
+
name: string;
|
|
94
|
+
baseUrl: string;
|
|
95
|
+
};
|
|
85
96
|
};
|
|
86
97
|
export type JsonReport = {
|
|
87
98
|
testCases: JsonTestProgress[];
|
|
@@ -109,10 +120,16 @@ export default class ReportGenerator {
|
|
|
109
120
|
private scenarioIterationCountMap;
|
|
110
121
|
private logs;
|
|
111
122
|
private networkLog;
|
|
123
|
+
private stepLogs;
|
|
124
|
+
private stepNetworkLogs;
|
|
112
125
|
private runName;
|
|
126
|
+
private ariaSnapshot;
|
|
127
|
+
private initialAriaSnapshot;
|
|
128
|
+
private testCaseLog;
|
|
129
|
+
private loggingOverridden;
|
|
113
130
|
reportFolder: null | string;
|
|
114
131
|
private uploadService;
|
|
115
|
-
handleMessage(envelope: EnvelopeWithMetaMessage): Promise<
|
|
132
|
+
handleMessage(envelope: EnvelopeWithMetaMessage | messages.Envelope, reRunId?: string): Promise<any>;
|
|
116
133
|
getReport(): JsonReport;
|
|
117
134
|
private handleParseError;
|
|
118
135
|
private onGherkinDocument;
|
|
@@ -125,11 +142,15 @@ export default class ReportGenerator {
|
|
|
125
142
|
private onTestCaseStarted;
|
|
126
143
|
private onTestStepStarted;
|
|
127
144
|
private onAttachment;
|
|
145
|
+
private getFailedTestStepResult;
|
|
128
146
|
private onTestStepFinished;
|
|
129
147
|
getLogFileContent(): any;
|
|
130
148
|
private getTestCaseResult;
|
|
131
149
|
private onTestCaseFinished;
|
|
150
|
+
private readonly retryCount;
|
|
132
151
|
private uploadTestCase;
|
|
152
|
+
private tryUpload;
|
|
153
|
+
private writeTestCaseReportToDisk;
|
|
133
154
|
private onTestRunFinished;
|
|
134
155
|
}
|
|
135
156
|
export {};
|
|
@@ -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,19 @@ 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.retryCount = 3;
|
|
46
84
|
}
|
|
47
|
-
async handleMessage(envelope) {
|
|
48
|
-
if (envelope.meta && envelope.meta
|
|
85
|
+
async handleMessage(envelope, reRunId) {
|
|
86
|
+
if (envelope.meta && 'runName' in envelope.meta) {
|
|
49
87
|
this.runName = envelope.meta.runName;
|
|
50
88
|
}
|
|
51
89
|
const type = Object.keys(envelope)[0];
|
|
@@ -72,10 +110,30 @@ class ReportGenerator {
|
|
|
72
110
|
case 'testRunStarted': {
|
|
73
111
|
const testRunStarted = envelope[type];
|
|
74
112
|
this.onTestRunStarted(testRunStarted);
|
|
113
|
+
await this.uploadService.createStatus('running');
|
|
75
114
|
break;
|
|
76
115
|
}
|
|
77
116
|
case 'testCase': {
|
|
78
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
|
|
79
137
|
this.onTestCase(testCase);
|
|
80
138
|
break;
|
|
81
139
|
}
|
|
@@ -101,13 +159,14 @@ class ReportGenerator {
|
|
|
101
159
|
}
|
|
102
160
|
case 'testCaseFinished': {
|
|
103
161
|
const testCaseFinished = envelope[type];
|
|
104
|
-
|
|
105
|
-
|
|
162
|
+
// Call the onTestCaseFinished method
|
|
163
|
+
const result = await this.onTestCaseFinished(testCaseFinished, reRunId);
|
|
164
|
+
return result;
|
|
106
165
|
}
|
|
107
166
|
// case "hook": { break} // After Hook
|
|
108
167
|
case 'testRunFinished': {
|
|
109
168
|
const testRunFinished = envelope[type];
|
|
110
|
-
this.onTestRunFinished(testRunFinished);
|
|
169
|
+
await this.onTestRunFinished(testRunFinished);
|
|
111
170
|
break;
|
|
112
171
|
}
|
|
113
172
|
// case "parameterType" : { break}
|
|
@@ -238,6 +297,10 @@ class ReportGenerator {
|
|
|
238
297
|
result: {
|
|
239
298
|
status: 'UNKNOWN',
|
|
240
299
|
},
|
|
300
|
+
networkData: [],
|
|
301
|
+
webLog: [],
|
|
302
|
+
data: {},
|
|
303
|
+
ariaSnapshot: this.ariaSnapshot,
|
|
241
304
|
});
|
|
242
305
|
return this.stepReportMap.get(pickleStep.id);
|
|
243
306
|
});
|
|
@@ -254,6 +317,10 @@ class ReportGenerator {
|
|
|
254
317
|
},
|
|
255
318
|
webLog: [],
|
|
256
319
|
networkLog: [],
|
|
320
|
+
env: {
|
|
321
|
+
name: this.report.env.name,
|
|
322
|
+
baseUrl: this.report.env.baseUrl,
|
|
323
|
+
},
|
|
257
324
|
});
|
|
258
325
|
this.report.testCases.push(this.testCaseReportMap.get(id));
|
|
259
326
|
}
|
|
@@ -276,19 +343,34 @@ class ReportGenerator {
|
|
|
276
343
|
this.reportFolder = body.replaceAll('\\', '/');
|
|
277
344
|
return;
|
|
278
345
|
}
|
|
346
|
+
if (mediaType === 'application/json+snapshot-before') {
|
|
347
|
+
this.initialAriaSnapshot = body;
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (mediaType === 'application/json+snapshot-after') {
|
|
351
|
+
this.ariaSnapshot = body;
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
279
354
|
if (mediaType === 'application/json+env') {
|
|
280
355
|
const data = JSON.parse(body);
|
|
281
356
|
this.report.env = data;
|
|
357
|
+
this.report.testCases.map((testCase) => {
|
|
358
|
+
testCase.env = data;
|
|
359
|
+
return testCase;
|
|
360
|
+
});
|
|
282
361
|
}
|
|
283
362
|
if (mediaType === 'application/json+log') {
|
|
284
363
|
const log = JSON.parse(body);
|
|
285
|
-
if (this.logs.length < 1000)
|
|
364
|
+
if (this.logs.length < 1000) {
|
|
286
365
|
this.logs.push(log);
|
|
366
|
+
this.stepLogs.push(log);
|
|
367
|
+
}
|
|
287
368
|
}
|
|
288
369
|
if (mediaType === 'application/json+network') {
|
|
289
370
|
const networkLog = JSON.parse(body);
|
|
290
371
|
if (this.networkLog.length < 1000)
|
|
291
372
|
this.networkLog.push(networkLog);
|
|
373
|
+
this.stepNetworkLogs.push(networkLog);
|
|
292
374
|
}
|
|
293
375
|
const testStep = this.testStepMap.get(testStepId);
|
|
294
376
|
if (testStep.pickleStepId === undefined)
|
|
@@ -298,16 +380,100 @@ class ReportGenerator {
|
|
|
298
380
|
const command = JSON.parse(body);
|
|
299
381
|
stepProgess.commands.push(command);
|
|
300
382
|
}
|
|
383
|
+
else if (mediaType === 'application/json+trace') {
|
|
384
|
+
const data = JSON.parse(body);
|
|
385
|
+
stepProgess.traceFilePath = data.traceFilePath;
|
|
386
|
+
}
|
|
387
|
+
if (mediaType === 'application/json+bruno') {
|
|
388
|
+
try {
|
|
389
|
+
const data = JSON.parse(body);
|
|
390
|
+
stepProgess.brunoData = data;
|
|
391
|
+
}
|
|
392
|
+
catch (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);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
getFailedTestStepResult({ commands, startTime, endTime, result, }) {
|
|
407
|
+
for (const command of commands) {
|
|
408
|
+
if (command.result.status === 'FAILED') {
|
|
409
|
+
return {
|
|
410
|
+
status: 'FAILED',
|
|
411
|
+
message: command.result.message,
|
|
412
|
+
startTime,
|
|
413
|
+
endTime,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
status: 'FAILED',
|
|
419
|
+
startTime,
|
|
420
|
+
endTime,
|
|
421
|
+
message: result.message,
|
|
422
|
+
};
|
|
301
423
|
}
|
|
302
424
|
onTestStepFinished(testStepFinished) {
|
|
303
425
|
const { testStepId, testStepResult, timestamp } = testStepFinished;
|
|
304
426
|
const testStep = this.testStepMap.get(testStepId);
|
|
305
427
|
if (testStep.pickleStepId === undefined) {
|
|
306
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);
|
|
307
454
|
console.error(`Before/After hook failed with message: ${testStepResult.message}`);
|
|
308
455
|
}
|
|
309
456
|
return;
|
|
310
457
|
}
|
|
458
|
+
if (testStepResult.status === 'UNDEFINED') {
|
|
459
|
+
const step = this.stepReportMap.get(testStep.pickleStepId);
|
|
460
|
+
const stepName = step ? step.keyword + ' ' + step.text : 'Undefined step';
|
|
461
|
+
const undefinedCommand = {
|
|
462
|
+
testStepId: testStepId,
|
|
463
|
+
body: JSON.stringify({
|
|
464
|
+
type: 'error',
|
|
465
|
+
text: 'Undefined step: ' + stepName,
|
|
466
|
+
result: {
|
|
467
|
+
status: 'FAILED',
|
|
468
|
+
startTime: this.getTimeStamp(timestamp),
|
|
469
|
+
endTime: this.getTimeStamp(timestamp),
|
|
470
|
+
},
|
|
471
|
+
}),
|
|
472
|
+
mediaType: 'application/json',
|
|
473
|
+
contentEncoding: messages.AttachmentContentEncoding.IDENTITY,
|
|
474
|
+
};
|
|
475
|
+
this.onAttachment(undefinedCommand);
|
|
476
|
+
}
|
|
311
477
|
const stepProgess = this.stepReportMap.get(testStep.pickleStepId);
|
|
312
478
|
const prevStepResult = stepProgess.result;
|
|
313
479
|
let data = {};
|
|
@@ -323,16 +489,73 @@ class ReportGenerator {
|
|
|
323
489
|
catch (error) {
|
|
324
490
|
console.log('Error reading data.json');
|
|
325
491
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
492
|
+
if (testStepResult.status === 'FAILED') {
|
|
493
|
+
stepProgess.result = this.getFailedTestStepResult({
|
|
494
|
+
commands: stepProgess.commands,
|
|
495
|
+
startTime: prevStepResult.startTime,
|
|
496
|
+
endTime: this.getTimeStamp(timestamp),
|
|
497
|
+
result: testStepResult,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
stepProgess.result = {
|
|
502
|
+
status: testStepResult.status,
|
|
503
|
+
startTime: prevStepResult.startTime,
|
|
504
|
+
endTime: this.getTimeStamp(timestamp),
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
stepProgess.webLog = this.stepLogs;
|
|
508
|
+
stepProgess.networkData = this.stepNetworkLogs;
|
|
509
|
+
stepProgess.ariaSnapshot = this.ariaSnapshot;
|
|
510
|
+
this.ariaSnapshot = '';
|
|
511
|
+
this.stepNetworkLogs = [];
|
|
512
|
+
this.stepLogs = [];
|
|
333
513
|
if (Object.keys(data).length > 0) {
|
|
334
514
|
stepProgess.data = data;
|
|
515
|
+
const id = testStepFinished.testCaseStartedId;
|
|
516
|
+
const parameters = this.testCaseReportMap.get(id).parameters;
|
|
517
|
+
const _parameters = {};
|
|
518
|
+
Object.keys(parameters).map((key) => {
|
|
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]);
|
|
524
|
+
if (value) {
|
|
525
|
+
if (value.startsWith('secret:')) {
|
|
526
|
+
value = 'secret:****';
|
|
527
|
+
}
|
|
528
|
+
else if (value.startsWith('totp:')) {
|
|
529
|
+
value = 'totp:****';
|
|
530
|
+
}
|
|
531
|
+
else if (value.startsWith('mask:')) {
|
|
532
|
+
value = 'mask:****';
|
|
533
|
+
}
|
|
534
|
+
_parameters[key] = value;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
_parameters[key] = parameters[key];
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
this.report.testCases.find((testCase) => {
|
|
542
|
+
return testCase.id === id;
|
|
543
|
+
}).parameters = _parameters;
|
|
335
544
|
}
|
|
545
|
+
// if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
|
|
546
|
+
// this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH
|
|
547
|
+
// if (!fs.existsSync(this.reportFolder)) {
|
|
548
|
+
// fs.mkdirSync(this.reportFolder)
|
|
549
|
+
// }
|
|
550
|
+
// const reportFilePath = path.join(
|
|
551
|
+
// this.reportFolder,
|
|
552
|
+
// `report.json`
|
|
553
|
+
// )
|
|
554
|
+
// writeFileSync(reportFilePath, JSON.stringify(this.report, null, 2))
|
|
555
|
+
// return undefined
|
|
556
|
+
// // } else {
|
|
557
|
+
// // return await this.uploadTestCase(testProgress, reRunId)
|
|
558
|
+
// }
|
|
336
559
|
}
|
|
337
560
|
getLogFileContent() {
|
|
338
561
|
let projectPath = process.cwd();
|
|
@@ -359,6 +582,12 @@ class ReportGenerator {
|
|
|
359
582
|
}
|
|
360
583
|
}
|
|
361
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
|
+
}
|
|
362
591
|
for (const step of steps) {
|
|
363
592
|
switch (step.result.status) {
|
|
364
593
|
case 'FAILED':
|
|
@@ -380,28 +609,87 @@ class ReportGenerator {
|
|
|
380
609
|
status: 'PASSED',
|
|
381
610
|
};
|
|
382
611
|
}
|
|
383
|
-
async onTestCaseFinished(testCaseFinished) {
|
|
612
|
+
async onTestCaseFinished(testCaseFinished, reRunId) {
|
|
384
613
|
const { testCaseStartedId, timestamp } = testCaseFinished;
|
|
385
614
|
const testProgress = this.testCaseReportMap.get(testCaseStartedId);
|
|
386
615
|
const prevResult = testProgress.result;
|
|
387
616
|
const steps = Object.values(testProgress.steps);
|
|
388
617
|
const result = this.getTestCaseResult(steps);
|
|
618
|
+
if (result.status === 'PASSED' && reRunId) {
|
|
619
|
+
this.uploadService.updateProjectAnalytics(process.env.PROJECT_ID);
|
|
620
|
+
}
|
|
621
|
+
const endTime = this.getTimeStamp(timestamp);
|
|
389
622
|
testProgress.result = {
|
|
390
623
|
...result,
|
|
391
624
|
startTime: prevResult.startTime,
|
|
392
|
-
endTime
|
|
625
|
+
endTime,
|
|
393
626
|
};
|
|
394
627
|
testProgress.webLog = this.logs;
|
|
395
628
|
testProgress.networkLog = this.networkLog;
|
|
629
|
+
testProgress.initialAriaSnapshot = this.initialAriaSnapshot;
|
|
630
|
+
this.initialAriaSnapshot = '';
|
|
396
631
|
this.networkLog = [];
|
|
397
632
|
this.logs = [];
|
|
398
|
-
|
|
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 = [];
|
|
646
|
+
if (process.env.TESTCASE_REPORT_FOLDER_PATH) {
|
|
647
|
+
this.reportFolder = process.env.TESTCASE_REPORT_FOLDER_PATH;
|
|
648
|
+
if (!fs_1.default.existsSync(this.reportFolder)) {
|
|
649
|
+
fs_1.default.mkdirSync(this.reportFolder);
|
|
650
|
+
}
|
|
651
|
+
const reportFilePath = path_1.default.join(this.reportFolder, `${endTime}_${testProgress.scenarioName}.json`);
|
|
652
|
+
(0, fs_extra_1.writeFileSync)(reportFilePath, JSON.stringify(testProgress, null, 2));
|
|
653
|
+
return undefined;
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
return await this.uploadTestCase(testProgress, reRunId);
|
|
657
|
+
}
|
|
399
658
|
}
|
|
400
|
-
async uploadTestCase(testCase) {
|
|
659
|
+
async uploadTestCase(testCase, rerunId) {
|
|
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) {
|
|
401
680
|
let runId = '';
|
|
402
681
|
let projectId = '';
|
|
682
|
+
if (!process.env.UPLOADING_TEST_CASE) {
|
|
683
|
+
process.env.UPLOADING_TEST_CASE = '[]';
|
|
684
|
+
}
|
|
685
|
+
const anyRemArr = JSON.parse(process.env.UPLOADING_TEST_CASE);
|
|
686
|
+
const randomID = Math.random().toString(36).substring(7);
|
|
687
|
+
anyRemArr.push(randomID);
|
|
688
|
+
process.env.UPLOADING_TEST_CASE = JSON.stringify(anyRemArr);
|
|
403
689
|
try {
|
|
404
|
-
if (process.env.RUN_ID &&
|
|
690
|
+
if (process.env.RUN_ID &&
|
|
691
|
+
process.env.PROJECT_ID &&
|
|
692
|
+
!process.env.IGNORE_ENV_VARIABLES) {
|
|
405
693
|
runId = process.env.RUN_ID;
|
|
406
694
|
projectId = process.env.PROJECT_ID;
|
|
407
695
|
}
|
|
@@ -409,16 +697,45 @@ class ReportGenerator {
|
|
|
409
697
|
const runDoc = await this.uploadService.createRunDocument(this.runName);
|
|
410
698
|
runId = runDoc._id;
|
|
411
699
|
projectId = runDoc.project_id;
|
|
412
|
-
process.env.
|
|
413
|
-
|
|
700
|
+
if (!process.env.IGNORE_ENV_VARIABLES) {
|
|
701
|
+
process.env.RUN_ID = runId;
|
|
702
|
+
process.env.PROJECT_ID = projectId;
|
|
703
|
+
}
|
|
414
704
|
}
|
|
415
|
-
await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder);
|
|
705
|
+
const data = await this.uploadService.uploadTestCase(testCase, runId, projectId, this.reportFolder, rerunId);
|
|
706
|
+
this.writeTestCaseReportToDisk(testCase);
|
|
707
|
+
return data;
|
|
416
708
|
}
|
|
417
|
-
|
|
418
|
-
|
|
709
|
+
finally {
|
|
710
|
+
const arrRem = JSON.parse(process.env.UPLOADING_TEST_CASE);
|
|
711
|
+
arrRem.splice(arrRem.indexOf(randomID), 1);
|
|
712
|
+
process.env.UPLOADING_TEST_CASE = JSON.stringify(arrRem);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
writeTestCaseReportToDisk(testCase) {
|
|
716
|
+
var _a;
|
|
717
|
+
const reportFolder = (_a = this.reportFolder) !== null && _a !== void 0 ? _a : process.env.TESTCASE_REPORT_FOLDER_PATH;
|
|
718
|
+
if (!reportFolder) {
|
|
719
|
+
console.error('Report folder is not defined');
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
try {
|
|
723
|
+
let i = 0;
|
|
724
|
+
while (fs_1.default.existsSync(path_1.default.join(reportFolder, `${i}`))) {
|
|
725
|
+
i++;
|
|
726
|
+
}
|
|
727
|
+
fs_1.default.mkdirSync(path_1.default.join(reportFolder, `${i}`));
|
|
728
|
+
//exclude network log from the saved report
|
|
729
|
+
const networkLog = testCase.networkLog;
|
|
730
|
+
delete testCase.networkLog;
|
|
731
|
+
fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `report.json`), JSON.stringify(testCase, null, 2));
|
|
732
|
+
fs_1.default.writeFileSync(path_1.default.join(reportFolder, `${i}`, `network.json`), JSON.stringify(networkLog, null, 2));
|
|
733
|
+
}
|
|
734
|
+
catch (error) {
|
|
735
|
+
console.error('Error writing test case report to disk:', error);
|
|
419
736
|
}
|
|
420
737
|
}
|
|
421
|
-
onTestRunFinished(testRunFinished) {
|
|
738
|
+
async onTestRunFinished(testRunFinished) {
|
|
422
739
|
const { timestamp, success, message } = testRunFinished;
|
|
423
740
|
const prevResult = this.report.result;
|
|
424
741
|
this.report.result = {
|
|
@@ -428,6 +745,7 @@ class ReportGenerator {
|
|
|
428
745
|
message,
|
|
429
746
|
// exception,
|
|
430
747
|
};
|
|
748
|
+
await this.uploadService.createStatus(success ? 'passed' : 'failed');
|
|
431
749
|
}
|
|
432
750
|
}
|
|
433
751
|
exports.default = ReportGenerator;
|