@dev-blinq/cucumber-js 1.0.84-dev → 1.0.84-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.
Files changed (34) hide show
  1. package/bin/download-install.js +40 -13
  2. package/lib/configuration/axios_client.js +1 -1
  3. package/lib/configuration/axios_client.js.map +1 -1
  4. package/lib/formatter/api.d.ts +2 -0
  5. package/lib/formatter/api.js +59 -0
  6. package/lib/formatter/api.js.map +1 -0
  7. package/lib/formatter/bvt_analysis_formatter.d.ts +14 -1
  8. package/lib/formatter/bvt_analysis_formatter.js +226 -73
  9. package/lib/formatter/bvt_analysis_formatter.js.map +1 -1
  10. package/lib/formatter/feature_data_format.js +15 -2
  11. package/lib/formatter/feature_data_format.js.map +1 -1
  12. package/lib/formatter/helpers/constants.d.ts +50 -0
  13. package/lib/formatter/helpers/constants.js +60 -0
  14. package/lib/formatter/helpers/constants.js.map +1 -0
  15. package/lib/formatter/helpers/report_generator.d.ts +40 -13
  16. package/lib/formatter/helpers/report_generator.js +349 -54
  17. package/lib/formatter/helpers/report_generator.js.map +1 -1
  18. package/lib/formatter/helpers/test_case_attempt_formatter.js +1 -1
  19. package/lib/formatter/helpers/test_case_attempt_formatter.js.map +1 -1
  20. package/lib/formatter/helpers/upload_serivce.d.ts +16 -3
  21. package/lib/formatter/helpers/upload_serivce.js +176 -34
  22. package/lib/formatter/helpers/upload_serivce.js.map +1 -1
  23. package/lib/formatter/helpers/uploader.d.ts +2 -1
  24. package/lib/formatter/helpers/uploader.js +59 -5
  25. package/lib/formatter/helpers/uploader.js.map +1 -1
  26. package/lib/formatter/summary_formatter.js +4 -0
  27. package/lib/formatter/summary_formatter.js.map +1 -1
  28. package/lib/runtime/test_case_runner.d.ts +1 -0
  29. package/lib/runtime/test_case_runner.js +10 -1
  30. package/lib/runtime/test_case_runner.js.map +1 -1
  31. package/lib/version.d.ts +1 -1
  32. package/lib/version.js +1 -1
  33. package/lib/version.js.map +1 -1
  34. package/package.json +4 -2
@@ -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
- default:
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
- default:
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 accessKeyUrl = `${ssoUrl}/getProjectByAccessKey`
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: response.data.project._id,
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]
@@ -27,7 +27,7 @@ const createAxiosClient = () => {
27
27
  try {
28
28
  const agent = getProxy();
29
29
  return axios_1.default.create({
30
- httpAgent: agent,
30
+ httpsAgent: agent,
31
31
  proxy: false,
32
32
  });
33
33
  }
@@ -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,SAAS,EAAE,KAAK;YAChB,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 httpAgent: 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"]}
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,2 @@
1
+ declare const getProjectByAccessKey: (access_key: string) => Promise<any>;
2
+ export { getProjectByAccessKey };
@@ -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,6 +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;
29
+ private getAppDataDir;
18
30
  }
31
+ export declare function logReportLink(runId: string, projectId: string, status: JsonTestResult): string;
@@ -3,44 +3,88 @@ 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");
9
+ const promises_1 = require("fs/promises");
8
10
  const path_1 = __importDefault(require("path"));
9
- const tmp_promise_1 = require("tmp-promise");
11
+ const tmp_1 = require("tmp");
10
12
  const _1 = __importDefault(require("."));
11
13
  const value_checker_1 = require("../value_checker");
12
14
  const report_generator_1 = __importDefault(require("./helpers/report_generator"));
13
15
  const uploader_1 = __importDefault(require("./helpers/uploader"));
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");
14
23
  //User token
15
24
  const TOKEN = process.env.TOKEN;
25
+ exports.globalReportLink = '';
16
26
  class BVTAnalysisFormatter extends _1.default {
17
27
  constructor(options) {
18
28
  super(options);
19
29
  this.reportGenerator = new report_generator_1.default();
20
30
  this.uploader = new uploader_1.default(this.reportGenerator);
21
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;
22
40
  if (!TOKEN && process.env.BVT_FORMATTER === 'ANALYSIS') {
23
41
  throw new Error('TOKEN must be set');
24
42
  }
25
- options.eventBroadcaster.on('envelope', async (envelope) => {
26
- this.reportGenerator.handleMessage(envelope);
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);
27
58
  if ((0, value_checker_1.doesHaveValue)(envelope.meta) &&
28
59
  (0, value_checker_1.doesHaveValue)(envelope.meta.runName)) {
29
60
  this.runName = envelope.meta.runName;
30
61
  }
31
62
  if ((0, value_checker_1.doesHaveValue)(envelope.testRunFinished)) {
32
- const report = this.reportGenerator.getReport();
33
63
  this.START = Date.now();
34
64
  if (process.env.BVT_FORMATTER === 'ANALYSIS') {
35
- await this.analyzeReport(report);
65
+ await this.analyzeReport();
36
66
  }
37
67
  else {
38
- await this.uploadReport(report);
68
+ // await this.uploadReport(report)
39
69
  }
40
70
  this.exit = true;
41
71
  }
42
72
  });
43
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
+ }
44
88
  async uploadReport(report) {
45
89
  const uploadSuccessful = await this.uploadFinalReport(report);
46
90
  if (uploadSuccessful && report.result.status !== 'FAILED') {
@@ -51,77 +95,80 @@ class BVTAnalysisFormatter extends _1.default {
51
95
  async finished() {
52
96
  await new Promise((resolve) => {
53
97
  const checkInterval = setInterval(() => {
54
- if (this.exit) {
55
- clearInterval(checkInterval);
56
- resolve(null);
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
+ }
57
114
  }
58
115
  }, 100); // check every 100ms
59
116
  });
60
117
  }
61
- async analyzeReport(report) {
62
- if (report.result.status === 'PASSED') {
63
- this.log('No test failed. No need to retrain\n');
64
- const uploadSuccessful = await this.uploadFinalReport(report);
65
- if (uploadSuccessful) {
66
- 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');
67
123
  }
68
- process.exit(1);
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;
69
131
  }
70
132
  //checking if the type of report.result is JsonResultFailed or not
71
133
  this.log('Some tests failed, starting the retraining...\n');
72
- if (!('startTime' in report.result) || !('endTime' in report.result)) {
73
- this.log('Unknown error occured,not retraining\n');
74
- await this.uploadFinalReport(report);
75
- return;
76
- }
77
- const finalReport = await this.processTestCases(report);
78
- const uploadSuccessful = await this.uploadFinalReport(finalReport);
79
- if (finalReport.result.status !== 'FAILED' && uploadSuccessful) {
80
- process.exit(0);
81
- }
82
- else {
134
+ await this.processTestCases();
135
+ if (this.reportGenerator.getReport().result.status === 'FAILED') {
83
136
  process.exit(1);
84
137
  }
138
+ process.exit(0);
85
139
  }
86
- async processTestCases(report) {
87
- const finalTestCases = [];
88
- for (const testCase of report.testCases) {
89
- const modifiedTestCase = await this.processTestCase(testCase, report);
90
- finalTestCases.push(modifiedTestCase);
140
+ async processTestCases() {
141
+ for (const { rootCause, report } of this.rootCauseArray) {
142
+ await this.processTestCase(rootCause, report);
91
143
  }
92
- const finalResult = finalTestCases.some((tc) => tc.result.status !== 'PASSED')
93
- ? report.result
94
- : {
95
- ...report.result,
96
- status: 'PASSED',
97
- };
98
- return {
99
- result: finalResult,
100
- testCases: finalTestCases,
101
- env: report.env,
102
- };
103
- }
104
- async processTestCase(testCase, report) {
105
- if (testCase.result.status === 'PASSED') {
106
- 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();
107
156
  }
108
- const failedTestSteps = testCase.steps
109
- .map((step, i) => (step.result.status === 'FAILED' ? i : null))
110
- .filter((i) => i !== null);
111
- const retrainStats = await this.retrain(failedTestSteps, testCase);
157
+ const retrainStats = await this.retrain(failedTestSteps, report);
112
158
  if (!retrainStats) {
113
- return testCase;
159
+ return;
114
160
  }
115
- return {
116
- ...testCase,
161
+ await this.uploader.modifyTestCase({
162
+ ...report,
117
163
  retrainStats,
118
- };
164
+ });
165
+ await this.rerun(report);
119
166
  }
120
167
  async uploadFinalReport(finalReport) {
121
168
  let success = true;
122
169
  try {
123
170
  const { projectId, runId } = await this.uploader.uploadRun(finalReport, this.runName);
124
- this.logReportLink(runId, projectId);
171
+ logReportLink(runId, projectId, finalReport.result);
125
172
  }
126
173
  catch (err) {
127
174
  this.log('Error uploading report\n');
@@ -130,12 +177,57 @@ class BVTAnalysisFormatter extends _1.default {
130
177
  }
131
178
  success = false;
132
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
+ }
133
188
  //this.log(JSON.stringify(finalReport, null, 2))
134
189
  return success;
135
190
  }
136
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
+ }
137
198
  return await this.call_cucumber_client(failedTestCases, testCase);
138
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
+ }
139
231
  async call_cucumber_client(stepsToRetrain, testCase) {
140
232
  return new Promise((resolve, reject) => {
141
233
  const cucumber_client_path = path_1.default.resolve(process.cwd(), 'node_modules', '@dev-blinq', 'cucumber_client', 'bin', 'client', 'cucumber.js');
@@ -144,14 +236,24 @@ class BVTAnalysisFormatter extends _1.default {
144
236
  path_1.default.join(process.cwd(), testCase.uri),
145
237
  `${testCase.scenarioName}`,
146
238
  'undefined',
147
- `${stepsToRetrain.join(',')}`,
239
+ `${stepsToRetrain},`,
148
240
  ];
149
241
  if (process.env.BLINQ_ENV) {
150
242
  args.push(`--env=${process.env.BLINQ_ENV}`);
151
243
  }
152
- // const temporaryFileTask = await import('tempy')
153
- (0, tmp_promise_1.withFile)(async ({ path: tempFile, fd }) => {
154
- // when this function returns or throws - release the file
244
+ if (!(0, fs_1.existsSync)(path_1.default.join(this.getAppDataDir(), 'blinq.io', '.temp'))) {
245
+ (0, promises_1.mkdir)(path_1.default.join(this.getAppDataDir(), 'blinq.io', '.temp'), {
246
+ recursive: true,
247
+ });
248
+ }
249
+ (0, tmp_1.tmpName)(async (err, name) => {
250
+ const tempFile = path_1.default.join(this.getAppDataDir(), 'blinq.io', '.temp', path_1.default.basename(name));
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
+ }
256
+ await (0, promises_1.writeFile)(tempFile, '', 'utf-8');
155
257
  args.push(`--temp-file=${tempFile}`);
156
258
  const cucumberClient = (0, child_process_1.spawn)('node', [cucumber_client_path, ...args], {
157
259
  env: {
@@ -164,34 +266,85 @@ class BVTAnalysisFormatter extends _1.default {
164
266
  cucumberClient.stderr.on('data', (data) => {
165
267
  console.error(data.toString());
166
268
  });
167
- cucumberClient.on('close', (code) => {
269
+ cucumberClient.on('close', async (code) => {
168
270
  if (code === 0) {
169
271
  const reportData = (0, fs_1.readFileSync)(tempFile, 'utf-8');
170
272
  const retrainStats = JSON.parse(reportData);
273
+ await (0, promises_1.unlink)(tempFile);
171
274
  resolve(retrainStats);
172
275
  }
173
276
  else {
174
277
  this.log('Error retraining\n');
175
- resolve(null);
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
+ }
176
288
  }
177
289
  });
178
290
  });
179
291
  });
180
292
  }
181
- logReportLink(runId, projectId) {
182
- let reportLinkBaseUrl = 'https://app.blinq.io';
183
- if (process.env.NODE_ENV_BLINQ === 'local') {
184
- reportLinkBaseUrl = 'http://localhost:3000';
293
+ getAppDataDir() {
294
+ if (process.env.BLINQ_APPDATA_DIR) {
295
+ return process.env.BLINQ_APPDATA_DIR;
185
296
  }
186
- else if (process.env.NODE_ENV_BLINQ === 'dev') {
187
- reportLinkBaseUrl = 'https://dev.app.blinq.io';
297
+ let appDataDir;
298
+ switch (process.platform) {
299
+ case 'win32':
300
+ appDataDir = process.env.APPDATA;
301
+ break;
302
+ case 'darwin':
303
+ appDataDir = path_1.default.join(os_1.default.homedir(), 'Library', 'Application Support');
304
+ break;
305
+ default:
306
+ appDataDir = path_1.default.join(os_1.default.homedir(), '.config');
307
+ break;
188
308
  }
189
- else if (process.env.NODE_ENV_BLINQ === 'stage') {
190
- reportLinkBaseUrl = 'https://stage.app.blinq.io';
191
- }
192
- const reportLink = `${reportLinkBaseUrl}/${projectId}/run-report/${runId}`;
193
- this.log(`Report link: ${reportLink}\n`);
309
+ return appDataDir;
194
310
  }
195
311
  }
196
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
+ }
197
350
  //# sourceMappingURL=bvt_analysis_formatter.js.map