k6-cucumber-steps 1.1.4 → 1.1.6
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 +38 -41
- package/bin/k6-cucumber-steps.js +58 -161
- package/package.json +13 -5
- package/scripts/linkReports.js +43 -50
- package/step_definitions/load_test_steps.js +15 -11
- package/.env +0 -38
- package/.github/workflows/k6-load-test.yml +0 -42
- package/.vscode/extensions.json +0 -3
- package/.vscode/settings.json +0 -14
- package/assets/k6-cucumber-report.png +0 -0
- package/assets/k6-cucumber-report2.png +0 -0
- package/assets/paschal logo (2).png +0 -0
- package/cucumber.js +0 -17
- package/reports/cucumber-report.html +0 -50
- package/reports/load-report.json +0 -294
- package/temp/load_script_6ae38e6d-f93e-443a-a516-587047b1f46b.js +0 -65
package/README.md
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
</td></tr></table>
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/k6-cucumber-steps)
|
|
8
|
-
[](https://github.com/qaPaschalE/k6-cucumber-steps/blob/main/LICENSE)
|
|
10
|
-
[](https://k6.io/)
|
|
9
|
+
[](https://github.com/qaPaschalE/k6-cucumber-steps/blob/main/LICENSE)
|
|
10
|
+
[](https://cucumber.io/)
|
|
11
11
|
[](https://nodejs.org/)
|
|
12
|
-
[](https://github.com/qaPaschalE/k6-cucumber-steps/actions/workflows/k6-load-test.yml)
|
|
13
|
+
[](https://github.com/qaPaschalE/k6-cucumber-steps/issues)
|
|
14
|
+
[](https://github.com/qaPaschalE/k6-cucumber-steps/stargazers)
|
|
15
|
+
[](https://www.npmjs.com/package/k6-cucumber-steps)
|
|
14
16
|
|
|
15
17
|
Run [k6](https://k6.io/) performance/load tests using [Cucumber](https://cucumber.io/) BDD syntax with ease.
|
|
16
18
|
|
|
@@ -18,20 +20,19 @@ Run [k6](https://k6.io/) performance/load tests using [Cucumber](https://cucumbe
|
|
|
18
20
|
|
|
19
21
|
## ✨ Features
|
|
20
22
|
|
|
21
|
-
- ✅ Cucumber + Gherkin for writing k6 tests
|
|
22
|
-
to generate JSON and HTML reports.
|
|
23
|
+
- ✅ Cucumber + Gherkin for writing k6 tests to generate JSON and HTML reports.
|
|
23
24
|
- ✅ Flexible configuration through Cucumber data tables.
|
|
24
|
-
- ✅ Support for JSON body parsing and escaping
|
|
25
|
+
- ✅ Support for JSON body parsing and escaping.
|
|
25
26
|
- ✅ Dynamic request body generation using environment variables, Faker templates, and JSON file includes.
|
|
26
27
|
- ✅ `.env` + `K6.env`-style variable resolution (`{{API_KEY}}`)
|
|
27
|
-
- ✅ Support for headers, query params, stages
|
|
28
|
+
- ✅ Support for headers, query params, stages.
|
|
28
29
|
- ✅ Supports multiple authentication types: API key, Bearer token, Basic Auth, and No Auth.
|
|
29
|
-
|
|
30
|
-
- ✅
|
|
31
|
-
- ✅ Built-in support for **distributed load testing** with stages
|
|
30
|
+
- ✅ Clean-up of temporary k6 files after execution.
|
|
31
|
+
- ✅ Built-in support for **distributed load testing** with stages.
|
|
32
32
|
- ✅ TypeScript-first 🧡
|
|
33
33
|
- ✅ **Optional report overwriting**: Use the `overwrite` option to control whether reports are overwritten or appended.
|
|
34
|
-
- ✅ **Generate detailed reports**: Use the `--reporter` flag
|
|
34
|
+
- ✅ **Generate detailed reports**: Use the `--reporter` flag.
|
|
35
|
+
- ✅ **Clean reports directory before run**: Use the `--cleanReports`/`--clean` CLI flag, `CLEAN_REPORTS=true` in `.env`, or `cleanReports: true` in your `cucumber.js` config.
|
|
35
36
|
|
|
36
37
|
---
|
|
37
38
|
|
|
@@ -55,13 +56,16 @@ The `run` command accepts the following options:
|
|
|
55
56
|
|
|
56
57
|
- `-f, --feature <path>`: Path to the feature file to execute.
|
|
57
58
|
- `-t, --tags <string>`: Cucumber tags to filter scenarios (e.g., `@smoke and not @regression`).
|
|
59
|
+
- `-c, --config <file>`: Custom config file (default: `cucumber.js`).
|
|
58
60
|
- `-r, --reporter`: Generate HTML and JSON reports in the `reports` directory. This is a boolean flag, so just include `-r, --reporter` to enable it.
|
|
59
61
|
- `-o, --overwrite`: Overwrite existing reports instead of appending them.
|
|
62
|
+
- `--cleanReports`, `--clean`: **Clean the `reports` directory before running.**
|
|
63
|
+
You can also set this via the `cleanReports` property in your `cucumber.js` config or with the `CLEAN_REPORTS=true` environment variable.
|
|
60
64
|
|
|
61
65
|
### Example Usage with Options
|
|
62
66
|
|
|
63
67
|
```bash
|
|
64
|
-
npx k6-cucumber-steps run --feature ./features/my_feature.feature --tags "@load and not @wip" --reporter
|
|
68
|
+
npx k6-cucumber-steps run --feature ./features/my_feature.feature --tags "@load and not @wip" --reporter --cleanReports
|
|
65
69
|
```
|
|
66
70
|
|
|
67
71
|
---
|
|
@@ -73,9 +77,9 @@ Here's a step-by-step guide to using `k6-cucumber-steps` in your project:
|
|
|
73
77
|
**Prerequisites:**
|
|
74
78
|
|
|
75
79
|
1. **Node.js and npm (or yarn):** Ensure you have Node.js and npm (or yarn) installed.
|
|
76
|
-
2. **k6:** Install k6 on your system following the instructions at [k6.io/docs/getting-started/installation/](https://
|
|
77
|
-
3. **@cucumber/cucumber
|
|
78
|
-
4. **cucumber-html-reporter
|
|
80
|
+
2. **k6:** Install k6 on your system following the instructions at [k6.io/docs/getting-started/installation/](https://k6.io/docs/getting-started/installation/).
|
|
81
|
+
3. **@cucumber/cucumber (optional):** This package is required for using Cucumber.
|
|
82
|
+
4. **cucumber-html-reporter (optional):** This package is needed if you intend to generate detailed HTML reports.
|
|
79
83
|
|
|
80
84
|
**Setup:**
|
|
81
85
|
|
|
@@ -116,7 +120,7 @@ Here's a step-by-step guide to using `k6-cucumber-steps` in your project:
|
|
|
116
120
|
require: [
|
|
117
121
|
// You can add paths to your local step definitions here if needed
|
|
118
122
|
],
|
|
119
|
-
reporter:true // To provide HTML and JSON report
|
|
123
|
+
reporter: true, // To provide HTML and JSON report
|
|
120
124
|
format: [
|
|
121
125
|
"summary",
|
|
122
126
|
"json:reports/load-report.json", // For JSON report
|
|
@@ -125,25 +129,27 @@ Here's a step-by-step guide to using `k6-cucumber-steps` in your project:
|
|
|
125
129
|
paths: ["./features/*.feature"],
|
|
126
130
|
tags: process.env.TAGS,
|
|
127
131
|
worldParameters: {
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
payloadPath: "apps/qa/performance/payloads",
|
|
133
|
+
},
|
|
130
134
|
overwrite: false, // Default to not overwrite the report file
|
|
135
|
+
cleanReports: true, // <--- Clean the reports directory before running
|
|
131
136
|
};
|
|
132
137
|
```
|
|
133
138
|
|
|
134
|
-
**
|
|
139
|
+
**Controlling Report Directory Clean-up**
|
|
135
140
|
|
|
136
|
-
|
|
141
|
+
You can control whether the `reports` directory is cleaned before each run using any of these methods:
|
|
137
142
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
```
|
|
143
|
+
- **Command-line:**
|
|
144
|
+
Add `--cleanReports` or `--clean` to your CLI command.
|
|
141
145
|
|
|
142
|
-
|
|
146
|
+
- **Environment variable:**
|
|
147
|
+
Add `CLEAN_REPORTS=true` to your `.env` file.
|
|
143
148
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
149
|
+
- **Config file:**
|
|
150
|
+
Set `cleanReports: true` in your `cucumber.js` config.
|
|
151
|
+
|
|
152
|
+
Priority order: **CLI > Environment variable > Config file**
|
|
147
153
|
|
|
148
154
|
---
|
|
149
155
|
|
|
@@ -152,8 +158,8 @@ npx k6-cucumber-steps run --configFile cucumber.prod.js
|
|
|
152
158
|
1. **Environment Variables**: Create a `.env` file in your project root based on the provided `.env.example`:
|
|
153
159
|
|
|
154
160
|
```env
|
|
155
|
-
BASE_URL=
|
|
156
|
-
API_BASE_URL=
|
|
161
|
+
BASE_URL=https://api.example.com
|
|
162
|
+
API_BASE_URL=https://api.example.com
|
|
157
163
|
API_KEY=your_api_key
|
|
158
164
|
BEARER_TOKEN=your_bearer_token
|
|
159
165
|
BASIC_USER=your_basic_user
|
|
@@ -180,7 +186,7 @@ Feature: API Performance Testing
|
|
|
180
186
|
And I set the following endpoints used:
|
|
181
187
|
"""
|
|
182
188
|
/api/profile
|
|
183
|
-
|
|
189
|
+
https://reqres.in/api/users?page=2
|
|
184
190
|
"""
|
|
185
191
|
And I set the authentication type to "none"
|
|
186
192
|
Then I see the API should handle the GET request successfully
|
|
@@ -234,7 +240,6 @@ When I set the request headers:
|
|
|
234
240
|
When I set the following endpoints used:
|
|
235
241
|
When I set the following {word} body is used for {string}
|
|
236
242
|
When I store the value at {string} as alias {string}
|
|
237
|
-
|
|
238
243
|
```
|
|
239
244
|
|
|
240
245
|
### Assertion Steps
|
|
@@ -272,12 +277,4 @@ If you find this package useful, consider [sponsoring me on GitHub](https://gith
|
|
|
272
277
|
|
|
273
278
|
MIT License - [@qaPaschalE](https://github.com/qaPaschalE)
|
|
274
279
|
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
## License
|
|
279
|
-
|
|
280
280
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
```
|
package/bin/k6-cucumber-steps.js
CHANGED
|
@@ -1,231 +1,128 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//bin/k6-cucumber-steps.js
|
|
3
2
|
const path = require("path");
|
|
4
3
|
const fs = require("fs");
|
|
5
4
|
const { spawn } = require("child_process");
|
|
6
|
-
const
|
|
7
|
-
const { hideBin } = require("yargs/helpers");
|
|
5
|
+
const { Command } = require("commander");
|
|
8
6
|
require("dotenv").config();
|
|
9
7
|
|
|
8
|
+
const { linkReports } = require("../scripts/linkReports");
|
|
9
|
+
|
|
10
10
|
console.log(`
|
|
11
11
|
-----------------------------------------
|
|
12
12
|
🚀 Starting k6-cucumber-steps execution...
|
|
13
13
|
-----------------------------------------
|
|
14
14
|
`);
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.option("
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
type: "boolean",
|
|
33
|
-
default: false,
|
|
34
|
-
})
|
|
35
|
-
.option("overwrite", {
|
|
36
|
-
alias: "o",
|
|
37
|
-
describe: "Overwrite existing reports",
|
|
38
|
-
type: "boolean",
|
|
39
|
-
default: false,
|
|
40
|
-
})
|
|
41
|
-
.option("configFile", {
|
|
42
|
-
alias: "c",
|
|
43
|
-
describe: "Custom cucumber config file",
|
|
44
|
-
type: "string",
|
|
45
|
-
})
|
|
46
|
-
.help().argv;
|
|
47
|
-
|
|
48
|
-
// Base Cucumber arguments
|
|
16
|
+
const program = new Command();
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.command("run")
|
|
20
|
+
.option("-f, --feature <path>", "Feature file path")
|
|
21
|
+
.option("-t, --tags <string>", "Cucumber tags")
|
|
22
|
+
.option("-c, --config <file>", "Custom config file") // changed from --configFile to --config
|
|
23
|
+
.option("-r, --reporter", "Enable report generation", false)
|
|
24
|
+
.option("-o, --overwrite", "Overwrite report files", false)
|
|
25
|
+
.option("--cleanReports", "Clean the reports folder before running")
|
|
26
|
+
.option("--clean", "Alias for --cleanReports");
|
|
27
|
+
|
|
28
|
+
program.parse(process.argv);
|
|
29
|
+
|
|
30
|
+
const argv = program.opts();
|
|
31
|
+
|
|
49
32
|
const cucumberArgs = ["cucumber-js"];
|
|
50
33
|
|
|
51
|
-
//
|
|
52
|
-
const
|
|
53
|
-
argv.
|
|
54
|
-
const configFilePath = path.
|
|
34
|
+
// Update all references to argv.configFile to argv.config:
|
|
35
|
+
const configFileInput =
|
|
36
|
+
argv.config || process.env.CUCUMBER_CONFIG_FILE || "cucumber.js";
|
|
37
|
+
const configFilePath = path.isAbsolute(configFileInput)
|
|
38
|
+
? configFileInput
|
|
39
|
+
: path.resolve(process.cwd(), configFileInput);
|
|
55
40
|
|
|
56
41
|
let configOptions = {};
|
|
42
|
+
|
|
57
43
|
if (fs.existsSync(configFilePath)) {
|
|
58
|
-
cucumberArgs.push("--config",
|
|
44
|
+
cucumberArgs.push("--config", configFileInput);
|
|
59
45
|
try {
|
|
60
46
|
const loadedConfig = require(configFilePath);
|
|
61
47
|
configOptions = loadedConfig.default || loadedConfig;
|
|
62
48
|
} catch (err) {
|
|
63
49
|
console.warn("⚠️ Could not load config file:", err.message);
|
|
64
50
|
}
|
|
51
|
+
} else {
|
|
52
|
+
console.warn(`⚠️ Config file not found at ${configFilePath}`);
|
|
65
53
|
}
|
|
66
54
|
|
|
67
|
-
//
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
55
|
+
// Resolve cleanReports: CLI > ENV > config file
|
|
56
|
+
const cleanReports =
|
|
57
|
+
typeof argv.cleanReports === "boolean"
|
|
58
|
+
? argv.cleanReports
|
|
59
|
+
: typeof argv.clean === "boolean"
|
|
60
|
+
? argv.clean
|
|
61
|
+
: process.env.CLEAN_REPORTS
|
|
62
|
+
? process.env.CLEAN_REPORTS === "true"
|
|
63
|
+
: configOptions.cleanReports;
|
|
64
|
+
|
|
65
|
+
// Clean reports directory if needed
|
|
66
|
+
const reportsDir = path.resolve("reports");
|
|
67
|
+
if (cleanReports) {
|
|
68
|
+
if (fs.existsSync(reportsDir)) {
|
|
69
|
+
fs.rmSync(reportsDir, { recursive: true, force: true });
|
|
70
|
+
console.log("🧹 Cleaned reports directory.");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!fs.existsSync(reportsDir)) {
|
|
74
|
+
fs.mkdirSync(reportsDir, { recursive: true });
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
//
|
|
77
|
+
// Build featureFiles array before using it
|
|
74
78
|
let featureFiles = [];
|
|
75
79
|
if (argv.feature) {
|
|
76
80
|
featureFiles.push(path.resolve(argv.feature));
|
|
77
|
-
} else if (
|
|
78
|
-
featureFiles
|
|
79
|
-
}
|
|
80
|
-
if (featureFiles.length > 0) {
|
|
81
|
-
cucumberArgs.push(...featureFiles);
|
|
81
|
+
} else if (Array.isArray(configOptions.paths)) {
|
|
82
|
+
featureFiles = configOptions.paths.map((f) => path.resolve(f));
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
// Require step definitions
|
|
85
|
-
const defaultStepsPath = path.resolve(
|
|
86
|
-
process.cwd(),
|
|
87
|
-
"node_modules",
|
|
88
|
-
"k6-cucumber-steps",
|
|
89
|
-
"step_definitions"
|
|
90
|
-
);
|
|
91
|
-
cucumberArgs.push("--require", defaultStepsPath);
|
|
92
|
-
|
|
93
|
-
// Include additional custom step definitions from config
|
|
94
|
-
if (configOptions.require && Array.isArray(configOptions.require)) {
|
|
95
|
-
for (const reqPath of configOptions.require) {
|
|
96
|
-
cucumberArgs.push("--require", path.resolve(reqPath));
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Reports directory setup
|
|
101
|
-
const reportsDir = path.join(process.cwd(), "reports");
|
|
102
|
-
|
|
103
|
-
// Clean and prepare reports directory
|
|
104
|
-
const cleanReportsDir = () => {
|
|
105
|
-
if (fs.existsSync(reportsDir)) {
|
|
106
|
-
try {
|
|
107
|
-
fs.rmSync(reportsDir, { recursive: true, force: true });
|
|
108
|
-
console.log("🧹 Cleaned existing reports directory.");
|
|
109
|
-
} catch (err) {
|
|
110
|
-
console.error("❌ Failed to clean reports directory:", err.message);
|
|
111
|
-
process.exit(1);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
fs.mkdirSync(reportsDir, { recursive: true });
|
|
117
|
-
console.log("📁 Created fresh reports directory.");
|
|
118
|
-
} catch (err) {
|
|
119
|
-
console.error("❌ Failed to create reports directory:", err.message);
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
cleanReportsDir();
|
|
125
|
-
|
|
126
|
-
// Determine base report name
|
|
127
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
128
|
-
|
|
129
85
|
let baseReportName = "load-report";
|
|
130
86
|
if (featureFiles.length === 1) {
|
|
131
|
-
|
|
132
|
-
baseReportName = nameFromFeature || baseReportName;
|
|
87
|
+
baseReportName = path.basename(featureFiles[0], ".feature");
|
|
133
88
|
} else if (featureFiles.length > 1) {
|
|
134
89
|
baseReportName = "multi-feature";
|
|
135
90
|
}
|
|
91
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
92
|
+
let reportHtmlPath = path.join(reportsDir, `cucumber-report.html`);
|
|
136
93
|
|
|
137
|
-
|
|
138
|
-
const shouldOverwrite =
|
|
139
|
-
argv.overwrite ||
|
|
140
|
-
process.env.K6_CUCUMBER_OVERWRITE === "true" ||
|
|
141
|
-
configOptions.overwrite === true;
|
|
142
|
-
|
|
143
|
-
let reportJsonPath = path.join(reportsDir, `${baseReportName}.json`);
|
|
144
|
-
let reportHtmlPath = path.join(reportsDir, `${baseReportName}.html`);
|
|
145
|
-
|
|
146
|
-
if (!shouldOverwrite) {
|
|
147
|
-
reportJsonPath = path.join(reportsDir, `${baseReportName}-${timestamp}.json`);
|
|
148
|
-
reportHtmlPath = path.join(reportsDir, `${baseReportName}-${timestamp}.html`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Respect config format path if defined
|
|
152
|
-
if (Array.isArray(configOptions.format)) {
|
|
153
|
-
const jsonFmt = configOptions.format.find((f) => f.startsWith("json:"));
|
|
154
|
-
if (jsonFmt) {
|
|
155
|
-
reportJsonPath = jsonFmt.split("json:")[1];
|
|
156
|
-
console.log(`📝 Using report path from config: ${reportJsonPath}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const formatInConfig =
|
|
161
|
-
Array.isArray(configOptions.format) && configOptions.format.length > 0;
|
|
162
|
-
|
|
163
|
-
if (shouldGenerateReports && !formatInConfig) {
|
|
94
|
+
if (argv.reporter && !Array.isArray(configOptions.format)) {
|
|
164
95
|
cucumberArgs.push("--format", "summary");
|
|
165
|
-
cucumberArgs.push("--format", `json:${reportJsonPath}`);
|
|
166
96
|
cucumberArgs.push("--format", `html:${reportHtmlPath}`);
|
|
167
97
|
}
|
|
168
98
|
|
|
169
99
|
console.log("\n▶️ Final arguments passed to cucumber-js:");
|
|
170
100
|
console.log(["npx", ...cucumberArgs].join(" ") + "\n");
|
|
171
101
|
|
|
172
|
-
// Execute Cucumber process
|
|
173
102
|
const cucumberProcess = spawn("npx", cucumberArgs, {
|
|
174
103
|
stdio: "inherit",
|
|
175
104
|
env: {
|
|
176
105
|
...process.env,
|
|
177
|
-
K6_CUCUMBER_OVERWRITE: shouldOverwrite ? "true" : "false",
|
|
178
|
-
TAGS: tags,
|
|
179
|
-
FEATURE_PATH: featureFiles.join(","),
|
|
180
|
-
REPORT_JSON_PATH: reportJsonPath,
|
|
181
106
|
REPORT_HTML_PATH: reportHtmlPath,
|
|
107
|
+
K6_CUCUMBER_OVERWRITE: argv.overwrite ? "true" : "false",
|
|
182
108
|
},
|
|
183
109
|
});
|
|
184
110
|
|
|
185
|
-
function detectMostRecentK6Report() {
|
|
186
|
-
const files = fs
|
|
187
|
-
.readdirSync(reportsDir)
|
|
188
|
-
.filter((file) => /^k6-report.*\.html$/.test(file))
|
|
189
|
-
.map((file) => ({
|
|
190
|
-
name: file,
|
|
191
|
-
time: fs.statSync(path.join(reportsDir, file)).mtime.getTime(),
|
|
192
|
-
}))
|
|
193
|
-
.sort((a, b) => b.time - a.time);
|
|
194
|
-
|
|
195
|
-
return files.length > 0 ? path.join(reportsDir, files[0].name) : null;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
111
|
cucumberProcess.on("close", async (code) => {
|
|
199
112
|
if (code === 0) {
|
|
200
113
|
console.log("-----------------------------------------");
|
|
201
114
|
console.log("✅ k6-cucumber-steps execution completed successfully.");
|
|
202
|
-
|
|
203
|
-
// Generate Cucumber HTML report
|
|
204
|
-
try {
|
|
205
|
-
await generateHtmlReports();
|
|
206
|
-
console.log(
|
|
207
|
-
`🚀 Cucumber HTML report generated successfully at: ${reportHtmlPath}`
|
|
208
|
-
);
|
|
209
|
-
} catch (err) {
|
|
210
|
-
console.error("⚠️ Failed to generate Cucumber HTML report:", err.message);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Link reports
|
|
214
115
|
try {
|
|
215
116
|
await linkReports();
|
|
216
|
-
console.log(
|
|
217
|
-
"🔗 Combined and minified HTML report available at: reports/combined-report.html"
|
|
218
|
-
);
|
|
117
|
+
console.log("🔗 Reports linked successfully with embedded Cucumber tab.");
|
|
219
118
|
} catch (err) {
|
|
220
119
|
console.error("⚠️ Failed to link reports:", err.message);
|
|
221
120
|
}
|
|
222
|
-
|
|
223
121
|
console.log("-----------------------------------------");
|
|
224
122
|
} else {
|
|
225
123
|
console.error("-----------------------------------------");
|
|
226
124
|
console.error("❌ k6-cucumber-steps execution failed.");
|
|
227
125
|
console.error("-----------------------------------------");
|
|
228
126
|
}
|
|
229
|
-
|
|
230
127
|
process.exit(code);
|
|
231
128
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "k6-cucumber-steps",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,6 +33,15 @@
|
|
|
33
33
|
"bin": {
|
|
34
34
|
"k6-cucumber-steps": "./bin/k6-cucumber-steps.js"
|
|
35
35
|
},
|
|
36
|
+
"files": [
|
|
37
|
+
"bin/",
|
|
38
|
+
"lib/",
|
|
39
|
+
"step_definitions/",
|
|
40
|
+
"scripts/",
|
|
41
|
+
"package.json",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
36
45
|
"keywords": [
|
|
37
46
|
"k6",
|
|
38
47
|
"cucumber",
|
|
@@ -59,12 +68,11 @@
|
|
|
59
68
|
"@babel/preset-env": "^7.27.2",
|
|
60
69
|
"@faker-js/faker": "^9.8.0",
|
|
61
70
|
"@types/k6": "^1.0.2",
|
|
62
|
-
"axios": "^1.10.0",
|
|
63
71
|
"dotenv": "^16.5.0",
|
|
64
|
-
"html-minifier-terser": "^7.2.0"
|
|
65
|
-
"yargs": "^18.0.0"
|
|
72
|
+
"html-minifier-terser": "^7.2.0"
|
|
66
73
|
},
|
|
67
74
|
"dependencies": {
|
|
68
|
-
"@babel/register": "^7.27.1"
|
|
75
|
+
"@babel/register": "^7.27.1",
|
|
76
|
+
"commander": "^14.0.0"
|
|
69
77
|
}
|
|
70
78
|
}
|
package/scripts/linkReports.js
CHANGED
|
@@ -1,69 +1,62 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
|
+
const { minify } = require("html-minifier-terser");
|
|
3
4
|
|
|
4
5
|
const reportsDir = path.resolve("reports");
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
* Finds the first file that looks like a Cucumber HTML report.
|
|
8
|
-
*/
|
|
9
|
-
function findCucumberReportFile() {
|
|
10
|
-
const files = fs.readdirSync(reportsDir);
|
|
11
|
-
return files.find((f) => f.includes("cucumber") && f.endsWith(".html"));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Adds a Cucumber report tab as an iframe.
|
|
16
|
-
*/
|
|
17
|
-
function addLinksToReport(targetFile, cucumberFileName) {
|
|
18
|
-
const content = fs.readFileSync(targetFile, "utf-8");
|
|
19
|
-
|
|
20
|
-
const cucumberTab = `
|
|
21
|
-
<input type="radio" name="tabs" id="tabcucumber">
|
|
22
|
-
<label for="tabcucumber"><i class="fas fa-file-alt"></i> Cucumber Report</label>
|
|
23
|
-
<div class="tab">
|
|
24
|
-
${
|
|
25
|
-
cucumberFileName
|
|
26
|
-
? `<iframe src="${cucumberFileName}" style="width:100%; min-height:600px; border:none;"></iframe>`
|
|
27
|
-
: `<p style="color:red; padding:1rem;">⚠️ Cucumber HTML report not found in <code>reports/</code> directory.</p>`
|
|
28
|
-
}
|
|
29
|
-
</div>
|
|
30
|
-
`;
|
|
31
|
-
|
|
32
|
-
const modifiedContent = content
|
|
33
|
-
.replace(
|
|
34
|
-
/<input type="radio" name="tabs" id="tabone"/,
|
|
35
|
-
`${cucumberTab}\n<input type="radio" name="tabs" id="tabone"`
|
|
36
|
-
)
|
|
37
|
-
.replace(/<div style="[^>]*margin-top:20px;[^>]*">[\s\S]*?<\/div>/g, "");
|
|
38
|
-
|
|
39
|
-
fs.writeFileSync(targetFile, modifiedContent, "utf-8");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Adds a Cucumber tab to every K6 HTML report found in /reports.
|
|
44
|
-
*/
|
|
45
|
-
function linkReports() {
|
|
7
|
+
async function linkReports() {
|
|
46
8
|
if (!fs.existsSync(reportsDir)) {
|
|
47
9
|
console.warn("⚠️ No reports directory found.");
|
|
48
10
|
return;
|
|
49
11
|
}
|
|
50
12
|
|
|
51
|
-
const cucumberFile = findCucumberReportFile();
|
|
52
|
-
|
|
53
13
|
const htmlFiles = fs
|
|
54
14
|
.readdirSync(reportsDir)
|
|
55
|
-
.filter((f) =>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
15
|
+
.filter((f) => f.endsWith(".html"));
|
|
16
|
+
const k6ReportFile = htmlFiles.find(
|
|
17
|
+
(f) => f.startsWith("k6-report") && f.endsWith(".html")
|
|
18
|
+
);
|
|
19
|
+
const cucumberReportFile = htmlFiles.find((f) =>
|
|
20
|
+
f.includes("cucumber-report")
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
if (!k6ReportFile || !cucumberReportFile) {
|
|
24
|
+
console.warn("⚠️ K6 or Cucumber HTML report not found.");
|
|
59
25
|
return;
|
|
60
26
|
}
|
|
61
27
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
28
|
+
const k6Path = path.join(reportsDir, k6ReportFile);
|
|
29
|
+
const cucumberPath = path.basename(cucumberReportFile);
|
|
30
|
+
let content = fs.readFileSync(k6Path, "utf8");
|
|
31
|
+
|
|
32
|
+
const cucumberTab = `
|
|
33
|
+
<input type="radio" name="tabs" id="tabcucumber">
|
|
34
|
+
<label for="tabcucumber"><i class="fas fa-file-alt"></i> Cucumber Report</label>
|
|
35
|
+
<div class="tab">
|
|
36
|
+
<iframe src="${cucumberPath}" style="width:100%; height:600px; border:none;"></iframe>
|
|
37
|
+
</div>
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
content = content.replace(
|
|
41
|
+
/<input type="radio" name="tabs" id="tabone"/,
|
|
42
|
+
`${cucumberTab}\n<input type="radio" name="tabs" id="tabone"`
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
content = content.replace(
|
|
46
|
+
/<div style="padding:10px;margin-top:20px;text-align:center">[\s\S]*?<\/div>/,
|
|
47
|
+
""
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const minified = await minify(content, {
|
|
51
|
+
collapseWhitespace: true,
|
|
52
|
+
removeComments: true,
|
|
53
|
+
minifyCSS: true,
|
|
66
54
|
});
|
|
55
|
+
|
|
56
|
+
const combinedPath = path.join(reportsDir, "combined-report.html");
|
|
57
|
+
fs.writeFileSync(combinedPath, minified, "utf8");
|
|
58
|
+
|
|
59
|
+
console.log(`📄 Combined report generated at: ${combinedPath}`);
|
|
67
60
|
}
|
|
68
61
|
|
|
69
62
|
module.exports = { linkReports };
|
|
@@ -9,7 +9,6 @@ const buildK6Script = require("../lib/helpers/buildK6Script.js");
|
|
|
9
9
|
const generateHeaders = require("../lib/helpers/generateHeaders.js");
|
|
10
10
|
const { generateK6Script, runK6Script } = require("../lib/utils/k6Runner.js");
|
|
11
11
|
require("dotenv").config();
|
|
12
|
-
const axios = require("axios");
|
|
13
12
|
|
|
14
13
|
// Validate thresholds (e.g., "rate<0.01")
|
|
15
14
|
const validateThreshold = (threshold) => {
|
|
@@ -278,17 +277,22 @@ When(
|
|
|
278
277
|
});
|
|
279
278
|
|
|
280
279
|
try {
|
|
281
|
-
const response = await
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
);
|
|
280
|
+
const response = await fetch(`${process.env.BASE_URL}${endpoint}`, {
|
|
281
|
+
method: "POST",
|
|
282
|
+
headers: {
|
|
283
|
+
"Content-Type": "application/json",
|
|
284
|
+
},
|
|
285
|
+
body: JSON.stringify(resolved),
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const data = await response.json();
|
|
289
|
+
|
|
290
|
+
if (!response.ok) {
|
|
291
|
+
console.error("❌ Login request failed:", data);
|
|
292
|
+
throw new Error(`Login request failed with status ${response.status}`);
|
|
293
|
+
}
|
|
290
294
|
|
|
291
|
-
this.lastResponse =
|
|
295
|
+
this.lastResponse = data; // ✅ Makes aliasing work
|
|
292
296
|
console.log("🔐 Login successful, response saved to alias context.");
|
|
293
297
|
} catch (err) {
|
|
294
298
|
console.error("❌ Login request failed:", err.message);
|