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