qase-javascript-commons 2.0.0-beta.5 → 2.0.0-beta.6

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/changelog.md CHANGED
@@ -1,8 +1,47 @@
1
+ # qase-javascript-commons@2.0.0-beta.6
2
+
3
+ ## What's new
4
+
5
+ ### Select the API version to use for reporting
6
+
7
+ Qase TestOps API has two endpoints for reporting test results:
8
+
9
+ - Version 1, stable and used my most test reporters.
10
+ https://developers.qase.io/reference/create-result-bulk
11
+ - Version 2, currently in beta access, and currently supported only
12
+ in the `playwright-qase-reporter`.
13
+ https://developers.qase.io/v2.0/reference/create-results-v2
14
+
15
+ This commit introduces a way to select the API version to use.
16
+ It enables using all new features of v2 JS reporters with the stable v1 API,
17
+ and elso experimenting with the new v2 API.
18
+
19
+ **Warning**: v2 API is still in beta.
20
+ If you want to try the v2 JS reporters, you don't have to enable the new API.
21
+
22
+ To enable using API v2, set an environment variable before running the tests:
23
+
24
+ ```bash
25
+ QASE_TESTOPS_API_V2=true
26
+ ```
27
+
28
+ ### Support adding test suite description to a test report.
29
+
30
+ Test reporters can now test suite description to test results.
31
+ Such description can be collected from test's location and attributes
32
+ or explicitly declared in the test.
33
+
34
+ Add new data models:
35
+ - Relation
36
+ - Suite
37
+ - SuiteData
38
+
39
+
1
40
  # qase-javascript-commons@2.0.0-beta.5
2
41
 
3
42
  ## What's new
4
43
 
5
- * Update the config of reporters. Added `framework.captureLogs` field. If it is set to `true`, the reporter will capture logs from the test framework.
44
+ * Update the config of reporters. Added `captureLogs` field. If it is set to `true`, the reporter will capture logs from the test framework.
6
45
  * Added `getMimeType` function to the commons package. It returns the MIME type of the file by its extension.
7
46
 
8
47
  # qase-javascript-commons@2.0.0-beta.4
@@ -115,6 +115,10 @@ exports.configValidationSchema = {
115
115
  type: 'boolean',
116
116
  nullable: true,
117
117
  },
118
+ useV2: {
119
+ type: 'boolean',
120
+ nullable: true,
121
+ },
118
122
  },
119
123
  },
120
124
  report: {
@@ -15,7 +15,8 @@ export declare enum EnvTestOpsEnum {
15
15
  project = "QASE_TESTOPS_PROJECT",
16
16
  uploadAttachments = "QASE_TESTOPS_UPLOAD_ATTACHMENTS",
17
17
  chunk = "QASE_TESTOPS_CHUNK",
18
- defect = "QASE_TESTOPS_DEFECT"
18
+ defect = "QASE_TESTOPS_DEFECT",
19
+ useV2 = "QASE_TESTOPS_API_V2"
19
20
  }
20
21
  /**
21
22
  * @enum {string}
@@ -21,6 +21,7 @@ var EnvTestOpsEnum;
21
21
  EnvTestOpsEnum["uploadAttachments"] = "QASE_TESTOPS_UPLOAD_ATTACHMENTS";
22
22
  EnvTestOpsEnum["chunk"] = "QASE_TESTOPS_CHUNK";
23
23
  EnvTestOpsEnum["defect"] = "QASE_TESTOPS_DEFECT";
24
+ EnvTestOpsEnum["useV2"] = "QASE_TESTOPS_API_V2";
24
25
  })(EnvTestOpsEnum || (exports.EnvTestOpsEnum = EnvTestOpsEnum = {}));
25
26
  /**
26
27
  * @enum {string}
@@ -30,6 +30,7 @@ const envToConfig = (env) => ({
30
30
  },
31
31
  chunk: env[env_enum_1.EnvTestOpsEnum.chunk],
32
32
  defect: env[env_enum_1.EnvTestOpsEnum.defect],
33
+ useV2: env[env_enum_1.EnvTestOpsEnum.useV2],
33
34
  },
34
35
  report: {
35
36
  connections: {
@@ -11,6 +11,7 @@ export type EnvType = {
11
11
  [EnvTestOpsEnum.uploadAttachments]?: boolean;
12
12
  [EnvTestOpsEnum.chunk]?: number;
13
13
  [EnvTestOpsEnum.defect]?: boolean;
14
+ [EnvTestOpsEnum.useV2]?: boolean;
14
15
  [EnvApiEnum.token]?: string;
15
16
  [EnvApiEnum.baseUrl]?: string;
16
17
  [EnvRunEnum.id]?: number;
@@ -48,6 +48,10 @@ exports.envValidationSchema = {
48
48
  type: 'boolean',
49
49
  nullable: true,
50
50
  },
51
+ [env_enum_1.EnvTestOpsEnum.useV2]: {
52
+ type: 'boolean',
53
+ nullable: true,
54
+ },
51
55
  [env_enum_1.EnvApiEnum.token]: {
52
56
  type: 'string',
53
57
  nullable: true,
@@ -1,4 +1,4 @@
1
- export { type TestResultType } from './test-result';
1
+ export { type TestResultType, Relation, Suite, SuiteData } from './test-result';
2
2
  export { TestExecution, TestStatusEnum } from './test-execution';
3
3
  export { type TestStepType } from './test-step';
4
4
  export { StepStatusEnum } from './step-execution';
@@ -13,7 +13,17 @@ export type TestResultType = {
13
13
  steps: TestStepType[];
14
14
  params: Record<string, string>;
15
15
  author: string | null;
16
- relations: any[];
16
+ relations: Relation | null;
17
17
  muted: boolean;
18
18
  message: string | null;
19
19
  };
20
+ export type Relation = {
21
+ suite?: Suite;
22
+ };
23
+ export type Suite = {
24
+ data: SuiteData[];
25
+ };
26
+ export type SuiteData = {
27
+ title: string;
28
+ public_id: number | null;
29
+ };
@@ -1,4 +1,4 @@
1
- import { QaseApiInterface, ResultStepStatus } from 'qaseio';
1
+ import { QaseApiInterface, ResultStepStatus, TestStepResultCreateStatusEnum } from 'qaseio';
2
2
  import { AbstractReporter, LoggerInterface, ReporterOptionsType } from './abstract-reporter';
3
3
  import { StepStatusEnum, TestStatusEnum } from '../models';
4
4
  export type TestOpsRunType = {
@@ -17,6 +17,7 @@ export type TestOpsOptionsType = {
17
17
  plan: TestOpsPlanType;
18
18
  chunk?: number | undefined;
19
19
  defect?: boolean | undefined;
20
+ useV2?: boolean | undefined;
20
21
  };
21
22
  /**
22
23
  * @class TestOpsReporter
@@ -32,6 +33,10 @@ export declare class TestOpsReporter extends AbstractReporter {
32
33
  * @type {Record<StepStatusEnum, ResultStepStatus>}
33
34
  */
34
35
  static stepStatusMap: Record<StepStatusEnum, ResultStepStatus>;
36
+ /**
37
+ * @type {Record<StepStatusEnum, ResultStepStatus>}
38
+ */
39
+ static stepStatusMapV1: Record<StepStatusEnum, TestStepResultCreateStatusEnum>;
35
40
  /**
36
41
  * @type {string}
37
42
  * @private
@@ -62,6 +67,16 @@ export declare class TestOpsReporter extends AbstractReporter {
62
67
  * @private
63
68
  */
64
69
  private readonly chunk;
70
+ /**
71
+ * @type {boolean | undefined}
72
+ * @private
73
+ */
74
+ private readonly useV2;
75
+ /**
76
+ * @type {boolean | undefined}
77
+ * @private
78
+ */
79
+ private readonly defect;
65
80
  /**
66
81
  * @param {ReporterOptionsType & TestOpsOptionsType} options
67
82
  * @param {QaseApiInterface} api
@@ -79,18 +94,36 @@ export declare class TestOpsReporter extends AbstractReporter {
79
94
  * @private
80
95
  */
81
96
  private transformTestResult;
97
+ /**
98
+ * @param {TestResultType} result
99
+ * @returns Promise<ResultCreate>
100
+ * @private
101
+ */
102
+ private transformTestResultV1;
82
103
  /**
83
104
  * @returns {ResultExecution}
84
105
  * @private
85
106
  * @param {TestExecution} exec
86
107
  */
87
108
  private getExecution;
109
+ /**
110
+ * @param {Relation | null} relation
111
+ * @returns {ResultRelations}
112
+ * @private
113
+ */
114
+ private getRelation;
88
115
  /**
89
116
  * @param {TestStepType[]} steps
90
117
  * @returns Promise<ResultStep[]>
91
118
  * @private
92
119
  */
93
120
  private transformSteps;
121
+ /**
122
+ * @param {TestStepType[]} steps
123
+ * @returns Promise<TestStepResultCreate[]>
124
+ * @private
125
+ */
126
+ private transformStepsV1;
94
127
  /**
95
128
  * @param {number} runId
96
129
  * @returns {Promise<void>}
@@ -33,6 +33,8 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
33
33
  this.run = { complete: true, ...run };
34
34
  this.environment = environment;
35
35
  this.chunk = options.chunk ?? defaultChunkSize;
36
+ this.useV2 = options.useV2 ?? false;
37
+ this.defect = options.defect ?? false;
36
38
  }
37
39
  /**
38
40
  * @returns {Promise<void>}
@@ -54,15 +56,29 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
54
56
  this.log('No test cases were matched. Ensure that your tests are declared correctly.');
55
57
  return;
56
58
  }
57
- const results = [];
58
- for (const result of this.results) {
59
- const resultCreateV2 = await this.transformTestResult(result);
60
- results.push(resultCreateV2);
59
+ if (this.useV2) {
60
+ const results = [];
61
+ for (const result of this.results) {
62
+ const resultCreateV2 = await this.transformTestResult(result);
63
+ results.push(resultCreateV2);
64
+ }
65
+ for (let i = 0; i < results.length; i += this.chunk) {
66
+ await this.api.result.createResultsV2(this.projectCode, runId, {
67
+ results: results.slice(i, i + this.chunk),
68
+ });
69
+ }
61
70
  }
62
- for (let i = 0; i < results.length; i += this.chunk) {
63
- await this.api.result.createResultsV2(this.projectCode, runId, {
64
- results: results.slice(i, i + this.chunk),
65
- });
71
+ else {
72
+ const results = [];
73
+ for (const result of this.results) {
74
+ const resultCreate = await this.transformTestResultV1(result);
75
+ results.push(resultCreate);
76
+ }
77
+ for (let i = 0; i < results.length; i += this.chunk) {
78
+ await this.api.results.createResultBulk(this.projectCode, runId, {
79
+ results: results.slice(i, i + this.chunk),
80
+ });
81
+ }
66
82
  }
67
83
  this.log((0, chalk_1.default) `{green ${this.results.length} result(s) sent to Qase}`);
68
84
  if (!this.run.complete) {
@@ -93,14 +109,41 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
93
109
  attachments: attachments,
94
110
  steps: steps,
95
111
  params: result.params,
96
- relations: {
97
- // suite: {
98
- // data: result.suiteTitle ? this.getSuites(result.suiteTitle) : [],
99
- // },
100
- },
112
+ relations: this.getRelation(result.relations),
101
113
  message: result.message,
102
114
  };
103
115
  }
116
+ /**
117
+ * @param {TestResultType} result
118
+ * @returns Promise<ResultCreate>
119
+ * @private
120
+ */
121
+ async transformTestResultV1(result) {
122
+ const attachments = await this.uploadAttachments(result.attachments);
123
+ const steps = await this.transformStepsV1(result.steps);
124
+ const resultCreate = {
125
+ attachments: attachments,
126
+ comment: result.message,
127
+ defect: this.defect,
128
+ param: result.params,
129
+ stacktrace: result.execution.stacktrace,
130
+ start_time: result.execution.start_time ? result.execution.start_time | 0 : null,
131
+ status: result.execution.status,
132
+ steps: steps,
133
+ time: result.execution.end_time,
134
+ time_ms: result.execution.duration,
135
+ };
136
+ const id = Array.isArray(result.testops_id) ? null : result.testops_id;
137
+ if (id) {
138
+ resultCreate.case_id = id;
139
+ return resultCreate;
140
+ }
141
+ resultCreate.case = {
142
+ title: result.title,
143
+ suite_title: result.relations?.suite ? result.relations?.suite?.data.map((suite) => suite.title).join('\t') : null,
144
+ };
145
+ return resultCreate;
146
+ }
104
147
  /**
105
148
  * @returns {ResultExecution}
106
149
  * @private
@@ -116,6 +159,28 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
116
159
  thread: exec.thread,
117
160
  };
118
161
  }
162
+ /**
163
+ * @param {Relation | null} relation
164
+ * @returns {ResultRelations}
165
+ * @private
166
+ */
167
+ getRelation(relation) {
168
+ if (!relation || !relation.suite) {
169
+ return {};
170
+ }
171
+ const suiteData = [];
172
+ for (const data of relation.suite.data) {
173
+ suiteData.push({
174
+ public_id: null,
175
+ title: data.title,
176
+ });
177
+ }
178
+ return {
179
+ suite: {
180
+ data: suiteData,
181
+ },
182
+ };
183
+ }
119
184
  /**
120
185
  * @param {TestStepType[]} steps
121
186
  * @returns Promise<ResultStep[]>
@@ -141,6 +206,27 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
141
206
  }
142
207
  return resultsSteps;
143
208
  }
209
+ /**
210
+ * @param {TestStepType[]} steps
211
+ * @returns Promise<TestStepResultCreate[]>
212
+ * @private
213
+ */
214
+ async transformStepsV1(steps) {
215
+ const resultsSteps = [];
216
+ for (const step of steps) {
217
+ const attachmentHashes = await this.uploadAttachments(step.attachments);
218
+ const resultStep = {
219
+ status: TestOpsReporter.stepStatusMapV1[step.execution.status],
220
+ action: step.data.action,
221
+ attachments: attachmentHashes,
222
+ };
223
+ if (step.steps.length > 0) {
224
+ resultStep.steps = await this.transformStepsV1(step.steps);
225
+ }
226
+ resultsSteps.push(resultStep);
227
+ }
228
+ return resultsSteps;
229
+ }
144
230
  /**
145
231
  * @param {number} runId
146
232
  * @returns {Promise<void>}
@@ -235,3 +321,11 @@ TestOpsReporter.stepStatusMap = {
235
321
  [models_1.StepStatusEnum.failed]: qaseio_1.ResultStepStatus.FAILED,
236
322
  [models_1.StepStatusEnum.blocked]: qaseio_1.ResultStepStatus.BLOCKED,
237
323
  };
324
+ /**
325
+ * @type {Record<StepStatusEnum, ResultStepStatus>}
326
+ */
327
+ TestOpsReporter.stepStatusMapV1 = {
328
+ [models_1.StepStatusEnum.passed]: qaseio_1.TestStepResultCreateStatusEnum.PASSED,
329
+ [models_1.StepStatusEnum.failed]: qaseio_1.TestStepResultCreateStatusEnum.FAILED,
330
+ [models_1.StepStatusEnum.blocked]: qaseio_1.TestStepResultCreateStatusEnum.BLOCKED,
331
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qase-javascript-commons",
3
- "version": "2.0.0-beta.5",
3
+ "version": "2.0.0-beta.6",
4
4
  "description": "Qase JS Reporters",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",