cypress-qase-reporter 2.2.3 → 2.2.5

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
@@ -165,7 +165,7 @@ the [Configuration reference](../qase-javascript-commons/README.md#configuration
165
165
 
166
166
  Example `cypress.config.js` config:
167
167
 
168
- ```js
168
+ ```javascript
169
169
  import cypress from 'cypress';
170
170
 
171
171
  module.exports = cypress.defineConfig({
@@ -211,6 +211,66 @@ module.exports = cypress.defineConfig({
211
211
  Check out the example of configuration for multiple reporters in the
212
212
  [demo project](../examples/cypress/cypress.config.js).
213
213
 
214
+ If you use Cucumber, you need to add the following configuration in `cypress.config.js`:
215
+
216
+ ```javascript
217
+ import cypress from 'cypress';
218
+
219
+ const cucumber = require('cypress-cucumber-preprocessor').default;
220
+
221
+ module.exports = cypress.defineConfig({
222
+ reporter: 'cypress-multi-reporters',
223
+ reporterOptions: {
224
+ reporterEnabled: 'cypress-mochawesome-reporter, cypress-qase-reporter',
225
+ cypressMochawesomeReporterReporterOptions: {
226
+ charts: true,
227
+ },
228
+ cypressQaseReporterReporterOptions: {
229
+ debug: true,
230
+
231
+ testops: {
232
+ api: {
233
+ token: 'api_key',
234
+ },
235
+
236
+ project: 'project_code',
237
+ uploadAttachments: true,
238
+
239
+ run: {
240
+ complete: true,
241
+ },
242
+ },
243
+
244
+ framework: {
245
+ cypress: {
246
+ screenshotsFolder: 'cypress/screenshots',
247
+ },
248
+ },
249
+ },
250
+ },
251
+ video: false,
252
+ e2e: {
253
+ setupNodeEvents(on, config) {
254
+ on('file:preprocessor', cucumber());
255
+ require('cypress-qase-reporter/plugin')(on, config);
256
+ require('cypress-qase-reporter/metadata')(on);
257
+ },
258
+ specPattern: 'cypress/e2e/*.feature',
259
+ },
260
+ });
261
+ ```
262
+
263
+ And add the following lines in `support/e2e.js` file:
264
+
265
+ ```javascript
266
+ import { enableCucumberSupport } from "cypress-qase-reporter";
267
+
268
+ enableCucumberSupport();
269
+ ```
270
+
271
+ Check out the example of configuration for multiple reporters in the
272
+ [demo project](../examples/cypressCucumber/cypress.config.js).
273
+
214
274
  ## Requirements
215
275
 
216
276
  We maintain the reporter on [LTS versions of Node](https://nodejs.org/en/about/releases/).
package/changelog.md CHANGED
@@ -1,3 +1,15 @@
1
+ # cypress-qase-reporter@2.2.5
2
+
3
+ ## What's new
4
+
5
+ Support Cucumber tests in Cypress with the `cypress-cucumber-preprocessor` plugin.
6
+
7
+ # cypress-qase-reporter@2.2.4
8
+
9
+ ## What's new
10
+
11
+ Fixed an issue with screenshots not being uploaded to Qase for failed tests.
12
+
1
13
  # cypress-qase-reporter@2.2.3
2
14
 
3
15
  ## What's new
@@ -0,0 +1 @@
1
+ export declare const enableCucumberSupport: () => void;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enableCucumberSupport = void 0;
4
+ const CUCUMBER_TASK_NAME = 'qaseCucumberStepStart';
5
+ const enableCucumberSupport = () => {
6
+ registerCypressEventListeners();
7
+ };
8
+ exports.enableCucumberSupport = enableCucumberSupport;
9
+ const registerCypressEventListeners = () => {
10
+ Cypress.on('log:added', handleLogAdded);
11
+ };
12
+ const handleLogAdded = (_, entry) => {
13
+ if (isCucumberStep(entry)) {
14
+ processCucumberStep(entry);
15
+ }
16
+ };
17
+ const isCucumberStep = ({ attributes: { name, event, instrument } }) => {
18
+ return instrument === 'command' && !event && name === 'step';
19
+ };
20
+ const processCucumberStep = ({ attributes: { displayName, message } }) => {
21
+ sendTaskMessage(`${displayName ?? ''} ${message}`);
22
+ };
23
+ const sendTaskMessage = (message) => {
24
+ cy.task(CUCUMBER_TASK_NAME, message, { log: false });
25
+ };
@@ -0,0 +1,11 @@
1
+ export declare class FileSearcher {
2
+ /**
3
+ * Finds all files in the given directory and its subdirectories
4
+ * that were created after the specified time.
5
+ *
6
+ * @param folderPath Relative path to the folder.
7
+ * @param time Time threshold as a Date object.
8
+ * @returns Array of absolute paths to the matching files.
9
+ */
10
+ static findFilesBeforeTime(folderPath: string, time: Date): string[];
11
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.FileSearcher = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ const path = __importStar(require("path"));
29
+ class FileSearcher {
30
+ /**
31
+ * Finds all files in the given directory and its subdirectories
32
+ * that were created after the specified time.
33
+ *
34
+ * @param folderPath Relative path to the folder.
35
+ * @param time Time threshold as a Date object.
36
+ * @returns Array of absolute paths to the matching files.
37
+ */
38
+ static findFilesBeforeTime(folderPath, time) {
39
+ const absolutePath = path.resolve(process.cwd(), folderPath);
40
+ const result = [];
41
+ const searchFiles = (dir) => {
42
+ if (!fs.existsSync(dir)) {
43
+ return;
44
+ }
45
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
46
+ for (const entry of entries) {
47
+ const entryPath = path.join(dir, entry.name);
48
+ if (entry.isDirectory()) {
49
+ searchFiles(entryPath);
50
+ }
51
+ else if (entry.isFile()) {
52
+ const stats = fs.statSync(entryPath);
53
+ if (stats.birthtime > time) {
54
+ result.push(entryPath);
55
+ }
56
+ }
57
+ }
58
+ };
59
+ searchFiles(absolutePath);
60
+ return result;
61
+ }
62
+ }
63
+ exports.FileSearcher = FileSearcher;
@@ -1 +1,2 @@
1
1
  export { qase } from './mocha';
2
+ export { enableCucumberSupport } from './cucumber';
package/dist/index.cjs.js CHANGED
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.qase = void 0;
3
+ exports.enableCucumberSupport = exports.qase = void 0;
4
4
  var mocha_1 = require("./mocha");
5
5
  Object.defineProperty(exports, "qase", { enumerable: true, get: function () { return mocha_1.qase; } });
6
+ var cucumber_1 = require("./cucumber");
7
+ Object.defineProperty(exports, "enableCucumberSupport", { enumerable: true, get: function () { return cucumber_1.enableCucumberSupport; } });
@@ -6,6 +6,7 @@ export declare class MetadataManager {
6
6
  static setIgnore(): void;
7
7
  static addStepStart(name: string): void;
8
8
  static addStepEnd(status: string): void;
9
+ static addCucumberStep(name: string): void;
9
10
  static addAttach(attach: Attach): void;
10
11
  static setSuite(suite: string): void;
11
12
  static setComment(comment: string): void;
@@ -10,6 +10,7 @@ const path_1 = __importDefault(require("path"));
10
10
  const qase_javascript_commons_1 = require("qase-javascript-commons");
11
11
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
12
12
  class MetadataManager {
13
+ static metadataPath = path_1.default.resolve(__dirname, 'qaseMetadata');
13
14
  static getMetadata() {
14
15
  if (!this.isExists()) {
15
16
  return undefined;
@@ -23,6 +24,7 @@ class MetadataManager {
23
24
  suite: undefined,
24
25
  comment: undefined,
25
26
  steps: [],
27
+ cucumberSteps: [],
26
28
  currentStepId: undefined,
27
29
  firstStepName: undefined,
28
30
  attachments: [],
@@ -70,6 +72,23 @@ class MetadataManager {
70
72
  metadata.currentStepId = parentId;
71
73
  this.setMetadata(metadata);
72
74
  }
75
+ static addCucumberStep(name) {
76
+ const metadata = this.getMetadata() ?? {};
77
+ if (metadata.firstStepName === name) {
78
+ return;
79
+ }
80
+ if (!metadata.cucumberSteps) {
81
+ metadata.cucumberSteps = [];
82
+ }
83
+ const id = (0, uuid_1.v4)();
84
+ const parentId = metadata.currentStepId ?? undefined;
85
+ metadata.cucumberSteps.push({ timestamp: Date.now(), name, id: id, parentId: parentId });
86
+ metadata.currentStepId = id;
87
+ if (!metadata.firstStepName) {
88
+ metadata.firstStepName = name;
89
+ }
90
+ this.setMetadata(metadata);
91
+ }
73
92
  static addAttach(attach) {
74
93
  const metadata = this.getMetadata() ?? {};
75
94
  if (!metadata.attachments) {
@@ -189,4 +208,3 @@ class MetadataManager {
189
208
  }
190
209
  }
191
210
  exports.MetadataManager = MetadataManager;
192
- MetadataManager.metadataPath = path_1.default.resolve(__dirname, 'qaseMetadata');
@@ -9,6 +9,7 @@ export interface Metadata {
9
9
  suite?: string | undefined;
10
10
  comment?: string | undefined;
11
11
  steps?: (StepStart | StepEnd)[];
12
+ cucumberSteps?: StepStart[];
12
13
  currentStepId?: string | undefined;
13
14
  firstStepName?: string | undefined;
14
15
  attachments?: Attachment[];
package/dist/metadata.js CHANGED
@@ -62,4 +62,10 @@ module.exports = function (on) {
62
62
  return null;
63
63
  },
64
64
  });
65
+ on('task', {
66
+ qaseCucumberStepStart(value) {
67
+ manager_1.MetadataManager.addCucumberStep(value);
68
+ return null;
69
+ },
70
+ });
65
71
  };
@@ -1,6 +1,6 @@
1
1
  /// <reference types="cypress" />
2
2
  import { MochaOptions, reporters, Runner } from 'mocha';
3
- import { ConfigLoader, TestStatusEnum, FrameworkOptionsType } from 'qase-javascript-commons';
3
+ import { ConfigLoader, FrameworkOptionsType, TestStatusEnum } from 'qase-javascript-commons';
4
4
  import { ReporterOptionsType } from './options';
5
5
  type CypressState = 'failed' | 'passed' | 'pending';
6
6
  export type CypressQaseOptionsType = Omit<MochaOptions, 'reporterOptions'> & {
@@ -25,13 +25,6 @@ export declare class CypressQaseReporter extends reporters.Base {
25
25
  * @private
26
26
  */
27
27
  private static getCaseId;
28
- /**
29
- * @param {number[]} ids
30
- * @param {string} dir
31
- * @returns {Attachment[]}
32
- * @private
33
- */
34
- private static findAttachments;
35
28
  /**
36
29
  * @type {string | undefined}
37
30
  * @private
@@ -42,6 +35,7 @@ export declare class CypressQaseReporter extends reporters.Base {
42
35
  * @private
43
36
  */
44
37
  private reporter;
38
+ private testBeginTime;
45
39
  private options;
46
40
  /**
47
41
  * @param {Runner} runner
@@ -65,6 +59,7 @@ export declare class CypressQaseReporter extends reporters.Base {
65
59
  * @private
66
60
  */
67
61
  private getSignature;
62
+ private getTestFileName;
68
63
  /**
69
64
  * @param {Suite} suite
70
65
  * @private
@@ -76,6 +71,13 @@ export declare class CypressQaseReporter extends reporters.Base {
76
71
  * @private
77
72
  */
78
73
  private removeQaseIdsFromTitle;
74
+ /**
75
+ * Extracts numbers from @qaseid tags, regardless of case.
76
+ * @param tags - An array of tags to process.
77
+ * @returns An array of numbers extracted from the tags.
78
+ */
79
+ private extractQaseIds;
80
+ private convertCypressMessages;
79
81
  private getSteps;
80
82
  }
81
83
  export {};
package/dist/reporter.js CHANGED
@@ -9,15 +9,28 @@ const uuid_1 = require("uuid");
9
9
  const child_process_1 = require("child_process");
10
10
  const mocha_1 = require("mocha");
11
11
  const qase_javascript_commons_1 = require("qase-javascript-commons");
12
- const traverse_dir_1 = require("./utils/traverse-dir");
13
12
  const configSchema_1 = require("./configSchema");
14
13
  const manager_1 = require("./metadata/manager");
15
- const { EVENT_TEST_FAIL, EVENT_TEST_PASS, EVENT_TEST_PENDING, EVENT_RUN_END, } = mocha_1.Runner.constants;
14
+ const fileSearcher_1 = require("./fileSearcher");
15
+ const tagParser_1 = require("./utils/tagParser");
16
+ const { EVENT_TEST_FAIL, EVENT_TEST_PASS, EVENT_TEST_PENDING, EVENT_RUN_END, EVENT_TEST_BEGIN, } = mocha_1.Runner.constants;
16
17
  /**
17
18
  * @class CypressQaseReporter
18
19
  * @extends reporters.Base
19
20
  */
20
21
  class CypressQaseReporter extends mocha_1.reporters.Base {
22
+ /**
23
+ * @type {RegExp}
24
+ */
25
+ static qaseIdRegExp = /\(Qase ID:? ([\d,]+)\)/;
26
+ /**
27
+ * @type {Record<CypressState, TestStatusEnum>}
28
+ */
29
+ static statusMap = {
30
+ failed: qase_javascript_commons_1.TestStatusEnum.failed,
31
+ passed: qase_javascript_commons_1.TestStatusEnum.passed,
32
+ pending: qase_javascript_commons_1.TestStatusEnum.skipped,
33
+ };
21
34
  /**
22
35
  * @param {string} title
23
36
  * @returns {number[]}
@@ -28,31 +41,17 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
28
41
  return ids ? ids.split(',').map((id) => Number(id)) : [];
29
42
  }
30
43
  /**
31
- * @param {number[]} ids
32
- * @param {string} dir
33
- * @returns {Attachment[]}
44
+ * @type {string | undefined}
34
45
  * @private
35
46
  */
36
- static findAttachments(ids, dir) {
37
- const idSet = new Set(ids);
38
- const attachments = [];
39
- try {
40
- (0, traverse_dir_1.traverseDir)(path_1.default.join(process.cwd(), dir), (filePath) => {
41
- if (CypressQaseReporter.getCaseId(filePath).some((item) => idSet.has(item))) {
42
- attachments.push({
43
- content: '',
44
- id: (0, uuid_1.v4)(),
45
- mime_type: '', size: 0,
46
- file_name: path_1.default.basename(filePath),
47
- file_path: filePath,
48
- });
49
- }
50
- });
51
- }
52
- catch (error) { /* ignore */
53
- }
54
- return attachments;
55
- }
47
+ screenshotsFolder;
48
+ /**
49
+ * @type {ReporterInterface}
50
+ * @private
51
+ */
52
+ reporter;
53
+ testBeginTime = Date.now();
54
+ options;
56
55
  /**
57
56
  * @param {Runner} runner
58
57
  * @param {CypressQaseOptionsType} options
@@ -81,6 +80,10 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
81
80
  runner.on(EVENT_TEST_PASS, (test) => this.addTestResult(test));
82
81
  runner.on(EVENT_TEST_PENDING, (test) => this.addTestResult(test));
83
82
  runner.on(EVENT_TEST_FAIL, (test) => this.addTestResult(test));
83
+ runner.on(EVENT_TEST_BEGIN, () => {
84
+ this.testBeginTime = Date.now();
85
+ manager_1.MetadataManager.clear();
86
+ });
84
87
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
85
88
  runner.once(EVENT_RUN_END, () => {
86
89
  const results = this.reporter.getResults();
@@ -104,10 +107,19 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
104
107
  return;
105
108
  }
106
109
  const ids = CypressQaseReporter.getCaseId(test.title);
107
- const attachments = this.screenshotsFolder
108
- ? CypressQaseReporter.findAttachments(ids, this.screenshotsFolder)
109
- : undefined;
110
- attachments?.push(...(metadata?.attachments ?? []));
110
+ const testFileName = this.getTestFileName(test);
111
+ const files = this.screenshotsFolder ?
112
+ fileSearcher_1.FileSearcher.findFilesBeforeTime(path_1.default.join(this.screenshotsFolder, testFileName), new Date(this.testBeginTime))
113
+ : [];
114
+ const attachments = files.map((file) => ({
115
+ content: '',
116
+ id: (0, uuid_1.v4)(),
117
+ mime_type: 'image/png',
118
+ size: 0,
119
+ file_name: path_1.default.basename(file),
120
+ file_path: file,
121
+ }));
122
+ attachments.push(...(metadata?.attachments ?? []));
111
123
  let relations = {};
112
124
  if (test.parent !== undefined) {
113
125
  const data = [];
@@ -135,15 +147,21 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
135
147
  },
136
148
  };
137
149
  }
138
- let message = null;
139
- if (metadata?.comment) {
140
- message = metadata.comment;
141
- }
150
+ let message = metadata?.comment ?? '';
142
151
  if (test.err?.message) {
143
- if (message) {
144
- message += '\n\n';
152
+ message += message ? `\n\n${test.err.message}` : test.err.message;
153
+ }
154
+ const steps = metadata?.steps ? this.getSteps(metadata.steps, metadata.stepAttachments ?? {}) : [];
155
+ // support for cucumber steps and metadata
156
+ if (metadata?.cucumberSteps && metadata.cucumberSteps.length > 0) {
157
+ steps.push(...this.convertCypressMessages(metadata.cucumberSteps, test.state ?? 'failed'));
158
+ if (test.parent) {
159
+ const file = this.getFile(test.parent);
160
+ if (file) {
161
+ const tags = (0, tagParser_1.extractTags)(file, test.title);
162
+ ids.push(...this.extractQaseIds(tags));
163
+ }
145
164
  }
146
- message += test.err.message;
147
165
  }
148
166
  const result = {
149
167
  attachments: attachments ?? [],
@@ -156,7 +174,7 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
156
174
  relations: relations,
157
175
  run_id: null,
158
176
  signature: this.getSignature(test, ids),
159
- steps: metadata?.steps ? this.getSteps(metadata.steps, metadata.stepAttachments ?? {}) : [],
177
+ steps: steps,
160
178
  id: (0, uuid_1.v4)(),
161
179
  execution: {
162
180
  status: test.state
@@ -196,6 +214,18 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
196
214
  }
197
215
  return signature;
198
216
  }
217
+ getTestFileName(test) {
218
+ if (!test.parent) {
219
+ return '';
220
+ }
221
+ const file = this.getFile(test.parent);
222
+ if (!file) {
223
+ return '';
224
+ }
225
+ const pathParts = file.split('/');
226
+ const fileName = pathParts[pathParts.length - 1];
227
+ return fileName ? fileName : '';
228
+ }
199
229
  /**
200
230
  * @param {Suite} suite
201
231
  * @private
@@ -221,6 +251,44 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
221
251
  }
222
252
  return title;
223
253
  }
254
+ /**
255
+ * Extracts numbers from @qaseid tags, regardless of case.
256
+ * @param tags - An array of tags to process.
257
+ * @returns An array of numbers extracted from the tags.
258
+ */
259
+ extractQaseIds(tags) {
260
+ const qaseIdRegex = /@qaseid\((\d+(?:,\d+)*)\)/i;
261
+ const qaseIds = [];
262
+ for (const tag of tags) {
263
+ const match = qaseIdRegex.exec(tag);
264
+ if (match) {
265
+ const ids = match[1]?.split(',').map(id => parseInt(id, 10));
266
+ if (ids) {
267
+ qaseIds.push(...ids);
268
+ }
269
+ }
270
+ }
271
+ return qaseIds;
272
+ }
273
+ convertCypressMessages(messages, testStatus) {
274
+ const result = [];
275
+ const lastIndex = messages.length - 1;
276
+ for (const message of messages) {
277
+ const step = new qase_javascript_commons_1.TestStepType(qase_javascript_commons_1.StepType.TEXT);
278
+ step.id = message.id;
279
+ step.execution.status = qase_javascript_commons_1.StepStatusEnum.passed;
280
+ step.execution.start_time = message.timestamp;
281
+ step.data = {
282
+ action: message.name,
283
+ expected_result: null,
284
+ };
285
+ if (lastIndex === messages.indexOf(message) && testStatus !== 'passed') {
286
+ step.execution.status = qase_javascript_commons_1.StepStatusEnum.failed;
287
+ }
288
+ result.push(step);
289
+ }
290
+ return result;
291
+ }
224
292
  getSteps(steps, attachments) {
225
293
  const result = [];
226
294
  const stepMap = new Map();
@@ -263,15 +331,3 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
263
331
  }
264
332
  }
265
333
  exports.CypressQaseReporter = CypressQaseReporter;
266
- /**
267
- * @type {RegExp}
268
- */
269
- CypressQaseReporter.qaseIdRegExp = /\(Qase ID:? ([\d,]+)\)/;
270
- /**
271
- * @type {Record<CypressState, TestStatusEnum>}
272
- */
273
- CypressQaseReporter.statusMap = {
274
- failed: qase_javascript_commons_1.TestStatusEnum.failed,
275
- passed: qase_javascript_commons_1.TestStatusEnum.passed,
276
- pending: qase_javascript_commons_1.TestStatusEnum.skipped,
277
- };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Extracts tags for a given scenario name from a Gherkin feature file.
3
+ * @param filePath - Path to the feature file.
4
+ * @param scenarioName - Name of the scenario to search for.
5
+ * @returns An array of tags found for the specified scenario.
6
+ */
7
+ export declare function extractTags(filePath: string, scenarioName: string): string[];
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.extractTags = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ /**
29
+ * Extracts tags for a given scenario name from a Gherkin feature file.
30
+ * @param filePath - Path to the feature file.
31
+ * @param scenarioName - Name of the scenario to search for.
32
+ * @returns An array of tags found for the specified scenario.
33
+ */
34
+ function extractTags(filePath, scenarioName) {
35
+ // Read the file content
36
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
37
+ // Split the content into lines
38
+ const lines = fileContent.split('\n');
39
+ let tags = [];
40
+ for (let i = 0; i < lines.length; i++) {
41
+ const trimmedLine = lines[i]?.trim(); // Ensure line exists and trim it
42
+ // Check if the line is a Scenario line and matches the provided name
43
+ if (trimmedLine?.startsWith('Scenario:') && trimmedLine === `Scenario: ${scenarioName}`) {
44
+ // Collect tags from preceding lines
45
+ for (let j = i - 1; j >= 0; j--) {
46
+ const previousLine = lines[j]?.trim(); // Ensure line exists and trim it
47
+ if (previousLine?.startsWith('@')) {
48
+ tags = previousLine.split(/\s+/).filter(tag => tag.startsWith('@'));
49
+ break;
50
+ }
51
+ else if (previousLine === '' || previousLine?.startsWith('Feature:')) {
52
+ // Stop searching if an empty line or the start of a feature is reached
53
+ break;
54
+ }
55
+ }
56
+ break; // Stop processing further as the scenario is found
57
+ }
58
+ }
59
+ return tags;
60
+ }
61
+ exports.extractTags = extractTags;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress-qase-reporter",
3
- "version": "2.2.3",
3
+ "version": "2.2.5",
4
4
  "description": "Qase Cypress Reporter",
5
5
  "homepage": "https://github.com/qase-tms/qase-javascript",
6
6
  "sideEffects": false,
@@ -13,7 +13,8 @@
13
13
  "./package.json": "./package.json",
14
14
  "./plugin": "./dist/plugin.js",
15
15
  "./metadata": "./dist/metadata.js",
16
- "./hooks": "./dist/hooks.js"
16
+ "./hooks": "./dist/hooks.js",
17
+ "./cucumber": "./dist/cucumber.js"
17
18
  },
18
19
  "typesVersions": {
19
20
  "*": {
@@ -25,6 +26,9 @@
25
26
  ],
26
27
  "reporter": [
27
28
  "./dist/reporter.d.ts"
29
+ ],
30
+ "cucumber": [
31
+ "./dist/cucumber.d.ts"
28
32
  ]
29
33
  }
30
34
  },