k6-cucumber-steps 1.0.26 → 1.0.28
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 +10 -3
- package/bin/k6-cucumber-runner.js +61 -17
- package/cucumber.js +4 -3
- package/lib/utils/k6Runner.js +24 -5
- package/package.json +1 -1
- package/step_definitions/load_test_steps.js +14 -2
- package/step_definitions/world.js +7 -3
package/README.md
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/k6-cucumber-steps)
|
|
8
8
|
[](https://www.npmjs.com/package/k6-cucumber-steps)
|
|
9
9
|
[](https://github.com/qaPaschalE/k6-cucumber-steps/blob/main/LICENSE)
|
|
10
|
-
|
|
11
10
|
[](https://cucumber.io/)
|
|
12
11
|
[](https://nodejs.org/)
|
|
13
12
|
[](https://github.com/sponsors/qaPaschalE)
|
|
@@ -20,13 +19,19 @@ Run [k6](https://k6.io/) performance/load tests using [Cucumber](https://cucumbe
|
|
|
20
19
|
## ✨ Features
|
|
21
20
|
|
|
22
21
|
- ✅ Cucumber + Gherkin for writing k6 tests
|
|
22
|
+
to generate JSON and HTML reports.
|
|
23
|
+
- ✅ Flexible configuration through Cucumber data tables.
|
|
23
24
|
- ✅ Support for JSON body parsing and escaping
|
|
24
|
-
- ✅ Faker
|
|
25
|
+
- ✅ Dynamic request body generation using environment variables, Faker templates, and JSON file includes.
|
|
25
26
|
- ✅ `.env` + `K6.env`-style variable resolution (`{{API_KEY}}`)
|
|
26
27
|
- ✅ Support for headers, query params, stages
|
|
28
|
+
- ✅ Supports multiple authentication types: API key, Bearer token, Basic Auth, and No Auth.
|
|
29
|
+
|
|
27
30
|
- ✅ Clean-up of temporary k6 files after execution
|
|
28
31
|
- ✅ Built-in support for **distributed load testing** with stages
|
|
29
32
|
- ✅ TypeScript-first 🧡
|
|
33
|
+
- ✅ **Optional report overwriting**: Use the `overwrite` option to control whether reports are overwritten or appended.
|
|
34
|
+
- ✅ **Generate detailed reports**: Use the `--reporter` flag
|
|
30
35
|
|
|
31
36
|
---
|
|
32
37
|
|
|
@@ -50,7 +55,8 @@ The `run` command accepts the following options:
|
|
|
50
55
|
|
|
51
56
|
- `-f, --feature <path>`: Path to the feature file to execute.
|
|
52
57
|
- `-t, --tags <string>`: Cucumber tags to filter scenarios (e.g., `@smoke and not @regression`).
|
|
53
|
-
- `-r, --reporter`: Generate HTML and JSON reports in the `reports` directory. This is a boolean flag, so just include `-r
|
|
58
|
+
- `-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
|
+
- `-o, --overwrite`: Overwrite existing reports instead of appending them.
|
|
54
60
|
|
|
55
61
|
### Example Usage with Options
|
|
56
62
|
|
|
@@ -117,6 +123,7 @@ Here's a step-by-step guide to using `k6-cucumber-steps` in your project:
|
|
|
117
123
|
"html:reports/report.html", // For HTML report (requires @cucumber/html-formatter)
|
|
118
124
|
],
|
|
119
125
|
tags: process.env.TAGS,
|
|
126
|
+
overwrite: false, // Default to not overwrite the report file
|
|
120
127
|
};
|
|
121
128
|
```
|
|
122
129
|
|
|
@@ -8,21 +8,32 @@ const path = require("path");
|
|
|
8
8
|
const { spawn } = require("child_process");
|
|
9
9
|
require("dotenv").config();
|
|
10
10
|
const argv = require("yargs")
|
|
11
|
-
.usage("Usage: $0 run [options]")
|
|
11
|
+
.usage("Usage: $0 run [options]")
|
|
12
12
|
.option("feature", {
|
|
13
13
|
alias: "f",
|
|
14
14
|
describe: "Path to the feature file",
|
|
15
15
|
type: "string",
|
|
16
|
-
})
|
|
17
|
-
.option("tags", {
|
|
16
|
+
})
|
|
17
|
+
.option("tags", {
|
|
18
|
+
alias: "t",
|
|
19
|
+
describe: "Cucumber tags to filter scenarios (e.g., @smoke)",
|
|
20
|
+
type: "string",
|
|
21
|
+
})
|
|
18
22
|
.option("reporter", {
|
|
19
23
|
alias: "r",
|
|
20
|
-
describe: "Generate reports",
|
|
24
|
+
describe: "Generate HTML and JSON reports in the `reports` directory",
|
|
25
|
+
type: "boolean",
|
|
26
|
+
default: false,
|
|
27
|
+
})
|
|
28
|
+
.option("overwrite", {
|
|
29
|
+
alias: "o",
|
|
30
|
+
describe: "Overwrite existing reports instead of appending them",
|
|
21
31
|
type: "boolean",
|
|
22
32
|
default: false,
|
|
23
33
|
})
|
|
24
34
|
.help().argv;
|
|
25
35
|
|
|
36
|
+
// Base Cucumber command and arguments
|
|
26
37
|
const cucumberCommand = "npx";
|
|
27
38
|
const cucumberArgs = [
|
|
28
39
|
"cucumber-js",
|
|
@@ -36,39 +47,72 @@ const cucumberArgs = [
|
|
|
36
47
|
"step_definitions"
|
|
37
48
|
),
|
|
38
49
|
"--require",
|
|
39
|
-
path.resolve(process.cwd(), "step_definitions"), //
|
|
50
|
+
path.resolve(process.cwd(), "step_definitions"), // Include user's local step definitions
|
|
40
51
|
"--format",
|
|
41
52
|
"summary",
|
|
42
53
|
"--format",
|
|
43
|
-
"progress", //
|
|
54
|
+
"progress", // Progress bar format
|
|
44
55
|
];
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
// Add tags from CLI or environment variables
|
|
58
|
+
if (argv.tags) {
|
|
59
|
+
cucumberArgs.push("--tags", argv.tags);
|
|
60
|
+
} else if (process.env.TAGS) {
|
|
61
|
+
cucumberArgs.push("--tags", process.env.TAGS);
|
|
62
|
+
}
|
|
48
63
|
|
|
64
|
+
// Add feature file if provided
|
|
49
65
|
if (argv.feature) {
|
|
50
66
|
cucumberArgs.push(path.resolve(process.cwd(), argv.feature));
|
|
51
67
|
}
|
|
52
68
|
|
|
69
|
+
// Add reporting options if enabled
|
|
53
70
|
if (argv.reporter) {
|
|
54
71
|
const reportsDir = path.resolve(process.cwd(), "reports");
|
|
72
|
+
try {
|
|
73
|
+
require("fs").mkdirSync(reportsDir, { recursive: true }); // Ensure reports directory exists
|
|
74
|
+
} catch (err) {
|
|
75
|
+
console.error(`Failed to create reports directory: ${err.message}`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
55
78
|
cucumberArgs.push(
|
|
56
79
|
"--format",
|
|
57
|
-
`json:${reportsDir
|
|
80
|
+
`json:${path.join(reportsDir, "load-results.json")}`,
|
|
58
81
|
"--format",
|
|
59
|
-
`html:${reportsDir
|
|
82
|
+
`html:${path.join(reportsDir, "load-results.html")}`
|
|
60
83
|
);
|
|
61
84
|
}
|
|
62
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Main function to execute the Cucumber process.
|
|
88
|
+
*/
|
|
63
89
|
async function main() {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
90
|
+
try {
|
|
91
|
+
const cucumberProcess = spawn(cucumberCommand, cucumberArgs, {
|
|
92
|
+
cwd: process.cwd(),
|
|
93
|
+
stdio: "inherit", // Inherit stdout/stderr for real-time logging
|
|
94
|
+
env: {
|
|
95
|
+
...process.env,
|
|
96
|
+
K6_CUCUMBER_OVERWRITE: argv.overwrite, // Pass overwrite flag to environment
|
|
97
|
+
},
|
|
98
|
+
});
|
|
68
99
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
100
|
+
cucumberProcess.on("close", (code) => {
|
|
101
|
+
if (code === 0) {
|
|
102
|
+
console.log("-----------------------------------------");
|
|
103
|
+
console.log("✅ k6-cucumber-steps execution completed successfully.");
|
|
104
|
+
console.log("-----------------------------------------");
|
|
105
|
+
} else {
|
|
106
|
+
console.error("-----------------------------------------");
|
|
107
|
+
console.error("❌ k6-cucumber-steps execution failed.");
|
|
108
|
+
console.error("-----------------------------------------");
|
|
109
|
+
}
|
|
110
|
+
process.exit(code);
|
|
111
|
+
});
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error("An unexpected error occurred:", error.message);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
72
116
|
}
|
|
73
117
|
|
|
74
118
|
main().catch((err) => console.error(err));
|
package/cucumber.js
CHANGED
|
@@ -4,10 +4,11 @@ module.exports = {
|
|
|
4
4
|
require: ["./step_definitions/**/*.js"],
|
|
5
5
|
format: [
|
|
6
6
|
"summary",
|
|
7
|
-
"json:reports/load-report.json",
|
|
8
|
-
"html:reports/report.html",
|
|
7
|
+
"json:src/examples/reports/load-report.json",
|
|
8
|
+
"html:src/examples/reports/report.html",
|
|
9
9
|
],
|
|
10
10
|
// Specify the path to your features folder here
|
|
11
|
-
paths: ["./features"],
|
|
11
|
+
paths: ["./src/examples/features/loadTestTemplate.feature"],
|
|
12
12
|
tags: "@loadTest", // Default tag for load tests
|
|
13
|
+
overwrite: false, // Default to not overwrite the report file
|
|
13
14
|
};
|
package/lib/utils/k6Runner.js
CHANGED
|
@@ -8,15 +8,33 @@ const packageJson = require("../../package.json"); // Access package version
|
|
|
8
8
|
* Generates a temporary k6 script file.
|
|
9
9
|
* @param {string} scriptContent - The content of the k6 script.
|
|
10
10
|
* @param {string} [scriptType='load'] - Type of script (e.g., 'load').
|
|
11
|
+
* @param {boolean} [overwrite=false] - Whether to overwrite the report file.
|
|
11
12
|
* @returns {Promise<string>} - Path to the generated k6 script file.
|
|
12
13
|
*/
|
|
13
|
-
const generateK6Script = async (
|
|
14
|
+
const generateK6Script = async (
|
|
15
|
+
scriptContent,
|
|
16
|
+
scriptType = "load",
|
|
17
|
+
overwrite = false
|
|
18
|
+
) => {
|
|
14
19
|
const tempDir = path.resolve(__dirname, "../../temp");
|
|
15
20
|
const scriptName = `${scriptType}_script_${uuidv4()}.js`;
|
|
16
21
|
const scriptPath = path.join(tempDir, scriptName);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
await fs.mkdir(tempDir, { recursive: true }); // Ensure temp directory exists
|
|
25
|
+
|
|
26
|
+
// Write the script content based on the overwrite flag
|
|
27
|
+
if (overwrite) {
|
|
28
|
+
await fs.writeFile(scriptPath, scriptContent, { flag: "w" }); // Overwrite mode
|
|
29
|
+
} else {
|
|
30
|
+
await fs.appendFile(scriptPath, scriptContent); // Append mode
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return scriptPath;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error(`Error generating k6 script: ${error.message}`);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
20
38
|
};
|
|
21
39
|
|
|
22
40
|
/**
|
|
@@ -29,9 +47,10 @@ const delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
|
29
47
|
/**
|
|
30
48
|
* Runs the k6 script with custom branding.
|
|
31
49
|
* @param {string} scriptPath - Path to the k6 script file.
|
|
50
|
+
* @param {boolean} [overwrite=false] - Whether to overwrite the report file.
|
|
32
51
|
* @returns {Promise<string>} - Standard output from k6 execution.
|
|
33
52
|
*/
|
|
34
|
-
const runK6Script = async (scriptPath) => {
|
|
53
|
+
const runK6Script = async (scriptPath, overwrite = false) => {
|
|
35
54
|
// ANSI escape codes for colors
|
|
36
55
|
const chalkGreen = "\x1b[38;2;0;255;0m"; // Green
|
|
37
56
|
const chalkYellow = "\x1b[38;2;255;255;0m"; // Yellow
|
package/package.json
CHANGED
|
@@ -174,11 +174,23 @@ Then(
|
|
|
174
174
|
);
|
|
175
175
|
}
|
|
176
176
|
try {
|
|
177
|
+
// Generate the k6 script content
|
|
177
178
|
const scriptContent = buildK6Script(this.config);
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
|
|
180
|
+
// Generate the temporary k6 script file with overwrite option
|
|
181
|
+
const scriptPath = await generateK6Script(
|
|
182
|
+
scriptContent,
|
|
183
|
+
"load",
|
|
184
|
+
this.overwrite
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// Run the k6 script with overwrite option
|
|
188
|
+
const stdout = await runK6Script(scriptPath, this.overwrite);
|
|
189
|
+
|
|
190
|
+
console.log(stdout);
|
|
180
191
|
} catch (error) {
|
|
181
192
|
console.error("k6 execution failed:", error.message);
|
|
193
|
+
console.error("k6 stderr:", error.stderr); // Log stderr for debugging
|
|
182
194
|
throw new Error("k6 test execution failed");
|
|
183
195
|
}
|
|
184
196
|
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
const { setWorldConstructor } = require(
|
|
1
|
+
const { setWorldConstructor } = require("@cucumber/cucumber");
|
|
2
2
|
|
|
3
3
|
class CustomWorld {
|
|
4
|
-
constructor() {
|
|
4
|
+
constructor({ parameters }) {
|
|
5
5
|
this.options = {};
|
|
6
6
|
this.configurations = {};
|
|
7
7
|
this.endpoints = [];
|
|
8
|
-
this.authType =
|
|
8
|
+
this.authType = "";
|
|
9
9
|
this.postBody = {};
|
|
10
|
+
this.overwrite =
|
|
11
|
+
parameters?.overwrite ||
|
|
12
|
+
process.env.K6_CUCUMBER_OVERWRITE === "true" ||
|
|
13
|
+
false;
|
|
10
14
|
}
|
|
11
15
|
}
|
|
12
16
|
|