cucumberjs-qase-reporter 2.1.7 → 2.1.9

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 CHANGED
@@ -1,3 +1,15 @@
1
+ # qase-cucumberjs@2.1.9
2
+
3
+ ## What's new
4
+
5
+ - Added support for QaseSuite tag.
6
+
7
+ # qase-cucumberjs@2.1.8
8
+
9
+ ## What's new
10
+
11
+ - Improved support for QaseParameters and QaseGroupParameters tags.
12
+
1
13
  # qase-cucumberjs@2.1.7
2
14
 
3
15
  ## What's new
package/dist/models.d.ts CHANGED
@@ -5,6 +5,7 @@ export interface TestMetadata {
5
5
  isIgnore: boolean;
6
6
  parameters: Record<string, string>;
7
7
  group_params: Record<string, string>;
8
+ suite: string | null;
8
9
  }
9
10
  export interface ScenarioData {
10
11
  name: string;
package/dist/storage.d.ts CHANGED
@@ -105,6 +105,14 @@ export declare class Storage {
105
105
  */
106
106
  private getSignature;
107
107
  private getError;
108
+ /**
109
+ * Normalize JSON string by converting single quotes to double quotes
110
+ * This allows parsing JSON-like strings with single quotes
111
+ * @param {string} jsonString
112
+ * @returns {string}
113
+ * @private
114
+ */
115
+ private normalizeJsonString;
108
116
  private getFileNameFromMediaType;
109
117
  }
110
118
  export {};
package/dist/storage.js CHANGED
@@ -10,6 +10,7 @@ const qaseTitleRegExp = /^@[Qq]ase[Tt]itle=(.+)$/;
10
10
  const qaseFieldsRegExp = /^@[Qq]ase[Ff]ields=(.+)$/;
11
11
  const qaseParametersRegExp = /^@[Qq]ase[Pp]arameters=(.+)$/;
12
12
  const qaseGroupParametersRegExp = /^@[Qq]ase[Gg]roup[Pp]arameters=(.+)$/;
13
+ const qaseSuiteRegExp = /^@[Qq]ase[Ss]uite=(.+)$/;
13
14
  const qaseIgnoreRegExp = /^@[Qq]ase[Ii][Gg][Nn][Oo][Rr][Ee]$/;
14
15
  class Storage {
15
16
  /**
@@ -198,7 +199,20 @@ class Storage {
198
199
  let relations = null;
199
200
  let params = {};
200
201
  const nodeId = pickle.astNodeIds[0];
201
- if (nodeId != undefined && this.scenarios[nodeId] != undefined) {
202
+ // If suite is specified in metadata, use it (split by tab for sub-suites)
203
+ if (metadata.suite) {
204
+ const suiteParts = metadata.suite.split('\t').filter(part => part.trim().length > 0);
205
+ relations = {
206
+ suite: {
207
+ data: suiteParts.map((suite) => ({
208
+ title: suite.trim(),
209
+ public_id: null,
210
+ })),
211
+ },
212
+ };
213
+ }
214
+ else if (nodeId != undefined && this.scenarios[nodeId] != undefined) {
215
+ // Otherwise, use feature name as suite
202
216
  relations = {
203
217
  suite: {
204
218
  data: [
@@ -209,6 +223,9 @@ class Storage {
209
223
  ],
210
224
  },
211
225
  };
226
+ }
227
+ // Extract parameters from Gherkin examples
228
+ if (nodeId != undefined && this.scenarios[nodeId] != undefined) {
212
229
  for (const id of pickle.astNodeIds) {
213
230
  if (this.scenarios[nodeId]?.parameters[id] != undefined) {
214
231
  params = { ...params, ...this.scenarios[nodeId]?.parameters[id] };
@@ -316,6 +333,7 @@ class Storage {
316
333
  isIgnore: false,
317
334
  parameters: {},
318
335
  group_params: {},
336
+ suite: null,
319
337
  };
320
338
  for (const tag of tags) {
321
339
  if (qaseIdRegExp.test(tag.name)) {
@@ -334,7 +352,7 @@ class Storage {
334
352
  const value = tag.name.replace(/^@[Qq]ase[Ff]ields=/, '');
335
353
  try {
336
354
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
337
- const record = JSON.parse(value);
355
+ const record = JSON.parse(this.normalizeJsonString(value));
338
356
  metadata.fields = { ...metadata.fields, ...record };
339
357
  }
340
358
  catch (e) {
@@ -345,7 +363,7 @@ class Storage {
345
363
  const value = tag.name.replace(/^@[Qq]ase[Pp]arameters=/, '');
346
364
  try {
347
365
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
348
- const record = JSON.parse(value);
366
+ const record = JSON.parse(this.normalizeJsonString(value));
349
367
  metadata.parameters = { ...metadata.parameters, ...record };
350
368
  }
351
369
  catch (e) {
@@ -356,13 +374,17 @@ class Storage {
356
374
  const value = tag.name.replace(/^@[Qq]ase[Gg]roup[Pp]arameters=/, '');
357
375
  try {
358
376
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
359
- const record = JSON.parse(value);
377
+ const record = JSON.parse(this.normalizeJsonString(value));
360
378
  metadata.group_params = { ...metadata.group_params, ...record };
361
379
  }
362
380
  catch (e) {
363
381
  // do nothing
364
382
  }
365
383
  }
384
+ if (qaseSuiteRegExp.test(tag.name)) {
385
+ metadata.suite = tag.name.replace(/^@[Qq]ase[Ss]uite=/, '');
386
+ continue;
387
+ }
366
388
  if (qaseIgnoreRegExp.test(tag.name)) {
367
389
  metadata.isIgnore = true;
368
390
  }
@@ -390,6 +412,22 @@ class Storage {
390
412
  });
391
413
  return error;
392
414
  }
415
+ /**
416
+ * Normalize JSON string by converting single quotes to double quotes
417
+ * This allows parsing JSON-like strings with single quotes
418
+ * @param {string} jsonString
419
+ * @returns {string}
420
+ * @private
421
+ */
422
+ normalizeJsonString(jsonString) {
423
+ // If the string contains single quotes, convert them to double quotes
424
+ // This handles cases like {'key':'value'} which should be {"key":"value"}
425
+ if (jsonString.includes("'")) {
426
+ return jsonString.replace(/'/g, '"');
427
+ }
428
+ // If no single quotes, return as-is (already valid JSON or will fail with proper error)
429
+ return jsonString;
430
+ }
393
431
  getFileNameFromMediaType(mediaType) {
394
432
  const extensions = {
395
433
  'text/plain': 'txt',
package/docs/usage.md CHANGED
@@ -8,7 +8,7 @@ fields, suites, comments, and file attachments to your test cases.
8
8
  ## Adding QaseID to a Test
9
9
 
10
10
  To associate a QaseID with a test in Cucumber.js, use the `@QaseId` tag in your Gherkin feature files. This tag accepts
11
- a single integer or multiple integers separated by commas representing the test's ID(s) in Qase.
11
+ a single integer or multiple integers separated by commas representing the test"s ID(s) in Qase.
12
12
 
13
13
  ### Example
14
14
 
@@ -33,7 +33,7 @@ Feature: User Authentication
33
33
  ## Adding a Title to a Test
34
34
 
35
35
  You can provide a custom title for your test using the `@Title` tag. The tag accepts a string, which will be used as
36
- the test's title in Qase. If no title is provided, the scenario name will be used by default.
36
+ the test"s title in Qase. If no title is provided, the scenario name will be used by default.
37
37
 
38
38
  ### Example
39
39
 
@@ -70,7 +70,7 @@ enhance test case information in Qase.
70
70
  Feature: User Authentication
71
71
 
72
72
  @QaseId=1
73
- @QaseFields={'severity':'high','priority':'medium','description':'Login functionality test'}
73
+ @QaseFields={"severity":"high","priority":"medium","description":"Login functionality test"}
74
74
  Scenario: Successful login
75
75
  Given I am on the login page
76
76
  When I enter valid credentials
@@ -136,7 +136,7 @@ parameter names and values.
136
136
  Feature: User Authentication
137
137
 
138
138
  @QaseId=1
139
- @QaseParameters={'browser':'chrome','environment':'staging'}
139
+ @QaseParameters={"browser":"chrome","environment":"staging"}
140
140
  Scenario: Successful login
141
141
  Given I am on the login page
142
142
  When I enter valid credentials
@@ -156,8 +156,8 @@ group parameter names and values.
156
156
  Feature: User Authentication
157
157
 
158
158
  @QaseId=1
159
- @QaseParameters={'browser':'chrome','environment':'staging'}
160
- @QaseGroupParameters={'test_group':'authentication','test_type':'smoke'}
159
+ @QaseParameters={"browser":"chrome","environment":"staging"}
160
+ @QaseGroupParameters={"test_group":"authentication","test_type":"smoke"}
161
161
  Scenario: Successful login
162
162
  Given I am on the login page
163
163
  When I enter valid credentials
@@ -185,23 +185,23 @@ Feature: User Authentication
185
185
 
186
186
  ```javascript
187
187
  // step_definitions/login_steps.js
188
- const { Given, When, Then } = require('@cucumber/cucumber');
188
+ const { Given, When, Then } = require("@cucumber/cucumber");
189
189
 
190
- Given('I am on the login page', async function() {
190
+ Given("I am on the login page", async function() {
191
191
  // Step implementation
192
- await this.page.goto('https://example.com/login');
192
+ await this.page.goto("https://example.com/login");
193
193
  });
194
194
 
195
- When('I enter valid credentials', async function() {
195
+ When("I enter valid credentials", async function() {
196
196
  // Step implementation
197
- await this.page.fill('#username', 'testuser');
198
- await this.page.fill('#password', 'password');
199
- await this.page.click('#login-button');
197
+ await this.page.fill("#username", "testuser");
198
+ await this.page.fill("#password", "password");
199
+ await this.page.click("#login-button");
200
200
  });
201
201
 
202
- Then('I should be logged in', async function() {
202
+ Then("I should be logged in", async function() {
203
203
  // Step implementation
204
- await this.page.waitForSelector('.dashboard');
204
+ await this.page.waitForSelector(".dashboard");
205
205
  });
206
206
  ```
207
207
 
@@ -216,32 +216,32 @@ attaching files with content, paths, or media types.
216
216
 
217
217
  ```javascript
218
218
  // step_definitions/login_steps.js
219
- const { Given, When, Then } = require('@cucumber/cucumber');
219
+ const { Given, When, Then } = require("@cucumber/cucumber");
220
220
 
221
- Given('I am on the login page', async function() {
222
- await this.page.goto('https://example.com/login');
221
+ Given("I am on the login page", async function() {
222
+ await this.page.goto("https://example.com/login");
223
223
 
224
224
  // Attach screenshot
225
225
  const screenshot = await this.page.screenshot();
226
- await this.attach(screenshot, 'image/png');
226
+ await this.attach(screenshot, "image/png");
227
227
  });
228
228
 
229
- When('I enter valid credentials', async function() {
230
- await this.page.fill('#username', 'testuser');
231
- await this.page.fill('#password', 'password');
229
+ When("I enter valid credentials", async function() {
230
+ await this.page.fill("#username", "testuser");
231
+ await this.page.fill("#password", "password");
232
232
 
233
233
  // Attach text content
234
- await this.attach('Credentials entered successfully', 'text/plain');
234
+ await this.attach("Credentials entered successfully", "text/plain");
235
235
 
236
- await this.page.click('#login-button');
236
+ await this.page.click("#login-button");
237
237
  });
238
238
 
239
- Then('I should be logged in', async function() {
240
- await this.page.waitForSelector('.dashboard');
239
+ Then("I should be logged in", async function() {
240
+ await this.page.waitForSelector(".dashboard");
241
241
 
242
242
  // Attach JSON data
243
- const userData = { username: 'testuser', status: 'logged_in' };
244
- await this.attach(JSON.stringify(userData, null, 2), 'application/json');
243
+ const userData = { username: "testuser", status: "logged_in" };
244
+ await this.attach(JSON.stringify(userData, null, 2), "application/json");
245
245
  });
246
246
  ```
247
247
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cucumberjs-qase-reporter",
3
- "version": "2.1.7",
3
+ "version": "2.1.9",
4
4
  "description": "Qase TMS CucumberJS Reporter",
5
5
  "homepage": "https://github.com/qase-tms/qase-javascript",
6
6
  "main": "./dist/index.js",