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 +1 -1
- package/bin/k6-cucumber-runner.js +59 -41
- package/cucumber.js +11 -24
- package/lib/helpers/buildK6Script.js +0 -29
- package/lib/utils/k6Runner.js +70 -54
- package/package.json +3 -2
- package/reports/load-results.html +1 -1
- package/reports/load-results.json +16 -14
- package/reports/report.html +13 -57
- package/step_definitions/load_test_steps.js +1 -33
- package/temp/load_script_2a96242d-8924-468d-a0f1-3f9555b4eef1.js +44 -0
- package/temp/load_script_e2119cce-eeb0-4b11-82e1-12f6827d6a82.js +44 -0
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://
|
|
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 {
|
|
8
|
+
const { spawn } = require("child_process");
|
|
5
9
|
require("dotenv").config();
|
|
6
|
-
|
|
7
10
|
const argv = require("yargs")
|
|
8
|
-
.usage("Usage: $0 run
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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(
|
package/lib/utils/k6Runner.js
CHANGED
|
@@ -1,71 +1,87 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 -
|
|
10
|
-
* @returns {string} -
|
|
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
|
-
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
fs.
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
*
|
|
24
|
-
* @param {
|
|
25
|
-
* @returns {Promise<
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
33
|
-
|
|
40
|
+
// Custom logo with version information
|
|
41
|
+
const customLogo = `${chalkGreen} with @qaPaschalE's ${chalkYellow}k6-cucumber-steps v${packageJson.version}${resetColor}`;
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
console.
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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.
|
|
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",
|