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 CHANGED
@@ -1,17 +1,20 @@
1
- # [Qase TMS](https://qase.io) Cucumber JS Reporter
1
+ > # Qase TMS Cucumber JS reporter
2
+ >
3
+ > Publish results simple and easy.
2
4
 
3
- [![License](https://lxgaming.github.io/badges/License-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
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
- ## Usage
13
+ The Cucumber JS reporter has the ability to auto-generate test cases
14
+ and suites from your test data.
13
15
 
14
- Decorate your scenarios with Qase TMS case IDs in format `Q-<case id>` or `Q123`, also `q` can be in any case:
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
- After that you can use `cucumberjs-qase-reporter` as formatter:
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
- "enabled": true,
66
- "logging": true,
67
- "apiToken": "a786b45e371e1097c4c78a3211e3a1d23018ceb9",
68
- "projectCode": "PROJECTCODE",
69
- "runName": "CucumberJS run %DATE%"
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 shouldPublish;
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 publishCaseResult;
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 models_1 = require("qaseio/dist/src/models");
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]: models_1.ResultStatus.PASSED,
17
- [Status.FAILED]: models_1.ResultStatus.FAILED,
18
- [Status.SKIPPED]: models_1.ResultStatus.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
- apiToken: process.env.QASE_API_TOKEN || config.apiToken,
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.shouldPublish = 0;
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.pickle) {
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
- tags: this.extractIds(envelope.pickle.tags), name: envelope.pickle.name,
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 && this.shouldPublish === 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
- if (envelope.testRunFinished.success) {
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] = models_1.ResultStatus.PASSED;
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 !== models_1.ResultStatus.PASSED) {
171
- this.addErrorMessage(stepFin.testCaseStartedId, (_a = stepFin.testStepResult) === null || _a === void 0 ? void 0 : _a.message);
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 !== models_1.ResultStatus.FAILED && newStatus) {
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
- tags: info.tags,
194
- // eslint-disable-next-line max-len, @typescript-eslint/no-unnecessary-type-assertion
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: (_b = this.testCaseStartedErrors[tcs.id]) === null || _b === void 0 ? void 0 : _b.join('\n\n'),
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.publishCaseResult(test, status);
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
- this.api.projects.exists(projectCode)
222
- .then(cb)
223
- .catch((err) => {
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
- checkRun(runId, cb) {
238
- if (runId !== undefined) {
239
- this.api.runs.exists(this.config.projectCode, runId)
240
- .then(cb)
241
- .catch((err) => {
242
- this._log(`Error on checking run ${err}`);
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
- else {
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
- publishCaseResult(test, status) {
364
+ addForSending(test, status) {
272
365
  this.logTestItem(test.name, status);
273
- const caseIds = test.tags;
274
- caseIds.forEach((caseId) => {
275
- this.shouldPublish++;
276
- const publishTest = (runId) => {
277
- if (caseId) {
278
- const add = caseIds.length > 1 ? chalk_1.default ` {white For case ${caseId}}` : '';
279
- this._log(chalk_1.default `{gray Start publishing: ${test.name}}${add}`);
280
- const result = new models_1.ResultCreate(parseInt(caseId, 10), status, {
281
- // eslint-disable-next-line camelcase
282
- time_ms: test.duration,
283
- stacktrace: test.error,
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