k6-cucumber-steps 1.0.41 → 1.1.2

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.
@@ -0,0 +1,283 @@
1
+ [
2
+ {
3
+ "description": "",
4
+ "elements": [
5
+ {
6
+ "description": "",
7
+ "id": "rate-limit-enforcement-for-/login-and-/bsp;api-allows-up-to-5-requests-in-10-seconds-(under-limit)",
8
+ "keyword": "Scenario",
9
+ "line": 9,
10
+ "name": "API allows up to 5 requests in 10 seconds (under limit)",
11
+ "steps": [
12
+ {
13
+ "arguments": [],
14
+ "keyword": "Given ",
15
+ "line": 5,
16
+ "name": "I login via POST to \"/api/v3/client/api/login\" with payload from \"login.json\"",
17
+ "match": {
18
+ "location": "step_definitions/load_test_steps.js:262"
19
+ },
20
+ "result": {
21
+ "status": "passed",
22
+ "duration": 894569875
23
+ }
24
+ },
25
+ {
26
+ "arguments": [],
27
+ "keyword": "Then ",
28
+ "line": 6,
29
+ "name": "I store the value at \"data.token\" as alias \"auth_token\"",
30
+ "match": {
31
+ "location": "step_definitions/load_test_steps.js:237"
32
+ },
33
+ "result": {
34
+ "status": "passed",
35
+ "duration": 217708
36
+ }
37
+ },
38
+ {
39
+ "arguments": [],
40
+ "keyword": "When ",
41
+ "line": 10,
42
+ "name": "I set a k6 script for POST testing",
43
+ "match": {
44
+ "location": "step_definitions/load_test_steps.js:28"
45
+ },
46
+ "result": {
47
+ "status": "passed",
48
+ "duration": 78040
49
+ }
50
+ },
51
+ {
52
+ "arguments": [
53
+ {
54
+ "rows": [
55
+ {
56
+ "cells": [
57
+ "virtual_users",
58
+ "duration",
59
+ "http_req_failed",
60
+ "http_req_duration"
61
+ ]
62
+ },
63
+ {
64
+ "cells": [
65
+ "1",
66
+ "10",
67
+ "rate<0.05",
68
+ "p(95)<2000"
69
+ ]
70
+ }
71
+ ]
72
+ }
73
+ ],
74
+ "keyword": "When ",
75
+ "line": 11,
76
+ "name": "I set to run the k6 script with the following configurations:",
77
+ "match": {
78
+ "location": "step_definitions/load_test_steps.js:40"
79
+ },
80
+ "result": {
81
+ "status": "passed",
82
+ "duration": 458667
83
+ }
84
+ },
85
+ {
86
+ "arguments": [],
87
+ "keyword": "When ",
88
+ "line": 14,
89
+ "name": "I use JSON payload from \"okra.json\" for POST to \"/api/v3/client/bsp\"",
90
+ "match": {
91
+ "location": "step_definitions/load_test_steps.js:174"
92
+ },
93
+ "result": {
94
+ "status": "passed",
95
+ "duration": 1823208
96
+ }
97
+ },
98
+ {
99
+ "arguments": [],
100
+ "keyword": "When ",
101
+ "line": 15,
102
+ "name": "I set the authentication type to \"auth_token\"",
103
+ "match": {
104
+ "location": "step_definitions/load_test_steps.js:226"
105
+ },
106
+ "result": {
107
+ "status": "passed",
108
+ "duration": 125207
109
+ }
110
+ },
111
+ {
112
+ "arguments": [],
113
+ "keyword": "Then ",
114
+ "line": 16,
115
+ "name": "I see the API should handle the POST request successfully",
116
+ "match": {
117
+ "location": "step_definitions/load_test_steps.js:306"
118
+ },
119
+ "result": {
120
+ "status": "failed",
121
+ "duration": 14665569374,
122
+ "error_message": "Error: k6 test execution failed\n at CustomWorld.<anonymous> (/Users/paschal/personal/k6-cucumber-steps/step_definitions/load_test_steps.js:334:13)"
123
+ }
124
+ }
125
+ ],
126
+ "tags": [
127
+ {
128
+ "name": "@rate-limit",
129
+ "line": 1
130
+ },
131
+ {
132
+ "name": "@within-limit",
133
+ "line": 8
134
+ }
135
+ ],
136
+ "type": "scenario"
137
+ },
138
+ {
139
+ "description": "",
140
+ "id": "rate-limit-enforcement-for-/login-and-/bsp;api-blocks-more-than-5-requests-in-10-seconds-(exceeds-limit)",
141
+ "keyword": "Scenario",
142
+ "line": 19,
143
+ "name": "API blocks more than 5 requests in 10 seconds (exceeds limit)",
144
+ "steps": [
145
+ {
146
+ "arguments": [],
147
+ "keyword": "Given ",
148
+ "line": 5,
149
+ "name": "I login via POST to \"/api/v3/client/api/login\" with payload from \"login.json\"",
150
+ "match": {
151
+ "location": "step_definitions/load_test_steps.js:262"
152
+ },
153
+ "result": {
154
+ "status": "passed",
155
+ "duration": 626931291
156
+ }
157
+ },
158
+ {
159
+ "arguments": [],
160
+ "keyword": "Then ",
161
+ "line": 6,
162
+ "name": "I store the value at \"data.token\" as alias \"auth_token\"",
163
+ "match": {
164
+ "location": "step_definitions/load_test_steps.js:237"
165
+ },
166
+ "result": {
167
+ "status": "passed",
168
+ "duration": 569790
169
+ }
170
+ },
171
+ {
172
+ "arguments": [],
173
+ "keyword": "When ",
174
+ "line": 20,
175
+ "name": "I set a k6 script for POST testing",
176
+ "match": {
177
+ "location": "step_definitions/load_test_steps.js:28"
178
+ },
179
+ "result": {
180
+ "status": "passed",
181
+ "duration": 76042
182
+ }
183
+ },
184
+ {
185
+ "arguments": [
186
+ {
187
+ "rows": [
188
+ {
189
+ "cells": [
190
+ "virtual_users",
191
+ "duration",
192
+ "http_req_failed",
193
+ "http_req_duration"
194
+ ]
195
+ },
196
+ {
197
+ "cells": [
198
+ "6",
199
+ "10",
200
+ "rate>=0.50",
201
+ "p(95)<3000"
202
+ ]
203
+ }
204
+ ]
205
+ }
206
+ ],
207
+ "keyword": "When ",
208
+ "line": 21,
209
+ "name": "I set to run the k6 script with the following configurations:",
210
+ "match": {
211
+ "location": "step_definitions/load_test_steps.js:40"
212
+ },
213
+ "result": {
214
+ "status": "passed",
215
+ "duration": 255083
216
+ }
217
+ },
218
+ {
219
+ "arguments": [],
220
+ "keyword": "When ",
221
+ "line": 24,
222
+ "name": "I use JSON payload from \"okra.json\" for POST to \"/api/v3/client/bsp\"",
223
+ "match": {
224
+ "location": "step_definitions/load_test_steps.js:174"
225
+ },
226
+ "result": {
227
+ "status": "passed",
228
+ "duration": 1752667
229
+ }
230
+ },
231
+ {
232
+ "arguments": [],
233
+ "keyword": "When ",
234
+ "line": 25,
235
+ "name": "I set the authentication type to \"auth_token\"",
236
+ "match": {
237
+ "location": "step_definitions/load_test_steps.js:226"
238
+ },
239
+ "result": {
240
+ "status": "passed",
241
+ "duration": 87707
242
+ }
243
+ },
244
+ {
245
+ "arguments": [],
246
+ "keyword": "Then ",
247
+ "line": 26,
248
+ "name": "I see the API should handle the POST request successfully",
249
+ "match": {
250
+ "location": "step_definitions/load_test_steps.js:306"
251
+ },
252
+ "result": {
253
+ "status": "passed",
254
+ "duration": 14650450625
255
+ }
256
+ }
257
+ ],
258
+ "tags": [
259
+ {
260
+ "name": "@rate-limit",
261
+ "line": 1
262
+ },
263
+ {
264
+ "name": "@exceed-limit",
265
+ "line": 18
266
+ }
267
+ ],
268
+ "type": "scenario"
269
+ }
270
+ ],
271
+ "id": "rate-limit-enforcement-for-/login-and-/bsp",
272
+ "line": 2,
273
+ "keyword": "Feature",
274
+ "name": "Rate Limit Enforcement for /login and /bsp",
275
+ "tags": [
276
+ {
277
+ "name": "@rate-limit",
278
+ "line": 1
279
+ }
280
+ ],
281
+ "uri": "features/bsp.feature"
282
+ }
283
+ ]
@@ -0,0 +1,53 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const reporter = require("cucumber-html-reporter");
4
+
5
+ function getJsonReportPath() {
6
+ // 1. Check for cucumber.js or custom config
7
+ const configFile = path.resolve("cucumber.js");
8
+ if (fs.existsSync(configFile)) {
9
+ const configText = fs.readFileSync(configFile, "utf-8");
10
+
11
+ const match = configText.match(/json:(.*?\.json)/);
12
+ if (match && match[1]) {
13
+ const reportPath = match[1].trim().replace(/['"`]/g, "");
14
+ console.log(`📝 Found report path in cucumber.js: ${reportPath}`);
15
+ return reportPath;
16
+ }
17
+ }
18
+
19
+ // 2. Check environment variable
20
+ if (process.env.CUCUMBER_JSON) {
21
+ console.log(
22
+ `📝 Using report path from CUCUMBER_JSON: ${process.env.CUCUMBER_JSON}`
23
+ );
24
+ return process.env.CUCUMBER_JSON;
25
+ }
26
+
27
+ // 3. Fallback to default
28
+ console.log("📝 Using default report path: reports/load-report.json");
29
+ return "reports/load-report.json";
30
+ }
31
+
32
+ function generateHtmlReports() {
33
+ const jsonReportPath = getJsonReportPath();
34
+
35
+ if (!fs.existsSync(jsonReportPath)) {
36
+ console.warn(`⚠️ Cucumber JSON report not found at: ${jsonReportPath}`);
37
+ return;
38
+ }
39
+
40
+ const reportDir = path.dirname(jsonReportPath);
41
+
42
+ reporter.generate({
43
+ theme: "bootstrap",
44
+ jsonFile: jsonReportPath,
45
+ output: path.join(reportDir, "cucumber-report.html"),
46
+ reportSuiteAsScenarios: true,
47
+ launchReport: false,
48
+ name: "k6-cucumber-steps Performance Report",
49
+ brandTitle: "📊 Performance Test Summary",
50
+ });
51
+ }
52
+
53
+ module.exports = { generateHtmlReports };
@@ -0,0 +1,122 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { minify } = require("html-minifier-terser");
4
+
5
+ const reportsDir = path.resolve("reports");
6
+
7
+ function findCucumberReportPath() {
8
+ const files = fs.readdirSync(reportsDir);
9
+ return files.find((f) => f.includes("cucumber") && f.endsWith(".html"));
10
+ }
11
+
12
+ function extractCucumberBody(filepath) {
13
+ const html = fs.readFileSync(filepath, "utf-8");
14
+
15
+ // Remove <script> tags to avoid JS conflicts
16
+ const withoutScripts = html.replace(/<script[\s\S]*?<\/script>/gi, "");
17
+
18
+ const match = withoutScripts.match(/<body[^>]*>([\s\S]*)<\/body>/i);
19
+ return match
20
+ ? match[1]
21
+ : "<p>⚠️ Failed to extract body of Cucumber report.</p>";
22
+ }
23
+
24
+ function extractK6ReportBody(file) {
25
+ const html = fs.readFileSync(file, "utf-8");
26
+ const match = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
27
+ return match ? match[1] : "";
28
+ }
29
+
30
+ function buildCombinedHtml({ title, k6Bodies, cucumberBody }) {
31
+ const tabs = k6Bodies
32
+ .map(
33
+ (_, i) => `
34
+ <input type="radio" name="tabs" id="tabk6${i}" ${i === 0 ? "checked" : ""}>
35
+ <label for="tabk6${i}">K6 Report ${i + 1}</label>
36
+ <div class="tab">
37
+ ${k6Bodies[i]}
38
+ </div>
39
+ `
40
+ )
41
+ .join("\n");
42
+
43
+ const cucumberTab = `
44
+ <input type="radio" name="tabs" id="tabcucumber">
45
+ <label for="tabcucumber">Cucumber Report</label>
46
+ <div class="tab">
47
+ <div style="max-height:80vh; overflow:auto; padding:1rem;">
48
+ ${cucumberBody}
49
+ </div>
50
+ </div>
51
+ `;
52
+
53
+ const fullTabs = cucumberBody ? cucumberTab + tabs : tabs;
54
+
55
+ return `
56
+ <!DOCTYPE html>
57
+ <html lang="en">
58
+ <head>
59
+ <meta charset="UTF-8" />
60
+ <title>${title}</title>
61
+ <link rel="stylesheet" href="https://unpkg.com/purecss@2.0.3/build/pure-min.css" crossorigin="anonymous">
62
+ <style>
63
+ body { margin:1rem; font-family:sans-serif; }
64
+ .tabs { display:flex; flex-wrap:wrap; }
65
+ .tabs label { order:1; padding:1rem; cursor:pointer; background:#ddd; margin-right:0.2rem; border-radius:5px 5px 0 0; }
66
+ .tabs .tab { order:99; flex-grow:1; width:100%; display:none; padding:1rem; background:#fff; }
67
+ .tabs input[type="radio"] { display:none; }
68
+ .tabs input[type="radio"]:checked + label { background:#fff; font-weight:bold; }
69
+ .tabs input[type="radio"]:checked + label + .tab { display:block; }
70
+ </style>
71
+ </head>
72
+ <body>
73
+ <h1>${title}</h1>
74
+ <div class="tabs">
75
+ ${fullTabs}
76
+ </div>
77
+ </body>
78
+ </html>`;
79
+ }
80
+
81
+ async function linkReports() {
82
+ if (!fs.existsSync(reportsDir)) {
83
+ console.warn("⚠️ No reports directory found.");
84
+ return;
85
+ }
86
+
87
+ const cucumberFile = findCucumberReportPath();
88
+ const cucumberBody = cucumberFile
89
+ ? extractCucumberBody(path.join(reportsDir, cucumberFile))
90
+ : null;
91
+
92
+ const k6Files = fs
93
+ .readdirSync(reportsDir)
94
+ .filter((f) => /^k6-report.*\.html$/.test(f));
95
+ if (k6Files.length === 0) {
96
+ console.warn("⚠️ No K6 reports found.");
97
+ return;
98
+ }
99
+
100
+ const k6Bodies = k6Files.map((f) =>
101
+ extractK6ReportBody(path.join(reportsDir, f))
102
+ );
103
+
104
+ const combinedHtml = buildCombinedHtml({
105
+ title: "Combined K6 + Cucumber Report",
106
+ k6Bodies,
107
+ cucumberBody,
108
+ });
109
+
110
+ const finalHtml = await minify(combinedHtml, {
111
+ collapseWhitespace: true,
112
+ removeComments: true,
113
+ minifyCSS: true,
114
+ });
115
+
116
+ const outPath = path.join(reportsDir, "combined-report.html");
117
+ fs.writeFileSync(outPath, finalHtml, "utf-8");
118
+
119
+ console.log(`✅ Combined and minified report saved to: ${outPath}`);
120
+ }
121
+
122
+ module.exports = { linkReports };
package/.env.example DELETED
@@ -1,17 +0,0 @@
1
- # .env
2
- TEST_ENVIRONMENT=STAGING
3
- APP_VERSION=1.0.0
4
- BROWSER=Chrome 100.0.4896.88
5
- PLATFORM=Windows 10
6
- PARALLEL=Scenarios
7
- EXECUTED=Remote
8
-
9
- # Base URLs
10
- API_BASE_URL=https://test-api.example.com
11
- BASE_URL=https://example.com
12
- AUTH_URL=https://auth.example.com
13
- PAYMENT_URL=https://payment.example.com
14
-
15
- # Secret Parameters
16
- API_KEY=your-secret-api-key-12345
17
- BEARER_TOKEN=your_bearer_token_here
package/generateReport.js DELETED
@@ -1,24 +0,0 @@
1
- const reporter = require("cucumber-html-reporter");
2
-
3
- // Configuration for the HTML report
4
- const options = {
5
- theme: "bootstrap", // You can change the theme to 'simple', 'compact', etc.
6
- jsonFile: "reports/load-results.json", // Path to the JSON file generated by Cucumber
7
- output: "reports/report.html", // Path where you want to save the HTML report
8
- reportSuiteAsScenarios: true, // Group scenarios by their name
9
- launchReport: true, // Automatically open the report in the browser
10
- metadata: {
11
- browser: {
12
- name: "Chrome" || "unknown",
13
- version: "89" || "unknown",
14
- },
15
- device: "Local test machine",
16
- platform: {
17
- name: "MacOS",
18
- version: "20.04",
19
- },
20
- },
21
- };
22
-
23
- // Generate the report
24
- reporter.generate(options);