cucumberjs-qase-reporter 2.0.0-beta.2 → 2.0.0-beta.3

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 ADDED
@@ -0,0 +1,31 @@
1
+ # qase-cucumberjs@2.0.0-beta.3
2
+
3
+ ## What's new
4
+
5
+ Added support new Qase tags.
6
+
7
+ ```diff
8
+ - @Q-1
9
+ + @QaseID=2
10
+ + @QaseTitle=Scenario_with_Qase_title_tag
11
+ + @QaseFields={"description":"Description","severity":"high"}
12
+ Scenario: simple test
13
+ ```
14
+
15
+ QaseID - is a unique identifier of the test case in the Qase TMS.
16
+ QaseTitle - is a title of the test case in the Qase TMS.
17
+ QaseFields - is a JSON object with additional fields for the test case in the Qase TMS.
18
+
19
+ # qase-cucumberjs@2.0.0-beta.2
20
+
21
+ ## What's new
22
+
23
+ Added support gherkin steps.
24
+ Before this version, the reporter was not able to parse the steps from the feature files.
25
+ Now, the reporter can parse the steps and send them to the Qase TMS.
26
+
27
+ # qase-cucumberjs@2.0.0-beta.1
28
+
29
+ ## What's new
30
+
31
+ First major beta release for the version 2 series of the Qase Cypress reporter.
@@ -0,0 +1,5 @@
1
+ interface TestMetadata {
2
+ ids: number[];
3
+ fields: Record<string, string>;
4
+ title: string | null;
5
+ }
package/dist/models.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";
@@ -1,6 +1,5 @@
1
- import { Formatter, IFormatterOptions, Status } from '@cucumber/cucumber';
2
- import { ConfigLoader, ConfigType, StepStatusEnum, TestStatusEnum } from 'qase-javascript-commons';
3
- type TestStepResultStatus = (typeof Status)[keyof typeof Status];
1
+ import { Formatter, IFormatterOptions } from '@cucumber/cucumber';
2
+ import { ConfigLoader, ConfigType } from 'qase-javascript-commons';
4
3
  export type CucumberQaseOptionsType = IFormatterOptions & {
5
4
  qase?: ConfigType;
6
5
  };
@@ -9,64 +8,11 @@ export type CucumberQaseOptionsType = IFormatterOptions & {
9
8
  * @extends Formatter
10
9
  */
11
10
  export declare class CucumberQaseReporter extends Formatter {
12
- /**
13
- * @type {Record<TestStepResultStatus, TestStatusEnum | null>}
14
- */
15
- static statusMap: Record<TestStepResultStatus, TestStatusEnum | null>;
16
- /**
17
- * @type {Record<TestStepResultStatus, StepStatusEnum>}
18
- */
19
- static stepStatusMap: Record<TestStepResultStatus, StepStatusEnum>;
20
- /**
21
- * @type {RegExp}
22
- */
23
- static qaseIdRegExp: RegExp;
24
- /**
25
- * @param {readonly PickleTag[]} tagsList
26
- * @returns {number[]}
27
- * @private
28
- */
29
- private static getCaseIds;
30
- /**
31
- * @type {Record<string, PickleInfoType>}
32
- * @private
33
- */
34
- private pickleInfo;
35
- /**
36
- * @type {Record<string, TestCaseStarted>}
37
- * @private
38
- */
39
- private testCaseStarts;
40
- /**
41
- * @type {Record<string, >}
42
- * @private
43
- */
44
- /**
45
- * @type {Record<string, TestStepFinished>}
46
- * @private
47
- */
48
- private testCaseStepsFinished;
49
- private testCaseStartedResult;
50
- /**
51
- * @type {Record<string, string[]>}
52
- * @private
53
- */
54
- private testCaseStartedErrors;
55
- /**
56
- * @type {Record<string, string>}
57
- * @private
58
- */
59
- private testCaseScenarioId;
60
- /**
61
- * @type {Record<string, string>}
62
- * @private
63
- */
64
- private scenarios;
65
11
  /**
66
12
  * @type {Record<string, string>}
67
13
  * @private
68
14
  */
69
- private attachments;
15
+ private storage;
70
16
  /**
71
17
  * @type {ReporterInterface}
72
18
  * @private
@@ -86,7 +32,6 @@ export declare class CucumberQaseReporter extends Formatter {
86
32
  * @private
87
33
  */
88
34
  private bindEventListeners;
89
- private convertSteps;
90
35
  /**
91
36
  * @returns {Promise<void>}
92
37
  * @private
@@ -98,4 +43,3 @@ export declare class CucumberQaseReporter extends Formatter {
98
43
  */
99
44
  private startTestRun;
100
45
  }
101
- export {};
package/dist/reporter.js CHANGED
@@ -3,25 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CucumberQaseReporter = void 0;
4
4
  const cucumber_1 = require("@cucumber/cucumber");
5
5
  const qase_javascript_commons_1 = require("qase-javascript-commons");
6
+ const storage_1 = require("./storage");
6
7
  /**
7
8
  * @class CucumberQaseReporter
8
9
  * @extends Formatter
9
10
  */
10
11
  class CucumberQaseReporter extends cucumber_1.Formatter {
11
- /**
12
- * @param {readonly PickleTag[]} tagsList
13
- * @returns {number[]}
14
- * @private
15
- */
16
- static getCaseIds(tagsList) {
17
- return tagsList.reduce((acc, tagInfo) => {
18
- const ids = Array.from(tagInfo.name.matchAll(CucumberQaseReporter.qaseIdRegExp))
19
- .map(([, id]) => Number(id))
20
- .filter((id) => id !== undefined);
21
- acc.push(...ids);
22
- return acc;
23
- }, []);
24
- }
25
12
  /**
26
13
  * @param {CucumberQaseOptionsType} options
27
14
  * @param {ConfigLoaderInterface} configLoader
@@ -30,46 +17,6 @@ class CucumberQaseReporter extends cucumber_1.Formatter {
30
17
  const { qase, ...formatterOptions } = options;
31
18
  const config = configLoader.load();
32
19
  super(formatterOptions);
33
- /**
34
- * @type {Record<string, PickleInfoType>}
35
- * @private
36
- */
37
- this.pickleInfo = {};
38
- /**
39
- * @type {Record<string, TestCaseStarted>}
40
- * @private
41
- */
42
- this.testCaseStarts = {};
43
- /**
44
- * @type {Record<string, >}
45
- * @private
46
- */
47
- /**
48
- * @type {Record<string, TestStepFinished>}
49
- * @private
50
- */
51
- this.testCaseStepsFinished = {};
52
- this.testCaseStartedResult = {};
53
- /**
54
- * @type {Record<string, string[]>}
55
- * @private
56
- */
57
- this.testCaseStartedErrors = {};
58
- /**
59
- * @type {Record<string, string>}
60
- * @private
61
- */
62
- this.testCaseScenarioId = {};
63
- /**
64
- * @type {Record<string, string>}
65
- * @private
66
- */
67
- this.scenarios = {};
68
- /**
69
- * @type {Record<string, string>}
70
- * @private
71
- */
72
- this.attachments = {};
73
20
  this.reporter = qase_javascript_commons_1.QaseReporter.getInstance({
74
21
  ...(0, qase_javascript_commons_1.composeOptions)(qase, config),
75
22
  frameworkPackage: '@cucumber/cucumber',
@@ -77,6 +24,7 @@ class CucumberQaseReporter extends cucumber_1.Formatter {
77
24
  reporterName: 'cucumberjs-qase-reporter',
78
25
  });
79
26
  this.eventBroadcaster = formatterOptions.eventBroadcaster;
27
+ this.storage = new storage_1.Storage();
80
28
  this.bindEventListeners();
81
29
  }
82
30
  /**
@@ -85,29 +33,13 @@ class CucumberQaseReporter extends cucumber_1.Formatter {
85
33
  bindEventListeners() {
86
34
  this.eventBroadcaster.on('envelope', (envelope) => {
87
35
  if (envelope.gherkinDocument) {
88
- if (envelope.gherkinDocument.feature) {
89
- const { children, name } = envelope.gherkinDocument.feature;
90
- children.forEach(({ scenario }) => {
91
- if (scenario) {
92
- this.scenarios[scenario.id] = name;
93
- }
94
- });
95
- }
36
+ this.storage.addScenario(envelope.gherkinDocument);
96
37
  }
97
38
  else if (envelope.pickle) {
98
- this.pickleInfo[envelope.pickle.id] = {
99
- caseIds: CucumberQaseReporter.getCaseIds(envelope.pickle.tags),
100
- name: envelope.pickle.name,
101
- lastAstNodeId: envelope.pickle.astNodeIds[envelope.pickle.astNodeIds.length - 1],
102
- steps: envelope.pickle.steps,
103
- };
39
+ this.storage.addPickle(envelope.pickle);
104
40
  }
105
41
  else if (envelope.attachment) {
106
- if (envelope.attachment.testCaseStartedId &&
107
- envelope.attachment.fileName) {
108
- this.attachments[envelope.attachment.testCaseStartedId] =
109
- envelope.attachment.fileName;
110
- }
42
+ this.storage.addAttachment(envelope.attachment);
111
43
  }
112
44
  else if (envelope.testRunStarted) {
113
45
  this.startTestRun();
@@ -116,131 +48,23 @@ class CucumberQaseReporter extends cucumber_1.Formatter {
116
48
  void this.publishResults();
117
49
  }
118
50
  else if (envelope.testCase) {
119
- this.testCaseScenarioId[envelope.testCase.id] =
120
- envelope.testCase;
51
+ this.storage.addTestCase(envelope.testCase);
121
52
  }
122
53
  else if (envelope.testCaseStarted) {
123
- this.testCaseStarts[envelope.testCaseStarted.id] =
124
- envelope.testCaseStarted;
125
- this.testCaseStartedResult[envelope.testCaseStarted.id] =
126
- qase_javascript_commons_1.TestStatusEnum.passed;
54
+ this.storage.addTestCaseStarted(envelope.testCaseStarted);
127
55
  }
128
56
  else if (envelope.testStepFinished) {
129
- const stepFin = envelope.testStepFinished;
130
- const oldStatus = this.testCaseStartedResult[stepFin.testCaseStartedId];
131
- const newStatus = CucumberQaseReporter.statusMap[stepFin.testStepResult.status];
132
- if (newStatus === null) {
133
- return;
134
- }
135
- this.testCaseStepsFinished[stepFin.testStepId] = stepFin;
136
- if (newStatus !== qase_javascript_commons_1.TestStatusEnum.passed) {
137
- if (stepFin.testStepResult.message) {
138
- const errors = this.testCaseStartedErrors[stepFin.testCaseStartedId] ?? [];
139
- if (!this.testCaseStartedErrors[stepFin.testCaseStartedId]) {
140
- this.testCaseStartedErrors[stepFin.testCaseStartedId] = errors;
141
- }
142
- errors.push(stepFin.testStepResult.message);
143
- }
144
- if (oldStatus) {
145
- if (oldStatus !== qase_javascript_commons_1.TestStatusEnum.failed) {
146
- this.testCaseStartedResult[stepFin.testCaseStartedId] = newStatus;
147
- }
148
- }
149
- else {
150
- this.testCaseStartedResult[stepFin.testCaseStartedId] = newStatus;
151
- }
152
- }
57
+ this.storage.addTestCaseStep(envelope.testStepFinished);
153
58
  }
154
59
  else if (envelope.testCaseFinished) {
155
- const tcs = this.testCaseStarts[envelope.testCaseFinished.testCaseStartedId];
156
- if (!tcs) {
157
- return;
158
- }
159
- const testCase = this.testCaseScenarioId[tcs.testCaseId];
160
- if (!testCase) {
161
- return;
162
- }
163
- const info = this.pickleInfo[testCase.pickleId];
164
- if (!info) {
60
+ const result = this.storage.convertTestCase(envelope.testCaseFinished);
61
+ if (!result) {
165
62
  return;
166
63
  }
167
- let error;
168
- if (this.testCaseStartedErrors[tcs.id]?.length) {
169
- error = new Error(this.testCaseStartedErrors[tcs.id]?.join('\n\n'));
170
- }
171
- let relations = null;
172
- if (info.lastAstNodeId != undefined && this.scenarios[info.lastAstNodeId] != undefined) {
173
- relations = {
174
- suite: {
175
- data: [
176
- {
177
- title: this.scenarios[info.lastAstNodeId] ?? '',
178
- public_id: null,
179
- },
180
- ],
181
- },
182
- };
183
- }
184
- void this.reporter.addTestResult({
185
- attachments: [],
186
- author: null,
187
- execution: {
188
- status: this.testCaseStartedResult[envelope.testCaseFinished.testCaseStartedId] ?? qase_javascript_commons_1.TestStatusEnum.passed,
189
- start_time: null,
190
- end_time: null,
191
- duration: Math.abs(envelope.testCaseFinished.timestamp.seconds - tcs.timestamp.seconds),
192
- stacktrace: error?.stack ?? null,
193
- thread: null,
194
- },
195
- fields: {},
196
- message: null,
197
- muted: false,
198
- params: {},
199
- relations: relations,
200
- run_id: null,
201
- signature: '',
202
- steps: this.convertSteps(info.steps, testCase),
203
- testops_id: info.caseIds.length > 0 ? info.caseIds : null,
204
- id: tcs.id,
205
- title: info.name,
206
- // suiteTitle: info.lastAstNodeId && this.scenarios[info.lastAstNodeId],
207
- });
64
+ void this.reporter.addTestResult(result);
208
65
  }
209
66
  });
210
67
  }
211
- convertSteps(steps, testCase) {
212
- const results = [];
213
- for (const s of testCase.testSteps) {
214
- const finished = this.testCaseStepsFinished[s.id];
215
- if (!finished) {
216
- continue;
217
- }
218
- const step = steps.find((step) => step.id === s.pickleStepId);
219
- if (!step) {
220
- continue;
221
- }
222
- const result = {
223
- id: s.id,
224
- step_type: qase_javascript_commons_1.StepType.GHERKIN,
225
- data: {
226
- keyword: step.text,
227
- name: step.text,
228
- line: 0,
229
- },
230
- execution: {
231
- status: CucumberQaseReporter.stepStatusMap[finished.testStepResult.status],
232
- start_time: null,
233
- end_time: null,
234
- duration: finished.testStepResult.duration.seconds,
235
- },
236
- attachments: [],
237
- steps: [],
238
- parent_id: null,
239
- };
240
- results.push(result);
241
- }
242
- return results;
243
- }
244
68
  /**
245
69
  * @returns {Promise<void>}
246
70
  * @private
@@ -257,31 +81,3 @@ class CucumberQaseReporter extends cucumber_1.Formatter {
257
81
  }
258
82
  }
259
83
  exports.CucumberQaseReporter = CucumberQaseReporter;
260
- /**
261
- * @type {Record<TestStepResultStatus, TestStatusEnum | null>}
262
- */
263
- CucumberQaseReporter.statusMap = {
264
- [cucumber_1.Status.PASSED]: qase_javascript_commons_1.TestStatusEnum.passed,
265
- [cucumber_1.Status.FAILED]: qase_javascript_commons_1.TestStatusEnum.failed,
266
- [cucumber_1.Status.SKIPPED]: qase_javascript_commons_1.TestStatusEnum.skipped,
267
- [cucumber_1.Status.AMBIGUOUS]: null,
268
- [cucumber_1.Status.PENDING]: qase_javascript_commons_1.TestStatusEnum.blocked,
269
- [cucumber_1.Status.UNDEFINED]: null,
270
- [cucumber_1.Status.UNKNOWN]: null,
271
- };
272
- /**
273
- * @type {Record<TestStepResultStatus, StepStatusEnum>}
274
- */
275
- CucumberQaseReporter.stepStatusMap = {
276
- [cucumber_1.Status.PASSED]: qase_javascript_commons_1.StepStatusEnum.passed,
277
- [cucumber_1.Status.FAILED]: qase_javascript_commons_1.StepStatusEnum.failed,
278
- [cucumber_1.Status.SKIPPED]: qase_javascript_commons_1.StepStatusEnum.blocked,
279
- [cucumber_1.Status.AMBIGUOUS]: qase_javascript_commons_1.StepStatusEnum.blocked,
280
- [cucumber_1.Status.PENDING]: qase_javascript_commons_1.StepStatusEnum.blocked,
281
- [cucumber_1.Status.UNDEFINED]: qase_javascript_commons_1.StepStatusEnum.blocked,
282
- [cucumber_1.Status.UNKNOWN]: qase_javascript_commons_1.StepStatusEnum.blocked,
283
- };
284
- /**
285
- * @type {RegExp}
286
- */
287
- CucumberQaseReporter.qaseIdRegExp = /^@[Qq]-?(\d+)$/g;
@@ -0,0 +1,101 @@
1
+ import { Attachment as Attach, GherkinDocument, Pickle, TestCaseFinished, TestCaseStarted, TestStepFinished } from '@cucumber/messages';
2
+ import { StepStatusEnum, TestResultType, TestStatusEnum } from 'qase-javascript-commons';
3
+ import { TestCase } from '@cucumber/messages/dist/esm/src/messages';
4
+ import { Status } from '@cucumber/cucumber';
5
+ type TestStepResultStatus = (typeof Status)[keyof typeof Status];
6
+ export declare class Storage {
7
+ /**
8
+ * @type {Record<string, Pickle>}
9
+ * @private
10
+ */
11
+ private pickles;
12
+ /**
13
+ * @type {Record<string, TestCaseStarted>}
14
+ * @private
15
+ */
16
+ private testCaseStarts;
17
+ /**
18
+ * @type {Record<string, TestStepFinished>}
19
+ * @private
20
+ */
21
+ private testCaseSteps;
22
+ /**
23
+ * @type {Record<string, TestStatusEnum>}
24
+ * @private
25
+ */
26
+ private testCaseStartedResult;
27
+ /**
28
+ * @type {Record<string, string[]>}
29
+ * @private
30
+ */
31
+ private testCaseStartedErrors;
32
+ /**
33
+ * @type {Record<string, string>}
34
+ * @private
35
+ */
36
+ private testCases;
37
+ /**
38
+ * @type {Record<string, string>}
39
+ * @private
40
+ */
41
+ private scenarios;
42
+ /**
43
+ * @type {Record<string, string>}
44
+ * @private
45
+ */
46
+ private attachments;
47
+ /**
48
+ * Add pickle to storage
49
+ * @param {Pickle} pickle
50
+ */
51
+ addPickle(pickle: Pickle): void;
52
+ /**
53
+ * Add scenario to storage
54
+ * @param {GherkinDocument} document
55
+ */
56
+ addScenario(document: GherkinDocument): void;
57
+ /**
58
+ * Add attachment to storage
59
+ * @param {Attach} attachment
60
+ */
61
+ addAttachment(attachment: Attach): void;
62
+ /**
63
+ * Add test case to storage
64
+ * @param {TestCase} testCase
65
+ */
66
+ addTestCase(testCase: TestCase): void;
67
+ /**
68
+ * Get all test cases
69
+ * @param {TestCaseStarted} testCaseStarted
70
+ */
71
+ addTestCaseStarted(testCaseStarted: TestCaseStarted): void;
72
+ /**
73
+ * Add test case step to storage
74
+ * @param {TestStepFinished} testCaseStep
75
+ */
76
+ addTestCaseStep(testCaseStep: TestStepFinished): void;
77
+ /**
78
+ * Convert test case to test result
79
+ * @param {TestCaseFinished} testCase
80
+ * @returns {undefined | TestResultType}
81
+ */
82
+ convertTestCase(testCase: TestCaseFinished): undefined | TestResultType;
83
+ /**
84
+ * Convert test steps to test result steps
85
+ * @param {readonly PickleStep[]} steps
86
+ * @param {TestCase} testCase
87
+ * @returns {TestStepType[]}
88
+ * @private
89
+ */
90
+ private convertSteps;
91
+ /**
92
+ * @type {Record<TestStepResultStatus, TestStatusEnum>}
93
+ */
94
+ static statusMap: Record<TestStepResultStatus, TestStatusEnum>;
95
+ /**
96
+ * @type {Record<TestStepResultStatus, StepStatusEnum>}
97
+ */
98
+ static stepStatusMap: Record<TestStepResultStatus, StepStatusEnum>;
99
+ private parseTags;
100
+ }
101
+ export {};
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Storage = void 0;
4
+ const qase_javascript_commons_1 = require("qase-javascript-commons");
5
+ const cucumber_1 = require("@cucumber/cucumber");
6
+ const qaseIdRegExp = /^@[Qq]-?(\d+)$/g;
7
+ const newQaseIdRegExp = /^@[Qq]ase[Ii][Dd]=(\d+)$/g;
8
+ const qaseTitleRegExp = /^@[Qq]ase[Tt]itle=(.+)$/g;
9
+ const qaseFieldsRegExp = /^@[Qq]ase[Ff]ields:(.+?)=(.+)$/g;
10
+ class Storage {
11
+ constructor() {
12
+ /**
13
+ * @type {Record<string, Pickle>}
14
+ * @private
15
+ */
16
+ this.pickles = {};
17
+ /**
18
+ * @type {Record<string, TestCaseStarted>}
19
+ * @private
20
+ */
21
+ this.testCaseStarts = {};
22
+ /**
23
+ * @type {Record<string, TestStepFinished>}
24
+ * @private
25
+ */
26
+ this.testCaseSteps = {};
27
+ /**
28
+ * @type {Record<string, TestStatusEnum>}
29
+ * @private
30
+ */
31
+ this.testCaseStartedResult = {};
32
+ /**
33
+ * @type {Record<string, string[]>}
34
+ * @private
35
+ */
36
+ this.testCaseStartedErrors = {};
37
+ /**
38
+ * @type {Record<string, string>}
39
+ * @private
40
+ */
41
+ this.testCases = {};
42
+ /**
43
+ * @type {Record<string, string>}
44
+ * @private
45
+ */
46
+ this.scenarios = {};
47
+ /**
48
+ * @type {Record<string, string>}
49
+ * @private
50
+ */
51
+ this.attachments = {};
52
+ }
53
+ /**
54
+ * Add pickle to storage
55
+ * @param {Pickle} pickle
56
+ */
57
+ addPickle(pickle) {
58
+ this.pickles[pickle.id] = pickle;
59
+ }
60
+ /**
61
+ * Add scenario to storage
62
+ * @param {GherkinDocument} document
63
+ */
64
+ addScenario(document) {
65
+ if (document.feature) {
66
+ const { children, name } = document.feature;
67
+ children.forEach(({ scenario }) => {
68
+ if (scenario) {
69
+ this.scenarios[scenario.id] = name;
70
+ }
71
+ });
72
+ }
73
+ }
74
+ /**
75
+ * Add attachment to storage
76
+ * @param {Attach} attachment
77
+ */
78
+ addAttachment(attachment) {
79
+ if (attachment.testCaseStartedId && attachment.fileName) {
80
+ if (!this.attachments[attachment.testCaseStartedId]) {
81
+ this.attachments[attachment.testCaseStartedId] = [];
82
+ }
83
+ this.attachments[attachment.testCaseStartedId]?.push({
84
+ file_name: attachment.fileName,
85
+ mime_type: attachment.mediaType,
86
+ file_path: null,
87
+ content: attachment.body,
88
+ size: 0,
89
+ id: attachment.fileName,
90
+ });
91
+ }
92
+ }
93
+ /**
94
+ * Add test case to storage
95
+ * @param {TestCase} testCase
96
+ */
97
+ addTestCase(testCase) {
98
+ this.testCases[testCase.id] = testCase;
99
+ }
100
+ /**
101
+ * Get all test cases
102
+ * @param {TestCaseStarted} testCaseStarted
103
+ */
104
+ addTestCaseStarted(testCaseStarted) {
105
+ this.testCaseStarts[testCaseStarted.id] =
106
+ testCaseStarted;
107
+ this.testCaseStartedResult[testCaseStarted.id] =
108
+ qase_javascript_commons_1.TestStatusEnum.passed;
109
+ }
110
+ /**
111
+ * Add test case step to storage
112
+ * @param {TestStepFinished} testCaseStep
113
+ */
114
+ addTestCaseStep(testCaseStep) {
115
+ const oldStatus = this.testCaseStartedResult[testCaseStep.testCaseStartedId];
116
+ const newStatus = Storage.statusMap[testCaseStep.testStepResult.status];
117
+ this.testCaseSteps[testCaseStep.testStepId] = testCaseStep;
118
+ if (newStatus !== qase_javascript_commons_1.TestStatusEnum.passed) {
119
+ if (testCaseStep.testStepResult.message) {
120
+ if (!this.testCaseStartedErrors[testCaseStep.testCaseStartedId]) {
121
+ this.testCaseStartedErrors[testCaseStep.testCaseStartedId] = [];
122
+ }
123
+ this.testCaseStartedErrors[testCaseStep.testCaseStartedId]?.push(testCaseStep.testStepResult.message);
124
+ }
125
+ if (oldStatus) {
126
+ if (oldStatus !== qase_javascript_commons_1.TestStatusEnum.failed) {
127
+ this.testCaseStartedResult[testCaseStep.testCaseStartedId] = newStatus;
128
+ }
129
+ }
130
+ else {
131
+ this.testCaseStartedResult[testCaseStep.testCaseStartedId] = newStatus;
132
+ }
133
+ }
134
+ }
135
+ /**
136
+ * Convert test case to test result
137
+ * @param {TestCaseFinished} testCase
138
+ * @returns {undefined | TestResultType}
139
+ */
140
+ convertTestCase(testCase) {
141
+ const tcs = this.testCaseStarts[testCase.testCaseStartedId];
142
+ if (!tcs) {
143
+ return undefined;
144
+ }
145
+ const tc = this.testCases[tcs.testCaseId];
146
+ if (!tc) {
147
+ return undefined;
148
+ }
149
+ const pickle = this.pickles[tc.pickleId];
150
+ if (!pickle) {
151
+ return undefined;
152
+ }
153
+ let error;
154
+ if (this.testCaseStartedErrors[tcs.id]?.length) {
155
+ error = new Error(this.testCaseStartedErrors[tcs.id]?.join('\n\n'));
156
+ }
157
+ let relations = null;
158
+ const nodeId = pickle.astNodeIds[pickle.astNodeIds.length - 1];
159
+ if (nodeId != undefined && this.scenarios[nodeId] != undefined) {
160
+ relations = {
161
+ suite: {
162
+ data: [
163
+ {
164
+ title: this.scenarios[nodeId] ?? '',
165
+ public_id: null,
166
+ },
167
+ ],
168
+ },
169
+ };
170
+ }
171
+ const metadata = this.parseTags(pickle.tags);
172
+ return {
173
+ attachments: [],
174
+ author: null,
175
+ execution: {
176
+ status: this.testCaseStartedResult[testCase.testCaseStartedId] ?? qase_javascript_commons_1.TestStatusEnum.passed,
177
+ start_time: null,
178
+ end_time: null,
179
+ duration: Math.abs(testCase.timestamp.seconds - tcs.timestamp.seconds),
180
+ stacktrace: error?.stack ?? null,
181
+ thread: null,
182
+ },
183
+ fields: metadata.fields,
184
+ message: null,
185
+ muted: false,
186
+ params: {},
187
+ relations: relations,
188
+ run_id: null,
189
+ signature: '',
190
+ steps: this.convertSteps(pickle.steps, tc),
191
+ testops_id: metadata.ids.length > 0 ? metadata.ids : null,
192
+ id: tcs.id,
193
+ title: metadata.title ?? pickle.name,
194
+ };
195
+ }
196
+ /**
197
+ * Convert test steps to test result steps
198
+ * @param {readonly PickleStep[]} steps
199
+ * @param {TestCase} testCase
200
+ * @returns {TestStepType[]}
201
+ * @private
202
+ */
203
+ convertSteps(steps, testCase) {
204
+ const results = [];
205
+ for (const s of testCase.testSteps) {
206
+ const finished = this.testCaseSteps[s.id];
207
+ if (!finished) {
208
+ continue;
209
+ }
210
+ const step = steps.find((step) => step.id === s.pickleStepId);
211
+ if (!step) {
212
+ continue;
213
+ }
214
+ const result = {
215
+ id: s.id,
216
+ step_type: qase_javascript_commons_1.StepType.GHERKIN,
217
+ data: {
218
+ keyword: step.text,
219
+ name: step.text,
220
+ line: 0,
221
+ },
222
+ execution: {
223
+ status: Storage.stepStatusMap[finished.testStepResult.status],
224
+ start_time: null,
225
+ end_time: null,
226
+ duration: finished.testStepResult.duration.seconds,
227
+ },
228
+ attachments: [],
229
+ steps: [],
230
+ parent_id: null,
231
+ };
232
+ results.push(result);
233
+ }
234
+ return results;
235
+ }
236
+ parseTags(tags) {
237
+ const metadata = {
238
+ ids: [],
239
+ fields: {},
240
+ title: null,
241
+ };
242
+ for (const tag of tags) {
243
+ if (qaseIdRegExp.test(tag.name)) {
244
+ metadata.ids.push(Number(tag.name.replace(/^@[Qq]-?/, '')));
245
+ continue;
246
+ }
247
+ if (newQaseIdRegExp.test(tag.name)) {
248
+ metadata.ids.push(Number(tag.name.replace(/^@[Qq]ase[Ii][Dd]=/, '')));
249
+ continue;
250
+ }
251
+ if (qaseTitleRegExp.test(tag.name)) {
252
+ metadata.title = tag.name.replace(/^@[Qq]ase[Tt]itle=/, '');
253
+ continue;
254
+ }
255
+ if (qaseFieldsRegExp.test(tag.name)) {
256
+ const value = tag.name.replace(/^@[Qq]ase[Ff]ields:/, '');
257
+ try {
258
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
259
+ const record = JSON.parse(value);
260
+ metadata.fields = { ...metadata.fields, ...record };
261
+ }
262
+ catch (e) {
263
+ // do nothing
264
+ }
265
+ }
266
+ }
267
+ return metadata;
268
+ }
269
+ }
270
+ exports.Storage = Storage;
271
+ /**
272
+ * @type {Record<TestStepResultStatus, TestStatusEnum>}
273
+ */
274
+ Storage.statusMap = {
275
+ [cucumber_1.Status.PASSED]: qase_javascript_commons_1.TestStatusEnum.passed,
276
+ [cucumber_1.Status.FAILED]: qase_javascript_commons_1.TestStatusEnum.failed,
277
+ [cucumber_1.Status.SKIPPED]: qase_javascript_commons_1.TestStatusEnum.skipped,
278
+ [cucumber_1.Status.AMBIGUOUS]: qase_javascript_commons_1.TestStatusEnum.failed,
279
+ [cucumber_1.Status.PENDING]: qase_javascript_commons_1.TestStatusEnum.skipped,
280
+ [cucumber_1.Status.UNDEFINED]: qase_javascript_commons_1.TestStatusEnum.skipped,
281
+ [cucumber_1.Status.UNKNOWN]: qase_javascript_commons_1.TestStatusEnum.skipped,
282
+ };
283
+ /**
284
+ * @type {Record<TestStepResultStatus, StepStatusEnum>}
285
+ */
286
+ Storage.stepStatusMap = {
287
+ [cucumber_1.Status.PASSED]: qase_javascript_commons_1.StepStatusEnum.passed,
288
+ [cucumber_1.Status.FAILED]: qase_javascript_commons_1.StepStatusEnum.failed,
289
+ [cucumber_1.Status.SKIPPED]: qase_javascript_commons_1.StepStatusEnum.skipped,
290
+ [cucumber_1.Status.AMBIGUOUS]: qase_javascript_commons_1.StepStatusEnum.failed,
291
+ [cucumber_1.Status.PENDING]: qase_javascript_commons_1.StepStatusEnum.skipped,
292
+ [cucumber_1.Status.UNDEFINED]: qase_javascript_commons_1.StepStatusEnum.skipped,
293
+ [cucumber_1.Status.UNKNOWN]: qase_javascript_commons_1.StepStatusEnum.skipped,
294
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cucumberjs-qase-reporter",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.3",
4
4
  "description": "Qase TMS CucumberJS Reporter",
5
5
  "homepage": "https://github.com/qase-tms/qase-javascript",
6
6
  "main": "./dist/index.js",