qase-javascript-commons 2.0.0-beta.1 → 2.0.0-beta.2

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 (52) hide show
  1. package/changelog.md +23 -0
  2. package/dist/config/config-validation-schema.js +22 -6
  3. package/dist/env/env-enum.d.ts +14 -7
  4. package/dist/env/env-enum.js +14 -6
  5. package/dist/env/env-to-config.js +6 -3
  6. package/dist/env/env-type.d.ts +7 -4
  7. package/dist/env/env-validation-schema.js +15 -4
  8. package/dist/formatter/index.d.ts +1 -0
  9. package/dist/formatter/index.js +3 -1
  10. package/dist/formatter/jsonp-formatter.d.ts +13 -0
  11. package/dist/formatter/jsonp-formatter.js +28 -0
  12. package/dist/models/attachment.d.ts +8 -0
  13. package/dist/models/attachment.js +2 -0
  14. package/dist/models/execution-sum.d.ts +6 -0
  15. package/dist/models/execution-sum.js +2 -0
  16. package/dist/models/host-data.d.ts +11 -0
  17. package/dist/models/host-data.js +2 -0
  18. package/dist/models/index.d.ts +6 -2
  19. package/dist/models/index.js +4 -4
  20. package/dist/models/report.d.ts +14 -0
  21. package/dist/models/report.js +2 -0
  22. package/dist/models/short-result.d.ts +7 -0
  23. package/dist/models/short-result.js +2 -0
  24. package/dist/models/stats.d.ts +8 -0
  25. package/dist/models/stats.js +2 -0
  26. package/dist/models/step-data.d.ts +4 -0
  27. package/dist/models/step-data.js +2 -0
  28. package/dist/models/step-execution.d.ts +11 -0
  29. package/dist/models/step-execution.js +9 -0
  30. package/dist/models/test-execution.d.ts +19 -0
  31. package/dist/models/test-execution.js +15 -0
  32. package/dist/models/test-result.d.ts +14 -20
  33. package/dist/models/test-result.js +0 -13
  34. package/dist/models/test-step.d.ts +9 -11
  35. package/dist/models/test-step.js +0 -7
  36. package/dist/options/options-type.d.ts +1 -0
  37. package/dist/qase.d.ts +22 -2
  38. package/dist/qase.js +103 -25
  39. package/dist/reporters/abstract-reporter.d.ts +18 -7
  40. package/dist/reporters/abstract-reporter.js +37 -2
  41. package/dist/reporters/report-reporter.d.ts +24 -12
  42. package/dist/reporters/report-reporter.js +152 -13
  43. package/dist/reporters/testops-reporter.d.ts +26 -49
  44. package/dist/reporters/testops-reporter.js +87 -155
  45. package/dist/writer/driver-enum.d.ts +7 -0
  46. package/dist/writer/driver-enum.js +9 -1
  47. package/dist/writer/fs-writer.d.ts +17 -8
  48. package/dist/writer/fs-writer.js +55 -8
  49. package/dist/writer/index.d.ts +1 -1
  50. package/dist/writer/index.js +2 -1
  51. package/dist/writer/writer-interface.d.ts +4 -2
  52. package/package.json +4 -3
package/dist/qase.d.ts CHANGED
@@ -18,12 +18,22 @@ export declare class QaseReporter extends AbstractReporter {
18
18
  * @type {ReporterInterface}
19
19
  * @private
20
20
  */
21
- private upstreamReporter?;
21
+ private readonly upstreamReporter?;
22
+ /**
23
+ * @type {ReporterInterface}
24
+ * @private
25
+ */
26
+ private readonly fallbackReporter?;
22
27
  /**
23
28
  * @type {boolean}
24
29
  * @private
25
30
  */
26
31
  private disabled;
32
+ /**
33
+ * @type {boolean}
34
+ * @private
35
+ */
36
+ private useFallback;
27
37
  /**
28
38
  * @param {OptionsType} options
29
39
  * @param {LoggerInterface} logger
@@ -33,18 +43,28 @@ export declare class QaseReporter extends AbstractReporter {
33
43
  * @param {TestResultType} result
34
44
  */
35
45
  addTestResult(result: TestResultType): void;
46
+ /**
47
+ * @param {TestResultType} result
48
+ * @private
49
+ */
50
+ private addTestResultToFallback;
36
51
  /**
37
52
  * @returns {Promise<void>}
38
53
  */
39
54
  publish(): Promise<void>;
55
+ /**
56
+ * @returns {Promise<void>}
57
+ */
58
+ private publishFallback;
40
59
  /**
41
60
  * @todo implement mode registry
61
+ * @param {ModeEnum} mode
42
62
  * @param {OptionsType} options
43
63
  * @param {LoggerInterface} logger
44
64
  * @returns {ReporterInterface}
45
65
  * @private
46
66
  */
47
- private createUpstreamReporter;
67
+ private createReporter;
48
68
  /**
49
69
  * @param {TestResultType} test
50
70
  * @private
package/dist/qase.js CHANGED
@@ -13,7 +13,6 @@ const options_1 = require("./options");
13
13
  const env_1 = require("./env");
14
14
  const models_1 = require("./models");
15
15
  const writer_1 = require("./writer");
16
- const formatter_1 = require("./formatter");
17
16
  const get_package_version_1 = require("./utils/get-package-version");
18
17
  const custom_boundary_1 = require("./utils/custom-boundary");
19
18
  const disabled_exception_1 = require("./utils/disabled-exception");
@@ -21,12 +20,12 @@ const disabled_exception_1 = require("./utils/disabled-exception");
21
20
  * @type {Record<TestStatusEnum, (test: TestResultType) => string>}
22
21
  */
23
22
  const resultLogMap = {
24
- [models_1.TestStatusEnum.failed]: (test) => (0, chalk_1.default) `{red Test ${test.title} ${test.status}}`,
25
- [models_1.TestStatusEnum.passed]: (test) => (0, chalk_1.default) `{green Test ${test.title} ${test.status}}`,
26
- [models_1.TestStatusEnum.skipped]: (test) => (0, chalk_1.default) `{blueBright Test ${test.title} ${test.status}}`,
27
- [models_1.TestStatusEnum.blocked]: (test) => (0, chalk_1.default) `{blueBright Test ${test.title} ${test.status}}`,
28
- [models_1.TestStatusEnum.disabled]: (test) => (0, chalk_1.default) `{grey Test ${test.title} ${test.status}}`,
29
- [models_1.TestStatusEnum.invalid]: (test) => (0, chalk_1.default) `{yellowBright Test ${test.title} ${test.status}}`,
23
+ [models_1.TestStatusEnum.failed]: (test) => (0, chalk_1.default) `{red Test ${test.title} ${test.execution.status}}`,
24
+ [models_1.TestStatusEnum.passed]: (test) => (0, chalk_1.default) `{green Test ${test.title} ${test.execution.status}}`,
25
+ [models_1.TestStatusEnum.skipped]: (test) => (0, chalk_1.default) `{blueBright Test ${test.title} ${test.execution.status}}`,
26
+ [models_1.TestStatusEnum.blocked]: (test) => (0, chalk_1.default) `{blueBright Test ${test.title} ${test.execution.status}}`,
27
+ [models_1.TestStatusEnum.disabled]: (test) => (0, chalk_1.default) `{grey Test ${test.title} ${test.execution.status}}`,
28
+ [models_1.TestStatusEnum.invalid]: (test) => (0, chalk_1.default) `{yellowBright Test ${test.title} ${test.execution.status}}`,
30
29
  };
31
30
  /**
32
31
  * @class QaseReporter
@@ -58,7 +57,7 @@ class QaseReporter extends reporters_1.AbstractReporter {
58
57
  client.push(`qase-core-reporter=${qaseReporterVersion}`);
59
58
  }
60
59
  if (qaseApiVersion) {
61
- client.push(`qaseapi=${String(qaseApiVersion)}`);
60
+ client.push(`qaseio=${String(qaseApiVersion)}`);
62
61
  }
63
62
  return {
64
63
  'X-Client': client.join('; '),
@@ -78,15 +77,45 @@ class QaseReporter extends reporters_1.AbstractReporter {
78
77
  * @private
79
78
  */
80
79
  this.disabled = false;
80
+ /**
81
+ * @type {boolean}
82
+ * @private
83
+ */
84
+ this.useFallback = false;
81
85
  try {
82
- this.upstreamReporter = this.createUpstreamReporter(composedOptions, logger);
86
+ this.upstreamReporter = this.createReporter(
87
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
88
+ composedOptions.mode || options_1.ModeEnum.off, composedOptions, logger);
83
89
  }
84
90
  catch (error) {
85
91
  if (error instanceof disabled_exception_1.DisabledException) {
86
92
  this.disabled = true;
87
93
  }
88
94
  else {
89
- throw error;
95
+ this.logError('Unable to create upstream reporter:', error);
96
+ if (composedOptions.fallback != undefined) {
97
+ this.disabled = true;
98
+ return;
99
+ }
100
+ this.useFallback = true;
101
+ }
102
+ }
103
+ try {
104
+ this.fallbackReporter = this.createReporter(
105
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
106
+ composedOptions.fallback || options_1.ModeEnum.off, composedOptions, logger);
107
+ }
108
+ catch (error) {
109
+ if (error instanceof disabled_exception_1.DisabledException) {
110
+ if (this.useFallback) {
111
+ this.disabled = true;
112
+ }
113
+ }
114
+ else {
115
+ this.logError('Unable to create fallback reporter:', error);
116
+ if (this.useFallback && this.upstreamReporter === undefined) {
117
+ this.disabled = true;
118
+ }
90
119
  }
91
120
  }
92
121
  }
@@ -95,42 +124,91 @@ class QaseReporter extends reporters_1.AbstractReporter {
95
124
  */
96
125
  addTestResult(result) {
97
126
  if (!this.disabled) {
127
+ this.logTestItem(result);
128
+ if (this.useFallback) {
129
+ this.addTestResultToFallback(result);
130
+ return;
131
+ }
98
132
  try {
99
- this.logTestItem(result);
100
133
  this.upstreamReporter?.addTestResult(result);
101
134
  }
102
135
  catch (error) {
103
- this.logError('Unable to process result:', error);
104
- this.disabled = true;
136
+ this.logError('Unable to add the result to the upstream reporter:', error);
137
+ if (this.fallbackReporter == undefined) {
138
+ this.disabled = true;
139
+ return;
140
+ }
141
+ if (!this.useFallback) {
142
+ this.fallbackReporter.setTestResults(this.upstreamReporter?.getTestResults() ?? []);
143
+ this.useFallback = true;
144
+ }
145
+ this.addTestResultToFallback(result);
105
146
  }
106
147
  }
107
148
  }
149
+ /**
150
+ * @param {TestResultType} result
151
+ * @private
152
+ */
153
+ addTestResultToFallback(result) {
154
+ try {
155
+ this.fallbackReporter?.addTestResult(result);
156
+ }
157
+ catch (error) {
158
+ this.logError('Unable to add the result to the fallback reporter:', error);
159
+ this.disabled = true;
160
+ }
161
+ }
108
162
  /**
109
163
  * @returns {Promise<void>}
110
164
  */
111
165
  async publish() {
112
166
  if (!this.disabled) {
167
+ if (this.useFallback) {
168
+ await this.publishFallback();
169
+ }
113
170
  try {
114
171
  await this.upstreamReporter?.publish();
115
172
  }
116
173
  catch (error) {
117
- this.logError('Unable to publish run results:', error);
118
- this.disabled = true;
174
+ this.logError('Unable to publish the run results to the upstream reporter:', error);
175
+ if (this.fallbackReporter == undefined) {
176
+ this.disabled = true;
177
+ return;
178
+ }
179
+ if (!this.useFallback) {
180
+ this.fallbackReporter.setTestResults(this.upstreamReporter?.getTestResults() ?? []);
181
+ this.useFallback = true;
182
+ }
183
+ await this.publishFallback();
119
184
  }
120
185
  }
121
186
  }
187
+ /**
188
+ * @returns {Promise<void>}
189
+ */
190
+ async publishFallback() {
191
+ try {
192
+ await this.fallbackReporter?.publish();
193
+ }
194
+ catch (error) {
195
+ this.logError('Unable to publish the run results to the fallback reporter:', error);
196
+ this.disabled = true;
197
+ }
198
+ }
122
199
  /**
123
200
  * @todo implement mode registry
201
+ * @param {ModeEnum} mode
124
202
  * @param {OptionsType} options
125
203
  * @param {LoggerInterface} logger
126
204
  * @returns {ReporterInterface}
127
205
  * @private
128
206
  */
129
- createUpstreamReporter(options, logger) {
130
- const { frameworkPackage, frameworkName, reporterName, mode = options_1.ModeEnum.off, environment, report = {}, testops = {}, ...commonOptions } = options;
207
+ createReporter(mode, options, logger) {
208
+ const { frameworkPackage, frameworkName, reporterName, environment, report = {}, testops = {}, ...commonOptions } = options;
131
209
  switch (mode) {
132
210
  case options_1.ModeEnum.testops: {
133
- const { api: { token, headers, ...api } = {}, baseUrl, project, run: { title, description, ...run } = {}, uploadAttachments, } = testops;
211
+ const { api: { token, headers, ...api } = {}, project, run: { title, description, ...run } = {}, plan = {}, chunk, uploadAttachments, } = testops;
134
212
  if (!token) {
135
213
  throw new Error(`Either "testops.api.token" parameter or "${env_1.EnvApiEnum.token}" environment variable is required in "testops" mode`);
136
214
  }
@@ -143,25 +221,25 @@ class QaseReporter extends reporters_1.AbstractReporter {
143
221
  ...headers,
144
222
  ...QaseReporter.createHeaders(frameworkPackage, frameworkName, reporterName),
145
223
  },
146
- ...api
224
+ ...api,
147
225
  }, custom_boundary_1.CustomBoundaryFormData);
148
226
  return new reporters_1.TestOpsReporter({
149
- baseUrl,
150
227
  project,
151
228
  uploadAttachments,
152
229
  run: {
153
230
  title: title ?? `Automated run ${new Date().toISOString()}`,
154
231
  description: description ?? `${reporterName} automated run`,
155
- environment: typeof environment === 'number' ? environment : undefined,
156
232
  ...run,
157
233
  },
234
+ plan,
235
+ chunk,
158
236
  ...commonOptions,
159
- }, apiClient, logger);
237
+ }, apiClient, logger, typeof environment === 'number' ? environment : undefined);
160
238
  }
161
239
  case options_1.ModeEnum.report: {
162
240
  const localOptions = report.connections?.[writer_1.DriverEnum.local];
163
- const writer = new writer_1.FsWriter(localOptions, new formatter_1.JsonFormatter());
164
- return new reporters_1.ReportReporter(commonOptions, writer, logger);
241
+ const writer = new writer_1.FsWriter(localOptions);
242
+ return new reporters_1.ReportReporter(commonOptions, writer, logger, typeof environment === 'number' ? environment.toString() : environment, testops.run?.id);
165
243
  }
166
244
  case options_1.ModeEnum.off:
167
245
  throw new disabled_exception_1.DisabledException();
@@ -174,7 +252,7 @@ class QaseReporter extends reporters_1.AbstractReporter {
174
252
  * @private
175
253
  */
176
254
  logTestItem(test) {
177
- this.log(resultLogMap[test.status](test));
255
+ this.log(resultLogMap[test.execution.status](test));
178
256
  }
179
257
  }
180
258
  exports.QaseReporter = QaseReporter;
@@ -4,12 +4,14 @@ export interface LoggerInterface {
4
4
  group(): void;
5
5
  groupEnd(): void;
6
6
  }
7
- export type ReporterOptionsType = {
7
+ export interface ReporterOptionsType {
8
8
  debug?: boolean | undefined;
9
- };
9
+ }
10
10
  export interface ReporterInterface {
11
11
  addTestResult(result: TestResultType): void;
12
12
  publish(): Promise<void>;
13
+ getTestResults(): TestResultType[];
14
+ setTestResults(results: TestResultType[]): void;
13
15
  }
14
16
  /**
15
17
  * @abstract
@@ -22,11 +24,8 @@ export declare abstract class AbstractReporter implements ReporterInterface {
22
24
  * @type {boolean | undefined}
23
25
  * @private
24
26
  */
25
- private debug;
26
- /**
27
- * @param {TestResultType} result
28
- */
29
- abstract addTestResult(result: TestResultType): void;
27
+ private readonly debug;
28
+ protected results: TestResultType[];
30
29
  /**
31
30
  * @returns {Promise<void>}
32
31
  */
@@ -37,6 +36,18 @@ export declare abstract class AbstractReporter implements ReporterInterface {
37
36
  * @protected
38
37
  */
39
38
  protected constructor(options: ReporterOptionsType | undefined, logger?: LoggerInterface);
39
+ /**
40
+ * @returns {TestResultType[]}
41
+ */
42
+ getTestResults(): TestResultType[];
43
+ /**
44
+ * @param {TestResultType} result
45
+ */
46
+ addTestResult(result: TestResultType): void;
47
+ /**
48
+ * @param {TestResultType[]} results
49
+ */
50
+ setTestResults(results: TestResultType[]): void;
40
51
  /**
41
52
  * @param {string} message
42
53
  * @protected
@@ -7,6 +7,7 @@ exports.AbstractReporter = void 0;
7
7
  const lodash_get_1 = __importDefault(require("lodash.get"));
8
8
  const qase_error_1 = require("../utils/qase-error");
9
9
  const is_axios_error_1 = require("../utils/is-axios-error");
10
+ const uuid_1 = require("uuid");
10
11
  /**
11
12
  * @abstract
12
13
  * @class AbstractReporter
@@ -20,9 +21,43 @@ class AbstractReporter {
20
21
  */
21
22
  constructor(options, logger = console) {
22
23
  this.logger = logger;
24
+ this.results = [];
23
25
  const { debug } = options ?? {};
24
26
  this.debug = debug;
25
27
  }
28
+ /**
29
+ * @returns {TestResultType[]}
30
+ */
31
+ getTestResults() {
32
+ return this.results;
33
+ }
34
+ /**
35
+ * @param {TestResultType} result
36
+ */
37
+ addTestResult(result) {
38
+ if (result.testops_id === null || !Array.isArray(result.testops_id)) {
39
+ this.results.push(result);
40
+ return;
41
+ }
42
+ // if we have multiple ids, we need to create multiple test results and set duration to 0 for all but the first one
43
+ let firstCase = true;
44
+ for (const id of result.testops_id) {
45
+ const testResultCopy = { ...result };
46
+ testResultCopy.testops_id = id;
47
+ testResultCopy.id = (0, uuid_1.v4)();
48
+ if (!firstCase) {
49
+ testResultCopy.execution.duration = 0;
50
+ }
51
+ firstCase = false;
52
+ this.results.push(testResultCopy);
53
+ }
54
+ }
55
+ /**
56
+ * @param {TestResultType[]} results
57
+ */
58
+ setTestResults(results) {
59
+ this.results = results;
60
+ }
26
61
  /**
27
62
  * @param {string} message
28
63
  * @protected
@@ -49,13 +84,13 @@ class AbstractReporter {
49
84
  this.logger.log(message);
50
85
  this.logger.group();
51
86
  if (error instanceof Error) {
52
- this.logger.log(`${error.stack || `${error.name}: ${error.message}`}`);
53
87
  if ((0, is_axios_error_1.isAxiosError)(error)) {
54
88
  this.logApiError(error);
55
89
  }
56
90
  else if (error instanceof qase_error_1.QaseError && error.cause) {
57
91
  this.doLogError('Caused by:', error.cause);
58
92
  }
93
+ this.logger.log(`${error.stack || `${error.name}: ${error.message}`}`);
59
94
  }
60
95
  else {
61
96
  this.logger.log(String(error));
@@ -72,7 +107,7 @@ class AbstractReporter {
72
107
  ?? (0, lodash_get_1.default)(error, 'response.statusText')
73
108
  ?? 'Unknown error';
74
109
  const errorFields = this.formatErrorFields((0, lodash_get_1.default)(error, 'response.data.errorFields'));
75
- this.logger.log(String(errorMessage));
110
+ this.logger.log(`Message: ${String(errorMessage)}`);
76
111
  if (errorFields) {
77
112
  this.logger.group();
78
113
  this.logger.log(errorFields);
@@ -1,5 +1,4 @@
1
- import { AbstractReporter, ReporterOptionsType, LoggerInterface } from './abstract-reporter';
2
- import { TestResultType } from '../models';
1
+ import { AbstractReporter, LoggerInterface, ReporterOptionsType } from './abstract-reporter';
3
2
  import { WriterInterface } from '../writer';
4
3
  /**
5
4
  * @class ReportReporter
@@ -7,25 +6,38 @@ import { WriterInterface } from '../writer';
7
6
  */
8
7
  export declare class ReportReporter extends AbstractReporter {
9
8
  private writer;
10
- /**
11
- * @type {TestResultType[]}
12
- * @private
13
- */
14
- private results;
9
+ private readonly environment;
10
+ private readonly runId;
11
+ private readonly startTime;
15
12
  /**
16
13
  * @param {ReporterOptionsType} options
17
14
  * @param {WriterInterface} writer
18
15
  * @param {LoggerInterface} logger
16
+ * @param {string | undefined} environment
17
+ * @param {number | undefined} runId
19
18
  */
20
- constructor(options: ReporterOptionsType | undefined, writer: WriterInterface, logger?: LoggerInterface);
21
- /**
22
- * @param {TestResultType} result
23
- */
24
- addTestResult(result: TestResultType): void;
19
+ constructor(options: ReporterOptionsType | undefined, writer: WriterInterface, logger?: LoggerInterface, environment?: string, runId?: number);
25
20
  /**
26
21
  * @returns {Promise<void>}
27
22
  *
28
23
  * eslint-disable-next-line @typescript-eslint/require-await
29
24
  */
30
25
  publish(): Promise<void>;
26
+ /**
27
+ * @param {TestStepType[]} steps
28
+ * @returns {TestStepType[]}
29
+ */
30
+ private copyStepAttachments;
31
+ /**
32
+ * @returns {HostData}
33
+ */
34
+ private getHostInfo;
35
+ /**
36
+ * @returns {string}
37
+ */
38
+ private getComputerName;
39
+ /**
40
+ * @returns {string}
41
+ */
42
+ private getDetailedOSInfo;
31
43
  }
@@ -1,7 +1,34 @@
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
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.ReportReporter = void 0;
4
27
  const abstract_reporter_1 = require("./abstract-reporter");
28
+ const models_1 = require("../models");
29
+ const os = __importStar(require("os"));
30
+ const cp = __importStar(require("child_process"));
31
+ const process = __importStar(require("process"));
5
32
  /**
6
33
  * @class ReportReporter
7
34
  * @extends AbstractReporter
@@ -11,21 +38,15 @@ class ReportReporter extends abstract_reporter_1.AbstractReporter {
11
38
  * @param {ReporterOptionsType} options
12
39
  * @param {WriterInterface} writer
13
40
  * @param {LoggerInterface} logger
41
+ * @param {string | undefined} environment
42
+ * @param {number | undefined} runId
14
43
  */
15
- constructor(options, writer, logger) {
44
+ constructor(options, writer, logger, environment, runId) {
16
45
  super(options, logger);
17
46
  this.writer = writer;
18
- /**
19
- * @type {TestResultType[]}
20
- * @private
21
- */
22
- this.results = [];
23
- }
24
- /**
25
- * @param {TestResultType} result
26
- */
27
- addTestResult(result) {
28
- this.results.push(result);
47
+ this.startTime = Date.now();
48
+ this.environment = environment;
49
+ this.runId = runId;
29
50
  }
30
51
  /**
31
52
  * @returns {Promise<void>}
@@ -33,8 +54,126 @@ class ReportReporter extends abstract_reporter_1.AbstractReporter {
33
54
  * eslint-disable-next-line @typescript-eslint/require-await
34
55
  */
35
56
  async publish() {
36
- const path = await this.writer.write(this.results);
57
+ const report = {
58
+ title: 'Test report',
59
+ execution: {
60
+ start_time: this.startTime,
61
+ end_time: Date.now(),
62
+ duration: Date.now() - this.startTime,
63
+ cumulative_duration: 0,
64
+ },
65
+ stats: {
66
+ total: 0,
67
+ passed: 0,
68
+ failed: 0,
69
+ skipped: 0,
70
+ broken: 0,
71
+ muted: 0,
72
+ },
73
+ results: [],
74
+ threads: [],
75
+ suites: [],
76
+ environment: this.environment ?? '',
77
+ host_data: this.getHostInfo(),
78
+ };
79
+ for (const result of this.results) {
80
+ report.stats.total++;
81
+ switch (result.execution.status) {
82
+ case models_1.TestStatusEnum.passed:
83
+ report.stats.passed++;
84
+ break;
85
+ case models_1.TestStatusEnum.failed:
86
+ report.stats.failed++;
87
+ break;
88
+ case models_1.TestStatusEnum.skipped:
89
+ report.stats.skipped++;
90
+ break;
91
+ case models_1.TestStatusEnum.invalid:
92
+ report.stats.broken++;
93
+ break;
94
+ case models_1.TestStatusEnum.blocked:
95
+ report.stats.muted++;
96
+ break;
97
+ }
98
+ if (result.execution.thread && !report.threads.includes(result.execution.thread)) {
99
+ report.threads.push(result.execution.thread);
100
+ }
101
+ report.execution.cumulative_duration += result.execution.duration ?? 0;
102
+ report.results.push({
103
+ duration: result.execution.duration ?? 0,
104
+ id: result.id,
105
+ status: result.execution.status,
106
+ thread: result.execution.thread,
107
+ title: result.title,
108
+ });
109
+ if (result.attachments.length > 0) {
110
+ result.attachments = this.writer.writeAttachment(result.attachments);
111
+ }
112
+ result.steps = this.copyStepAttachments(result.steps);
113
+ result.run_id = this.runId ?? null;
114
+ await this.writer.writeTestResult(result);
115
+ }
116
+ const path = await this.writer.writeReport(report);
37
117
  this.log(`Report saved to ${path}`);
38
118
  }
119
+ /**
120
+ * @param {TestStepType[]} steps
121
+ * @returns {TestStepType[]}
122
+ */
123
+ copyStepAttachments(steps) {
124
+ for (const step of steps) {
125
+ if (step.attachments.length > 0) {
126
+ step.attachments = this.writer.writeAttachment(step.attachments);
127
+ }
128
+ if (step.steps.length > 0) {
129
+ step.steps = this.copyStepAttachments(step.steps);
130
+ }
131
+ }
132
+ return steps;
133
+ }
134
+ /**
135
+ * @returns {HostData}
136
+ */
137
+ getHostInfo() {
138
+ return {
139
+ system: process.platform,
140
+ node: this.getComputerName(),
141
+ release: os.release(),
142
+ version: this.getDetailedOSInfo(),
143
+ machine: os.arch(),
144
+ python: '',
145
+ pip: '',
146
+ node_version: cp.execSync('node --version').toString().trim(),
147
+ npm: cp.execSync('npm --version').toString().trim(),
148
+ };
149
+ }
150
+ /**
151
+ * @returns {string}
152
+ */
153
+ getComputerName() {
154
+ switch (process.platform) {
155
+ case 'win32':
156
+ return process.env['COMPUTERNAME'] ?? '';
157
+ case 'darwin':
158
+ return cp.execSync('scutil --get ComputerName').toString().trim();
159
+ case 'linux': {
160
+ const prettyname = cp.execSync('hostnamectl --pretty').toString().trim();
161
+ return prettyname === '' ? os.hostname() : prettyname;
162
+ }
163
+ default:
164
+ return os.hostname();
165
+ }
166
+ }
167
+ /**
168
+ * @returns {string}
169
+ */
170
+ getDetailedOSInfo() {
171
+ if (process.platform === 'darwin') {
172
+ return cp.execSync('uname -a').toString().trim();
173
+ }
174
+ else {
175
+ return `${os.type()} ${os.release()} ${os.arch()}`;
176
+ }
177
+ }
39
178
  }
40
179
  exports.ReportReporter = ReportReporter;