k6-cucumber-steps 1.0.41 โ 1.1.1
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/bin/k6-cucumber-steps.js +47 -4
- package/cucumber.js +4 -4
- package/lib/helpers/buildK6Script.js +26 -18
- package/package.json +1 -1
- package/scripts/generateHtmlReports.js +53 -0
- package/scripts/linkReports.js +60 -0
- package/.env.example +0 -17
- package/generateReport.js +0 -24
package/bin/k6-cucumber-steps.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
//bin/k6-cucumber-steps.js
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const { spawn } = require("child_process");
|
|
6
6
|
const yargs = require("yargs");
|
|
7
7
|
require("dotenv").config();
|
|
8
|
+
const { generateHtmlReports } = require("../scripts/generateHtmlReports");
|
|
9
|
+
const { linkReports } = require("../scripts/linkReports");
|
|
8
10
|
|
|
9
11
|
console.log(`
|
|
10
12
|
-----------------------------------------
|
|
@@ -95,9 +97,32 @@ if (configOptions.require && Array.isArray(configOptions.require)) {
|
|
|
95
97
|
|
|
96
98
|
// Determine base report name
|
|
97
99
|
const reportsDir = path.join(process.cwd(), "reports");
|
|
100
|
+
// Clean and prepare reports directory
|
|
101
|
+
const cleanReportsDir = () => {
|
|
102
|
+
if (fs.existsSync(reportsDir)) {
|
|
103
|
+
try {
|
|
104
|
+
fs.rmSync(reportsDir, { recursive: true, force: true });
|
|
105
|
+
console.log("๐งน Cleaned existing reports directory.");
|
|
106
|
+
} catch (err) {
|
|
107
|
+
console.error("โ Failed to clean reports directory:", err.message);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
fs.mkdirSync(reportsDir, { recursive: true });
|
|
114
|
+
console.log("๐ Created fresh reports directory.");
|
|
115
|
+
} catch (err) {
|
|
116
|
+
console.error("โ Failed to create reports directory:", err.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
cleanReportsDir();
|
|
122
|
+
|
|
98
123
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
99
124
|
|
|
100
|
-
let baseReportName = "load-
|
|
125
|
+
let baseReportName = "load-report";
|
|
101
126
|
if (featureFiles.length === 1) {
|
|
102
127
|
const nameFromFeature = path.basename(featureFiles[0], ".feature");
|
|
103
128
|
baseReportName = nameFromFeature || baseReportName;
|
|
@@ -145,12 +170,30 @@ const cucumberProcess = spawn("npx", cucumberArgs, {
|
|
|
145
170
|
});
|
|
146
171
|
|
|
147
172
|
cucumberProcess.on("close", (code) => {
|
|
148
|
-
console.log(`\n-----------------------------------------`);
|
|
149
173
|
if (code === 0) {
|
|
174
|
+
console.log("-----------------------------------------");
|
|
150
175
|
console.log("โ
k6-cucumber-steps execution completed successfully.");
|
|
176
|
+
|
|
177
|
+
generateHtmlReports(); // Cucumber HTML
|
|
178
|
+
console.log(
|
|
179
|
+
"๐ Cucumber HTML report reports/cucumber-report.html generated successfully ๐"
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const k6ReportPath = detectMostRecentK6Report(); // Add this helper function
|
|
183
|
+
if (k6ReportPath) {
|
|
184
|
+
console.log(
|
|
185
|
+
`๐ K6 HTML report ${k6ReportPath} generated successfully ๐`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
linkReports(); // Link both reports
|
|
190
|
+
|
|
191
|
+
console.log("-----------------------------------------");
|
|
151
192
|
} else {
|
|
193
|
+
console.error("-----------------------------------------");
|
|
152
194
|
console.error("โ k6-cucumber-steps execution failed.");
|
|
195
|
+
console.error("-----------------------------------------");
|
|
153
196
|
}
|
|
154
|
-
|
|
197
|
+
|
|
155
198
|
process.exit(code);
|
|
156
199
|
});
|
package/cucumber.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
default: {
|
|
3
|
-
require: ["./step_definitions/**/*.js"],
|
|
3
|
+
// require: ["./step_definitions/**/*.js"],
|
|
4
4
|
format: [
|
|
5
5
|
"summary",
|
|
6
|
-
"json:./
|
|
7
|
-
"html:./
|
|
6
|
+
"json:./reports/load-report.json",
|
|
7
|
+
"html:./reports/cucumber-report.html",
|
|
8
8
|
],
|
|
9
|
-
paths: ["./
|
|
9
|
+
paths: ["./features/bsp.feature"],
|
|
10
10
|
tags: "@load",
|
|
11
11
|
worldParameters: {
|
|
12
12
|
payloadPath: "src/examples/payloads",
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
module.exports = function buildK6Script(config) {
|
|
2
2
|
const { method, endpoints, endpoint, body, headers, options } = config;
|
|
3
3
|
|
|
4
|
-
// Ensure at least one of `endpoints` or `endpoint` is defined
|
|
5
4
|
if (!endpoints?.length && !endpoint) {
|
|
6
5
|
throw new Error(
|
|
7
6
|
'Either "endpoints" or "endpoint" must be defined in the configuration.'
|
|
8
7
|
);
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
// Prefer API_BASE_URL, fallback to BASE_URL
|
|
12
10
|
const BASE_URL = process.env.API_BASE_URL || process.env.BASE_URL;
|
|
13
11
|
if (!BASE_URL) {
|
|
14
12
|
throw new Error(
|
|
@@ -16,18 +14,18 @@ module.exports = function buildK6Script(config) {
|
|
|
16
14
|
);
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
// Resolve relative endpoints by prepending BASE_URL
|
|
20
17
|
const resolveEndpoint = (url) => {
|
|
21
18
|
return url.startsWith("/") ? `${BASE_URL}${url}` : url;
|
|
22
19
|
};
|
|
23
20
|
|
|
24
|
-
// Convert to inline JS object (not stringified) so K6 can call JSON.stringify() itself
|
|
25
21
|
const stringifiedHeaders = JSON.stringify(headers, null, 2);
|
|
26
22
|
const stringifiedBody = JSON.stringify(body, null, 2);
|
|
27
23
|
|
|
28
24
|
return `
|
|
29
25
|
import http from 'k6/http';
|
|
30
26
|
import { check } from 'k6';
|
|
27
|
+
import { htmlReport } from "https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js";
|
|
28
|
+
import { textSummary } from "https://jslib.k6.io/k6-summary/0.0.1/index.js";
|
|
31
29
|
|
|
32
30
|
export const options = ${JSON.stringify(options, null, 2)};
|
|
33
31
|
|
|
@@ -40,32 +38,42 @@ export default function () {
|
|
|
40
38
|
? endpoints
|
|
41
39
|
.map(
|
|
42
40
|
(url, i) => `
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
const resolvedUrl${i} = "${resolveEndpoint(url)}";
|
|
42
|
+
const res${i} = http.request("${method}", resolvedUrl${i}, ${
|
|
45
43
|
method === "GET" || method === "DELETE"
|
|
46
44
|
? "null"
|
|
47
45
|
: "JSON.stringify(body)"
|
|
48
46
|
}, { headers });
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
console.log(\`Response Body for \${resolvedUrl${i}}: \${res${i}.body}\`);
|
|
48
|
+
check(res${i}, {
|
|
49
|
+
"status is 2xx": (r) => r.status >= 200 && r.status < 300
|
|
50
|
+
});
|
|
51
|
+
`
|
|
54
52
|
)
|
|
55
53
|
.join("\n")
|
|
56
54
|
: `
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
const resolvedUrl = "${resolveEndpoint(endpoint)}";
|
|
56
|
+
const res = http.request("${method}", resolvedUrl, ${
|
|
59
57
|
method === "GET" || method === "DELETE"
|
|
60
58
|
? "null"
|
|
61
59
|
: "JSON.stringify(body)"
|
|
62
60
|
}, { headers });
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
console.log(\`Response Body for \${resolvedUrl}: \${res.body}\`);
|
|
62
|
+
check(res, {
|
|
63
|
+
"status is 2xx": (r) => r.status >= 200 && r.status < 300
|
|
64
|
+
});
|
|
67
65
|
`
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
|
-
|
|
68
|
+
|
|
69
|
+
export function handleSummary(data) {
|
|
70
|
+
const outputDir = __ENV.REPORT_OUTPUT_DIR || "reports";
|
|
71
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
72
|
+
const filename = \`\${outputDir}/k6-report-\${timestamp}.html\`;
|
|
73
|
+
return {
|
|
74
|
+
[filename]: htmlReport(data),
|
|
75
|
+
stdout: textSummary(data, { indent: " ", enableColors: true }),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
`;
|
|
71
79
|
};
|
package/package.json
CHANGED
|
@@ -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,60 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
const reportsDir = path.resolve("reports");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Adds internal cross-links between reports.
|
|
8
|
+
*/
|
|
9
|
+
function addLinksToReport(targetFile, otherFiles) {
|
|
10
|
+
const content = fs.readFileSync(targetFile, "utf-8");
|
|
11
|
+
|
|
12
|
+
// Inject the Cucumber Report tab before the Request Metrics tab
|
|
13
|
+
const cucumberTab = `
|
|
14
|
+
<input type="radio" name="tabs" id="tabcucumber">
|
|
15
|
+
<label for="tabcucumber"><i class="fas fa-file-alt"></i> Cucumber Report</label>
|
|
16
|
+
<div class="tab">
|
|
17
|
+
<iframe src="cucumber-report.html" style="width:100%; height:600px; border:none;"></iframe>
|
|
18
|
+
</div>
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const modifiedContent = content
|
|
22
|
+
.replace(
|
|
23
|
+
/<input type="radio" name="tabs" id="tabone"/,
|
|
24
|
+
`${cucumberTab}\n<input type="radio" name="tabs" id="tabone"`
|
|
25
|
+
)
|
|
26
|
+
// Remove standalone links to cucumber-report.html or k6-report.html
|
|
27
|
+
.replace(
|
|
28
|
+
/<div style="padding:10px;margin-top:20px;text-align:center">[\s\S]*?View (Cucumber|k6).*?<\/div>/,
|
|
29
|
+
""
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
fs.writeFileSync(targetFile, modifiedContent, "utf-8");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Auto-link all HTML reports in the reports directory.
|
|
37
|
+
*/
|
|
38
|
+
function linkReports() {
|
|
39
|
+
if (!fs.existsSync(reportsDir)) {
|
|
40
|
+
console.warn("โ ๏ธ No reports directory found.");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const htmlFiles = fs
|
|
45
|
+
.readdirSync(reportsDir)
|
|
46
|
+
.filter((f) => f.endsWith(".html"))
|
|
47
|
+
.map((f) => path.join(reportsDir, f));
|
|
48
|
+
|
|
49
|
+
if (htmlFiles.length < 2) {
|
|
50
|
+
console.warn("โ ๏ธ Not enough HTML files to link.");
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for (const file of htmlFiles) {
|
|
55
|
+
const others = htmlFiles.filter((f) => f !== file);
|
|
56
|
+
addLinksToReport(file, others);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
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);
|