qase-javascript-commons 2.0.0-beta.5 → 2.0.0-beta.7
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 +67 -1
- package/dist/config/config-validation-schema.js +4 -0
- package/dist/env/env-enum.d.ts +2 -1
- package/dist/env/env-enum.js +1 -0
- package/dist/env/env-to-config.js +1 -0
- package/dist/env/env-type.d.ts +1 -0
- package/dist/env/env-validation-schema.js +4 -0
- package/dist/models/index.d.ts +1 -1
- package/dist/models/test-result.d.ts +11 -1
- package/dist/qase.d.ts +5 -1
- package/dist/qase.js +30 -6
- package/dist/reporters/abstract-reporter.d.ts +7 -2
- package/dist/reporters/abstract-reporter.js +2 -1
- package/dist/reporters/report-reporter.d.ts +5 -2
- package/dist/reporters/report-reporter.js +7 -1
- package/dist/reporters/testops-reporter.d.ts +64 -2
- package/dist/reporters/testops-reporter.js +161 -26
- package/package.json +1 -1
package/changelog.md
CHANGED
|
@@ -1,8 +1,74 @@
|
|
|
1
|
+
# qase-javascript-commons@2.0.0-beta.7
|
|
2
|
+
|
|
3
|
+
## What's new
|
|
4
|
+
|
|
5
|
+
TestOps reporter supports uploading test result in real-time.
|
|
6
|
+
It can be useful for long-running tests, where you want to see the results as soon as they are available.
|
|
7
|
+
You can use chunk size to control the size of the data sent to the Qase.
|
|
8
|
+
|
|
9
|
+
To enable real-time reporting, set an environment variable before running the tests or use the reporter's configuration:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
QASE_TESTOPS_CHUNK=10
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```diff
|
|
16
|
+
{
|
|
17
|
+
...
|
|
18
|
+
"testops": {
|
|
19
|
+
+ "chunk": 10
|
|
20
|
+
...
|
|
21
|
+
},
|
|
22
|
+
...
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
where `10` is the size of the chunk in test result's count.
|
|
27
|
+
|
|
28
|
+
# qase-javascript-commons@2.0.0-beta.6
|
|
29
|
+
|
|
30
|
+
## What's new
|
|
31
|
+
|
|
32
|
+
### Select the API version to use for reporting
|
|
33
|
+
|
|
34
|
+
Qase TestOps API has two endpoints for reporting test results:
|
|
35
|
+
|
|
36
|
+
- Version 1, stable and used my most test reporters.
|
|
37
|
+
https://developers.qase.io/reference/create-result-bulk
|
|
38
|
+
- Version 2, currently in beta access, and currently supported only
|
|
39
|
+
in the `playwright-qase-reporter`.
|
|
40
|
+
https://developers.qase.io/v2.0/reference/create-results-v2
|
|
41
|
+
|
|
42
|
+
This commit introduces a way to select the API version to use.
|
|
43
|
+
It enables using all new features of v2 JS reporters with the stable v1 API,
|
|
44
|
+
and elso experimenting with the new v2 API.
|
|
45
|
+
|
|
46
|
+
**Warning**: v2 API is still in beta.
|
|
47
|
+
If you want to try the v2 JS reporters, you don't have to enable the new API.
|
|
48
|
+
|
|
49
|
+
To enable using API v2, set an environment variable before running the tests:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
QASE_TESTOPS_API_V2=true
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Support adding test suite description to a test report.
|
|
56
|
+
|
|
57
|
+
Test reporters can now test suite description to test results.
|
|
58
|
+
Such description can be collected from test's location and attributes
|
|
59
|
+
or explicitly declared in the test.
|
|
60
|
+
|
|
61
|
+
Add new data models:
|
|
62
|
+
- Relation
|
|
63
|
+
- Suite
|
|
64
|
+
- SuiteData
|
|
65
|
+
|
|
66
|
+
|
|
1
67
|
# qase-javascript-commons@2.0.0-beta.5
|
|
2
68
|
|
|
3
69
|
## What's new
|
|
4
70
|
|
|
5
|
-
* Update the config of reporters. Added `
|
|
71
|
+
* Update the config of reporters. Added `captureLogs` field. If it is set to `true`, the reporter will capture logs from the test framework.
|
|
6
72
|
* Added `getMimeType` function to the commons package. It returns the MIME type of the file by its extension.
|
|
7
73
|
|
|
8
74
|
# qase-javascript-commons@2.0.0-beta.4
|
package/dist/env/env-enum.d.ts
CHANGED
|
@@ -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}
|
package/dist/env/env-enum.js
CHANGED
|
@@ -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}
|
package/dist/env/env-type.d.ts
CHANGED
|
@@ -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;
|
package/dist/models/index.d.ts
CHANGED
|
@@ -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:
|
|
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
|
+
};
|
package/dist/qase.d.ts
CHANGED
|
@@ -39,10 +39,14 @@ export declare class QaseReporter extends AbstractReporter {
|
|
|
39
39
|
* @param {LoggerInterface} logger
|
|
40
40
|
*/
|
|
41
41
|
constructor(options: OptionsType, logger?: LoggerInterface);
|
|
42
|
+
/**
|
|
43
|
+
* @returns {Promise<void>}
|
|
44
|
+
*/
|
|
45
|
+
startTestRun(): Promise<void>;
|
|
42
46
|
/**
|
|
43
47
|
* @param {TestResultType} result
|
|
44
48
|
*/
|
|
45
|
-
addTestResult(result: TestResultType): void
|
|
49
|
+
addTestResult(result: TestResultType): Promise<void>;
|
|
46
50
|
/**
|
|
47
51
|
* @param {TestResultType} result
|
|
48
52
|
* @private
|
package/dist/qase.js
CHANGED
|
@@ -119,18 +119,42 @@ class QaseReporter extends reporters_1.AbstractReporter {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* @returns {Promise<void>}
|
|
124
|
+
*/
|
|
125
|
+
async startTestRun() {
|
|
126
|
+
if (!this.disabled) {
|
|
127
|
+
try {
|
|
128
|
+
await this.upstreamReporter?.startTestRun();
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
this.logError('Unable to start test run in the upstream reporter: ', error);
|
|
132
|
+
if (this.fallbackReporter == undefined) {
|
|
133
|
+
this.disabled = true;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
await this.fallbackReporter?.startTestRun();
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
this.logError('Unable to start test run in the fallback reporter: ', error);
|
|
141
|
+
this.disabled = true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
122
146
|
/**
|
|
123
147
|
* @param {TestResultType} result
|
|
124
148
|
*/
|
|
125
|
-
addTestResult(result) {
|
|
149
|
+
async addTestResult(result) {
|
|
126
150
|
if (!this.disabled) {
|
|
127
151
|
this.logTestItem(result);
|
|
128
152
|
if (this.useFallback) {
|
|
129
|
-
this.addTestResultToFallback(result);
|
|
153
|
+
await this.addTestResultToFallback(result);
|
|
130
154
|
return;
|
|
131
155
|
}
|
|
132
156
|
try {
|
|
133
|
-
this.upstreamReporter?.addTestResult(result);
|
|
157
|
+
await this.upstreamReporter?.addTestResult(result);
|
|
134
158
|
}
|
|
135
159
|
catch (error) {
|
|
136
160
|
this.logError('Unable to add the result to the upstream reporter:', error);
|
|
@@ -142,7 +166,7 @@ class QaseReporter extends reporters_1.AbstractReporter {
|
|
|
142
166
|
this.fallbackReporter.setTestResults(this.upstreamReporter?.getTestResults() ?? []);
|
|
143
167
|
this.useFallback = true;
|
|
144
168
|
}
|
|
145
|
-
this.addTestResultToFallback(result);
|
|
169
|
+
await this.addTestResultToFallback(result);
|
|
146
170
|
}
|
|
147
171
|
}
|
|
148
172
|
}
|
|
@@ -150,9 +174,9 @@ class QaseReporter extends reporters_1.AbstractReporter {
|
|
|
150
174
|
* @param {TestResultType} result
|
|
151
175
|
* @private
|
|
152
176
|
*/
|
|
153
|
-
addTestResultToFallback(result) {
|
|
177
|
+
async addTestResultToFallback(result) {
|
|
154
178
|
try {
|
|
155
|
-
this.fallbackReporter?.addTestResult(result);
|
|
179
|
+
await this.fallbackReporter?.addTestResult(result);
|
|
156
180
|
}
|
|
157
181
|
catch (error) {
|
|
158
182
|
this.logError('Unable to add the result to the fallback reporter:', error);
|
|
@@ -9,8 +9,9 @@ export interface ReporterOptionsType {
|
|
|
9
9
|
captureLogs?: boolean | undefined;
|
|
10
10
|
}
|
|
11
11
|
export interface ReporterInterface {
|
|
12
|
-
addTestResult(result: TestResultType): void
|
|
12
|
+
addTestResult(result: TestResultType): Promise<void>;
|
|
13
13
|
publish(): Promise<void>;
|
|
14
|
+
startTestRun(): Promise<void>;
|
|
14
15
|
getTestResults(): TestResultType[];
|
|
15
16
|
setTestResults(results: TestResultType[]): void;
|
|
16
17
|
isCaptureLogs(): boolean;
|
|
@@ -41,6 +42,10 @@ export declare abstract class AbstractReporter implements ReporterInterface {
|
|
|
41
42
|
* @returns {Promise<void>}
|
|
42
43
|
*/
|
|
43
44
|
abstract publish(): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
*/
|
|
48
|
+
abstract startTestRun(): Promise<void>;
|
|
44
49
|
/**
|
|
45
50
|
* @param {ReporterOptionsType} options
|
|
46
51
|
* @param {LoggerInterface} logger
|
|
@@ -58,7 +63,7 @@ export declare abstract class AbstractReporter implements ReporterInterface {
|
|
|
58
63
|
/**
|
|
59
64
|
* @param {TestResultType} result
|
|
60
65
|
*/
|
|
61
|
-
addTestResult(result: TestResultType): void
|
|
66
|
+
addTestResult(result: TestResultType): Promise<void>;
|
|
62
67
|
/**
|
|
63
68
|
* @param {TestResultType[]} results
|
|
64
69
|
*/
|
|
@@ -45,7 +45,8 @@ class AbstractReporter {
|
|
|
45
45
|
/**
|
|
46
46
|
* @param {TestResultType} result
|
|
47
47
|
*/
|
|
48
|
-
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
49
|
+
async addTestResult(result) {
|
|
49
50
|
if (result.testops_id === null || !Array.isArray(result.testops_id)) {
|
|
50
51
|
this.results.push(result);
|
|
51
52
|
return;
|
|
@@ -8,7 +8,7 @@ export declare class ReportReporter extends AbstractReporter {
|
|
|
8
8
|
private writer;
|
|
9
9
|
private readonly environment;
|
|
10
10
|
private readonly runId;
|
|
11
|
-
private
|
|
11
|
+
private startTime;
|
|
12
12
|
/**
|
|
13
13
|
* @param {ReporterOptionsType} options
|
|
14
14
|
* @param {WriterInterface} writer
|
|
@@ -17,10 +17,13 @@ export declare class ReportReporter extends AbstractReporter {
|
|
|
17
17
|
* @param {number | undefined} runId
|
|
18
18
|
*/
|
|
19
19
|
constructor(options: ReporterOptionsType | undefined, writer: WriterInterface, logger?: LoggerInterface, environment?: string, runId?: number);
|
|
20
|
+
/**
|
|
21
|
+
* @returns {Promise<void>}
|
|
22
|
+
*/
|
|
23
|
+
startTestRun(): Promise<void>;
|
|
20
24
|
/**
|
|
21
25
|
* @returns {Promise<void>}
|
|
22
26
|
*
|
|
23
|
-
* eslint-disable-next-line @typescript-eslint/require-await
|
|
24
27
|
*/
|
|
25
28
|
publish(): Promise<void>;
|
|
26
29
|
/**
|
|
@@ -48,10 +48,16 @@ class ReportReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
48
48
|
this.environment = environment;
|
|
49
49
|
this.runId = runId;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* @returns {Promise<void>}
|
|
53
|
+
*/
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
55
|
+
async startTestRun() {
|
|
56
|
+
this.startTime = Date.now();
|
|
57
|
+
}
|
|
51
58
|
/**
|
|
52
59
|
* @returns {Promise<void>}
|
|
53
60
|
*
|
|
54
|
-
* eslint-disable-next-line @typescript-eslint/require-await
|
|
55
61
|
*/
|
|
56
62
|
async publish() {
|
|
57
63
|
const report = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { QaseApiInterface, ResultStepStatus } from 'qaseio';
|
|
1
|
+
import { QaseApiInterface, ResultStepStatus, TestStepResultCreateStatusEnum } from 'qaseio';
|
|
2
2
|
import { AbstractReporter, LoggerInterface, ReporterOptionsType } from './abstract-reporter';
|
|
3
|
-
import { StepStatusEnum, TestStatusEnum } from '../models';
|
|
3
|
+
import { StepStatusEnum, TestResultType, TestStatusEnum } from '../models';
|
|
4
4
|
export type TestOpsRunType = {
|
|
5
5
|
id?: number | undefined;
|
|
6
6
|
title: string;
|
|
@@ -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,26 @@ 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;
|
|
80
|
+
/**
|
|
81
|
+
* @type {number}
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
84
|
+
private firstIndex;
|
|
85
|
+
/**
|
|
86
|
+
* @type {boolean}
|
|
87
|
+
* @private
|
|
88
|
+
*/
|
|
89
|
+
private isTestRunReady;
|
|
65
90
|
/**
|
|
66
91
|
* @param {ReporterOptionsType & TestOpsOptionsType} options
|
|
67
92
|
* @param {QaseApiInterface} api
|
|
@@ -69,6 +94,25 @@ export declare class TestOpsReporter extends AbstractReporter {
|
|
|
69
94
|
* @param {number} environment
|
|
70
95
|
*/
|
|
71
96
|
constructor(options: ReporterOptionsType & TestOpsOptionsType, api: QaseApiInterface, logger?: LoggerInterface, environment?: number);
|
|
97
|
+
/**
|
|
98
|
+
* @returns {Promise<void>}
|
|
99
|
+
*/
|
|
100
|
+
startTestRun(): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* @param {TestResultType} result
|
|
103
|
+
* @returns {Promise<void>}
|
|
104
|
+
*/
|
|
105
|
+
addTestResult(result: TestResultType): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* @returns {Promise<void>}
|
|
108
|
+
*/
|
|
109
|
+
private checkOrCreateTestRun;
|
|
110
|
+
/**
|
|
111
|
+
* @returns {Promise<void>}
|
|
112
|
+
* @param testResults
|
|
113
|
+
* @private
|
|
114
|
+
*/
|
|
115
|
+
private publishResults;
|
|
72
116
|
/**
|
|
73
117
|
* @returns {Promise<void>}
|
|
74
118
|
*/
|
|
@@ -79,18 +123,36 @@ export declare class TestOpsReporter extends AbstractReporter {
|
|
|
79
123
|
* @private
|
|
80
124
|
*/
|
|
81
125
|
private transformTestResult;
|
|
126
|
+
/**
|
|
127
|
+
* @param {TestResultType} result
|
|
128
|
+
* @returns Promise<ResultCreate>
|
|
129
|
+
* @private
|
|
130
|
+
*/
|
|
131
|
+
private transformTestResultV1;
|
|
82
132
|
/**
|
|
83
133
|
* @returns {ResultExecution}
|
|
84
134
|
* @private
|
|
85
135
|
* @param {TestExecution} exec
|
|
86
136
|
*/
|
|
87
137
|
private getExecution;
|
|
138
|
+
/**
|
|
139
|
+
* @param {Relation | null} relation
|
|
140
|
+
* @returns {ResultRelations}
|
|
141
|
+
* @private
|
|
142
|
+
*/
|
|
143
|
+
private getRelation;
|
|
88
144
|
/**
|
|
89
145
|
* @param {TestStepType[]} steps
|
|
90
146
|
* @returns Promise<ResultStep[]>
|
|
91
147
|
* @private
|
|
92
148
|
*/
|
|
93
149
|
private transformSteps;
|
|
150
|
+
/**
|
|
151
|
+
* @param {TestStepType[]} steps
|
|
152
|
+
* @returns Promise<TestStepResultCreate[]>
|
|
153
|
+
* @private
|
|
154
|
+
*/
|
|
155
|
+
private transformStepsV1;
|
|
94
156
|
/**
|
|
95
157
|
* @param {number} runId
|
|
96
158
|
* @returns {Promise<void>}
|
|
@@ -26,6 +26,16 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
26
26
|
const { project, uploadAttachments, run, ...restOptions } = options;
|
|
27
27
|
super(restOptions, logger);
|
|
28
28
|
this.api = api;
|
|
29
|
+
/**
|
|
30
|
+
* @type {number}
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
this.firstIndex = 0;
|
|
34
|
+
/**
|
|
35
|
+
* @type {boolean}
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
this.isTestRunReady = false;
|
|
29
39
|
const baseUrl = 'https://app.qase.io';
|
|
30
40
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
31
41
|
this.projectCode = project;
|
|
@@ -33,49 +43,96 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
33
43
|
this.run = { complete: true, ...run };
|
|
34
44
|
this.environment = environment;
|
|
35
45
|
this.chunk = options.chunk ?? defaultChunkSize;
|
|
46
|
+
this.useV2 = options.useV2 ?? false;
|
|
47
|
+
this.defect = options.defect ?? false;
|
|
36
48
|
}
|
|
37
49
|
/**
|
|
38
50
|
* @returns {Promise<void>}
|
|
39
51
|
*/
|
|
40
|
-
async
|
|
41
|
-
|
|
52
|
+
async startTestRun() {
|
|
53
|
+
await this.checkOrCreateTestRun();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* @param {TestResultType} result
|
|
57
|
+
* @returns {Promise<void>}
|
|
58
|
+
*/
|
|
59
|
+
async addTestResult(result) {
|
|
60
|
+
await super.addTestResult(result);
|
|
61
|
+
if (!this.isTestRunReady) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const countOfResults = this.chunk + this.firstIndex;
|
|
65
|
+
if (this.results.length >= countOfResults) {
|
|
66
|
+
await this.publishResults(this.results.slice(this.firstIndex, countOfResults));
|
|
67
|
+
this.firstIndex = countOfResults;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* @returns {Promise<void>}
|
|
72
|
+
*/
|
|
73
|
+
async checkOrCreateTestRun() {
|
|
42
74
|
if (this.run.id !== undefined) {
|
|
43
75
|
await this.checkRun(this.run.id);
|
|
44
|
-
|
|
76
|
+
this.isTestRunReady = true;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const { result } = await this.createRun(this.run.title, this.run.description, this.environment);
|
|
80
|
+
if (!result?.id) {
|
|
81
|
+
throw new Error('Cannot create run.');
|
|
82
|
+
}
|
|
83
|
+
this.run.id = result.id;
|
|
84
|
+
this.isTestRunReady = true;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* @returns {Promise<void>}
|
|
88
|
+
* @param testResults
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
async publishResults(testResults) {
|
|
92
|
+
if (this.useV2) {
|
|
93
|
+
const results = [];
|
|
94
|
+
for (const result of testResults) {
|
|
95
|
+
const resultCreateV2 = await this.transformTestResult(result);
|
|
96
|
+
results.push(resultCreateV2);
|
|
97
|
+
}
|
|
98
|
+
await this.api.result.createResultsV2(this.projectCode, this.run.id, {
|
|
99
|
+
results: results,
|
|
100
|
+
});
|
|
45
101
|
}
|
|
46
102
|
else {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
103
|
+
const results = [];
|
|
104
|
+
for (const result of testResults) {
|
|
105
|
+
const resultCreate = await this.transformTestResultV1(result);
|
|
106
|
+
results.push(resultCreate);
|
|
50
107
|
}
|
|
51
|
-
|
|
108
|
+
await this.api.results.createResultBulk(this.projectCode, this.run.id, {
|
|
109
|
+
results: results,
|
|
110
|
+
});
|
|
52
111
|
}
|
|
53
|
-
|
|
54
|
-
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* @returns {Promise<void>}
|
|
115
|
+
*/
|
|
116
|
+
async publish() {
|
|
117
|
+
if (this.results.length === 0) {
|
|
118
|
+
this.log((0, chalk_1.default) `{yellow No results to send to Qase}`);
|
|
55
119
|
return;
|
|
56
120
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const resultCreateV2 = await this.transformTestResult(result);
|
|
60
|
-
results.push(resultCreateV2);
|
|
61
|
-
}
|
|
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
|
-
});
|
|
121
|
+
if (this.firstIndex < this.results.length) {
|
|
122
|
+
await this.publishResults(this.results.slice(this.firstIndex));
|
|
66
123
|
}
|
|
67
124
|
this.log((0, chalk_1.default) `{green ${this.results.length} result(s) sent to Qase}`);
|
|
68
125
|
if (!this.run.complete) {
|
|
69
126
|
return;
|
|
70
127
|
}
|
|
71
128
|
try {
|
|
72
|
-
await this.api.runs.completeRun(this.projectCode,
|
|
73
|
-
this.log((0, chalk_1.default) `{green Run ${
|
|
129
|
+
await this.api.runs.completeRun(this.projectCode, this.run.id);
|
|
130
|
+
this.log((0, chalk_1.default) `{green Run ${this.run.id} completed}`);
|
|
74
131
|
}
|
|
75
132
|
catch (error) {
|
|
76
133
|
throw new qase_error_1.QaseError('Error on completing run', { cause: error });
|
|
77
134
|
}
|
|
78
|
-
const runUrl = `${this.baseUrl}/run/${this.projectCode}/dashboard/${
|
|
135
|
+
const runUrl = `${this.baseUrl}/run/${this.projectCode}/dashboard/${this.run.id}`;
|
|
79
136
|
this.log((0, chalk_1.default) `{blue Test run link: ${runUrl}}`);
|
|
80
137
|
}
|
|
81
138
|
/**
|
|
@@ -93,14 +150,41 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
93
150
|
attachments: attachments,
|
|
94
151
|
steps: steps,
|
|
95
152
|
params: result.params,
|
|
96
|
-
relations:
|
|
97
|
-
// suite: {
|
|
98
|
-
// data: result.suiteTitle ? this.getSuites(result.suiteTitle) : [],
|
|
99
|
-
// },
|
|
100
|
-
},
|
|
153
|
+
relations: this.getRelation(result.relations),
|
|
101
154
|
message: result.message,
|
|
102
155
|
};
|
|
103
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* @param {TestResultType} result
|
|
159
|
+
* @returns Promise<ResultCreate>
|
|
160
|
+
* @private
|
|
161
|
+
*/
|
|
162
|
+
async transformTestResultV1(result) {
|
|
163
|
+
const attachments = await this.uploadAttachments(result.attachments);
|
|
164
|
+
const steps = await this.transformStepsV1(result.steps);
|
|
165
|
+
const resultCreate = {
|
|
166
|
+
attachments: attachments,
|
|
167
|
+
comment: result.message,
|
|
168
|
+
defect: this.defect,
|
|
169
|
+
param: result.params,
|
|
170
|
+
stacktrace: result.execution.stacktrace,
|
|
171
|
+
start_time: result.execution.start_time ? result.execution.start_time | 0 : null,
|
|
172
|
+
status: result.execution.status,
|
|
173
|
+
steps: steps,
|
|
174
|
+
time: result.execution.end_time,
|
|
175
|
+
time_ms: result.execution.duration,
|
|
176
|
+
};
|
|
177
|
+
const id = Array.isArray(result.testops_id) ? null : result.testops_id;
|
|
178
|
+
if (id) {
|
|
179
|
+
resultCreate.case_id = id;
|
|
180
|
+
return resultCreate;
|
|
181
|
+
}
|
|
182
|
+
resultCreate.case = {
|
|
183
|
+
title: result.title,
|
|
184
|
+
suite_title: result.relations?.suite ? result.relations?.suite?.data.map((suite) => suite.title).join('\t') : null,
|
|
185
|
+
};
|
|
186
|
+
return resultCreate;
|
|
187
|
+
}
|
|
104
188
|
/**
|
|
105
189
|
* @returns {ResultExecution}
|
|
106
190
|
* @private
|
|
@@ -116,6 +200,28 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
116
200
|
thread: exec.thread,
|
|
117
201
|
};
|
|
118
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* @param {Relation | null} relation
|
|
205
|
+
* @returns {ResultRelations}
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
getRelation(relation) {
|
|
209
|
+
if (!relation || !relation.suite) {
|
|
210
|
+
return {};
|
|
211
|
+
}
|
|
212
|
+
const suiteData = [];
|
|
213
|
+
for (const data of relation.suite.data) {
|
|
214
|
+
suiteData.push({
|
|
215
|
+
public_id: null,
|
|
216
|
+
title: data.title,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
suite: {
|
|
221
|
+
data: suiteData,
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
119
225
|
/**
|
|
120
226
|
* @param {TestStepType[]} steps
|
|
121
227
|
* @returns Promise<ResultStep[]>
|
|
@@ -141,6 +247,27 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
141
247
|
}
|
|
142
248
|
return resultsSteps;
|
|
143
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* @param {TestStepType[]} steps
|
|
252
|
+
* @returns Promise<TestStepResultCreate[]>
|
|
253
|
+
* @private
|
|
254
|
+
*/
|
|
255
|
+
async transformStepsV1(steps) {
|
|
256
|
+
const resultsSteps = [];
|
|
257
|
+
for (const step of steps) {
|
|
258
|
+
const attachmentHashes = await this.uploadAttachments(step.attachments);
|
|
259
|
+
const resultStep = {
|
|
260
|
+
status: TestOpsReporter.stepStatusMapV1[step.execution.status],
|
|
261
|
+
action: step.data.action,
|
|
262
|
+
attachments: attachmentHashes,
|
|
263
|
+
};
|
|
264
|
+
if (step.steps.length > 0) {
|
|
265
|
+
resultStep.steps = await this.transformStepsV1(step.steps);
|
|
266
|
+
}
|
|
267
|
+
resultsSteps.push(resultStep);
|
|
268
|
+
}
|
|
269
|
+
return resultsSteps;
|
|
270
|
+
}
|
|
144
271
|
/**
|
|
145
272
|
* @param {number} runId
|
|
146
273
|
* @returns {Promise<void>}
|
|
@@ -235,3 +362,11 @@ TestOpsReporter.stepStatusMap = {
|
|
|
235
362
|
[models_1.StepStatusEnum.failed]: qaseio_1.ResultStepStatus.FAILED,
|
|
236
363
|
[models_1.StepStatusEnum.blocked]: qaseio_1.ResultStepStatus.BLOCKED,
|
|
237
364
|
};
|
|
365
|
+
/**
|
|
366
|
+
* @type {Record<StepStatusEnum, ResultStepStatus>}
|
|
367
|
+
*/
|
|
368
|
+
TestOpsReporter.stepStatusMapV1 = {
|
|
369
|
+
[models_1.StepStatusEnum.passed]: qaseio_1.TestStepResultCreateStatusEnum.PASSED,
|
|
370
|
+
[models_1.StepStatusEnum.failed]: qaseio_1.TestStepResultCreateStatusEnum.FAILED,
|
|
371
|
+
[models_1.StepStatusEnum.blocked]: qaseio_1.TestStepResultCreateStatusEnum.BLOCKED,
|
|
372
|
+
};
|