k6-cucumber-steps 1.2.27 → 2.0.0
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 +190 -177
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +72 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.command.d.ts +4 -0
- package/dist/commands/init.command.d.ts.map +1 -0
- package/dist/commands/init.command.js +30 -0
- package/dist/commands/init.command.js.map +1 -0
- package/dist/generators/feature.parser.d.ts +12 -0
- package/dist/generators/feature.parser.d.ts.map +1 -0
- package/dist/generators/feature.parser.js +208 -0
- package/dist/generators/feature.parser.js.map +1 -0
- package/dist/generators/k6-script.generator.d.ts +11 -0
- package/dist/generators/k6-script.generator.d.ts.map +1 -0
- package/dist/generators/k6-script.generator.js +233 -0
- package/dist/generators/k6-script.generator.js.map +1 -0
- package/dist/generators/project.generator.d.ts +14 -0
- package/dist/generators/project.generator.d.ts.map +1 -0
- package/dist/generators/project.generator.js +497 -0
- package/dist/generators/project.generator.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/runners/k6.runner.d.ts +19 -0
- package/dist/runners/k6.runner.d.ts.map +1 -0
- package/dist/runners/k6.runner.js +127 -0
- package/dist/runners/k6.runner.js.map +1 -0
- package/dist/step-registry.d.ts +14 -0
- package/dist/step-registry.d.ts.map +1 -0
- package/dist/step-registry.js +36 -0
- package/dist/step-registry.js.map +1 -0
- package/dist/types/index.d.ts +35 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +40 -62
- package/LICENSE +0 -21
- package/bin/k6-cucumber-steps.js +0 -176
- package/docs/data/search.json +0 -1
- package/docs/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/global.html +0 -36
- package/docs/index.html +0 -91
- package/docs/k6-cucumber-steps/1.2.8/data/search.json +0 -1
- package/docs/k6-cucumber-steps/1.2.8/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/k6-cucumber-steps/1.2.8/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/k6-cucumber-steps/1.2.8/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/k6-cucumber-steps/1.2.8/global.html +0 -3
- package/docs/k6-cucumber-steps/1.2.8/helpers_generateHeaders.js.html +0 -38
- package/docs/k6-cucumber-steps/1.2.8/helpers_resolveBody.js.html +0 -65
- package/docs/k6-cucumber-steps/1.2.8/index.html +0 -91
- package/docs/k6-cucumber-steps/1.2.8/module-generateHeaders.html +0 -3
- package/docs/k6-cucumber-steps/1.2.8/module-resolveBody.html +0 -3
- package/docs/k6-cucumber-steps/1.2.8/scripts/core.js +0 -726
- package/docs/k6-cucumber-steps/1.2.8/scripts/core.min.js +0 -23
- package/docs/k6-cucumber-steps/1.2.8/scripts/resize.js +0 -90
- package/docs/k6-cucumber-steps/1.2.8/scripts/search.js +0 -265
- package/docs/k6-cucumber-steps/1.2.8/scripts/search.min.js +0 -6
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/Apache-License-2.0.txt +0 -202
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/fuse.js +0 -9
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/hljs-line-num-original.js +0 -369
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/hljs-line-num.js +0 -1
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/hljs-original.js +0 -5171
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/hljs.js +0 -1
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/popper.js +0 -5
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/tippy.js +0 -1
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/tocbot.js +0 -672
- package/docs/k6-cucumber-steps/1.2.8/scripts/third-party/tocbot.min.js +0 -1
- package/docs/k6-cucumber-steps/1.2.8/styles/clean-jsdoc-theme-base.css +0 -1159
- package/docs/k6-cucumber-steps/1.2.8/styles/clean-jsdoc-theme-dark.css +0 -412
- package/docs/k6-cucumber-steps/1.2.8/styles/clean-jsdoc-theme-light.css +0 -482
- package/docs/k6-cucumber-steps/1.2.8/styles/clean-jsdoc-theme-scrollbar.css +0 -30
- package/docs/k6-cucumber-steps/1.2.8/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -1
- package/docs/k6-cucumber-steps/1.2.8/styles/clean-jsdoc-theme.min.css +0 -1
- package/docs/k6-cucumber-steps/1.2.8/utils_k6Runner.js.html +0 -95
- package/docs/load_test_steps.js.html +0 -664
- package/docs/scripts/core.js +0 -726
- package/docs/scripts/core.min.js +0 -23
- package/docs/scripts/resize.js +0 -90
- package/docs/scripts/search.js +0 -265
- package/docs/scripts/search.min.js +0 -6
- package/docs/scripts/third-party/Apache-License-2.0.txt +0 -202
- package/docs/scripts/third-party/fuse.js +0 -9
- package/docs/scripts/third-party/hljs-line-num-original.js +0 -369
- package/docs/scripts/third-party/hljs-line-num.js +0 -1
- package/docs/scripts/third-party/hljs-original.js +0 -5171
- package/docs/scripts/third-party/hljs.js +0 -1
- package/docs/scripts/third-party/popper.js +0 -5
- package/docs/scripts/third-party/tippy.js +0 -1
- package/docs/scripts/third-party/tocbot.js +0 -672
- package/docs/scripts/third-party/tocbot.min.js +0 -1
- package/docs/styles/clean-jsdoc-theme-base.css +0 -1159
- package/docs/styles/clean-jsdoc-theme-dark.css +0 -412
- package/docs/styles/clean-jsdoc-theme-light.css +0 -482
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -30
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -1
- package/docs/styles/clean-jsdoc-theme.min.css +0 -1
- package/index.js +0 -1
- package/lib/helpers/buildK6Script.d.ts +0 -1
- package/lib/helpers/buildK6Script.js +0 -103
- package/lib/helpers/generateHeaders.d.ts +0 -5
- package/lib/helpers/generateHeaders.js +0 -48
- package/lib/helpers/resolveBody.d.ts +0 -2
- package/lib/helpers/resolveBody.js +0 -78
- package/lib/helpers/resolvePayloadPath.js +0 -25
- package/lib/helpers/runK6ScriptFromWorld.js +0 -26
- package/lib/utils/k6Runner.d.ts +0 -6
- package/lib/utils/k6Runner.js +0 -89
- package/scripts/cucumber.js +0 -18
- package/scripts/linkReports.js +0 -107
- package/step_definitions/load_test_steps.d.ts +0 -89
- package/step_definitions/load_test_steps.js +0 -689
- package/step_definitions/world.js +0 -41
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module generateHeaders
|
|
3
|
-
* @description
|
|
4
|
-
* Generates HTTP headers for API requests based on the specified authentication type.
|
|
5
|
-
* Supports: api_key, bearer_token, basic, none, and alias-based token resolution.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export default function generateHeaders(authType, env = {}, aliases = {}) {
|
|
9
|
-
const headers = { "Content-Type": "application/json" };
|
|
10
|
-
|
|
11
|
-
const getValue = (key) => env[key] || aliases[key] || "";
|
|
12
|
-
|
|
13
|
-
switch (authType) {
|
|
14
|
-
case "api_key":
|
|
15
|
-
headers["x-api-key"] = getValue("API_KEY");
|
|
16
|
-
break;
|
|
17
|
-
|
|
18
|
-
case "bearer_token":
|
|
19
|
-
headers["Authorization"] = `Bearer ${getValue("token")}`;
|
|
20
|
-
break;
|
|
21
|
-
|
|
22
|
-
case "basic":
|
|
23
|
-
const user = getValue("BASIC_USER");
|
|
24
|
-
const pass = getValue("BASIC_PASS");
|
|
25
|
-
if (!user || !pass) {
|
|
26
|
-
throw new Error("Missing BASIC_USER or BASIC_PASS for basic auth.");
|
|
27
|
-
}
|
|
28
|
-
headers["Authorization"] = `Basic ${Buffer.from(
|
|
29
|
-
`${user}:${pass}`
|
|
30
|
-
).toString("base64")}`;
|
|
31
|
-
break;
|
|
32
|
-
|
|
33
|
-
case "none":
|
|
34
|
-
// Only content-type
|
|
35
|
-
break;
|
|
36
|
-
|
|
37
|
-
default:
|
|
38
|
-
if (aliases[authType]) {
|
|
39
|
-
headers["Authorization"] = `Bearer ${getValue(authType)}`;
|
|
40
|
-
} else {
|
|
41
|
-
throw new Error(
|
|
42
|
-
`Unsupported authentication type or missing alias: ${authType}`
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return headers;
|
|
48
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
import { faker } from "@faker-js/faker";
|
|
5
|
-
|
|
6
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
-
const __dirname = path.dirname(__filename);
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Recursively resolves all placeholders in an object.
|
|
11
|
-
* @param {*} data - The parsed JSON (object, array, string, etc)
|
|
12
|
-
* @param {object} env - Environment variables + aliases
|
|
13
|
-
* @returns {*} - Fully resolved structure
|
|
14
|
-
*/
|
|
15
|
-
function resolveDeep(data, env) {
|
|
16
|
-
if (typeof data === "string") {
|
|
17
|
-
// 1. Resolve env vars like {{username}}
|
|
18
|
-
data = data.replace(/{{(\w+)}}/g, (_, key) => {
|
|
19
|
-
return env[key] || "";
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// 2. Resolve faker like {{faker.internet.email}}
|
|
23
|
-
data = data.replace(/{{faker\.([\w.]+)}}/g, (_, methodPath) => {
|
|
24
|
-
const parts = methodPath.split(".");
|
|
25
|
-
let fn = faker;
|
|
26
|
-
for (const part of parts) {
|
|
27
|
-
fn = fn?.[part];
|
|
28
|
-
if (!fn) throw new Error(`Invalid Faker method: faker.${methodPath}`);
|
|
29
|
-
}
|
|
30
|
-
return typeof fn === "function" ? fn() : fn;
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// 3. Replace JSON file includes like <address.json>
|
|
34
|
-
data = data.replace(/<([\w-]+\.json)>/g, (_, fileName) => {
|
|
35
|
-
const filePath = path.join(__dirname, "../payloads", fileName);
|
|
36
|
-
if (!fs.existsSync(filePath)) {
|
|
37
|
-
throw new Error(`Payload file not found: ${fileName}`);
|
|
38
|
-
}
|
|
39
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
40
|
-
return fileContent.trim();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
return data;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (Array.isArray(data)) {
|
|
47
|
-
return data.map((item) => resolveDeep(item, env));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (typeof data === "object" && data !== null) {
|
|
51
|
-
const resolved = {};
|
|
52
|
-
for (const key in data) {
|
|
53
|
-
resolved[key] = resolveDeep(data[key], env);
|
|
54
|
-
}
|
|
55
|
-
return resolved;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return data;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Resolves JSON templates using env vars, Faker, and JSON includes.
|
|
63
|
-
* @param {string} template - The raw JSON string template
|
|
64
|
-
* @param {object} env - Object containing environment variables or aliases
|
|
65
|
-
* @returns {object} - Fully resolved JS object
|
|
66
|
-
*/
|
|
67
|
-
export default function resolveBody(template, env = {}) {
|
|
68
|
-
try {
|
|
69
|
-
const parsed = JSON.parse(template);
|
|
70
|
-
return resolveDeep(parsed, env);
|
|
71
|
-
} catch (err) {
|
|
72
|
-
console.error(
|
|
73
|
-
"❌ Failed to parse input JSON before resolving:",
|
|
74
|
-
err.message
|
|
75
|
-
);
|
|
76
|
-
throw new Error("Invalid JSON template provided to resolveBody");
|
|
77
|
-
}
|
|
78
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Resolves the full path to a payload file based on a root directory (e.g., from config)
|
|
6
|
-
* and filename. Throws a clear error if file does not exist.
|
|
7
|
-
*
|
|
8
|
-
* @param {string} fileName - The file name (e.g., login.json)
|
|
9
|
-
* @param {string} payloadDir - Directory path for payloads (absolute or relative)
|
|
10
|
-
* @returns {string} - Full path to the resolved file
|
|
11
|
-
*/
|
|
12
|
-
export default function resolvePayloadPath(fileName, payloadDir = "payloads") {
|
|
13
|
-
const projectRoot = path.resolve(process.cwd());
|
|
14
|
-
const baseDir = path.isAbsolute(payloadDir)
|
|
15
|
-
? payloadDir
|
|
16
|
-
: path.join(projectRoot, payloadDir);
|
|
17
|
-
|
|
18
|
-
const fullPath = path.join(baseDir, fileName);
|
|
19
|
-
|
|
20
|
-
if (!fs.existsSync(fullPath)) {
|
|
21
|
-
throw new Error(`❌ Payload file not found: "${fullPath}"`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return fullPath;
|
|
25
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { generateK6Script, runK6Script } from "../utils/k6Runner.js";
|
|
2
|
-
import buildK6Script from "./buildK6Script.js";
|
|
3
|
-
|
|
4
|
-
export async function runK6ScriptFromWorld(world, method, isMulti = false) {
|
|
5
|
-
const scriptContent = buildK6Script({
|
|
6
|
-
method,
|
|
7
|
-
endpoint: isMulti ? undefined : world.endpoint,
|
|
8
|
-
endpoints: isMulti ? world.endpoints : undefined,
|
|
9
|
-
body: world.body,
|
|
10
|
-
headers: world.headers,
|
|
11
|
-
options: world.k6Options,
|
|
12
|
-
baseUrl: world.baseUrl,
|
|
13
|
-
worldParameters: world.worldParameters,
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const scriptPath = await generateK6Script(scriptContent, "api", true);
|
|
17
|
-
const { stdout, stderr, code } = await runK6Script(scriptPath, true);
|
|
18
|
-
|
|
19
|
-
console.log(stdout);
|
|
20
|
-
if (stderr) console.error(stderr);
|
|
21
|
-
if (code !== 0) {
|
|
22
|
-
throw new Error("❌ K6 script execution failed.");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
console.log("✅ K6 script ran successfully.");
|
|
26
|
-
}
|
package/lib/utils/k6Runner.d.ts
DELETED
package/lib/utils/k6Runner.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import { exec } from "child_process";
|
|
3
|
-
import { v4 as uuidv4 } from "uuid";
|
|
4
|
-
import { promises as fs } from "fs";
|
|
5
|
-
import { fileURLToPath } from "url";
|
|
6
|
-
|
|
7
|
-
// __dirname workaround for ESM
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = path.dirname(__filename);
|
|
10
|
-
const pkgPath = path.resolve(__dirname, "../../package.json");
|
|
11
|
-
const pkgContent = await fs.readFile(pkgPath, "utf-8");
|
|
12
|
-
const packageJson = JSON.parse(pkgContent);
|
|
13
|
-
/**
|
|
14
|
-
* Generates a temporary k6 script file.
|
|
15
|
-
* @param {string} scriptContent - The content of the k6 script.
|
|
16
|
-
* @param {string} [scriptType='load'] - Type of script (e.g., 'load').
|
|
17
|
-
* @param {boolean} [overwrite=false] - Whether to overwrite the report file.
|
|
18
|
-
* @returns {Promise<string>} - Path to the generated k6 script file.
|
|
19
|
-
*/
|
|
20
|
-
export async function generateK6Script(
|
|
21
|
-
scriptContent,
|
|
22
|
-
scriptType = "load",
|
|
23
|
-
overwrite = false
|
|
24
|
-
) {
|
|
25
|
-
const tempDir = path.resolve(__dirname, "../../temp");
|
|
26
|
-
const scriptName = `${scriptType}_script_${uuidv4()}.js`;
|
|
27
|
-
const scriptPath = path.join(tempDir, scriptName);
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
await fs.mkdir(tempDir, { recursive: true });
|
|
31
|
-
|
|
32
|
-
if (overwrite) {
|
|
33
|
-
await fs.writeFile(scriptPath, scriptContent, { flag: "w" });
|
|
34
|
-
} else {
|
|
35
|
-
await fs.appendFile(scriptPath, scriptContent);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return scriptPath;
|
|
39
|
-
} catch (error) {
|
|
40
|
-
console.error(`Error generating k6 script: ${error.message}`);
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Introduce a delay in milliseconds.
|
|
47
|
-
* @param {number} ms - Duration of the delay.
|
|
48
|
-
* @returns {Promise<void>}
|
|
49
|
-
*/
|
|
50
|
-
export const delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Runs the k6 script with custom branding.
|
|
54
|
-
* @param {string} scriptPath - Path to the k6 script file.
|
|
55
|
-
* @param {boolean} [overwrite=false] - Whether to overwrite the report file.
|
|
56
|
-
* @returns {Promise<{stdout: string, stderr: string, code: number}>}
|
|
57
|
-
*/
|
|
58
|
-
export async function runK6Script(scriptPath, overwrite = false) {
|
|
59
|
-
const chalkGreen = "\x1b[38;2;0;255;0m";
|
|
60
|
-
const chalkYellow = "\x1b[38;2;255;255;0m";
|
|
61
|
-
const resetColor = "\x1b[0m";
|
|
62
|
-
|
|
63
|
-
const customLogo = `${chalkGreen} with @qaPaschalE's ${chalkYellow}k6-cucumber-steps v${packageJson.version}${resetColor}`;
|
|
64
|
-
|
|
65
|
-
return new Promise((resolve) => {
|
|
66
|
-
exec(`k6 run "${scriptPath}"`, async (error, stdout, stderr) => {
|
|
67
|
-
const logoLines = stdout.split("\n");
|
|
68
|
-
|
|
69
|
-
let modifiedStdout = "";
|
|
70
|
-
for (let i = 0; i < logoLines.length; i++) {
|
|
71
|
-
modifiedStdout += logoLines[i];
|
|
72
|
-
if (i === 5) {
|
|
73
|
-
modifiedStdout += ` ${customLogo}\n`;
|
|
74
|
-
}
|
|
75
|
-
modifiedStdout += "\n";
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
fs.unlink(scriptPath).catch((err) =>
|
|
79
|
-
console.error("Error deleting temporary k6 script:", err)
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
resolve({
|
|
83
|
-
stdout: modifiedStdout,
|
|
84
|
-
stderr,
|
|
85
|
-
code: error ? error.code ?? 1 : 0,
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
}
|
package/scripts/cucumber.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
default: {
|
|
3
|
-
require: ["./step_definitions/**/*.js"],
|
|
4
|
-
format: [
|
|
5
|
-
"summary",
|
|
6
|
-
"json:./reports/load-report.json",
|
|
7
|
-
"html:./reports/cucumber-report.html",
|
|
8
|
-
],
|
|
9
|
-
paths: ["./features/bsp.feature"],
|
|
10
|
-
tags: "@get",
|
|
11
|
-
cleanReports: true,
|
|
12
|
-
worldParameters: {
|
|
13
|
-
payloadPath: "payloads",
|
|
14
|
-
},
|
|
15
|
-
overwrite: true,
|
|
16
|
-
reporter: true,
|
|
17
|
-
},
|
|
18
|
-
};
|
package/scripts/linkReports.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { minify } from "html-minifier-terser";
|
|
4
|
-
import { fileURLToPath } from "url";
|
|
5
|
-
import { exec } from "child_process";
|
|
6
|
-
import os from "os";
|
|
7
|
-
|
|
8
|
-
// ESM __dirname workaround
|
|
9
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
-
const __dirname = path.dirname(__filename);
|
|
11
|
-
|
|
12
|
-
const reportsDir = path.resolve(__dirname, "../reports");
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Opens a file in the default browser based on OS.
|
|
16
|
-
* @param {string} filePath - Absolute file path to open.
|
|
17
|
-
*/
|
|
18
|
-
function openInBrowser(filePath) {
|
|
19
|
-
const platform = os.platform();
|
|
20
|
-
const command =
|
|
21
|
-
platform === "darwin"
|
|
22
|
-
? `open "${filePath}"`
|
|
23
|
-
: platform === "win32"
|
|
24
|
-
? `start "" "${filePath}"`
|
|
25
|
-
: `xdg-open "${filePath}"`; // Linux
|
|
26
|
-
|
|
27
|
-
exec(command, (err) => {
|
|
28
|
-
if (err) {
|
|
29
|
-
console.error("⚠️ Failed to open the report in browser:", err.message);
|
|
30
|
-
} else {
|
|
31
|
-
console.log("🌐 Report opened in your default browser.");
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export async function linkReports() {
|
|
37
|
-
if (!fs.existsSync(reportsDir)) {
|
|
38
|
-
console.warn("⚠️ No reports directory found.");
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const htmlFiles = fs
|
|
43
|
-
.readdirSync(reportsDir)
|
|
44
|
-
.filter((f) => f.endsWith(".html") && !f.includes("combined-"))
|
|
45
|
-
.map((f) => ({
|
|
46
|
-
name: f,
|
|
47
|
-
path: path.join(reportsDir, f),
|
|
48
|
-
mtime: fs.statSync(path.join(reportsDir, f)).mtime.getTime(),
|
|
49
|
-
}));
|
|
50
|
-
|
|
51
|
-
if (htmlFiles.length === 0) {
|
|
52
|
-
console.warn("⚠️ No HTML reports found.");
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let k6Report = htmlFiles.find((f) => f.name.startsWith("k6-"));
|
|
57
|
-
if (!k6Report) {
|
|
58
|
-
k6Report = htmlFiles.reduce((a, b) => (a.mtime > b.mtime ? a : b));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const otherReports = htmlFiles.filter((f) => f.name !== k6Report.name);
|
|
62
|
-
if (!k6Report || otherReports.length === 0) {
|
|
63
|
-
console.warn("⚠️ K6 or any other HTML report not found.");
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let content = fs.readFileSync(k6Report.path, "utf8");
|
|
68
|
-
|
|
69
|
-
const tabs = otherReports
|
|
70
|
-
.map(
|
|
71
|
-
(report, idx) => `
|
|
72
|
-
<input type="radio" name="tabs" id="tab${idx + 2}">
|
|
73
|
-
<label for="tab${idx + 2}"><i class="fas fa-file-alt"></i> ${
|
|
74
|
-
report.name
|
|
75
|
-
}</label>
|
|
76
|
-
<div class="tab">
|
|
77
|
-
<iframe src="${
|
|
78
|
-
report.name
|
|
79
|
-
}" style="width:100%; height:600px; border:none;"></iframe>
|
|
80
|
-
</div>
|
|
81
|
-
`
|
|
82
|
-
)
|
|
83
|
-
.join("\n");
|
|
84
|
-
|
|
85
|
-
content = content.replace(
|
|
86
|
-
/<input type="radio" name="tabs" id="tabone"/,
|
|
87
|
-
`${tabs}\n<input type="radio" name="tabs" id="tabone"`
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
content = content.replace(
|
|
91
|
-
/<div style="padding:10px;margin-top:20px;text-align:center">[\s\S]*?<\/div>/,
|
|
92
|
-
""
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const minified = await minify(content, {
|
|
96
|
-
collapseWhitespace: true,
|
|
97
|
-
removeComments: true,
|
|
98
|
-
minifyCSS: true,
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
const combinedPath = path.join(reportsDir, "combined-report.html");
|
|
102
|
-
fs.writeFileSync(combinedPath, minified, "utf8");
|
|
103
|
-
|
|
104
|
-
console.log(`📄 Combined report generated at: ${combinedPath}`);
|
|
105
|
-
|
|
106
|
-
openInBrowser(combinedPath);
|
|
107
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { DataTable } from "@cucumber/cucumber";
|
|
2
|
-
|
|
3
|
-
declare module "@cucumber/cucumber" {
|
|
4
|
-
interface World {
|
|
5
|
-
config: {
|
|
6
|
-
method?: string;
|
|
7
|
-
options?: any;
|
|
8
|
-
headers?: Record<string, string>;
|
|
9
|
-
endpoints?: string[];
|
|
10
|
-
body?: any;
|
|
11
|
-
endpoint?: string;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function Given(
|
|
17
|
-
pattern: string,
|
|
18
|
-
fn: (
|
|
19
|
-
this: import("@cucumber/cucumber").World,
|
|
20
|
-
...args: any[]
|
|
21
|
-
) => Promise<any> | void
|
|
22
|
-
): void;
|
|
23
|
-
export function When(
|
|
24
|
-
pattern: string,
|
|
25
|
-
fn: (
|
|
26
|
-
this: import("@cucumber/cucumber").World,
|
|
27
|
-
...args: any[]
|
|
28
|
-
) => Promise<any> | void
|
|
29
|
-
): void;
|
|
30
|
-
export function Then(
|
|
31
|
-
pattern: string,
|
|
32
|
-
fn: (
|
|
33
|
-
this: import("@cucumber/cucumber").World,
|
|
34
|
-
...args: any[]
|
|
35
|
-
) => Promise<any> | void
|
|
36
|
-
): void;
|
|
37
|
-
|
|
38
|
-
declare function Given(
|
|
39
|
-
pattern: "I set a k6 script for {word} testing",
|
|
40
|
-
implementation: (
|
|
41
|
-
this: import("@cucumber/cucumber").World,
|
|
42
|
-
method: string
|
|
43
|
-
) => void
|
|
44
|
-
): void;
|
|
45
|
-
declare function When(
|
|
46
|
-
pattern: "I set to run the k6 script with the following configurations:",
|
|
47
|
-
implementation: (
|
|
48
|
-
this: import("@cucumber/cucumber").World,
|
|
49
|
-
dataTable: DataTable
|
|
50
|
-
) => void
|
|
51
|
-
): void;
|
|
52
|
-
declare function When(
|
|
53
|
-
pattern: "I set the request headers:",
|
|
54
|
-
implementation: (
|
|
55
|
-
this: import("@cucumber/cucumber").World,
|
|
56
|
-
dataTable: DataTable
|
|
57
|
-
) => void
|
|
58
|
-
): void;
|
|
59
|
-
declare function When(
|
|
60
|
-
pattern: "I set the following endpoints used:",
|
|
61
|
-
implementation: (
|
|
62
|
-
this: import("@cucumber/cucumber").World,
|
|
63
|
-
docString: string
|
|
64
|
-
) => void
|
|
65
|
-
): void;
|
|
66
|
-
declare function When(
|
|
67
|
-
pattern: "I set the following {word} body is used for {string}",
|
|
68
|
-
implementation: (
|
|
69
|
-
this: import("@cucumber/cucumber").World,
|
|
70
|
-
method: string,
|
|
71
|
-
endpoint: string,
|
|
72
|
-
docString: string
|
|
73
|
-
) => void
|
|
74
|
-
): void;
|
|
75
|
-
declare function When(
|
|
76
|
-
pattern: "I set the authentication type to {string}",
|
|
77
|
-
implementation: (
|
|
78
|
-
this: import("@cucumber/cucumber").World,
|
|
79
|
-
authType: string
|
|
80
|
-
) => void
|
|
81
|
-
): void;
|
|
82
|
-
declare function Then(
|
|
83
|
-
pattern: "I see the API should handle the {word} request successfully",
|
|
84
|
-
implementation: (
|
|
85
|
-
this: import("@cucumber/cucumber").World,
|
|
86
|
-
method: string,
|
|
87
|
-
options?: { timeout?: number }
|
|
88
|
-
) => Promise<void>
|
|
89
|
-
): void;
|