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 +12 -0
- package/dist/models.d.ts +1 -0
- package/dist/storage.d.ts +8 -0
- package/dist/storage.js +42 -4
- package/docs/usage.md +28 -28
- package/package.json +1 -1
package/changelog.md
CHANGED
package/dist/models.d.ts
CHANGED
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
|
-
|
|
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
|
|
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
|
|
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={
|
|
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={
|
|
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={
|
|
160
|
-
@QaseGroupParameters={
|
|
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(
|
|
188
|
+
const { Given, When, Then } = require("@cucumber/cucumber");
|
|
189
189
|
|
|
190
|
-
Given(
|
|
190
|
+
Given("I am on the login page", async function() {
|
|
191
191
|
// Step implementation
|
|
192
|
-
await this.page.goto(
|
|
192
|
+
await this.page.goto("https://example.com/login");
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
-
When(
|
|
195
|
+
When("I enter valid credentials", async function() {
|
|
196
196
|
// Step implementation
|
|
197
|
-
await this.page.fill(
|
|
198
|
-
await this.page.fill(
|
|
199
|
-
await this.page.click(
|
|
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(
|
|
202
|
+
Then("I should be logged in", async function() {
|
|
203
203
|
// Step implementation
|
|
204
|
-
await this.page.waitForSelector(
|
|
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(
|
|
219
|
+
const { Given, When, Then } = require("@cucumber/cucumber");
|
|
220
220
|
|
|
221
|
-
Given(
|
|
222
|
-
await this.page.goto(
|
|
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,
|
|
226
|
+
await this.attach(screenshot, "image/png");
|
|
227
227
|
});
|
|
228
228
|
|
|
229
|
-
When(
|
|
230
|
-
await this.page.fill(
|
|
231
|
-
await this.page.fill(
|
|
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(
|
|
234
|
+
await this.attach("Credentials entered successfully", "text/plain");
|
|
235
235
|
|
|
236
|
-
await this.page.click(
|
|
236
|
+
await this.page.click("#login-button");
|
|
237
237
|
});
|
|
238
238
|
|
|
239
|
-
Then(
|
|
240
|
-
await this.page.waitForSelector(
|
|
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:
|
|
244
|
-
await this.attach(JSON.stringify(userData, null, 2),
|
|
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
|
|