qase-javascript-commons 2.2.19 → 2.3.1

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 (42) hide show
  1. package/README.md +24 -24
  2. package/changelog.md +21 -15
  3. package/dist/client/clientV1.d.ts +31 -0
  4. package/dist/client/clientV1.js +177 -0
  5. package/dist/client/clientV2.d.ts +26 -0
  6. package/dist/client/clientV2.js +197 -0
  7. package/dist/client/dateUtils.d.ts +2 -0
  8. package/dist/client/dateUtils.js +20 -0
  9. package/dist/client/interface.d.ts +6 -0
  10. package/dist/client/interface.js +2 -0
  11. package/dist/config/config-validation-schema.js +0 -22
  12. package/dist/env/env-enum.d.ts +1 -2
  13. package/dist/env/env-enum.js +0 -1
  14. package/dist/env/env-to-config.js +0 -1
  15. package/dist/env/env-type.d.ts +2 -3
  16. package/dist/env/env-validation-schema.js +0 -4
  17. package/dist/formatter/json-formatter.d.ts +2 -2
  18. package/dist/formatter/jsonp-formatter.d.ts +2 -2
  19. package/dist/models/attachment.d.ts +2 -2
  20. package/dist/models/config/TestOpsOptionsType.d.ts +25 -0
  21. package/dist/models/config/TestOpsOptionsType.js +2 -0
  22. package/dist/models/execution-sum.d.ts +2 -2
  23. package/dist/models/host-data.d.ts +2 -1
  24. package/dist/models/report.d.ts +3 -3
  25. package/dist/models/short-result.d.ts +2 -2
  26. package/dist/models/stats.d.ts +2 -2
  27. package/dist/models/test-result.d.ts +6 -6
  28. package/dist/options/options-type.d.ts +2 -6
  29. package/dist/qase.d.ts +1 -0
  30. package/dist/qase.js +16 -53
  31. package/dist/reporters/index.d.ts +1 -1
  32. package/dist/reporters/testops-reporter.d.ts +8 -161
  33. package/dist/reporters/testops-reporter.js +24 -537
  34. package/dist/state/state.js +1 -0
  35. package/dist/steps/step.d.ts +1 -1
  36. package/dist/steps/step.js +2 -2
  37. package/dist/utils/hostData.js +4 -2
  38. package/dist/utils/logger.js +17 -23
  39. package/dist/writer/fs-writer.d.ts +3 -3
  40. package/package.json +3 -2
  41. package/dist/utils/custom-boundary.d.ts +0 -26
  42. package/dist/utils/custom-boundary.js +0 -30
package/README.md CHANGED
@@ -31,31 +31,31 @@ Qase JS Reporters can be configured in multiple ways:
31
31
 
32
32
  All configuration options are listed in the table below:
33
33
 
34
- | Description | Config file | Environment variable | Default value | Required | Possible values |
35
- |----------------------------------------------------------------------------------------------------------------------------|----------------------------|---------------------------------|-----------------------------------------|----------|----------------------------|
36
- | **Common** | | | | | |
37
- | Mode of reporter | `mode` | `QASE_MODE` | `off` | No | `testops`, `report`, `off` |
38
- | Fallback mode of reporter | `fallback` | `QASE_FALLBACK` | `off` | No | `testops`, `report`, `off` |
39
- | Environment | `environment` | `QASE_ENVIRONMENT` | undefined | No | Any string |
40
- | Root suite | `rootSuite` | `QASE_ROOT_SUITE` | undefined | No | Any string |
41
- | Enable debug logs | `debug` | `QASE_DEBUG` | `False` | No | `True`, `False` |
42
- | Enable capture logs from `stdout` and `stderr` | `testops.defect` | `QASE_CAPTURE_LOGS` | `False` | No | `True`, `False` |
43
- | **Qase Report configuration** | | | | | |
44
- | Driver used for report mode | `report.driver` | `QASE_REPORT_DRIVER` | `local` | No | `local` |
45
- | Path to save the report | `report.connection.path` | `QASE_REPORT_CONNECTION_PATH` | `./build/qase-report` | | |
46
- | Local report format | `report.connection.format` | `QASE_REPORT_CONNECTION_FORMAT` | `json` | | `json`, `jsonp` |
47
- | **Qase TestOps configuration** | | | | | |
48
- | Token for [API access](https://developers.qase.io/#authentication) | `testops.api.token` | `QASE_TESTOPS_API_TOKEN` | undefined | Yes | Any string |
49
- | Qase API host. For enterprise users, specify full address: `api-example.qase.io` | `testops.api.host` | `QASE_TESTOPS_API_HOST` | `qase.io` | No | Any string |
50
- | Qase enterprise environment | `testops.api.enterprise` | `QASE_TESTOPS_API_ENTERPRISE` | `False` | No | `True`, `False` |
34
+ | Description | Config file | Environment variable | Default value | Required | Possible values |
35
+ |-----------------------------------------------------------------------------------------------------------------------|----------------------------|---------------------------------|-----------------------------------------|----------|----------------------------|
36
+ | **Common** | | | | | |
37
+ | Mode of reporter | `mode` | `QASE_MODE` | `off` | No | `testops`, `report`, `off` |
38
+ | Fallback mode of reporter | `fallback` | `QASE_FALLBACK` | `off` | No | `testops`, `report`, `off` |
39
+ | Environment | `environment` | `QASE_ENVIRONMENT` | undefined | No | Any string |
40
+ | Root suite | `rootSuite` | `QASE_ROOT_SUITE` | undefined | No | Any string |
41
+ | Enable debug logs | `debug` | `QASE_DEBUG` | `False` | No | `True`, `False` |
42
+ | Enable capture logs from `stdout` and `stderr` | `testops.defect` | `QASE_CAPTURE_LOGS` | `False` | No | `True`, `False` |
43
+ | **Qase Report configuration** | | | | | |
44
+ | Driver used for report mode | `report.driver` | `QASE_REPORT_DRIVER` | `local` | No | `local` |
45
+ | Path to save the report | `report.connection.path` | `QASE_REPORT_CONNECTION_PATH` | `./build/qase-report` | | |
46
+ | Local report format | `report.connection.format` | `QASE_REPORT_CONNECTION_FORMAT` | `json` | | `json`, `jsonp` |
47
+ | **Qase TestOps configuration** | | | | | |
48
+ | Token for [API access](https://developers.qase.io/#authentication) | `testops.api.token` | `QASE_TESTOPS_API_TOKEN` | undefined | Yes | Any string |
49
+ | Qase API host. For enterprise users, specify address: `example.qase.io` | `testops.api.host` | `QASE_TESTOPS_API_HOST` | `qase.io` | No | Any string |
50
+ | Qase enterprise environment | `testops.api.enterprise` | `QASE_TESTOPS_API_ENTERPRISE` | `False` | No | `True`, `False` |
51
51
  | Code of your project, which you can take from the URL: `https://app.qase.io/project/DEMOTR` - `DEMOTR` is the project code | `testops.project` | `QASE_TESTOPS_PROJECT` | undefined | Yes | Any string |
52
- | Qase test run ID | `testops.run.id` | `QASE_TESTOPS_RUN_ID` | undefined | No | Any integer |
53
- | Qase test run title | `testops.run.title` | `QASE_TESTOPS_RUN_TITLE` | `Automated run <Current date and time>` | No | Any string |
54
- | Qase test run description | `testops.run.description` | `QASE_TESTOPS_RUN_DESCRIPTION` | `<Framework name> automated run` | No | Any string |
55
- | Qase test run complete | `testops.run.complete` | `QASE_TESTOPS_RUN_COMPLETE` | `True` | | `True`, `False` |
56
- | Qase test plan ID | `testops.plan.id` | `QASE_TESTOPS_PLAN_ID` | undefined | No | Any integer |
57
- | Size of batch for sending test results | `testops.batch.size` | `QASE_TESTOPS_BATCH_SIZE` | `200` | No | Any integer |
58
- | Enable defects for failed test cases | `testops.defect` | `QASE_TESTOPS_DEFECT` | `False` | No | `True`, `False` |
52
+ | Qase test run ID | `testops.run.id` | `QASE_TESTOPS_RUN_ID` | undefined | No | Any integer |
53
+ | Qase test run title | `testops.run.title` | `QASE_TESTOPS_RUN_TITLE` | `Automated run <Current date and time>` | No | Any string |
54
+ | Qase test run description | `testops.run.description` | `QASE_TESTOPS_RUN_DESCRIPTION` | `<Framework name> automated run` | No | Any string |
55
+ | Qase test run complete | `testops.run.complete` | `QASE_TESTOPS_RUN_COMPLETE` | `True` | | `True`, `False` |
56
+ | Qase test plan ID | `testops.plan.id` | `QASE_TESTOPS_PLAN_ID` | undefined | No | Any integer |
57
+ | Size of batch for sending test results | `testops.batch.size` | `QASE_TESTOPS_BATCH_SIZE` | `200` | No | Any integer |
58
+ | Enable defects for failed test cases | `testops.defect` | `QASE_TESTOPS_DEFECT` | `False` | No | `True`, `False` |
59
59
 
60
60
  ### Example `qase.config.json` config:
61
61
 
package/changelog.md CHANGED
@@ -1,3 +1,9 @@
1
+ # qase-javascript-commons@2.3.0
2
+
3
+ ## What's new
4
+
5
+ Migrated to the new API clients for v1 (`qase-api-client`) and v2 (`qase-api-v2-client`) from the `qaseio`.
6
+
1
7
  # qase-javascript-commons@2.2.18
2
8
 
3
9
  ## What's new
@@ -289,10 +295,10 @@ log a warning message.
289
295
 
290
296
  ## What's new
291
297
 
292
- * The `useV2` option in the reporter's configuration will now enable using the experimental v2 API.
298
+ - The `useV2` option in the reporter's configuration will now enable using the experimental v2 API.
293
299
  Before this fix, v1 API was used despite the configuration.
294
300
 
295
- * Attachments from test steps will now be uploaded to Qase.
301
+ - Attachments from test steps will now be uploaded to Qase.
296
302
  Before this fix, the reporter uploaded only the attachments made outside of any step scope.
297
303
 
298
304
  # qase-javascript-commons@2.0.0-beta.10
@@ -380,10 +386,10 @@ where `10` is the size of the chunk in test result's count.
380
386
  Qase TestOps API has two endpoints for reporting test results:
381
387
 
382
388
  - Version 1, stable and used my most test reporters.
383
- https://developers.qase.io/reference/create-result-bulk
389
+ <https://developers.qase.io/reference/create-result-bulk>
384
390
  - Version 2, currently in beta access, and currently supported only
385
391
  in the `playwright-qase-reporter`.
386
- https://developers.qase.io/v2.0/reference/create-results-v2
392
+ <https://developers.qase.io/v2.0/reference/create-results-v2>
387
393
 
388
394
  This commit introduces a way to select the API version to use.
389
395
  It enables using all new features of v2 JS reporters with the stable v1 API,
@@ -398,7 +404,7 @@ To enable using API v2, set an environment variable before running the tests:
398
404
  QASE_TESTOPS_API_V2=true
399
405
  ```
400
406
 
401
- ### Support adding test suite description to a test report.
407
+ ### Support adding test suite description to a test report
402
408
 
403
409
  Test reporters can now test suite description to test results.
404
410
  Such description can be collected from test's location and attributes
@@ -414,22 +420,22 @@ Add new data models:
414
420
 
415
421
  ## What's new
416
422
 
417
- * Update the config of reporters. Added `captureLogs` field. If it is set to `true`, the reporter will capture logs from
423
+ - Update the config of reporters. Added `captureLogs` field. If it is set to `true`, the reporter will capture logs from
418
424
  the test framework.
419
- * Added `getMimeType` function to the commons package. It returns the MIME type of the file by its extension.
425
+ - Added `getMimeType` function to the commons package. It returns the MIME type of the file by its extension.
420
426
 
421
427
  # qase-javascript-commons@2.0.0-beta.4
422
428
 
423
429
  ## What's new
424
430
 
425
- * Added support for uploading attachments from strings and buffers in the testops reporter.
426
- * Changed data type of `content` in the attachment data from `any` to `string | Buffer`.
431
+ - Added support for uploading attachments from strings and buffers in the testops reporter.
432
+ - Changed data type of `content` in the attachment data from `any` to `string | Buffer`.
427
433
 
428
434
  # qase-javascript-commons@2.0.0-beta.3
429
435
 
430
436
  ## What's new
431
437
 
432
- * Changed data type of `fields` and `parameters` in the test result data
438
+ - Changed data type of `fields` and `parameters` in the test result data
433
439
  from `Map<string, string>` to `Record<string, string>`.
434
440
 
435
441
  # qase-javascript-commons@2.0.0-beta.2
@@ -448,10 +454,10 @@ npm install playwright-qase-reporter@beta
448
454
 
449
455
  ## What's new
450
456
 
451
- * Set a fallback reporter when the primary reporter can't be used,
457
+ - Set a fallback reporter when the primary reporter can't be used,
452
458
  such as when the `testops` reporter can't authenticate with the Qase API.
453
- * Rename some environment variables to keep naming consistent between reporters in all languages.
454
- * Add several environment variables for new config options.
455
- * Write outputs in JSONP format, which can be used with
459
+ - Rename some environment variables to keep naming consistent between reporters in all languages.
460
+ - Add several environment variables for new config options.
461
+ - Write outputs in JSONP format, which can be used with
456
462
  [Qase Report](https://github.com/qase-tms/qase-report).
457
- * Logic for handling test with multiple case IDs moved to the commons package.
463
+ - Logic for handling test with multiple case IDs moved to the commons package.
@@ -0,0 +1,31 @@
1
+ import { Attachment, TestResultType } from '../models';
2
+ import { TestOpsOptionsType } from '../models/config/TestOpsOptionsType';
3
+ import { QaseError } from '../utils/qase-error';
4
+ import { IClient } from './interface';
5
+ import { LoggerInterface } from '../utils/logger';
6
+ export declare class ClientV1 implements IClient {
7
+ protected readonly logger: LoggerInterface;
8
+ protected readonly config: TestOpsOptionsType;
9
+ private readonly environment;
10
+ private readonly appUrl;
11
+ private readonly runClient;
12
+ private readonly environmentClient;
13
+ private readonly attachmentClient;
14
+ constructor(logger: LoggerInterface, config: TestOpsOptionsType, environment: string | undefined);
15
+ private createApiConfig;
16
+ uploadResults(_runId: number, _results: TestResultType[]): Promise<void>;
17
+ createRun(): Promise<number>;
18
+ completeRun(runId: number): Promise<void>;
19
+ protected uploadAttachments(attachments: Attachment[]): Promise<string[]>;
20
+ private prepareAttachmentData;
21
+ private getEnvironmentId;
22
+ private prepareRunObject;
23
+ /**
24
+ * Process error and throw QaseError
25
+ * @param {Error | AxiosError} error
26
+ * @param {string} message
27
+ * @param {object} model
28
+ * @private
29
+ */
30
+ protected processError(error: unknown, message: string, model?: object): QaseError;
31
+ }
@@ -0,0 +1,177 @@
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.ClientV1 = void 0;
7
+ const qase_api_client_1 = require("qase-api-client");
8
+ const is_axios_error_1 = require("../utils/is-axios-error");
9
+ const qase_error_1 = require("../utils/qase-error");
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const fs_1 = require("fs");
12
+ const dateUtils_1 = require("./dateUtils");
13
+ const form_data_1 = __importDefault(require("form-data"));
14
+ const DEFAULT_API_HOST = 'qase.io';
15
+ const API_BASE_URL = 'https://api-';
16
+ const APP_BASE_URL = 'https://app-';
17
+ const API_VERSION = '/v1';
18
+ var ApiErrorCode;
19
+ (function (ApiErrorCode) {
20
+ ApiErrorCode[ApiErrorCode["UNAUTHORIZED"] = 401] = "UNAUTHORIZED";
21
+ ApiErrorCode[ApiErrorCode["FORBIDDEN"] = 403] = "FORBIDDEN";
22
+ ApiErrorCode[ApiErrorCode["NOT_FOUND"] = 404] = "NOT_FOUND";
23
+ ApiErrorCode[ApiErrorCode["BAD_REQUEST"] = 400] = "BAD_REQUEST";
24
+ ApiErrorCode[ApiErrorCode["UNPROCESSABLE_ENTITY"] = 422] = "UNPROCESSABLE_ENTITY";
25
+ })(ApiErrorCode || (ApiErrorCode = {}));
26
+ class ClientV1 {
27
+ logger;
28
+ config;
29
+ environment;
30
+ appUrl;
31
+ runClient;
32
+ environmentClient;
33
+ attachmentClient;
34
+ constructor(logger, config, environment) {
35
+ this.logger = logger;
36
+ this.config = config;
37
+ this.environment = environment;
38
+ const { apiConfig, appUrl } = this.createApiConfig();
39
+ this.appUrl = appUrl;
40
+ this.runClient = new qase_api_client_1.RunsApi(apiConfig);
41
+ this.environmentClient = new qase_api_client_1.EnvironmentsApi(apiConfig);
42
+ this.attachmentClient = new qase_api_client_1.AttachmentsApi(apiConfig);
43
+ }
44
+ createApiConfig() {
45
+ const apiConfig = new qase_api_client_1.Configuration({ apiKey: this.config.api.token, formDataCtor: form_data_1.default });
46
+ if (this.config.api.host && this.config.api.host != DEFAULT_API_HOST) {
47
+ apiConfig.basePath = `${API_BASE_URL}${this.config.api.host}${API_VERSION}`;
48
+ return { apiConfig, appUrl: `${APP_BASE_URL}${this.config.api.host}` };
49
+ }
50
+ apiConfig.basePath = `https://api.${DEFAULT_API_HOST}${API_VERSION}`;
51
+ return { apiConfig, appUrl: `https://app.${DEFAULT_API_HOST}` };
52
+ }
53
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
54
+ uploadResults(_runId, _results) {
55
+ throw new Error('Use ClientV2 to upload results');
56
+ }
57
+ async createRun() {
58
+ if (this.config.run.id) {
59
+ return this.config.run.id;
60
+ }
61
+ try {
62
+ const environmentId = await this.getEnvironmentId();
63
+ const runObject = this.prepareRunObject(environmentId);
64
+ this.logger.logDebug(`Creating test run: ${JSON.stringify(runObject)}`);
65
+ const { data } = await this.runClient.createRun(this.config.project, runObject);
66
+ if (!data.result?.id) {
67
+ throw new qase_error_1.QaseError('Failed to create test run');
68
+ }
69
+ this.logger.logDebug(`Test run created: ${JSON.stringify(data)}`);
70
+ return data.result.id;
71
+ }
72
+ catch (error) {
73
+ throw this.processError(error, 'Error creating test run');
74
+ }
75
+ }
76
+ async completeRun(runId) {
77
+ if (!this.config.run.complete) {
78
+ return;
79
+ }
80
+ try {
81
+ await this.runClient.completeRun(this.config.project, runId);
82
+ }
83
+ catch (error) {
84
+ throw this.processError(error, 'Error on completing run');
85
+ }
86
+ if (this.appUrl) {
87
+ const runUrl = `${this.appUrl}/run/${this.config.project}/dashboard/${runId}`;
88
+ this.logger.log((0, chalk_1.default) `{blue Test run link: ${runUrl}}`);
89
+ }
90
+ }
91
+ async uploadAttachments(attachments) {
92
+ if (!this.config.uploadAttachments) {
93
+ return [];
94
+ }
95
+ const uploadedHashes = [];
96
+ for (const attachment of attachments) {
97
+ try {
98
+ this.logger.logDebug(`Uploading attachment: ${attachment.file_path ?? attachment.file_name}`);
99
+ const data = this.prepareAttachmentData(attachment);
100
+ const response = await this.attachmentClient.uploadAttachment(this.config.project, [data]);
101
+ const hash = response.data.result?.[0]?.hash;
102
+ if (hash) {
103
+ uploadedHashes.push(hash);
104
+ }
105
+ }
106
+ catch (error) {
107
+ this.logger.logError('Cannot upload attachment:', error);
108
+ }
109
+ }
110
+ return uploadedHashes;
111
+ }
112
+ prepareAttachmentData(attachment) {
113
+ if (attachment.file_path) {
114
+ return {
115
+ name: attachment.file_name,
116
+ value: (0, fs_1.createReadStream)(attachment.file_path),
117
+ };
118
+ }
119
+ return {
120
+ name: attachment.file_name,
121
+ value: typeof attachment.content === 'string'
122
+ ? Buffer.from(attachment.content)
123
+ : attachment.content,
124
+ };
125
+ }
126
+ async getEnvironmentId() {
127
+ if (!this.environment)
128
+ return undefined;
129
+ const { data } = await this.environmentClient.getEnvironments(this.config.project, undefined, this.environment, 100);
130
+ return data.result?.entities?.find((env) => env.slug === this.environment)?.id;
131
+ }
132
+ prepareRunObject(environmentId) {
133
+ const runObject = {
134
+ title: this.config.run.title ?? `Automated run ${new Date().toISOString()}`,
135
+ description: this.config.run.description ?? '',
136
+ is_autotest: true,
137
+ cases: [],
138
+ start_time: (0, dateUtils_1.getStartTime)(),
139
+ };
140
+ if (environmentId !== undefined) {
141
+ runObject.environment_id = environmentId;
142
+ }
143
+ if (this.config.plan.id) {
144
+ runObject.plan_id = this.config.plan.id;
145
+ }
146
+ return runObject;
147
+ }
148
+ /**
149
+ * Process error and throw QaseError
150
+ * @param {Error | AxiosError} error
151
+ * @param {string} message
152
+ * @param {object} model
153
+ * @private
154
+ */
155
+ processError(error, message, model) {
156
+ if (!(0, is_axios_error_1.isAxiosError)(error)) {
157
+ return new qase_error_1.QaseError(message, { cause: error });
158
+ }
159
+ const err = error;
160
+ const errorData = err.response?.data;
161
+ const status = err.response?.status;
162
+ switch (status) {
163
+ case ApiErrorCode.UNAUTHORIZED:
164
+ return new qase_error_1.QaseError(`${message}: Unauthorized. Please check your API token.`);
165
+ case ApiErrorCode.FORBIDDEN:
166
+ return new qase_error_1.QaseError(`${message}: ${errorData?.errorMessage ?? 'Forbidden'}`);
167
+ case ApiErrorCode.NOT_FOUND:
168
+ return new qase_error_1.QaseError(`${message}: Not found.`);
169
+ case ApiErrorCode.BAD_REQUEST:
170
+ case ApiErrorCode.UNPROCESSABLE_ENTITY:
171
+ return new qase_error_1.QaseError(`${message}: Bad request\n${JSON.stringify(errorData)}\nBody: ${JSON.stringify(model)}`);
172
+ default:
173
+ return new qase_error_1.QaseError(message, { cause: err });
174
+ }
175
+ }
176
+ }
177
+ exports.ClientV1 = ClientV1;
@@ -0,0 +1,26 @@
1
+ import { ResultStepStatus } from "qase-api-v2-client";
2
+ import { StepStatusEnum, TestResultType, TestStatusEnum } from "../models";
3
+ import { LoggerInterface } from "../utils/logger";
4
+ import { ClientV1 } from "./clientV1";
5
+ import { TestOpsOptionsType } from "../models/config/TestOpsOptionsType";
6
+ export declare class ClientV2 extends ClientV1 {
7
+ private readonly rootSuite;
8
+ static statusMap: Record<TestStatusEnum, string>;
9
+ static stepStatusMap: Record<StepStatusEnum, ResultStepStatus>;
10
+ private readonly resultsClient;
11
+ constructor(logger: LoggerInterface, config: TestOpsOptionsType, environment: string | undefined, rootSuite: string | undefined);
12
+ private createApiConfigV2;
13
+ uploadResults(runId: number, results: TestResultType[]): Promise<void>;
14
+ private transformTestResult;
15
+ private transformParams;
16
+ private transformGroupParams;
17
+ private transformSteps;
18
+ private transformStep;
19
+ private createBaseResultStep;
20
+ private processTextStep;
21
+ private processGherkinStep;
22
+ private getExecution;
23
+ private getRelation;
24
+ private getDefaultSuiteRelation;
25
+ private buildSuiteData;
26
+ }
@@ -0,0 +1,197 @@
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.ClientV2 = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const qase_api_v2_client_1 = require("qase-api-v2-client");
9
+ const models_1 = require("../models");
10
+ const clientV1_1 = require("./clientV1");
11
+ const form_data_1 = __importDefault(require("form-data"));
12
+ const API_CONFIG = {
13
+ DEFAULT_HOST: 'qase.io',
14
+ BASE_URL: 'https://api-',
15
+ VERSION: '/v2'
16
+ };
17
+ class ClientV2 extends clientV1_1.ClientV1 {
18
+ rootSuite;
19
+ static statusMap = {
20
+ [models_1.TestStatusEnum.passed]: 'passed',
21
+ [models_1.TestStatusEnum.failed]: 'failed',
22
+ [models_1.TestStatusEnum.skipped]: 'skipped',
23
+ [models_1.TestStatusEnum.disabled]: 'disabled',
24
+ [models_1.TestStatusEnum.blocked]: 'blocked',
25
+ [models_1.TestStatusEnum.invalid]: 'invalid',
26
+ };
27
+ static stepStatusMap = {
28
+ [models_1.StepStatusEnum.passed]: qase_api_v2_client_1.ResultStepStatus.PASSED,
29
+ [models_1.StepStatusEnum.failed]: qase_api_v2_client_1.ResultStepStatus.FAILED,
30
+ [models_1.StepStatusEnum.blocked]: qase_api_v2_client_1.ResultStepStatus.BLOCKED,
31
+ [models_1.StepStatusEnum.skipped]: qase_api_v2_client_1.ResultStepStatus.SKIPPED,
32
+ };
33
+ resultsClient;
34
+ constructor(logger, config, environment, rootSuite) {
35
+ super(logger, config, environment);
36
+ this.rootSuite = rootSuite;
37
+ const apiConfig = this.createApiConfigV2();
38
+ this.resultsClient = new qase_api_v2_client_1.ResultsApi(apiConfig);
39
+ }
40
+ createApiConfigV2() {
41
+ const apiConfig = new qase_api_v2_client_1.Configuration({ apiKey: this.config.api.token, formDataCtor: form_data_1.default });
42
+ apiConfig.basePath = this.config.api.host && this.config.api.host != API_CONFIG.DEFAULT_HOST
43
+ ? `${API_CONFIG.BASE_URL}${this.config.api.host}${API_CONFIG.VERSION}`
44
+ : `https://api.${API_CONFIG.DEFAULT_HOST}${API_CONFIG.VERSION}`;
45
+ return apiConfig;
46
+ }
47
+ async uploadResults(runId, results) {
48
+ try {
49
+ const models = await Promise.all(results.map(result => this.transformTestResult(result)));
50
+ await this.resultsClient.createResultsV2(this.config.project, runId, {
51
+ results: models,
52
+ });
53
+ }
54
+ catch (error) {
55
+ throw this.processError(error, 'Error on uploading results', results);
56
+ }
57
+ }
58
+ async transformTestResult(result) {
59
+ const attachments = await this.uploadAttachments(result.attachments);
60
+ const steps = await this.transformSteps(result.steps, result.title);
61
+ const params = this.transformParams(result.params);
62
+ const groupParams = this.transformGroupParams(result.group_params, params);
63
+ const relations = this.getRelation(result.relations);
64
+ const model = {
65
+ title: result.title,
66
+ execution: this.getExecution(result.execution),
67
+ testops_ids: Array.isArray(result.testops_id)
68
+ ? result.testops_id
69
+ : result.testops_id !== null ? [result.testops_id] : null,
70
+ attachments: attachments,
71
+ steps: steps,
72
+ params: params,
73
+ param_groups: groupParams,
74
+ relations: relations,
75
+ message: result.message,
76
+ fields: result.fields,
77
+ defect: this.config.defect ?? false,
78
+ };
79
+ this.logger.logDebug(`Transformed result: ${JSON.stringify(model)}`);
80
+ return model;
81
+ }
82
+ transformParams(params) {
83
+ const transformedParams = {};
84
+ for (const [key, value] of Object.entries(params)) {
85
+ if (value) {
86
+ transformedParams[key] = value;
87
+ }
88
+ }
89
+ return transformedParams;
90
+ }
91
+ transformGroupParams(groupParams, params) {
92
+ const keys = Object.keys(groupParams);
93
+ if (keys.length === 0) {
94
+ return [];
95
+ }
96
+ for (const [key, value] of Object.entries(groupParams)) {
97
+ if (value) {
98
+ params[key] = value;
99
+ }
100
+ }
101
+ return [keys];
102
+ }
103
+ async transformSteps(steps, testTitle) {
104
+ return Promise.all(steps.map(step => this.transformStep(step, testTitle)));
105
+ }
106
+ async transformStep(step, testTitle) {
107
+ const attachmentHashes = await this.uploadAttachments(step.attachments);
108
+ const resultStep = this.createBaseResultStep(attachmentHashes, step.execution.status);
109
+ if (step.step_type === models_1.StepType.TEXT) {
110
+ this.processTextStep(step, resultStep, testTitle);
111
+ }
112
+ else {
113
+ this.processGherkinStep(step, resultStep);
114
+ }
115
+ if (step.steps.length > 0) {
116
+ resultStep.steps = await this.transformSteps(step.steps, testTitle);
117
+ }
118
+ return resultStep;
119
+ }
120
+ createBaseResultStep(attachmentHashes, status) {
121
+ return {
122
+ data: {
123
+ action: '',
124
+ },
125
+ execution: {
126
+ status: ClientV2.stepStatusMap[status],
127
+ attachments: attachmentHashes,
128
+ },
129
+ };
130
+ }
131
+ processTextStep(step, resultStep, testTitle) {
132
+ if (!('action' in step.data) || !resultStep.data) {
133
+ return;
134
+ }
135
+ const stepData = step.data;
136
+ resultStep.data.action = stepData.action || 'Unnamed step';
137
+ if (stepData.action === '') {
138
+ this.logger.log((0, chalk_1.default) `{magenta Test '${testTitle}' has empty action in step. The reporter will mark this step as unnamed step.}`);
139
+ }
140
+ if (stepData.expected_result != null) {
141
+ resultStep.data.expected_result = stepData.expected_result;
142
+ }
143
+ if (stepData.data != null) {
144
+ resultStep.data.input_data = stepData.data;
145
+ }
146
+ }
147
+ processGherkinStep(step, resultStep) {
148
+ if (!('keyword' in step.data) || !resultStep.data) {
149
+ return;
150
+ }
151
+ const stepData = step.data;
152
+ resultStep.data.action = stepData.keyword;
153
+ }
154
+ getExecution(exec) {
155
+ return {
156
+ status: ClientV2.statusMap[exec.status],
157
+ start_time: exec.start_time,
158
+ end_time: exec.end_time,
159
+ duration: exec.duration,
160
+ stacktrace: exec.stacktrace,
161
+ thread: exec.thread,
162
+ };
163
+ }
164
+ getRelation(relation) {
165
+ if (!relation?.suite) {
166
+ return this.getDefaultSuiteRelation();
167
+ }
168
+ const suiteData = this.buildSuiteData(relation.suite.data);
169
+ return { suite: { data: suiteData } };
170
+ }
171
+ getDefaultSuiteRelation() {
172
+ if (!this.rootSuite)
173
+ return {};
174
+ return {
175
+ suite: {
176
+ data: [{
177
+ public_id: null,
178
+ title: this.rootSuite,
179
+ }],
180
+ },
181
+ };
182
+ }
183
+ buildSuiteData(suiteData) {
184
+ const result = [];
185
+ if (this.rootSuite) {
186
+ result.push({
187
+ public_id: null,
188
+ title: this.rootSuite,
189
+ });
190
+ }
191
+ return result.concat(suiteData.map(data => ({
192
+ public_id: null,
193
+ title: data.title,
194
+ })));
195
+ }
196
+ }
197
+ exports.ClientV2 = ClientV2;
@@ -0,0 +1,2 @@
1
+ export declare function formatUTCDate(date: Date): string;
2
+ export declare function getStartTime(): string;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getStartTime = exports.formatUTCDate = void 0;
4
+ // Utils
5
+ const pad = (num) => num.toString().padStart(2, '0');
6
+ function formatUTCDate(date) {
7
+ const year = date.getUTCFullYear();
8
+ const month = pad(date.getUTCMonth() + 1);
9
+ const day = pad(date.getUTCDate());
10
+ const hours = pad(date.getUTCHours());
11
+ const minutes = pad(date.getUTCMinutes());
12
+ const seconds = pad(date.getUTCSeconds());
13
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
14
+ }
15
+ exports.formatUTCDate = formatUTCDate;
16
+ function getStartTime() {
17
+ const date = new Date();
18
+ return formatUTCDate(new Date(date.getTime() - 10000));
19
+ }
20
+ exports.getStartTime = getStartTime;
@@ -0,0 +1,6 @@
1
+ import { TestResultType } from "../models";
2
+ export interface IClient {
3
+ createRun(): Promise<number>;
4
+ completeRun(runId: number): Promise<void>;
5
+ uploadResults(runId: number, results: TestResultType[]): Promise<void>;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -51,24 +51,6 @@ exports.configValidationSchema = {
51
51
  type: 'string',
52
52
  nullable: true,
53
53
  },
54
- headers: {
55
- type: 'object',
56
- nullable: true,
57
- additionalProperties: false,
58
- patternProperties: {
59
- '^.*$': {
60
- type: 'string',
61
- },
62
- },
63
- },
64
- retries: {
65
- type: 'number',
66
- nullable: true,
67
- },
68
- retryDelay: {
69
- type: 'number',
70
- nullable: true,
71
- },
72
54
  },
73
55
  },
74
56
  project: {
@@ -125,10 +107,6 @@ exports.configValidationSchema = {
125
107
  type: 'boolean',
126
108
  nullable: true,
127
109
  },
128
- useV2: {
129
- type: 'boolean',
130
- nullable: true,
131
- },
132
110
  },
133
111
  },
134
112
  report: {