@dev-blinq/cucumber-js 1.0.86-dev → 1.0.86-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/download-install.js +40 -13
- package/lib/configuration/axios_client.js +1 -1
- package/lib/configuration/axios_client.js.map +1 -1
- package/lib/formatter/api.d.ts +2 -0
- package/lib/formatter/api.js +59 -0
- package/lib/formatter/api.js.map +1 -0
- package/lib/formatter/bvt_analysis_formatter.d.ts +13 -1
- package/lib/formatter/bvt_analysis_formatter.js +197 -72
- package/lib/formatter/bvt_analysis_formatter.js.map +1 -1
- package/lib/formatter/feature_data_format.js +15 -2
- 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 +31 -2
- package/lib/formatter/helpers/report_generator.js +334 -16
- 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/upload_serivce.d.ts +16 -2
- package/lib/formatter/helpers/upload_serivce.js +176 -16
- 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 +59 -5
- 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 +4 -2
package/bin/download-install.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
/* eslint-disable no-undef */
|
|
1
4
|
const { argv } = require('node:process')
|
|
2
5
|
const fs = require('fs')
|
|
3
6
|
const path = require('path')
|
|
@@ -14,8 +17,16 @@ const getSSoUrl = () => {
|
|
|
14
17
|
return 'http://localhost:5000/api/auth'
|
|
15
18
|
case 'dev':
|
|
16
19
|
return 'https://dev.api.blinq.io/api/auth'
|
|
17
|
-
|
|
20
|
+
case 'stage':
|
|
21
|
+
return 'https://stage.api.blinq.io/api/auth'
|
|
22
|
+
case 'prod':
|
|
23
|
+
return 'https://api.blinq.io/api/auth'
|
|
24
|
+
case null:
|
|
25
|
+
return 'https://api.blinq.io/api/auth'
|
|
26
|
+
case undefined:
|
|
18
27
|
return 'https://api.blinq.io/api/auth'
|
|
28
|
+
default:
|
|
29
|
+
return `${process.env.NODE_ENV_BLINQ}/api/auth`
|
|
19
30
|
}
|
|
20
31
|
}
|
|
21
32
|
|
|
@@ -46,8 +57,14 @@ const getWorkSpaceUrl = () => {
|
|
|
46
57
|
return 'https://dev.api.blinq.io/api/workspace'
|
|
47
58
|
case "stage":
|
|
48
59
|
return 'https://stage.api.blinq.io/api/workspace'
|
|
49
|
-
|
|
60
|
+
case 'prod':
|
|
50
61
|
return 'https://api.blinq.io/api/workspace'
|
|
62
|
+
case null:
|
|
63
|
+
return 'https://api.blinq.io/api/workspace'
|
|
64
|
+
case undefined:
|
|
65
|
+
return 'https://api.blinq.io/api/workspace'
|
|
66
|
+
default:
|
|
67
|
+
return `${process.env.NODE_ENV_BLINQ}/api/workspace`
|
|
51
68
|
}
|
|
52
69
|
}
|
|
53
70
|
|
|
@@ -100,26 +117,31 @@ const dirExists = (path) => {
|
|
|
100
117
|
}
|
|
101
118
|
const ssoUrl = getSSoUrl()
|
|
102
119
|
|
|
120
|
+
const getProjectByAccessKey = async (access_key) => {
|
|
121
|
+
const accessKeyUrl = `${ssoUrl}/getProjectByAccessKey`
|
|
122
|
+
const response = await axios.post(accessKeyUrl, {
|
|
123
|
+
access_key,
|
|
124
|
+
httpAgent: getProxy(),
|
|
125
|
+
proxy: false,
|
|
126
|
+
})
|
|
127
|
+
if (response.status !== 200) {
|
|
128
|
+
console.error('Error: Invalid access key')
|
|
129
|
+
process.exit(1)
|
|
130
|
+
}
|
|
131
|
+
return response.data
|
|
132
|
+
};
|
|
133
|
+
|
|
103
134
|
const downloadAndInstall = async (extractPath, token) => {
|
|
104
135
|
if (!dirExists(extractPath)) {
|
|
105
136
|
fs.mkdirSync(extractPath, { recursive: true })
|
|
106
137
|
}
|
|
107
138
|
try {
|
|
108
|
-
const
|
|
109
|
-
const response = await axios.post(accessKeyUrl, {
|
|
110
|
-
access_key: token,
|
|
111
|
-
httpAgent: getProxy(),
|
|
112
|
-
proxy: false,
|
|
113
|
-
})
|
|
114
|
-
if (response.status !== 200) {
|
|
115
|
-
console.error('Error: Invalid access key')
|
|
116
|
-
process.exit(1)
|
|
117
|
-
}
|
|
139
|
+
const data = await getProjectByAccessKey(token)
|
|
118
140
|
|
|
119
141
|
const workspaceUrl = getWorkSpaceUrl() + '/pull-workspace'
|
|
120
142
|
const res = await axios.get(workspaceUrl, {
|
|
121
143
|
params: {
|
|
122
|
-
projectId:
|
|
144
|
+
projectId: data.project._id,
|
|
123
145
|
},
|
|
124
146
|
httpAgent: getProxy(),
|
|
125
147
|
proxy: false,
|
|
@@ -130,6 +152,11 @@ const downloadAndInstall = async (extractPath, token) => {
|
|
|
130
152
|
},
|
|
131
153
|
})
|
|
132
154
|
|
|
155
|
+
if (res.status !== 200) {
|
|
156
|
+
console.error('Error: Unable to fetch workspace')
|
|
157
|
+
process.exit(1)
|
|
158
|
+
}
|
|
159
|
+
|
|
133
160
|
const zip = await JSZip.loadAsync(res.data)
|
|
134
161
|
for (const filename of Object.keys(zip.files)) {
|
|
135
162
|
const fileData = zip.files[filename]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"axios_client.js","sourceRoot":"","sources":["../../src/configuration/axios_client.ts"],"names":[],"mappings":";;;;;;AAAA,+BAA+B;AAC/B,kDAAyB;AACzB,oDAA6C;AAG7C,MAAM,QAAQ,GAAG,GAAiB,EAAE;IAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE;QACtB,OAAO,IAAI,CAAA;KACZ;IAED,MAAM,KAAK,GAAkB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAA;IAC9C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IAC1B,MAAM,WAAW,GAAiB;QAChC,IAAI,EAAE,GAAG,CAAC,QAAQ;QAClB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;KACvB,CAAA;IAED,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAA;IAElC,IAAI,QAAQ,IAAI,QAAQ,EAAE;QACxB,WAAW,CAAC,SAAS,GAAG,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAA;KAClD;IACD,OAAO,gBAAM,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAA;AACrD,CAAC,CAAA;AAED,MAAM,iBAAiB,GAAG,GAAG,EAAE;IAC7B,IAAI;QACF,MAAM,KAAK,GAAmB,QAAQ,EAAE,CAAA;QACxC,OAAO,eAAK,CAAC,MAAM,CAAC;YAClB,
|
|
1
|
+
{"version":3,"file":"axios_client.js","sourceRoot":"","sources":["../../src/configuration/axios_client.ts"],"names":[],"mappings":";;;;;;AAAA,+BAA+B;AAC/B,kDAAyB;AACzB,oDAA6C;AAG7C,MAAM,QAAQ,GAAG,GAAiB,EAAE;IAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE;QACtB,OAAO,IAAI,CAAA;KACZ;IAED,MAAM,KAAK,GAAkB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAA;IAC9C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IAC1B,MAAM,WAAW,GAAiB;QAChC,IAAI,EAAE,GAAG,CAAC,QAAQ;QAClB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;KACvB,CAAA;IAED,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAA;IAElC,IAAI,QAAQ,IAAI,QAAQ,EAAE;QACxB,WAAW,CAAC,SAAS,GAAG,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAA;KAClD;IACD,OAAO,gBAAM,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAA;AACrD,CAAC,CAAA;AAED,MAAM,iBAAiB,GAAG,GAAG,EAAE;IAC7B,IAAI;QACF,MAAM,KAAK,GAAmB,QAAQ,EAAE,CAAA;QACxC,OAAO,eAAK,CAAC,MAAM,CAAC;YAClB,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,KAAK;SACb,CAAC,CAAA;KACH;IAAC,OAAO,KAAK,EAAE;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC1B,MAAM,IAAI,KAAK,CACb,+BACE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAC1D,EAAE,CACH,CAAA;KACF;AACH,CAAC,CAAA;AAEY,QAAA,WAAW,GAAG,iBAAiB,EAAE,CAAA","sourcesContent":["/* eslint-disable no-console */\nimport axios from 'axios'\nimport tunnel, { ProxyOptions } from 'tunnel'\nimport { Agent } from 'http'\n\nconst getProxy = (): Agent | null => {\n if (!process.env.PROXY) {\n return null\n }\n\n const proxy: string | null = process.env.PROXY\n const url = new URL(proxy)\n const proxyObject: ProxyOptions = {\n host: url.hostname,\n port: Number(url.port),\n }\n\n const { username, password } = url\n\n if (username && password) {\n proxyObject.proxyAuth = `${username}:${password}`\n }\n return tunnel.httpsOverHttp({ proxy: proxyObject })\n}\n\nconst createAxiosClient = () => {\n try {\n const agent: string | Agent = getProxy()\n return axios.create({\n httpsAgent: agent,\n proxy: false,\n })\n } catch (error) {\n console.log(error.message)\n throw new Error(\n `Error creating axios client ${\n error instanceof Error ? error.message : error.response.data\n }`\n )\n }\n}\n\nexport const axiosClient = createAxiosClient()\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getProjectByAccessKey = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const tunnel_1 = __importDefault(require("tunnel"));
|
|
9
|
+
const getSSoUrl = () => {
|
|
10
|
+
switch (process.env.NODE_ENV_BLINQ) {
|
|
11
|
+
case 'local':
|
|
12
|
+
return 'http://localhost:5000/api/auth';
|
|
13
|
+
case 'dev':
|
|
14
|
+
return 'https://dev.api.blinq.io/api/auth';
|
|
15
|
+
case 'stage':
|
|
16
|
+
return 'https://stage.api.blinq.io/api/auth';
|
|
17
|
+
case 'prod':
|
|
18
|
+
return 'https://api.blinq.io/api/auth';
|
|
19
|
+
case null:
|
|
20
|
+
return 'https://api.blinq.io/api/auth';
|
|
21
|
+
case undefined:
|
|
22
|
+
return 'https://api.blinq.io/api/auth';
|
|
23
|
+
default:
|
|
24
|
+
return `${process.env.NODE_ENV_BLINQ}/api/auth`;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const getProxy = () => {
|
|
28
|
+
if (!process.env.PROXY) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const proxy = process.env.PROXY;
|
|
32
|
+
const url = new URL(proxy);
|
|
33
|
+
const proxyObject = {
|
|
34
|
+
host: url.hostname,
|
|
35
|
+
port: Number(url.port),
|
|
36
|
+
};
|
|
37
|
+
const { username, password } = url;
|
|
38
|
+
if (username && password) {
|
|
39
|
+
//@ts-ignore
|
|
40
|
+
proxyObject.proxyAuth = `${username}:${password}`;
|
|
41
|
+
}
|
|
42
|
+
return tunnel_1.default.httpsOverHttp({ proxy: proxyObject });
|
|
43
|
+
};
|
|
44
|
+
const getProjectByAccessKey = async (access_key) => {
|
|
45
|
+
const ssoUrl = getSSoUrl();
|
|
46
|
+
const accessKeyUrl = `${ssoUrl}/getProjectByAccessKey`;
|
|
47
|
+
const response = await axios_1.default.post(accessKeyUrl, {
|
|
48
|
+
access_key,
|
|
49
|
+
httpAgent: getProxy(),
|
|
50
|
+
proxy: false,
|
|
51
|
+
});
|
|
52
|
+
if (response.status !== 200) {
|
|
53
|
+
console.error('Error: Invalid access key');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
return response.data;
|
|
57
|
+
};
|
|
58
|
+
exports.getProjectByAccessKey = getProjectByAccessKey;
|
|
59
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/formatter/api.ts"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,oDAA2B;AAE3B,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,QAAQ,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE;QAClC,KAAK,OAAO;YACV,OAAO,gCAAgC,CAAA;QACzC,KAAK,KAAK;YACR,OAAO,mCAAmC,CAAA;QAC5C,KAAK,OAAO;YACV,OAAO,qCAAqC,CAAA;QAC9C,KAAK,MAAM;YACT,OAAO,+BAA+B,CAAA;QACxC,KAAK,IAAI;YACP,OAAO,+BAA+B,CAAA;QACxC,KAAK,SAAS;YACZ,OAAO,+BAA+B,CAAA;QACxC;YACE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,WAAW,CAAA;KAClD;AACH,CAAC,CAAA;AACD,MAAM,QAAQ,GAAG,GAAG,EAAE;IACpB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE;QACtB,OAAO,IAAI,CAAA;KACZ;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAA;IAC/B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IAC1B,MAAM,WAAW,GAAG;QAClB,IAAI,EAAE,GAAG,CAAC,QAAQ;QAClB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;KACvB,CAAA;IAED,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAA;IAElC,IAAI,QAAQ,IAAI,QAAQ,EAAE;QACxB,YAAY;QACZ,WAAW,CAAC,SAAS,GAAG,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAA;KAClD;IACD,OAAO,gBAAM,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAA;AACrD,CAAC,CAAA;AAED,MAAM,qBAAqB,GAAG,KAAK,EAAE,UAAkB,EAAE,EAAE;IACzD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,YAAY,GAAG,GAAG,MAAM,wBAAwB,CAAA;IACtD,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAAC,YAAY,EAAE;QAC9C,UAAU;QACV,SAAS,EAAE,QAAQ,EAAE;QACrB,KAAK,EAAE,KAAK;KACb,CAAC,CAAA;IACF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;QAC3B,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAA;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;KAChB;IACD,OAAO,QAAQ,CAAC,IAAI,CAAA;AACtB,CAAC,CAAA;AAEQ,sDAAqB","sourcesContent":["import axios from 'axios'\nimport tunnel from 'tunnel'\n\nconst getSSoUrl = () => {\n switch (process.env.NODE_ENV_BLINQ) {\n case 'local':\n return 'http://localhost:5000/api/auth'\n case 'dev':\n return 'https://dev.api.blinq.io/api/auth'\n case 'stage':\n return 'https://stage.api.blinq.io/api/auth'\n case 'prod':\n return 'https://api.blinq.io/api/auth'\n case null:\n return 'https://api.blinq.io/api/auth'\n case undefined:\n return 'https://api.blinq.io/api/auth'\n default:\n return `${process.env.NODE_ENV_BLINQ}/api/auth`\n }\n}\nconst getProxy = () => {\n if (!process.env.PROXY) {\n return null\n }\n\n const proxy = process.env.PROXY\n const url = new URL(proxy)\n const proxyObject = {\n host: url.hostname,\n port: Number(url.port),\n }\n\n const { username, password } = url\n\n if (username && password) {\n //@ts-ignore\n proxyObject.proxyAuth = `${username}:${password}`\n }\n return tunnel.httpsOverHttp({ proxy: proxyObject })\n}\n\nconst getProjectByAccessKey = async (access_key: string) => {\n const ssoUrl = getSSoUrl()\n const accessKeyUrl = `${ssoUrl}/getProjectByAccessKey`\n const response = await axios.post(accessKeyUrl, {\n access_key,\n httpAgent: getProxy(),\n proxy: false,\n })\n if (response.status !== 200) {\n console.error('Error: Invalid access key')\n process.exit(1)\n }\n return response.data\n}\n\nexport { getProjectByAccessKey }\n"]}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import Formatter, { IFormatterOptions } from '.';
|
|
2
|
+
import ReportGenerator, { JsonTestResult } from './helpers/report_generator';
|
|
3
|
+
export declare let globalReportLink: string;
|
|
2
4
|
export default class BVTAnalysisFormatter extends Formatter {
|
|
5
|
+
static reportGenerator: ReportGenerator;
|
|
6
|
+
static reRunFailedStepsIndex: {
|
|
7
|
+
testCaseId: string;
|
|
8
|
+
failedStepIndex: number;
|
|
9
|
+
}[] | null;
|
|
3
10
|
private reportGenerator;
|
|
4
11
|
private uploader;
|
|
5
12
|
private exit;
|
|
6
13
|
private START;
|
|
7
14
|
private runName;
|
|
15
|
+
private failedStepsIndex;
|
|
16
|
+
private summaryFormatter;
|
|
17
|
+
private rootCauseArray;
|
|
8
18
|
constructor(options: IFormatterOptions);
|
|
19
|
+
private sendEvent;
|
|
9
20
|
private uploadReport;
|
|
10
21
|
finished(): Promise<any>;
|
|
11
22
|
private analyzeReport;
|
|
@@ -13,7 +24,8 @@ export default class BVTAnalysisFormatter extends Formatter {
|
|
|
13
24
|
private processTestCase;
|
|
14
25
|
private uploadFinalReport;
|
|
15
26
|
private retrain;
|
|
27
|
+
private rerun;
|
|
16
28
|
private call_cucumber_client;
|
|
17
|
-
private logReportLink;
|
|
18
29
|
private getAppDataDir;
|
|
19
30
|
}
|
|
31
|
+
export declare function logReportLink(runId: string, projectId: string, status: JsonTestResult): string;
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.logReportLink = exports.globalReportLink = void 0;
|
|
6
7
|
const child_process_1 = require("child_process");
|
|
7
8
|
const fs_1 = require("fs");
|
|
8
9
|
const promises_1 = require("fs/promises");
|
|
@@ -13,36 +14,77 @@ const value_checker_1 = require("../value_checker");
|
|
|
13
14
|
const report_generator_1 = __importDefault(require("./helpers/report_generator"));
|
|
14
15
|
const uploader_1 = __importDefault(require("./helpers/uploader"));
|
|
15
16
|
const os_1 = __importDefault(require("os"));
|
|
17
|
+
const api_1 = require("./api");
|
|
18
|
+
const summary_formatter_1 = __importDefault(require("./summary_formatter"));
|
|
19
|
+
const constants_1 = require("./helpers/constants");
|
|
20
|
+
const axios_client_1 = require("../configuration/axios_client");
|
|
21
|
+
const util_1 = require("util");
|
|
22
|
+
const child_process_2 = require("child_process");
|
|
16
23
|
//User token
|
|
17
24
|
const TOKEN = process.env.TOKEN;
|
|
25
|
+
exports.globalReportLink = '';
|
|
18
26
|
class BVTAnalysisFormatter extends _1.default {
|
|
19
27
|
constructor(options) {
|
|
20
28
|
super(options);
|
|
21
29
|
this.reportGenerator = new report_generator_1.default();
|
|
22
30
|
this.uploader = new uploader_1.default(this.reportGenerator);
|
|
23
31
|
this.exit = false;
|
|
32
|
+
this.rootCauseArray = [];
|
|
33
|
+
this.summaryFormatter = new summary_formatter_1.default(options);
|
|
34
|
+
BVTAnalysisFormatter.reportGenerator = this.reportGenerator;
|
|
35
|
+
this.rootCauseArray = [];
|
|
36
|
+
this.failedStepsIndex = [];
|
|
37
|
+
BVTAnalysisFormatter.reRunFailedStepsIndex = process.env.RERUN
|
|
38
|
+
? JSON.parse(process.env.RERUN)
|
|
39
|
+
: null;
|
|
24
40
|
if (!TOKEN && process.env.BVT_FORMATTER === 'ANALYSIS') {
|
|
25
41
|
throw new Error('TOKEN must be set');
|
|
26
42
|
}
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
this.sendEvent(constants_1.ActionEvents.cli_run_tests);
|
|
44
|
+
options.eventBroadcaster.on('envelope', async (envelope, data) => {
|
|
45
|
+
if ((0, value_checker_1.doesHaveValue)(envelope.testCaseFinished) && data) {
|
|
46
|
+
const { rootCause, report } = data;
|
|
47
|
+
if (!rootCause.status) {
|
|
48
|
+
console.error(`Root cause: ${rootCause.failClass}\n, ${rootCause.analysis}\nfailing step: ${rootCause.failedStep}`);
|
|
49
|
+
this.rootCauseArray.push({ rootCause, report });
|
|
50
|
+
this.failedStepsIndex.push({
|
|
51
|
+
testCaseId: report.id,
|
|
52
|
+
failedStepIndex: rootCause.failedStep,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
await this.reportGenerator.handleMessage(envelope);
|
|
29
58
|
if ((0, value_checker_1.doesHaveValue)(envelope.meta) &&
|
|
30
59
|
(0, value_checker_1.doesHaveValue)(envelope.meta.runName)) {
|
|
31
60
|
this.runName = envelope.meta.runName;
|
|
32
61
|
}
|
|
33
62
|
if ((0, value_checker_1.doesHaveValue)(envelope.testRunFinished)) {
|
|
34
|
-
const report = this.reportGenerator.getReport();
|
|
35
63
|
this.START = Date.now();
|
|
36
64
|
if (process.env.BVT_FORMATTER === 'ANALYSIS') {
|
|
37
|
-
await this.analyzeReport(
|
|
65
|
+
await this.analyzeReport();
|
|
38
66
|
}
|
|
39
67
|
else {
|
|
40
|
-
await this.uploadReport(report)
|
|
68
|
+
// await this.uploadReport(report)
|
|
41
69
|
}
|
|
42
70
|
this.exit = true;
|
|
43
71
|
}
|
|
44
72
|
});
|
|
45
73
|
}
|
|
74
|
+
sendEvent(event) {
|
|
75
|
+
axios_client_1.axiosClient
|
|
76
|
+
.post(`${constants_1.SERVICES_URI.STORAGE}/event`, {
|
|
77
|
+
event,
|
|
78
|
+
}, {
|
|
79
|
+
headers: {
|
|
80
|
+
Authorization: `Bearer ${TOKEN}`,
|
|
81
|
+
'x-source': 'cucumber_js',
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
.catch((err) => {
|
|
85
|
+
// Error with events, ignoring
|
|
86
|
+
});
|
|
87
|
+
}
|
|
46
88
|
async uploadReport(report) {
|
|
47
89
|
const uploadSuccessful = await this.uploadFinalReport(report);
|
|
48
90
|
if (uploadSuccessful && report.result.status !== 'FAILED') {
|
|
@@ -53,77 +95,80 @@ class BVTAnalysisFormatter extends _1.default {
|
|
|
53
95
|
async finished() {
|
|
54
96
|
await new Promise((resolve) => {
|
|
55
97
|
const checkInterval = setInterval(() => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
98
|
+
let anyRem;
|
|
99
|
+
if (process.env.UPLOADING_TEST_CASE) {
|
|
100
|
+
anyRem = JSON.parse(process.env.UPLOADING_TEST_CASE);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
anyRem = undefined;
|
|
104
|
+
}
|
|
105
|
+
if (this.exit && (!anyRem || anyRem.length === 0)) {
|
|
106
|
+
// clearInterval(checkInterval)
|
|
107
|
+
// resolve(null)
|
|
108
|
+
if (this.reportGenerator.getReport().result.status === 'FAILED') {
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
59
114
|
}
|
|
60
115
|
}, 100); // check every 100ms
|
|
61
116
|
});
|
|
62
117
|
}
|
|
63
|
-
async analyzeReport(
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
process.exit(0);
|
|
118
|
+
async analyzeReport() {
|
|
119
|
+
if (this.rootCauseArray.length === 0 ||
|
|
120
|
+
process.env.NO_RETRAIN === 'false') {
|
|
121
|
+
if (this.rootCauseArray.length === 0) {
|
|
122
|
+
this.log('No test failed. No need to retrain\n');
|
|
69
123
|
}
|
|
70
|
-
process.
|
|
124
|
+
if (process.env.NO_RETRAIN === 'false') {
|
|
125
|
+
this.log('Retraining is skipped since the failed step contains an API request\n');
|
|
126
|
+
}
|
|
127
|
+
// const uploadSuccessful = await this.uploadFinalReport(report)
|
|
128
|
+
// process.exit(0)
|
|
129
|
+
this.exit = true;
|
|
130
|
+
return;
|
|
71
131
|
}
|
|
72
132
|
//checking if the type of report.result is JsonResultFailed or not
|
|
73
133
|
this.log('Some tests failed, starting the retraining...\n');
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
await this.uploadFinalReport(report);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
const finalReport = await this.processTestCases(report);
|
|
80
|
-
const uploadSuccessful = await this.uploadFinalReport(finalReport);
|
|
81
|
-
if (finalReport.result.status !== 'FAILED' && uploadSuccessful) {
|
|
82
|
-
process.exit(0);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
134
|
+
await this.processTestCases();
|
|
135
|
+
if (this.reportGenerator.getReport().result.status === 'FAILED') {
|
|
85
136
|
process.exit(1);
|
|
86
137
|
}
|
|
138
|
+
process.exit(0);
|
|
87
139
|
}
|
|
88
|
-
async processTestCases(
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
const modifiedTestCase = await this.processTestCase(testCase, report);
|
|
92
|
-
finalTestCases.push(modifiedTestCase);
|
|
140
|
+
async processTestCases() {
|
|
141
|
+
for (const { rootCause, report } of this.rootCauseArray) {
|
|
142
|
+
await this.processTestCase(rootCause, report);
|
|
93
143
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
async processTestCase(testCase, report) {
|
|
107
|
-
if (testCase.result.status === 'PASSED') {
|
|
108
|
-
return testCase;
|
|
144
|
+
}
|
|
145
|
+
async processTestCase(rootCause, report) {
|
|
146
|
+
const failedTestSteps = rootCause.failedStep;
|
|
147
|
+
if (BVTAnalysisFormatter.reRunFailedStepsIndex &&
|
|
148
|
+
BVTAnalysisFormatter.reRunFailedStepsIndex.length > 0) {
|
|
149
|
+
const previousRun = BVTAnalysisFormatter.reRunFailedStepsIndex[0];
|
|
150
|
+
if (previousRun.failedStepIndex === failedTestSteps) {
|
|
151
|
+
console.log('Same step has failed again, skipping retraining');
|
|
152
|
+
BVTAnalysisFormatter.reRunFailedStepsIndex.shift();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
BVTAnalysisFormatter.reRunFailedStepsIndex.shift();
|
|
109
156
|
}
|
|
110
|
-
const
|
|
111
|
-
.map((step, i) => (step.result.status === 'FAILED' ? i : null))
|
|
112
|
-
.filter((i) => i !== null);
|
|
113
|
-
const retrainStats = await this.retrain(failedTestSteps, testCase);
|
|
157
|
+
const retrainStats = await this.retrain(failedTestSteps, report);
|
|
114
158
|
if (!retrainStats) {
|
|
115
|
-
return
|
|
159
|
+
return;
|
|
116
160
|
}
|
|
117
|
-
|
|
118
|
-
...
|
|
161
|
+
await this.uploader.modifyTestCase({
|
|
162
|
+
...report,
|
|
119
163
|
retrainStats,
|
|
120
|
-
};
|
|
164
|
+
});
|
|
165
|
+
await this.rerun(report);
|
|
121
166
|
}
|
|
122
167
|
async uploadFinalReport(finalReport) {
|
|
123
168
|
let success = true;
|
|
124
169
|
try {
|
|
125
170
|
const { projectId, runId } = await this.uploader.uploadRun(finalReport, this.runName);
|
|
126
|
-
|
|
171
|
+
logReportLink(runId, projectId, finalReport.result);
|
|
127
172
|
}
|
|
128
173
|
catch (err) {
|
|
129
174
|
this.log('Error uploading report\n');
|
|
@@ -132,12 +177,57 @@ class BVTAnalysisFormatter extends _1.default {
|
|
|
132
177
|
}
|
|
133
178
|
success = false;
|
|
134
179
|
}
|
|
180
|
+
finally {
|
|
181
|
+
try {
|
|
182
|
+
(0, fs_1.writeFileSync)(path_1.default.join(this.reportGenerator.reportFolder, 'report.json'), JSON.stringify(finalReport, null, 2), 'utf-8');
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
console.error('failed to write report.json to local disk');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
135
188
|
//this.log(JSON.stringify(finalReport, null, 2))
|
|
136
189
|
return success;
|
|
137
190
|
}
|
|
138
191
|
async retrain(failedTestCases, testCase) {
|
|
192
|
+
const data = await (0, api_1.getProjectByAccessKey)(TOKEN);
|
|
193
|
+
const currentTimestampInSeconds = Math.floor(Date.now() / 1000);
|
|
194
|
+
if (data.project.expriration_date < currentTimestampInSeconds) {
|
|
195
|
+
console.log('Warning: Your project has expired, retraining is restricted. Please contact sales.');
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
139
198
|
return await this.call_cucumber_client(failedTestCases, testCase);
|
|
140
199
|
}
|
|
200
|
+
async rerun(report) {
|
|
201
|
+
await new Promise((resolve) => {
|
|
202
|
+
const node_path = process.argv.shift();
|
|
203
|
+
const args = [
|
|
204
|
+
path_1.default.join(process.cwd(), 'node_modules', '@dev-blinq', 'cucumber-js', 'bin', 'cucumber.js'),
|
|
205
|
+
'--name',
|
|
206
|
+
`^${report.scenarioName}$`,
|
|
207
|
+
'--exit',
|
|
208
|
+
'--format',
|
|
209
|
+
'bvt',
|
|
210
|
+
'--run-name',
|
|
211
|
+
`${report.scenarioName}@debug`,
|
|
212
|
+
path_1.default.join(process.cwd(), 'features', `${report.featureName}.feature`),
|
|
213
|
+
];
|
|
214
|
+
const cucumberClient = (0, child_process_1.spawn)(node_path, args, {
|
|
215
|
+
env: {
|
|
216
|
+
...process.env,
|
|
217
|
+
RERUN: JSON.stringify(this.failedStepsIndex),
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
cucumberClient.stdout.on('data', (data) => {
|
|
221
|
+
console.log(data.toString());
|
|
222
|
+
});
|
|
223
|
+
cucumberClient.stderr.on('data', (data) => {
|
|
224
|
+
console.error(data.toString());
|
|
225
|
+
});
|
|
226
|
+
cucumberClient.on('close', () => {
|
|
227
|
+
resolve();
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
}
|
|
141
231
|
async call_cucumber_client(stepsToRetrain, testCase) {
|
|
142
232
|
return new Promise((resolve, reject) => {
|
|
143
233
|
const cucumber_client_path = path_1.default.resolve(process.cwd(), 'node_modules', '@dev-blinq', 'cucumber_client', 'bin', 'client', 'cucumber.js');
|
|
@@ -146,7 +236,7 @@ class BVTAnalysisFormatter extends _1.default {
|
|
|
146
236
|
path_1.default.join(process.cwd(), testCase.uri),
|
|
147
237
|
`${testCase.scenarioName}`,
|
|
148
238
|
'undefined',
|
|
149
|
-
`${stepsToRetrain
|
|
239
|
+
`${stepsToRetrain},`,
|
|
150
240
|
];
|
|
151
241
|
if (process.env.BLINQ_ENV) {
|
|
152
242
|
args.push(`--env=${process.env.BLINQ_ENV}`);
|
|
@@ -159,12 +249,15 @@ class BVTAnalysisFormatter extends _1.default {
|
|
|
159
249
|
(0, tmp_1.tmpName)(async (err, name) => {
|
|
160
250
|
const tempFile = path_1.default.join(this.getAppDataDir(), 'blinq.io', '.temp', path_1.default.basename(name));
|
|
161
251
|
console.log('File path: ', tempFile);
|
|
252
|
+
// check if the file directory exists, if not create it
|
|
253
|
+
if (!(0, fs_1.existsSync)(path_1.default.dirname(tempFile))) {
|
|
254
|
+
await (0, promises_1.mkdir)(path_1.default.dirname(tempFile), { recursive: true });
|
|
255
|
+
}
|
|
162
256
|
await (0, promises_1.writeFile)(tempFile, '', 'utf-8');
|
|
163
257
|
args.push(`--temp-file=${tempFile}`);
|
|
164
258
|
const cucumberClient = (0, child_process_1.spawn)('node', [cucumber_client_path, ...args], {
|
|
165
259
|
env: {
|
|
166
260
|
...process.env,
|
|
167
|
-
TEMP_FILE_PATH: tempFile,
|
|
168
261
|
},
|
|
169
262
|
});
|
|
170
263
|
cucumberClient.stdout.on('data', (data) => {
|
|
@@ -182,26 +275,21 @@ class BVTAnalysisFormatter extends _1.default {
|
|
|
182
275
|
}
|
|
183
276
|
else {
|
|
184
277
|
this.log('Error retraining\n');
|
|
185
|
-
|
|
278
|
+
try {
|
|
279
|
+
const reportData = (0, fs_1.readFileSync)(tempFile, 'utf-8');
|
|
280
|
+
const retrainStats = JSON.parse(reportData);
|
|
281
|
+
await (0, promises_1.unlink)(tempFile);
|
|
282
|
+
resolve(retrainStats);
|
|
283
|
+
}
|
|
284
|
+
catch (e) {
|
|
285
|
+
this.log('Error reading scenario report\n ' + e);
|
|
286
|
+
resolve(null);
|
|
287
|
+
}
|
|
186
288
|
}
|
|
187
289
|
});
|
|
188
290
|
});
|
|
189
291
|
});
|
|
190
292
|
}
|
|
191
|
-
logReportLink(runId, projectId) {
|
|
192
|
-
let reportLinkBaseUrl = 'https://app.blinq.io';
|
|
193
|
-
if (process.env.NODE_ENV_BLINQ === 'local') {
|
|
194
|
-
reportLinkBaseUrl = 'http://localhost:3000';
|
|
195
|
-
}
|
|
196
|
-
else if (process.env.NODE_ENV_BLINQ === 'dev') {
|
|
197
|
-
reportLinkBaseUrl = 'https://dev.app.blinq.io';
|
|
198
|
-
}
|
|
199
|
-
else if (process.env.NODE_ENV_BLINQ === 'stage') {
|
|
200
|
-
reportLinkBaseUrl = 'https://stage.app.blinq.io';
|
|
201
|
-
}
|
|
202
|
-
const reportLink = `${reportLinkBaseUrl}/${projectId}/run-report/${runId}`;
|
|
203
|
-
this.log(`Report link: ${reportLink}\n`);
|
|
204
|
-
}
|
|
205
293
|
getAppDataDir() {
|
|
206
294
|
if (process.env.BLINQ_APPDATA_DIR) {
|
|
207
295
|
return process.env.BLINQ_APPDATA_DIR;
|
|
@@ -222,4 +310,41 @@ class BVTAnalysisFormatter extends _1.default {
|
|
|
222
310
|
}
|
|
223
311
|
}
|
|
224
312
|
exports.default = BVTAnalysisFormatter;
|
|
313
|
+
function logReportLink(runId, projectId, status) {
|
|
314
|
+
let reportLinkBaseUrl = 'https://app.blinq.io';
|
|
315
|
+
if (process.env.NODE_ENV_BLINQ === 'local') {
|
|
316
|
+
reportLinkBaseUrl = 'http://localhost:3000';
|
|
317
|
+
}
|
|
318
|
+
else if (process.env.NODE_ENV_BLINQ === 'dev') {
|
|
319
|
+
reportLinkBaseUrl = 'https://dev.app.blinq.io';
|
|
320
|
+
}
|
|
321
|
+
else if (process.env.NODE_ENV_BLINQ === 'stage') {
|
|
322
|
+
reportLinkBaseUrl = 'https://stage.app.blinq.io';
|
|
323
|
+
}
|
|
324
|
+
else if (process.env.NODE_ENV_BLINQ === 'prod') {
|
|
325
|
+
reportLinkBaseUrl = 'https://app.blinq.io';
|
|
326
|
+
}
|
|
327
|
+
else if (!process.env.NODE_ENV_BLINQ) {
|
|
328
|
+
reportLinkBaseUrl = 'https://app.blinq.io';
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
reportLinkBaseUrl = process.env.NODE_ENV_BLINQ.replace('api', 'app');
|
|
332
|
+
}
|
|
333
|
+
const reportLink = `${reportLinkBaseUrl}/${projectId}/run-report/${runId}`;
|
|
334
|
+
exports.globalReportLink = reportLink;
|
|
335
|
+
try {
|
|
336
|
+
publishReportLinkToGuacServer(reportLink, status.status === "PASSED");
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
// Error with events, ignoring
|
|
340
|
+
}
|
|
341
|
+
return reportLink;
|
|
342
|
+
}
|
|
343
|
+
exports.logReportLink = logReportLink;
|
|
344
|
+
function publishReportLinkToGuacServer(reportLink, result) {
|
|
345
|
+
if ((0, fs_1.existsSync)('/tmp/report_publish.sh')) {
|
|
346
|
+
const execAsync = (0, util_1.promisify)(child_process_2.exec);
|
|
347
|
+
execAsync('sh /tmp/report_publish.sh ' + reportLink + ' ' + result);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
225
350
|
//# sourceMappingURL=bvt_analysis_formatter.js.map
|