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 CHANGED
@@ -7,7 +7,6 @@
7
7
  [![npm version](https://img.shields.io/npm/v/k6-cucumber-steps.svg)](https://www.npmjs.com/package/k6-cucumber-steps)
8
8
  [![npm downloads](https://img.shields.io/npm/dt/k6-cucumber-steps.svg)](https://www.npmjs.com/package/k6-cucumber-steps)
9
9
  [![license](https://img.shields.io/npm/l/k6-cucumber-steps)](https://github.com/qaPaschalE/k6-cucumber-steps/blob/main/LICENSE)
10
-
11
10
  [![Cucumber](https://img.shields.io/badge/built%20with-Cucumber-3178c6.svg)](https://cucumber.io/)
12
11
  [![Node.js](https://img.shields.io/badge/node-%3E=18-green.svg)](https://nodejs.org/)
13
12
  [![Sponsor](https://img.shields.io/github/sponsors/qaPaschalE?style=social)](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 support (`{{faker.name.firstName}}`)
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` or `--reporter` to enable it.
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]") // Removed the --feature requirement from usage
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
- }) // Keep the option but don't demand it
17
- .option("tags", { alias: "t", describe: "Cucumber tags", type: "string" })
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"), // Keep the user's local step definitions as well
50
+ path.resolve(process.cwd(), "step_definitions"), // Include user's local step definitions
40
51
  "--format",
41
52
  "summary",
42
53
  "--format",
43
- "progress", // Add this line
54
+ "progress", // Progress bar format
44
55
  ];
45
56
 
46
- const tagsFromEnv = process.env.TAGS || " ";
47
- cucumberArgs.push("--tags", tagsFromEnv);
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}/load-results.json`,
80
+ `json:${path.join(reportsDir, "load-results.json")}`,
58
81
  "--format",
59
- `html:${reportsDir}/load-results.html`
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
- const cucumberProcess = spawn(cucumberCommand, cucumberArgs, {
65
- cwd: process.cwd(),
66
- stdio: "inherit",
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
- cucumberProcess.on("close", (code) => {
70
- process.exit(code);
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
  };
@@ -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 (scriptContent, scriptType = "load") => {
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
- await fs.mkdir(tempDir, { recursive: true }); // Ensure temp directory exists
18
- await fs.writeFile(scriptPath, scriptContent, "utf8");
19
- return scriptPath;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "k6-cucumber-steps",
3
- "version": "1.0.26",
3
+ "version": "1.0.28",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -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
- const scriptPath = await generateK6Script(scriptContent);
179
- const stdout = await runK6Script(scriptPath);
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('@cucumber/cucumber');
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