k6-cucumber-steps 1.0.11 → 1.0.13

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/.env CHANGED
@@ -10,7 +10,7 @@ TAGS=@loadTest
10
10
  # Base URLs
11
11
  # API_URL=https://unstable-performance.seamlesshrms.com
12
12
  # BASE_URL=https://unstable-performance.seamlesshrms.com
13
- BASE_URL=https://reqres.in
13
+ BASE_URL=https://postman-echo.com
14
14
 
15
15
  # Secret Parameters
16
16
  API_KEY=Talent123!
@@ -1,57 +1,75 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ console.log("-----------------------------------------");
4
+ console.log("🚀 Starting k6-cucumber-steps execution...");
5
+ console.log("-----------------------------------------");
6
+
3
7
  const path = require("path");
4
- const { runCucumber } = require("@cucumber/cucumber/api");
8
+ const { spawn } = require("child_process");
5
9
  require("dotenv").config();
6
-
7
10
  const argv = require("yargs")
8
- .usage("Usage: $0 run --feature <path> [options]")
11
+ .usage("Usage: $0 run [options]") // Removed the --feature requirement from usage
9
12
  .option("feature", {
10
13
  alias: "f",
11
14
  describe: "Path to the feature file",
12
15
  type: "string",
13
- demandOption: true,
16
+ }) // Keep the option but don't demand it
17
+ .option("tags", { alias: "t", describe: "Cucumber tags", type: "string" })
18
+ .option("reporter", {
19
+ alias: "r",
20
+ describe: "Generate reports",
21
+ type: "boolean",
22
+ default: false,
14
23
  })
15
24
  .help().argv;
16
25
 
17
- const featureFilePath = path.resolve(process.cwd(), argv.feature);
26
+ const cucumberCommand = "npx";
27
+ const cucumberArgs = [
28
+ "cucumber-js",
29
+ "--require-module",
30
+ "@babel/register",
31
+ "--require",
32
+ path.resolve(
33
+ process.cwd(),
34
+ "node_modules",
35
+ "k6-cucumber-steps",
36
+ "step_definitions"
37
+ ),
38
+ "--require",
39
+ path.resolve(process.cwd(), "step_definitions"), // Keep the user's local step definitions as well
40
+ "--format",
41
+ "summary",
42
+ "--format",
43
+ "cucumber-console-formatter", // Add this line
44
+ ];
45
+
46
+ // Explicitly add tags, defaulting to '@loadTest' if no TAGS env variable is set
47
+ const tagsFromEnv = process.env.TAGS || "@loadTest";
48
+ cucumberArgs.push("--tags", tagsFromEnv);
49
+
50
+ if (argv.feature) {
51
+ cucumberArgs.push(path.resolve(process.cwd(), argv.feature));
52
+ }
53
+
54
+ if (argv.reporter) {
55
+ const reportsDir = path.resolve(process.cwd(), "reports");
56
+ cucumberArgs.push(
57
+ "--format",
58
+ `json:${reportsDir}/load-results.json`,
59
+ "--format",
60
+ `html:${reportsDir}/load-results.html`
61
+ );
62
+ }
18
63
 
19
64
  async function main() {
20
- try {
21
- console.log(`Running tests for feature file: ${featureFilePath}`);
22
-
23
- const result = await runCucumber({
24
- argv: [
25
- "node",
26
- "cucumber-js",
27
- "--require-module",
28
- "@babel/register",
29
- "--require",
30
- path.resolve(
31
- process.cwd(),
32
- "node_modules",
33
- "k6-cucumber-steps",
34
- "step_definitions"
35
- ),
36
- ],
37
- cwd: process.cwd(),
38
- featurePaths: [featureFilePath],
39
- format: ["summary"],
40
- });
41
-
42
- if (!result.success) {
43
- console.error("K6 Cucumber tests failed.");
44
- process.exit(1);
45
- }
46
-
47
- console.log("K6 Cucumber tests finished successfully.");
48
- } catch (error) {
49
- console.error("An error occurred during K6 Cucumber execution:", error);
50
- process.exit(1);
51
- }
65
+ const cucumberProcess = spawn(cucumberCommand, cucumberArgs, {
66
+ cwd: process.cwd(),
67
+ stdio: "inherit",
68
+ });
69
+
70
+ cucumberProcess.on("close", (code) => {
71
+ process.exit(code);
72
+ });
52
73
  }
53
74
 
54
- main().catch((err) => {
55
- console.error("An unexpected error occurred:", err);
56
- process.exit(1);
57
- });
75
+ main().catch((err) => console.error(err));
package/cucumber.js CHANGED
@@ -1,26 +1,13 @@
1
- /**
2
- * @module cucumber
3
- * @description
4
- * This module configures the Cucumber.js test runner for load testing with k6.
5
- * It specifies the paths to feature files, step definitions, and the output format.
6
- * It also sets the timeout for each test and allows for filtering tests by tags.
7
- */
8
- const reporter = require("cucumber-html-reporter");
1
+ // cucumber.js
2
+
9
3
  module.exports = {
10
- default: {
11
- require: ["step_definitions/world.js", "step_definitions/*.js"],
12
- paths: ["src/examples/features/*.feature"],
13
- format: ["progress", "json:reports/load-results.json"],
14
- timeout: 60000,
15
- tags: process.env.TAGS || "@loadTest",
16
- },
4
+ require: ["./step_definitions/**/*.js"],
5
+ format: [
6
+ "summary",
7
+ "json:reports/load-report.json",
8
+ "html:reports/report.html",
9
+ ],
10
+ // Specify the path to your features folder here
11
+ paths: ["./features"],
12
+ tags: "@loadTest", // Default tag for load tests
17
13
  };
18
-
19
- // // Generate an HTML report after tests complete
20
- // reporter.generate({
21
- // theme: "bootstrap",
22
- // jsonFile: "reports/load-results.json",
23
- // output: "reports/report.html",
24
- // reportSuiteAsScenarios: true,
25
- // scenarioTimestamp: true,
26
- // });
@@ -1,34 +1,5 @@
1
- /**
2
- * @module generateHeaders
3
- * @description
4
- * This module generates HTTP headers for API requests based on the specified authentication type.
5
- * It supports API key, bearer token, and basic authentication.
6
- * Generates HTTP headers based on the specified authentication type.
7
- * Supported auth types: api_key, bearer_token, basic.
8
- * @param {string} authType - The type of authentication to use.
9
- * @param {object} env - The environment variables object.
10
- * @returns {object} - The generated headers object.
11
- * @throws {Error} - If the authentication type is unsupported.
12
- * @example
13
- * const headers = generateHeaders('api_key', process.env);
14
- * // headers will contain the API key in the x-api-key header.
15
- * @example
16
- * const headers = generateHeaders('bearer_token', process.env);
17
- * // headers will contain the bearer token in the Authorization header.
18
- * @example
19
- * const headers = generateHeaders('basic', process.env);
20
- * // headers will contain the basic auth credentials in the Authorization header.
21
- * @example
22
- * const headers = generateHeaders('none', process.env);
23
- * // headers will contain only the Content-Type header.
24
- * @example
25
- * const headers = generateHeaders('invalid_auth_type', process.env);
26
- * // throws an error: Unsupported authentication type: invalid_auth_type
27
- */
28
-
29
1
  module.exports = function buildK6Script(config) {
30
2
  const { method, endpoints, endpoint, body, headers, options } = config;
31
- console.log("Generating k6 script with config:", config);
32
3
  // Ensure at least one of `endpoints` or `endpoint` is defined
33
4
  if (!endpoints?.length && !endpoint) {
34
5
  throw new Error(
@@ -1,71 +1,87 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { v4 as uuidv4 } from "uuid";
4
- import { spawn } from "child_process";
1
+ const path = require("path");
2
+ const { exec } = require("child_process");
3
+ const { v4: uuidv4 } = require("uuid");
4
+ const fs = require("fs").promises; // Use promises for cleaner async/await
5
+ const packageJson = require("../../package.json"); // Access package version
5
6
 
6
7
  /**
7
8
  * Generates a temporary k6 script file.
8
9
  * @param {string} scriptContent - The content of the k6 script.
9
- * @param {string} scriptType - The type of script (default: "k6").
10
- * @returns {string} - The path to the generated temporary script file.
10
+ * @param {string} [scriptType='load'] - Type of script (e.g., 'load').
11
+ * @returns {Promise<string>} - Path to the generated k6 script file.
11
12
  */
12
- export function generateK6Script(scriptContent, scriptType = "k6") {
13
- const tempFileName = `${scriptType}_script_${uuidv4()}.js`;
14
- const tempFilePath = path.join(process.cwd(), "tmp", tempFileName);
15
-
16
- // Ensure the directory exists and write the script content
17
- fs.mkdirSync(path.dirname(tempFilePath), { recursive: true });
18
- fs.writeFileSync(tempFilePath, scriptContent);
19
- return tempFilePath;
20
- }
13
+ const generateK6Script = async (scriptContent, scriptType = "load") => {
14
+ const tempDir = path.resolve(__dirname, "../../temp");
15
+ const scriptName = `${scriptType}_script_${uuidv4()}.js`;
16
+ 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;
20
+ };
21
21
 
22
22
  /**
23
- * Runs the k6 script using the `k6 run` command.
24
- * @param {string} scriptPath - The path to the k6 script file.
25
- * @returns {Promise<string>} - Resolves with the stdout of the k6 execution.
23
+ * Introduce a delay in milliseconds.
24
+ * @param {number} ms - The duration of the delay in milliseconds.
25
+ * @returns {Promise<void>} - A Promise that resolves after the delay.
26
26
  */
27
+ const delay = (ms) => new Promise((res) => setTimeout(res, ms));
27
28
 
28
- export async function runK6Script(scriptPath) {
29
- return new Promise((resolve, reject) => {
30
- const k6Process = spawn("k6", ["run", scriptPath]);
29
+ /**
30
+ * Runs the k6 script with custom branding.
31
+ * @param {string} scriptPath - Path to the k6 script file.
32
+ * @returns {Promise<string>} - Standard output from k6 execution.
33
+ */
34
+ const runK6Script = async (scriptPath) => {
35
+ // ANSI escape codes for colors
36
+ const chalkGreen = "\x1b[38;2;0;255;0m"; // Green
37
+ const chalkYellow = "\x1b[38;2;255;255;0m"; // Yellow
38
+ const resetColor = "\x1b[0m";
31
39
 
32
- let stdout = "";
33
- let stderr = "";
40
+ // Custom logo with version information
41
+ const customLogo = `${chalkGreen} with @qaPaschalE's ${chalkYellow}k6-cucumber-steps v${packageJson.version}${resetColor}`;
34
42
 
35
- // Capture stdout and log it in real-time
36
- k6Process.stdout.on("data", (data) => {
37
- stdout += data.toString();
38
- console.log(data.toString()); // Log output in real-time
39
- });
43
+ return new Promise(async (resolve, reject) => {
44
+ exec(
45
+ `k6 run --vus 1 --iterations 1 "${scriptPath}"`,
46
+ async (error, stdout, stderr) => {
47
+ // Split the k6 logo lines
48
+ const logoLines = stdout.split("\n");
40
49
 
41
- // Capture stderr and log it in real-time
42
- k6Process.stderr.on("data", (data) => {
43
- stderr += data.toString();
44
- console.error(data.toString()); // Log errors in real-time
45
- });
50
+ // Insert the custom logo under "Grafana" (on the third line)
51
+ let modifiedStdout = "";
52
+ for (let i = 0; i < logoLines.length; i++) {
53
+ modifiedStdout += logoLines[i];
54
+ if (i === 5) {
55
+ // Target the third line (index 2) of the k6 logo
56
+ modifiedStdout += ` ${customLogo}\n`;
57
+ }
58
+ modifiedStdout += "\n";
59
+ }
46
60
 
47
- // Handle process exit
48
- k6Process.on("close", (code) => {
49
- // Always clean up temp file
50
- fs.unlink(scriptPath, (unlinkErr) => {
51
- if (unlinkErr) {
52
- console.warn(`Failed to delete temp script: ${unlinkErr.message}`);
61
+ // Handle errors and cleanup
62
+ if (error) {
63
+ console.error("k6 error:", error);
64
+ console.error("k6 stdout:", modifiedStdout);
65
+ await delay(3000); // Wait for 3 seconds
66
+ console.error("k6 stderr:", stderr);
67
+ reject(new Error(`k6 test execution failed: ${error.message}`));
68
+ } else if (stderr) {
69
+ console.log("k6 stdout:", modifiedStdout);
70
+ await delay(3000); // Wait for 3 seconds
71
+ resolve(stdout);
72
+ } else {
73
+ console.log("k6 stdout:", modifiedStdout);
74
+ await delay(3000); // Wait for 3 seconds
75
+ resolve(stdout);
53
76
  }
54
- });
55
77
 
56
- if (code !== 0) {
57
- console.error("k6 run failed with code:", code);
58
- console.error("stderr:", stderr);
59
- reject(new Error(`k6 run failed with code ${code}: ${stderr}`));
60
- } else {
61
- resolve(stdout);
78
+ // Clean up the temporary script file
79
+ fs.unlink(scriptPath).catch((err) =>
80
+ console.error("Error deleting temporary k6 script:", err)
81
+ );
62
82
  }
63
- });
64
-
65
- // Handle spawn errors
66
- k6Process.on("error", (err) => {
67
- console.error("Failed to start k6 process:", err.message);
68
- reject(err);
69
- });
83
+ );
70
84
  });
71
- }
85
+ };
86
+
87
+ module.exports = { generateK6Script, runK6Script };
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "k6-cucumber-steps",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "main": "index.js",
5
+ "license": "MIT",
5
6
  "repository": {
6
7
  "type": "git",
7
8
  "url": "https://github.com/qaPaschalE/k6-cucumber-steps.git"
@@ -43,7 +44,6 @@
43
44
  "node": ">=18"
44
45
  },
45
46
  "author": "qaPaschalE",
46
- "license": "ISC",
47
47
  "description": "Cucumber step definitions for running k6 performance tests.",
48
48
  "devDependencies": {
49
49
  "@babel/cli": "^7.27.0",
@@ -51,6 +51,7 @@
51
51
  "@babel/preset-env": "^7.26.9",
52
52
  "@types/k6": "^1.0.2",
53
53
  "child_process": "^1.0.2",
54
+ "cucumber-console-formatter": "^1.0.0",
54
55
  "cucumber-html-reporter": "^6.0.0",
55
56
  "esbuild": "^0.25.3",
56
57
  "form-data": "^4.0.2",