cucumberjs-qase-reporter 0.2.5 → 0.2.8-alpha.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.
- package/README.md +66 -13
- package/dist/index.d.ts +13 -3
- package/dist/index.js +230 -95
- package/dist/index.js.map +1 -1
- package/examples/examples/zombie/logo.svg +4 -0
- package/examples/examples/zombie/steps/cucumber_documentation.js +10 -3
- package/examples/features/cucumber_documentation.feature +1 -36
- package/examples/features/cucumber_documentation2.feature +23 -0
- package/examples/package-lock.json +16480 -2476
- package/examples/package.json +2 -2
- package/examples/screenshots/demo.gif +0 -0
- package/examples/screenshots/screenshot.png +0 -0
- package/package.json +9 -4
- package/examples/README.md +0 -7
package/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
#
|
|
1
|
+
> # Qase TMS Cucumber JS reporter
|
|
2
|
+
>
|
|
3
|
+
> Publish results simple and easy.
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
5
|
+
## How to integrate
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
npm install cucumberjs-qase-reporter
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
## Example of usage
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
The Cucumber JS reporter has the ability to auto-generate test cases
|
|
14
|
+
and suites from your test data.
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
But if necessary, you can independently register the ID of already
|
|
17
|
+
existing test cases from TMS before the executing tests. You can decorate your scenarios with Qase TMS case IDs in format `Q-<case id>` or `Q123`, also `q` can be in any case:
|
|
15
18
|
|
|
16
19
|
```gherkin
|
|
17
20
|
Feature: Cucumber documentation
|
|
@@ -34,12 +37,45 @@ Feature: Cucumber documentation
|
|
|
34
37
|
And I should see a "Dependencies" badge
|
|
35
38
|
```
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
You should also have an active item in the project settings at
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
https://app.qase.io/project/QASE_PROJECT_CODE/settings/options
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
options in the `Test Runs` block:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Auto create test cases
|
|
50
|
+
```
|
|
51
|
+
and
|
|
38
52
|
|
|
53
|
+
```
|
|
54
|
+
Allow submitting results in bulk
|
|
55
|
+
```
|
|
56
|
+
---
|
|
57
|
+
To run tests and create a test run, execute the command (for example from folder examples):
|
|
39
58
|
```bash
|
|
40
|
-
cucumber-js -f cucumberjs-qase-reporter features
|
|
59
|
+
cucumber-js -f cucumberjs-qase-reporter --format-options='{\"qaseConfig\": \"./.qaserc\"}' features -r examples/zombie/support -r examples/zombie/steps
|
|
60
|
+
```
|
|
61
|
+
or
|
|
62
|
+
```bash
|
|
63
|
+
npm test
|
|
64
|
+
```
|
|
65
|
+
<p align="center">
|
|
66
|
+
<img width="65%" src="./examples/screenshots/screenshot.png">
|
|
67
|
+
</p>
|
|
68
|
+
|
|
69
|
+
A test run will be performed and available at:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
https://app.qase.io/run/QASE_PROJECT_CODE
|
|
41
73
|
```
|
|
42
74
|
|
|
75
|
+
<p align="center">
|
|
76
|
+
<img src="./examples/screenshots/demo.gif">
|
|
77
|
+
</p>
|
|
78
|
+
|
|
43
79
|
## Configuration
|
|
44
80
|
|
|
45
81
|
Qase reporter supports passing parameters using two ways:
|
|
@@ -47,6 +83,8 @@ using `.qaserc` file and using ENV variables.
|
|
|
47
83
|
|
|
48
84
|
`.qaserc` parameters:
|
|
49
85
|
- `enabled` - Enable reporter
|
|
86
|
+
- `basePath` - URL Qase.io
|
|
87
|
+
- `environmentId` - To execute with the sending of the envinroment information
|
|
50
88
|
- `apiToken` - Token for API access, you can find more information
|
|
51
89
|
[here](https://developers.qase.io/#authentication)
|
|
52
90
|
- `projectCode` - Code of your project (can be extracted from main
|
|
@@ -58,27 +96,38 @@ using `.qaserc` file and using ENV variables.
|
|
|
58
96
|
- `%DATE%`
|
|
59
97
|
- `runDescription` - Set custom Run description, when new run is created
|
|
60
98
|
- `logging` - Enabled debug logging from reporter or not
|
|
99
|
+
- `rootSuiteTitle` - A parent suite for your autocreated tests
|
|
61
100
|
|
|
62
101
|
Example configuration file:
|
|
63
102
|
```json
|
|
64
103
|
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
104
|
+
"enabled": true,
|
|
105
|
+
"logging": true,
|
|
106
|
+
"apiToken": "api_key",
|
|
107
|
+
"projectCode": "project_code",
|
|
108
|
+
"runName": "CucumberJS run %DATE%",
|
|
109
|
+
"environmentId": 1,
|
|
110
|
+
"basePath": "https://api.qase.io/v1"
|
|
70
111
|
}
|
|
71
112
|
```
|
|
72
113
|
|
|
73
114
|
Supported ENV variables:
|
|
74
115
|
|
|
75
116
|
- `QASE_ENABLED` - Same as `enabled`
|
|
117
|
+
- `QASE_API_BASE_URL` - Same as `basePath`
|
|
76
118
|
- `QASE_API_TOKEN` - Same as `apiToken`
|
|
77
119
|
- `QASE_PROJECT` - Same as `projectCode`
|
|
78
120
|
- `QASE_RUN_ID` - Pass Run ID from ENV and override reporter options
|
|
79
121
|
- `QASE_RUN_NAME` - Same as `runName`
|
|
80
122
|
- `QASE_RUN_DESCRIPTION` - Same as `runDescription`
|
|
123
|
+
- `QASE_ENVIRONMENT_ID` - Same as `environmentId`
|
|
81
124
|
- `QASE_LOGGING` - Same as `logging`
|
|
125
|
+
- `QASE_ROOT_SUITE_TITLE` - Same as `rootSuiteTitle`
|
|
126
|
+
|
|
127
|
+
To run using ENV you have to execute:
|
|
128
|
+
```bash
|
|
129
|
+
cucumber-js -f cucumberjs-qase-reporter features
|
|
130
|
+
```
|
|
82
131
|
|
|
83
132
|
## Setup with Protractor
|
|
84
133
|
|
|
@@ -105,3 +154,7 @@ exports.config = {
|
|
|
105
154
|
```
|
|
106
155
|
|
|
107
156
|
**Do not forget to add .qaserc file!**
|
|
157
|
+
|
|
158
|
+
<!-- references -->
|
|
159
|
+
|
|
160
|
+
[auth]: https://developers.qase.io/#authentication
|
package/dist/index.d.ts
CHANGED
|
@@ -1,26 +1,36 @@
|
|
|
1
1
|
import { Formatter } from '@cucumber/cucumber';
|
|
2
2
|
import { IFormatterOptions } from '@cucumber/cucumber/lib/formatter';
|
|
3
3
|
declare class QaseReporter extends Formatter {
|
|
4
|
-
private config;
|
|
4
|
+
private readonly config;
|
|
5
5
|
private api;
|
|
6
6
|
private enabled;
|
|
7
7
|
private pickleInfo;
|
|
8
8
|
private testCaseStarts;
|
|
9
9
|
private testCaseStartedResult;
|
|
10
|
+
private testCaseStartedAttachment;
|
|
10
11
|
private testCaseStartedErrors;
|
|
11
12
|
private testCaseScenarioId;
|
|
12
13
|
private pending;
|
|
13
14
|
private results;
|
|
14
|
-
private
|
|
15
|
+
private scenarios;
|
|
16
|
+
private uploadsInQueueCount;
|
|
15
17
|
constructor(options: IFormatterOptions);
|
|
18
|
+
private waitUploads;
|
|
19
|
+
private upload;
|
|
20
|
+
private publishResults;
|
|
16
21
|
private addErrorMessage;
|
|
17
22
|
private _log;
|
|
18
23
|
private checkProject;
|
|
19
24
|
private createRun;
|
|
25
|
+
private createRunObject;
|
|
20
26
|
private checkRun;
|
|
21
27
|
private saveRunId;
|
|
22
28
|
private logTestItem;
|
|
23
|
-
private
|
|
29
|
+
private addForSending;
|
|
30
|
+
private addKnownCasesForSending;
|
|
31
|
+
private addNewCasesForSending;
|
|
24
32
|
private extractIds;
|
|
33
|
+
private createHeaders;
|
|
34
|
+
private getPackageVersion;
|
|
25
35
|
}
|
|
26
36
|
export = QaseReporter;
|
package/dist/index.js
CHANGED
|
@@ -2,25 +2,45 @@
|
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
|
+
/* eslint-disable camelcase */
|
|
6
|
+
/* eslint-disable max-len */
|
|
5
7
|
/* eslint-disable no-console,no-underscore-dangle,@typescript-eslint/no-non-null-assertion */
|
|
6
|
-
const
|
|
8
|
+
const src_1 = require("qaseio/dist/src");
|
|
9
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
7
10
|
const cucumber_1 = require("@cucumber/cucumber");
|
|
8
11
|
const qaseio_1 = require("qaseio");
|
|
9
12
|
const chalk_1 = __importDefault(require("chalk"));
|
|
13
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
14
|
+
const child_process_1 = require("child_process");
|
|
10
15
|
const fs_1 = __importDefault(require("fs"));
|
|
11
16
|
const messages_1 = require("@cucumber/messages/dist/src/messages");
|
|
17
|
+
const mime_types_1 = __importDefault(require("mime-types"));
|
|
12
18
|
const moment_1 = __importDefault(require("moment"));
|
|
19
|
+
const os_1 = __importDefault(require("os"));
|
|
13
20
|
const path_1 = __importDefault(require("path"));
|
|
14
21
|
var Status = messages_1.io.cucumber.messages.TestStepFinished.TestStepResult.Status;
|
|
15
22
|
const StatusMapping = {
|
|
16
|
-
[Status.PASSED]:
|
|
17
|
-
[Status.FAILED]:
|
|
18
|
-
[Status.SKIPPED]:
|
|
23
|
+
[Status.PASSED]: src_1.ResultCreateStatusEnum.PASSED,
|
|
24
|
+
[Status.FAILED]: src_1.ResultCreateStatusEnum.FAILED,
|
|
25
|
+
[Status.SKIPPED]: src_1.ResultCreateStatusEnum.SKIPPED,
|
|
19
26
|
[Status.AMBIGUOUS]: null,
|
|
20
27
|
[Status.PENDING]: null,
|
|
21
28
|
[Status.UNDEFINED]: null,
|
|
22
29
|
[Status.UNKNOWN]: null,
|
|
23
30
|
};
|
|
31
|
+
let customBoundary = '----------------------------';
|
|
32
|
+
crypto_1.default.randomBytes(24).forEach((value) => {
|
|
33
|
+
customBoundary += Math.floor(value * 10).toString(16);
|
|
34
|
+
});
|
|
35
|
+
class CustomBoundaryFormData extends form_data_1.default {
|
|
36
|
+
constructor() {
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
38
|
+
super();
|
|
39
|
+
}
|
|
40
|
+
getBoundary() {
|
|
41
|
+
return customBoundary;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
24
44
|
const loadJSON = (file) => {
|
|
25
45
|
try {
|
|
26
46
|
const data = fs_1.default.readFileSync(file, { encoding: 'utf8' });
|
|
@@ -42,12 +62,13 @@ const prepareConfig = (options = {}, configFile = '.qaserc') => {
|
|
|
42
62
|
const config = Object.assign(loaded || {}, options);
|
|
43
63
|
return {
|
|
44
64
|
enabled: process.env.QASE_ENABLED === 'true' || config.enabled || false,
|
|
45
|
-
|
|
65
|
+
basePath: process.env.QASE_API_BASE_URL || config.basePath,
|
|
66
|
+
apiToken: process.env.QASE_API_TOKEN || config.apiToken || '',
|
|
67
|
+
rootSuiteTitle: process.env.QASE_ROOT_SUITE_TITLE || config.rootSuiteTitle,
|
|
68
|
+
environmentId: Number.parseInt(process.env.QASE_ENVIRONMENT_ID, 10) || config.environmentId,
|
|
46
69
|
projectCode: process.env.QASE_PROJECT || config.projectCode || '',
|
|
47
70
|
runId: process.env.QASE_RUN_ID || config.runId || '',
|
|
48
|
-
runName: process.env.QASE_RUN_NAME ||
|
|
49
|
-
config.runName ||
|
|
50
|
-
'Automated Run %DATE%',
|
|
71
|
+
runName: process.env.QASE_RUN_NAME || config.runName || 'Automated Run %DATE%',
|
|
51
72
|
runDescription: process.env.QASE_RUN_DESCRIPTION || config.runDescription,
|
|
52
73
|
logging: process.env.QASE_LOGGING !== '' || config.logging,
|
|
53
74
|
};
|
|
@@ -76,34 +97,49 @@ class QaseReporter extends cucumber_1.Formatter {
|
|
|
76
97
|
this.pickleInfo = {};
|
|
77
98
|
this.testCaseStarts = {};
|
|
78
99
|
this.testCaseStartedResult = {};
|
|
100
|
+
this.testCaseStartedAttachment = {};
|
|
79
101
|
this.testCaseStartedErrors = {};
|
|
80
102
|
this.testCaseScenarioId = {};
|
|
81
103
|
this.pending = [];
|
|
82
|
-
this.results =
|
|
83
|
-
this.
|
|
104
|
+
this.results = {};
|
|
105
|
+
this.scenarios = {};
|
|
106
|
+
this.uploadsInQueueCount = 0;
|
|
84
107
|
this.config = prepareConfig(options.parsedArgvOptions, (_a = options.parsedArgvOptions) === null || _a === void 0 ? void 0 : _a.qaseConfig);
|
|
85
108
|
this.enabled = verifyConfig(this.config);
|
|
86
|
-
this.api = new qaseio_1.QaseApi(this.config.apiToken);
|
|
109
|
+
this.api = new qaseio_1.QaseApi(this.config.apiToken, this.config.basePath, this.createHeaders(), CustomBoundaryFormData);
|
|
87
110
|
if (!this.enabled) {
|
|
88
111
|
return;
|
|
89
112
|
}
|
|
90
113
|
this.config.runName = prepareReportName(this.config);
|
|
91
114
|
options.eventBroadcaster
|
|
92
115
|
.on('envelope', (envelope) => {
|
|
93
|
-
var _a, _b;
|
|
94
|
-
if (envelope.
|
|
116
|
+
var _a, _b, _c, _d;
|
|
117
|
+
if (envelope.gherkinDocument) {
|
|
118
|
+
(_b = (_a = envelope.gherkinDocument.feature) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b.forEach((featureChild) => {
|
|
119
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
120
|
+
if (((_b = (_a = envelope.gherkinDocument) === null || _a === void 0 ? void 0 : _a.feature) === null || _b === void 0 ? void 0 : _b.name) != null && ((_c = featureChild.scenario) === null || _c === void 0 ? void 0 : _c.id) !== undefined && ((_d = featureChild.scenario) === null || _d === void 0 ? void 0 : _d.id) !== null) {
|
|
121
|
+
this.scenarios[(_e = featureChild.scenario) === null || _e === void 0 ? void 0 : _e.id] = (_g = (_f = envelope.gherkinDocument) === null || _f === void 0 ? void 0 : _f.feature) === null || _g === void 0 ? void 0 : _g.name;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else if (envelope.pickle) {
|
|
95
126
|
this.pickleInfo[envelope.pickle.id] = {
|
|
96
|
-
|
|
127
|
+
caseIds: this.extractIds(envelope.pickle.tags),
|
|
128
|
+
name: envelope.pickle.name,
|
|
129
|
+
lastAstNodeId: envelope.pickle.astNodeIds ? envelope.pickle.astNodeIds[envelope.pickle.astNodeIds.length - 1] : null,
|
|
97
130
|
};
|
|
98
131
|
}
|
|
132
|
+
else if (envelope.attachment) {
|
|
133
|
+
void this.upload(envelope.attachment);
|
|
134
|
+
}
|
|
99
135
|
else if (envelope.testRunStarted) {
|
|
100
|
-
this.checkProject(this.config.projectCode, (prjExists) => {
|
|
136
|
+
void this.checkProject(this.config.projectCode, async (prjExists) => {
|
|
101
137
|
if (prjExists) {
|
|
102
138
|
this._log(chalk_1.default `{green Project ${this.config.projectCode} exists}`);
|
|
103
139
|
const willRun = Object.keys(this.pickleInfo).length !== 0;
|
|
104
140
|
if (this.config.runId && willRun) {
|
|
105
141
|
this.saveRunId(this.config.runId);
|
|
106
|
-
this.checkRun(this.config.runId, (runExists) => {
|
|
142
|
+
return this.checkRun(this.config.runId, (runExists) => {
|
|
107
143
|
const run = this.config.runId;
|
|
108
144
|
if (runExists) {
|
|
109
145
|
this._log(chalk_1.default `{green Using run ${run} to publish test results}`);
|
|
@@ -114,17 +150,14 @@ class QaseReporter extends cucumber_1.Formatter {
|
|
|
114
150
|
});
|
|
115
151
|
}
|
|
116
152
|
else if (!this.config.runId && willRun) {
|
|
117
|
-
this.createRun(this.config.runName, this.config.runDescription, (created) => {
|
|
153
|
+
return this.createRun(this.config.runName, this.config.runDescription, (created) => {
|
|
154
|
+
var _a;
|
|
118
155
|
if (created) {
|
|
119
|
-
this.saveRunId(created.id);
|
|
120
|
-
this._log(
|
|
121
|
-
// eslint-disable-next-line max-len
|
|
122
|
-
chalk_1.default `{green Using run ${this.config.runId} to publish test results}`);
|
|
156
|
+
this.saveRunId((_a = created.result) === null || _a === void 0 ? void 0 : _a.id);
|
|
157
|
+
this._log(chalk_1.default `{green Using run ${this.config.runId} to publish test results}`);
|
|
123
158
|
}
|
|
124
159
|
else {
|
|
125
|
-
this._log(
|
|
126
|
-
// eslint-disable-next-line max-len
|
|
127
|
-
chalk_1.default `{red Could not create run in project ${this.config.projectCode}}`);
|
|
160
|
+
this._log(chalk_1.default `{red Could not create run in project ${this.config.projectCode}}`);
|
|
128
161
|
}
|
|
129
162
|
});
|
|
130
163
|
}
|
|
@@ -138,22 +171,18 @@ class QaseReporter extends cucumber_1.Formatter {
|
|
|
138
171
|
});
|
|
139
172
|
}
|
|
140
173
|
else if (envelope.testRunFinished) {
|
|
141
|
-
if (this.results.length === 0
|
|
174
|
+
if (Object.keys(this.results).length === 0) {
|
|
142
175
|
this._log('No testcases were matched. Ensure that your tests are declared correctly.');
|
|
176
|
+
return;
|
|
143
177
|
}
|
|
144
|
-
|
|
145
|
-
this._log('Finished success');
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
this._log('Finished with errors');
|
|
149
|
-
}
|
|
178
|
+
void this.publishResults();
|
|
150
179
|
}
|
|
151
180
|
else if (envelope.testCase) {
|
|
152
181
|
this.testCaseScenarioId[envelope.testCase.id] = envelope.testCase.pickleId;
|
|
153
182
|
}
|
|
154
183
|
else if (envelope.testCaseStarted) {
|
|
155
184
|
this.testCaseStarts[envelope.testCaseStarted.id] = envelope.testCaseStarted;
|
|
156
|
-
this.testCaseStartedResult[envelope.testCaseStarted.id] =
|
|
185
|
+
this.testCaseStartedResult[envelope.testCaseStarted.id] = src_1.ResultCreateStatusEnum.PASSED;
|
|
157
186
|
}
|
|
158
187
|
else if (envelope.testStepFinished) {
|
|
159
188
|
const stepFin = envelope.testStepFinished;
|
|
@@ -162,15 +191,13 @@ class QaseReporter extends cucumber_1.Formatter {
|
|
|
162
191
|
const oldStatus = this.testCaseStartedResult[stepFin.testCaseStartedId];
|
|
163
192
|
const newStatus = StatusMapping[stepFin.testStepResult.status];
|
|
164
193
|
if (newStatus === null) {
|
|
165
|
-
this._log(
|
|
166
|
-
// eslint-disable-next-line max-len
|
|
167
|
-
chalk_1.default `{redBright Unexpected finish status ${stepStatus} received for step ${stepMessage}}`);
|
|
194
|
+
this._log(chalk_1.default `{redBright Unexpected finish status ${stepStatus} received for step ${stepMessage}}`);
|
|
168
195
|
return;
|
|
169
196
|
}
|
|
170
|
-
if (newStatus !==
|
|
171
|
-
this.addErrorMessage(stepFin.testCaseStartedId, (
|
|
197
|
+
if (newStatus !== src_1.ResultCreateStatusEnum.PASSED) {
|
|
198
|
+
this.addErrorMessage(stepFin.testCaseStartedId, (_c = stepFin.testStepResult) === null || _c === void 0 ? void 0 : _c.message);
|
|
172
199
|
if (oldStatus) {
|
|
173
|
-
if (oldStatus !==
|
|
200
|
+
if (oldStatus !== src_1.ResultCreateStatusEnum.FAILED && newStatus) {
|
|
174
201
|
this.testCaseStartedResult[stepFin.testCaseStartedId] = newStatus;
|
|
175
202
|
}
|
|
176
203
|
}
|
|
@@ -190,18 +217,67 @@ class QaseReporter extends cucumber_1.Formatter {
|
|
|
190
217
|
name: info.name,
|
|
191
218
|
started: tcs,
|
|
192
219
|
finished: envelope.testCaseFinished,
|
|
193
|
-
|
|
194
|
-
// eslint-disable-next-line
|
|
220
|
+
caseIds: info.caseIds,
|
|
221
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
195
222
|
duration: Math.abs((envelope.testCaseFinished.timestamp.seconds - tcs.timestamp.seconds)),
|
|
196
|
-
error: (
|
|
223
|
+
error: (_d = this.testCaseStartedErrors[tcs.id]) === null || _d === void 0 ? void 0 : _d.join('\n\n'),
|
|
224
|
+
lastAstNodeId: info.lastAstNodeId,
|
|
197
225
|
};
|
|
198
|
-
this.
|
|
226
|
+
this.addForSending(test, status);
|
|
199
227
|
}
|
|
200
228
|
else if (envelope.parseError) {
|
|
201
229
|
console.log('Error:', envelope.parseError);
|
|
202
230
|
}
|
|
203
231
|
});
|
|
204
232
|
}
|
|
233
|
+
async waitUploads() {
|
|
234
|
+
while (this.uploadsInQueueCount > 0) {
|
|
235
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async upload(attachment) {
|
|
239
|
+
const randomString = crypto_1.default.randomBytes(20).toString('hex');
|
|
240
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call
|
|
241
|
+
const tmpFilePath = os_1.default.tmpdir().concat(randomString, '.', mime_types_1.default.extension(attachment.mediaType));
|
|
242
|
+
fs_1.default.writeFile(tmpFilePath, attachment.body, 'base64', (err) => {
|
|
243
|
+
if (err !== null) {
|
|
244
|
+
this._log(err.message);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
this.uploadsInQueueCount++;
|
|
248
|
+
await this.api.attachments.uploadAttachment(this.config.projectCode, [fs_1.default.createReadStream(tmpFilePath)], {
|
|
249
|
+
headers: {
|
|
250
|
+
'Content-Type': 'multipart/form-data; boundary=' + customBoundary,
|
|
251
|
+
},
|
|
252
|
+
}).then((response) => {
|
|
253
|
+
var _a;
|
|
254
|
+
const fileHash = (_a = response.data.result) === null || _a === void 0 ? void 0 : _a[0].hash;
|
|
255
|
+
const caseAttachments = this.testCaseStartedAttachment[attachment.testCaseStartedId] || [];
|
|
256
|
+
caseAttachments.push(fileHash);
|
|
257
|
+
this.testCaseStartedAttachment[attachment.testCaseStartedId] = caseAttachments;
|
|
258
|
+
this.uploadsInQueueCount--;
|
|
259
|
+
}).catch((err) => {
|
|
260
|
+
this.log(`Error on uploading file ${err}`);
|
|
261
|
+
this.uploadsInQueueCount--;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
async publishResults() {
|
|
265
|
+
await this.waitUploads();
|
|
266
|
+
const res = [];
|
|
267
|
+
Object.keys(this.results).forEach((testCaseStartedId) => {
|
|
268
|
+
var _a;
|
|
269
|
+
const result = this.results[testCaseStartedId];
|
|
270
|
+
result.attachments = (_a = this.testCaseStartedAttachment[testCaseStartedId]) !== null && _a !== void 0 ? _a : [];
|
|
271
|
+
res.push(result);
|
|
272
|
+
});
|
|
273
|
+
this.api.results.createResultBulk(this.config.projectCode, Number(this.config.runId), {
|
|
274
|
+
results: res,
|
|
275
|
+
}).then(() => {
|
|
276
|
+
this._log(chalk_1.default `{gray Results sent}`);
|
|
277
|
+
}).catch((err) => {
|
|
278
|
+
this._log(err);
|
|
279
|
+
});
|
|
280
|
+
}
|
|
205
281
|
addErrorMessage(tcsid, error) {
|
|
206
282
|
if (error) {
|
|
207
283
|
if (tcsid in this.testCaseStartedErrors) {
|
|
@@ -217,34 +293,50 @@ class QaseReporter extends cucumber_1.Formatter {
|
|
|
217
293
|
console.log(chalk_1.default `{bold {blue qase:}} ${message}`, ...optionalParams);
|
|
218
294
|
}
|
|
219
295
|
}
|
|
220
|
-
checkProject(projectCode, cb) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
.
|
|
296
|
+
async checkProject(projectCode, cb) {
|
|
297
|
+
var _a;
|
|
298
|
+
try {
|
|
299
|
+
const resp = await this.api.projects.getProject(projectCode);
|
|
300
|
+
await cb(Boolean((_a = resp.data.result) === null || _a === void 0 ? void 0 : _a.code));
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
224
303
|
this._log(err);
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
createRun(name, description, cb) {
|
|
228
|
-
this.api.runs.create(this.config.projectCode, new models_1.RunCreate(name || `Automated run ${new Date().toISOString()}`, [],
|
|
229
|
-
// eslint-disable-next-line camelcase
|
|
230
|
-
{ description: description || 'Cypress automated run', is_autotest: true }))
|
|
231
|
-
.then((res) => res.data)
|
|
232
|
-
.then(cb)
|
|
233
|
-
.catch((err) => {
|
|
234
|
-
this._log(`Error on creating run ${err}`);
|
|
235
|
-
});
|
|
304
|
+
this.enabled = false;
|
|
305
|
+
}
|
|
236
306
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
this.
|
|
240
|
-
|
|
241
|
-
.
|
|
242
|
-
|
|
307
|
+
async createRun(name, description, cb) {
|
|
308
|
+
try {
|
|
309
|
+
const runObject = this.createRunObject(name || `Automated run ${new Date().toISOString()}`, [], {
|
|
310
|
+
description: description || 'CucumberJS automated run',
|
|
311
|
+
environment_id: this.config.environmentId,
|
|
312
|
+
is_autotest: true,
|
|
243
313
|
});
|
|
314
|
+
const res = await this.api.runs.createRun(this.config.projectCode, runObject);
|
|
315
|
+
cb(res.data);
|
|
244
316
|
}
|
|
245
|
-
|
|
317
|
+
catch (err) {
|
|
318
|
+
this._log(`Error on creating run ${err}`);
|
|
319
|
+
this.enabled = false;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
createRunObject(name, cases, args) {
|
|
323
|
+
return Object.assign({ title: name, cases }, args);
|
|
324
|
+
}
|
|
325
|
+
async checkRun(runId, cb) {
|
|
326
|
+
if (runId === undefined) {
|
|
246
327
|
cb(false);
|
|
328
|
+
return;
|
|
247
329
|
}
|
|
330
|
+
return this.api.runs.getRun(this.config.projectCode, Number(runId))
|
|
331
|
+
.then((resp) => {
|
|
332
|
+
var _a, _b;
|
|
333
|
+
this._log(`Get run result on checking run ${(_a = resp.data.result) === null || _a === void 0 ? void 0 : _a.id}`);
|
|
334
|
+
cb(Boolean((_b = resp.data.result) === null || _b === void 0 ? void 0 : _b.id));
|
|
335
|
+
})
|
|
336
|
+
.catch((err) => {
|
|
337
|
+
this._log(`Error on checking run ${err}`);
|
|
338
|
+
this.enabled = false;
|
|
339
|
+
});
|
|
248
340
|
}
|
|
249
341
|
saveRunId(runId) {
|
|
250
342
|
this.config.runId = runId;
|
|
@@ -263,50 +355,93 @@ class QaseReporter extends cucumber_1.Formatter {
|
|
|
263
355
|
failed: chalk_1.default `{red Test ${name} ${status}}`,
|
|
264
356
|
passed: chalk_1.default `{green Test ${name} ${status}}`,
|
|
265
357
|
pending: chalk_1.default `{blueBright Test ${name} ${status}}`,
|
|
358
|
+
skipped: chalk_1.default `{bgGray Test ${name} ${status}}`,
|
|
266
359
|
};
|
|
267
360
|
if (status) {
|
|
268
361
|
this._log(map[status]);
|
|
269
362
|
}
|
|
270
363
|
}
|
|
271
|
-
|
|
364
|
+
addForSending(test, status) {
|
|
272
365
|
this.logTestItem(test.name, status);
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
comment: test.error ? test.error.split('\n')[0] : undefined,
|
|
285
|
-
});
|
|
286
|
-
this.api.results.create(this.config.projectCode, runId, result)
|
|
287
|
-
.then((res) => {
|
|
288
|
-
this.results.push({ test, result: res.data });
|
|
289
|
-
this._log(chalk_1.default `{gray Result published: ${test.name} ${res.data.hash}}${add}`);
|
|
290
|
-
this.shouldPublish--;
|
|
291
|
-
})
|
|
292
|
-
.catch((err) => {
|
|
293
|
-
this._log(err);
|
|
294
|
-
this.shouldPublish--;
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
if (this.config.runId) {
|
|
299
|
-
publishTest(this.config.runId);
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
302
|
-
this.pending.push(publishTest);
|
|
366
|
+
if (test.caseIds.length) {
|
|
367
|
+
this.addKnownCasesForSending(test, status);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
this.addNewCasesForSending(test, status);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
addKnownCasesForSending(test, status) {
|
|
374
|
+
test.caseIds.forEach((caseId) => {
|
|
375
|
+
if (!caseId) {
|
|
376
|
+
return;
|
|
303
377
|
}
|
|
378
|
+
const add = test.caseIds.length > 1 ? chalk_1.default ` {white For case ${caseId}}` : '';
|
|
379
|
+
this._log(chalk_1.default `{gray Added for publishing: ${test.name}}${add}`);
|
|
380
|
+
this.results[test.finished.testCaseStartedId] = {
|
|
381
|
+
status,
|
|
382
|
+
case_id: parseInt(caseId, 10),
|
|
383
|
+
time: test.duration,
|
|
384
|
+
stacktrace: test.error,
|
|
385
|
+
comment: test.error ? test.error.split('\n')[0] : undefined,
|
|
386
|
+
};
|
|
304
387
|
});
|
|
305
388
|
}
|
|
389
|
+
addNewCasesForSending(test, status) {
|
|
390
|
+
const suiteTitle = [test.lastAstNodeId ? this.scenarios[test.lastAstNodeId] : ''];
|
|
391
|
+
if (this.config.rootSuiteTitle) {
|
|
392
|
+
suiteTitle.unshift(this.config.rootSuiteTitle);
|
|
393
|
+
}
|
|
394
|
+
this._log(chalk_1.default `{gray Added for publishing: ${suiteTitle.join('/')}/${test.name}}`);
|
|
395
|
+
this.results[test.finished.testCaseStartedId] = {
|
|
396
|
+
case: {
|
|
397
|
+
title: test.name,
|
|
398
|
+
suite_title: suiteTitle.join('\t'),
|
|
399
|
+
},
|
|
400
|
+
status,
|
|
401
|
+
time: test.duration,
|
|
402
|
+
stacktrace: test.error,
|
|
403
|
+
comment: test.error ? test.error.split('\n')[0] : undefined,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
306
406
|
extractIds(tagsList) {
|
|
307
407
|
const regex = /[Qq]-*(\d+)/;
|
|
308
408
|
return tagsList.filter((tagInfo) => regex.test(tagInfo.name)).map((tagInfo) => regex.exec(tagInfo.name)[1]);
|
|
309
409
|
}
|
|
410
|
+
createHeaders() {
|
|
411
|
+
const { version: nodeVersion } = process;
|
|
412
|
+
const npmVersion = child_process_1.execSync('npm -v', { encoding: 'utf8' }).replace(/['"\n]+/g, '');
|
|
413
|
+
const qaseapiVersion = this.getPackageVersion('qaseio');
|
|
414
|
+
const frameworkVersion = this.getPackageVersion('@cucumber/cucumber');
|
|
415
|
+
const reporterVersion = this.getPackageVersion('cucumberjs-qase-reporter');
|
|
416
|
+
const xPlatformHeader = `node=${nodeVersion};npm=${npmVersion};os=${os_1.default.platform()};arch=${os_1.default.arch()}`;
|
|
417
|
+
const xClientHeader = `cucumberjs=${frameworkVersion};qase-cucumberjs=${reporterVersion};qaseapi=${qaseapiVersion}`;
|
|
418
|
+
return {
|
|
419
|
+
'X-Client': xClientHeader,
|
|
420
|
+
'X-Platform': xPlatformHeader,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
getPackageVersion(name) {
|
|
424
|
+
const UNDEFINED = 'undefined';
|
|
425
|
+
try {
|
|
426
|
+
const pathToPackageJson = require.resolve(`${name}/package.json`, { paths: [process.cwd()] });
|
|
427
|
+
if (pathToPackageJson) {
|
|
428
|
+
try {
|
|
429
|
+
const packageString = fs_1.default.readFileSync(pathToPackageJson, { encoding: 'utf8' });
|
|
430
|
+
if (packageString) {
|
|
431
|
+
const packageObject = JSON.parse(packageString);
|
|
432
|
+
return packageObject.version;
|
|
433
|
+
}
|
|
434
|
+
return UNDEFINED;
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
return UNDEFINED;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
return UNDEFINED;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
310
445
|
}
|
|
311
446
|
module.exports = QaseReporter;
|
|
312
447
|
//# sourceMappingURL=index.js.map
|