k6-cucumber-steps 1.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.
Files changed (74) hide show
  1. package/.env +17 -0
  2. package/.env.example +17 -0
  3. package/.github/workflows/k6-load-test.yml +35 -0
  4. package/.vscode/extensions.json +5 -0
  5. package/.vscode/settings.json +10 -0
  6. package/LICENSE +21 -0
  7. package/README.md +179 -0
  8. package/assets/k6-cucumber-report.png +0 -0
  9. package/assets/paschal logo (2).png +0 -0
  10. package/cucumber.js +26 -0
  11. package/generateReport.js +24 -0
  12. package/libs/helpers/buildK6Script.js +94 -0
  13. package/libs/helpers/generateHeaders.js +29 -0
  14. package/libs/helpers/resolveBody.js +55 -0
  15. package/libs/utils/k6Runner.js +71 -0
  16. package/package.json +60 -0
  17. package/reports/load-results.json +231 -0
  18. package/reports/report.html +1234 -0
  19. package/step_definitions/load_test_steps.js +130 -0
  20. package/step_definitions/world.js +13 -0
  21. package/temp/k6_script.js +27 -0
  22. package/tmp/k6_script_01d24b4b-b76e-45b1-a457-9668fb82d33a.js +32 -0
  23. package/tmp/k6_script_1438a7b8-37a7-4556-8da9-12e588e666da.js +32 -0
  24. package/tmp/k6_script_15971355-7bba-45c2-85a8-81899162beab.js +32 -0
  25. package/tmp/k6_script_32f4609f-8abb-4d48-9454-321bd66409eb.js +32 -0
  26. package/tmp/k6_script_42cd4c8b-dee1-4b23-997b-ca1b0b8aae34.js +32 -0
  27. package/tmp/k6_script_49e30b01-9631-4b7f-a2e9-f538bfdade19.js +31 -0
  28. package/tmp/k6_script_4c01eb2e-b7d2-4597-a146-a6990dd92853.js +32 -0
  29. package/tmp/k6_script_4d779cfb-0c34-472c-b5fe-85ceb25f2422.js +31 -0
  30. package/tmp/k6_script_4f00954e-7f02-4c0c-8a89-df8183266fac.js +32 -0
  31. package/tmp/k6_script_4f166411-c40b-44a9-9561-94ab8d4c97bd.js +32 -0
  32. package/tmp/k6_script_4fba8ca6-c90f-467e-bc49-15f30a8eae81.js +32 -0
  33. package/tmp/k6_script_5054b6db-ae03-453e-ad29-8b79869c17b7.js +32 -0
  34. package/tmp/k6_script_5d64d2e5-7cde-4313-969c-ca14c9178bff.js +32 -0
  35. package/tmp/k6_script_61db2aea-6187-4b51-b450-67f773c8050c.js +32 -0
  36. package/tmp/k6_script_6b6147df-69a8-4ed3-9479-0edd8a3e64cd.js +32 -0
  37. package/tmp/k6_script_6dda7a7d-dd36-4775-87f5-d0365715ae2b.js +32 -0
  38. package/tmp/k6_script_6fca496e-f9d3-47e6-b214-8b998b69e9c8.js +32 -0
  39. package/tmp/k6_script_7ca87434-af5c-4ecc-9a7e-0ce7ae5c05c3.js +32 -0
  40. package/tmp/k6_script_7ff302b6-5bfd-440d-a7e4-bf60cf3ec23b.js +31 -0
  41. package/tmp/k6_script_817f7c24-46a8-4c8e-8c8b-7d63ae8c90f9.js +32 -0
  42. package/tmp/k6_script_88b6b615-94b7-4af4-a05b-40439f73c38a.js +32 -0
  43. package/tmp/k6_script_8a9b2d06-fdf9-408b-98e6-4228e039f66b.js +32 -0
  44. package/tmp/k6_script_93acfc41-ce38-4363-8394-faf4568c62a7.js +33 -0
  45. package/tmp/k6_script_9424816a-7712-400d-80b1-235cf298b102.js +32 -0
  46. package/tmp/k6_script_a8ddb599-632f-4a05-9d6f-b99c93e7533f.js +32 -0
  47. package/tmp/k6_script_a9b18f14-bf36-4423-a706-1e132ff3cfda.js +32 -0
  48. package/tmp/k6_script_a9eb065f-d0b9-42b8-b4fa-90d9c67787a4.js +32 -0
  49. package/tmp/k6_script_aac9cc10-b5cd-4fd6-9ba7-ad37b55a5e0c.js +32 -0
  50. package/tmp/k6_script_ac7f2225-f35b-4330-aa95-ea7468d652ed.js +32 -0
  51. package/tmp/k6_script_acb5057c-60cc-47b3-b8aa-718912587694.js +32 -0
  52. package/tmp/k6_script_aecaaf81-a2e9-4342-a90b-3077eba3fdbe.js +32 -0
  53. package/tmp/k6_script_b054781a-fbe3-41ab-8a55-52c7923bb4e3.js +32 -0
  54. package/tmp/k6_script_b210e574-c636-4b1a-9245-f9d9ce9ba731.js +32 -0
  55. package/tmp/k6_script_b4abecc0-91a9-4dc4-8e40-480a31b7954e.js +32 -0
  56. package/tmp/k6_script_b5a61631-afe3-47c4-af92-40213c3afe1a.js +32 -0
  57. package/tmp/k6_script_b6c1de34-edde-4e1d-be3f-504147837617.js +32 -0
  58. package/tmp/k6_script_be52dc14-7325-4ba0-ba2c-125c1dffab0c.js +42 -0
  59. package/tmp/k6_script_c2dbe965-703c-4c8d-83f0-db2eb73b1ab3.js +32 -0
  60. package/tmp/k6_script_c2ecca4f-7a01-4560-9fe0-4a5184497482.js +33 -0
  61. package/tmp/k6_script_cd13c408-4d59-490a-b788-f2e69ab5aeac.js +32 -0
  62. package/tmp/k6_script_cde84f7c-9d97-4c51-a315-005af6463f40.js +33 -0
  63. package/tmp/k6_script_cfbf49b0-d50a-4e00-b0ee-c1f37ae101bc.js +32 -0
  64. package/tmp/k6_script_d0599a1d-7fe5-4a58-b1f7-571a9c586732.js +32 -0
  65. package/tmp/k6_script_d1cd0a14-dc18-4034-a859-cd8b30da7c68.js +32 -0
  66. package/tmp/k6_script_d2365925-9612-48b5-87e9-4ecd81212133.js +32 -0
  67. package/tmp/k6_script_d38531f2-a437-4117-a4d3-076a11f7dfa6.js +32 -0
  68. package/tmp/k6_script_d415abc5-41b3-4445-a8bf-9c13c3208c59.js +32 -0
  69. package/tmp/k6_script_d9a6e7f4-5b88-4fcf-90d8-0183a1b96608.js +32 -0
  70. package/tmp/k6_script_e70b4a0a-1d52-431c-92e1-a53fd6739dfc.js +32 -0
  71. package/tmp/k6_script_e7bc2c96-7603-468b-b4be-d609d3c2f6ce.js +32 -0
  72. package/tmp/k6_script_e9687b8a-7885-48e5-91ad-9dcd21acc401.js +32 -0
  73. package/tmp/k6_script_ee2c199b-643d-4a78-b8df-7319e02783c1.js +32 -0
  74. package/tmp/k6_script_fe495d2f-7943-4151-a7fe-004ad443083d.js +32 -0
package/.env ADDED
@@ -0,0 +1,17 @@
1
+ # .env
2
+ TEST_ENVIRONMENT=STAGING
3
+ APP_VERSION=1.0.0
4
+ BROWSER=Chrome 100.0.4896.88
5
+ PLATFORM=Windows 10
6
+ PARALLEL=Scenarios
7
+ EXECUTED=Remote
8
+ TAGS=@loadTest
9
+
10
+ # Base URLs
11
+ # API_URL=https://unstable-performance.seamlesshrms.com
12
+ # BASE_URL=https://unstable-performance.seamlesshrms.com
13
+ BASE_URL=https://grafana.com
14
+
15
+ # Secret Parameters
16
+ API_KEY=Talent123!
17
+ BEARER_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3J1bnRocm91Z2gtdHdvLnNlYW1sZXNzaHJtcy5jb20vYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE3NDU2MjAwNDEsImV4cCI6MTc0NTYyMzY0MSwibmJmIjoxNzQ1NjIwMDQxLCJqdGkiOiJkQmZHZW9Takh3MlZ0NEF6Iiwic3ViIjoiMjI2IiwicHJ2IjoiYzIwM2QyYmJmODZhN2IyNzcyZWUyNGNhODIyNzBmOTA5NTgyZjg3YyJ9.WGdq8QMpSZvCJB6cj0hn3xrUIfhIbOE4Ft4bo8u1JKw
package/.env.example ADDED
@@ -0,0 +1,17 @@
1
+ # .env
2
+ TEST_ENVIRONMENT=STAGING
3
+ APP_VERSION=1.0.0
4
+ BROWSER=Chrome 100.0.4896.88
5
+ PLATFORM=Windows 10
6
+ PARALLEL=Scenarios
7
+ EXECUTED=Remote
8
+
9
+ # Base URLs
10
+ API_URL=https://test-api.example.com
11
+ BASE_URL=https://example.com
12
+ AUTH_URL=https://auth.example.com
13
+ PAYMENT_URL=https://payment.example.com
14
+
15
+ # Secret Parameters
16
+ API_KEY=your-secret-api-key-12345
17
+ BEARER_TOKEN=your_bearer_token_here
@@ -0,0 +1,35 @@
1
+ name: Node.js Package Workflow
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+ branches: ["main"]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ matrix:
15
+ node-version: [lts/*]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - name: Use Node.js ${{ matrix.node-version }}
20
+ uses: actions/setup-node@v4
21
+ with:
22
+ node-version: ${{ matrix.node-version }}
23
+ cache: "npm"
24
+ - name: Install k6
25
+ run: |
26
+ sudo apt-get update
27
+ sudo apt-get install -y --no-install-recommends k6
28
+ - name: Verify k6 Installation
29
+ run: k6 version
30
+ - name: Install Dependencies
31
+ run: npm install
32
+ - name: List Dependencies
33
+ run: npm list --all
34
+ - name: Run Load Tests
35
+ run: npm loadTest
@@ -0,0 +1,5 @@
1
+ {
2
+ "recommendations": [
3
+ "cucumberopen.cucumber-official"
4
+ ]
5
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "cucumber.features": [
3
+ "src/features/*.feature",
4
+ "src/features/**/*.feature",
5
+ "src/features/**/*.k6.feature",
6
+ "src/features/template/*.feature"
7
+ ],
8
+ "cucumber.glue": ["step_definitions/*.js","src/features/stepDefinitions/*.js"
9
+ ]
10
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Enyimiri Chetachi Paschal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of **k6-cucumber-steps** (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # k6-cucumber-steps 🥒🧪
2
+
3
+ <table align="center" style="margin-bottom:30px;"><tr><td align="center" width="9999" heigth="9999 " >
4
+ <img src="assets/paschal logo (2).png" alt="paschal Logo" style="margin-top:25px;" align="center"/>
5
+
6
+ #
7
+
8
+ [![npm version](https://img.shields.io/npm/v/k6-cucumber-steps.svg)](https://www.npmjs.com/package/k6-cucumber-steps)
9
+ [![npm downloads](https://img.shields.io/npm/dt/k6-cucumber-steps.svg)](https://www.npmjs.com/package/k6-cucumber-steps)
10
+ [![License](https://img.shields.io/npm/l/k6-cucumber-steps.svg)](./LICENSE)
11
+ [![Cucumber](https://img.shields.io/badge/built%20with-Cucumber-3178c6.svg)](https://cucumber.io/)
12
+ [![Node.js](https://img.shields.io/badge/node-%3E=18-green.svg)](https://nodejs.org/)
13
+
14
+ Run [k6](https://k6.io/) performance/load tests using [Cucumber](https://cucumber.io/) BDD syntax with ease.
15
+
16
+ ---
17
+
18
+ ## ✨ Features
19
+
20
+ - ✅ Cucumber + Gherkin for writing k6 tests
21
+ - ✅ Support for JSON body parsing and escaping
22
+ - ✅ Faker support (`{{faker.name.firstName}}`)
23
+ - ✅ `.env` + `K6.env`-style variable resolution (`{{API_KEY}}`)
24
+ - ✅ Support for headers, query params, stages
25
+ - ✅ Clean-up of temporary k6 files after execution
26
+ - ✅ Built-in support for **distributed load testing** with stages
27
+ - ✅ TypeScript-first 🧡
28
+
29
+ ---
30
+
31
+ ## 📦 Install
32
+
33
+ ```bash
34
+ npm install k6-cucumber-steps
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 🚀 Usage
40
+
41
+ ### CLI
42
+
43
+ ```bash
44
+ npx k6-cucumber-steps run --feature ./features/example.feature
45
+ ```
46
+
47
+ ### Programmatic
48
+
49
+ ```ts
50
+ import { runK6Feature } from "k6-cucumber-steps";
51
+
52
+ await runK6Feature("./features/example.feature");
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Setup
58
+
59
+ 1. **Environment Variables**: Create a `.env` file in your project root based on the provided `.env.example`:
60
+
61
+ ```env
62
+ BASE_URL=https://api.example.com
63
+ API_KEY=your_api_key
64
+ BEARER_TOKEN=your_bearer_token
65
+ BASIC_USER=your_basic_user
66
+ BASIC_PASS=your_basic_pass
67
+ ```
68
+
69
+ 2. **Feature Files**: Write your feature files using the provided step definitions.
70
+
71
+ ## Gherkin Examples
72
+
73
+ Here’s how you can write a feature file using the provided step definitions:
74
+
75
+ ### Example 1: Test GET Endpoint with No Authentication
76
+
77
+ ```gherkin
78
+ Feature: API Performance Testing
79
+
80
+ Scenario: Run load tests with dynamic GET requests
81
+ Given I have a k6 script for GET testing
82
+ When I run the k6 script with the following configurations:
83
+ | virtual_users | duration | http_req_failed | http_req_duration |
84
+ | 50 | 10 | rate<0.05 | p(95)<3000 |
85
+ And the following endpoint(s) is/are used:
86
+ """
87
+ /api/profile
88
+ https://reqres.in/api/users?page=2
89
+ """
90
+ And when the authentication type is "none"
91
+ Then the API should handle the GET request successfully
92
+ ```
93
+
94
+ ### Example 2: Test POST Endpoint with Bearer Token Authentication
95
+
96
+ ```gherkin
97
+ Feature: API Performance Testing
98
+
99
+ Scenario: Run load tests with dynamic POST requests
100
+ Given I have a k6 script for POST testing
101
+ When I run the k6 script with the following configurations:
102
+ | virtual_users | duration | http_req_failed | http_req_duration |
103
+ | 20 | 60 | rate<0.01 | p(95)<300 |
104
+ And the authentication type is "bearer_token"
105
+ And the following endpoint(s) is/are used:
106
+ """
107
+ /api/v1/users
108
+ """
109
+ And the following POST body is used for "/api/v1/users"
110
+ """
111
+ {
112
+ "username": "{{username}}",
113
+ "email": "{{faker.internet.email}}"
114
+ }
115
+ """
116
+ Then the API should handle the POST request successfully
117
+ ```
118
+
119
+ ## Step Definitions
120
+
121
+ ### Authentication Steps
122
+
123
+ ```gherkin
124
+ When the authentication type is "api_key"
125
+ When the authentication type is "bearer_token"
126
+ When the authentication type is "basic"
127
+ When the authentication type is "none"
128
+ ```
129
+
130
+ ### Request Configuration Steps
131
+
132
+ ```gherkin
133
+ Given I have a k6 script for {word} testing
134
+ When I run the k6 script with the following configurations:
135
+ When the request headers are:
136
+ When the following endpoint(s) is/are used:
137
+ When the following {word} body is used for {string}
138
+ ```
139
+
140
+ ### Assertion Steps
141
+
142
+ ```gherkin
143
+ Then the API should handle the {word} request successfully
144
+ ```
145
+
146
+ ## Test Results
147
+
148
+ Below is an example of the Cucumber report generated after running the tests:
149
+
150
+ ![Cucumber Report](./assets/k6-cucumber-report.png)
151
+
152
+ ### Explanation of the Report
153
+
154
+ - **All Scenarios**: Total number of scenarios executed.
155
+ - **Passed Scenarios**: Number of scenarios that passed.
156
+ - **Failed Scenarios**: Number of scenarios that failed.
157
+ - **Metadata**: Information about the test environment (e.g., browser, platform).
158
+ - **Feature Overview**: Summary of the feature being tested.
159
+ - **Scenario Details**: Detailed steps and their execution status.
160
+
161
+ ## 🧼 Temporary Files Clean-up
162
+
163
+ All generated k6 scripts and artifacts are cleaned automatically after test execution.
164
+
165
+ ---
166
+
167
+ ## 📄 License
168
+
169
+ MIT License - [@qaPaschalE](https://github.com/qaPaschalE)
170
+
171
+ ```
172
+
173
+
174
+ ## License
175
+
176
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
177
+
178
+
179
+ ```
Binary file
Binary file
package/cucumber.js ADDED
@@ -0,0 +1,26 @@
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");
9
+ 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
+ },
17
+ };
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
+ // });
@@ -0,0 +1,24 @@
1
+ const reporter = require("cucumber-html-reporter");
2
+
3
+ // Configuration for the HTML report
4
+ const options = {
5
+ theme: "bootstrap", // You can change the theme to 'simple', 'compact', etc.
6
+ jsonFile: "reports/load-results.json", // Path to the JSON file generated by Cucumber
7
+ output: "reports/report.html", // Path where you want to save the HTML report
8
+ reportSuiteAsScenarios: true, // Group scenarios by their name
9
+ launchReport: true, // Automatically open the report in the browser
10
+ metadata: {
11
+ browser: {
12
+ name: "Chrome" || "unknown",
13
+ version: "89" || "unknown",
14
+ },
15
+ device: "Local test machine",
16
+ platform: {
17
+ name: "MacOS",
18
+ version: "20.04",
19
+ },
20
+ },
21
+ };
22
+
23
+ // Generate the report
24
+ reporter.generate(options);
@@ -0,0 +1,94 @@
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
+ module.exports = function buildK6Script(config) {
30
+ const { method, endpoints, endpoint, body, headers, options } = config;
31
+
32
+ // Ensure at least one of `endpoints` or `endpoint` is defined
33
+ if (!endpoints?.length && !endpoint) {
34
+ throw new Error(
35
+ 'Either "endpoints" or "endpoint" must be defined in the configuration.'
36
+ );
37
+ }
38
+
39
+ // Get BASE_URL from environment variables
40
+ const BASE_URL = process.env.BASE_URL;
41
+ if (!BASE_URL) {
42
+ throw new Error("BASE_URL is not defined in the environment variables.");
43
+ }
44
+
45
+ // Resolve relative endpoints by prepending BASE_URL
46
+ const resolveEndpoint = (url) => {
47
+ return url.startsWith("/") ? `${BASE_URL}${url}` : url;
48
+ };
49
+
50
+ return `
51
+ import http from 'k6/http';
52
+ import { check } from 'k6';
53
+
54
+ export const options = ${JSON.stringify(options, null, 2)};
55
+
56
+ export default function () {
57
+ ${
58
+ endpoints?.length
59
+ ? endpoints
60
+ .map(
61
+ (url, i) => `
62
+ const resolvedUrl${i} = "${resolveEndpoint(url)}";
63
+ const res${i} = http.request("${method}", resolvedUrl${i}, ${
64
+ method === "GET" || method === "DELETE"
65
+ ? "null"
66
+ : JSON.stringify(body)
67
+ }, {
68
+ headers: ${JSON.stringify(headers, null, 2)}
69
+ });
70
+ console.log(\`Response Body for \${resolvedUrl${i}}: \${res${i}.body}\`);
71
+ check(res${i}, {
72
+ "status is 2xx": (r) => r.status >= 200 && r.status < 300
73
+ });
74
+ `
75
+ )
76
+ .join("\n")
77
+ : `
78
+ const resolvedUrl = "${resolveEndpoint(endpoint)}";
79
+ \ const res = http.request("${method}", resolvedUrl, ${
80
+ method === "GET" || method === "DELETE"
81
+ ? "null"
82
+ : JSON.stringify(body)
83
+ }, {
84
+ headers: ${JSON.stringify(headers, null, 2)}
85
+ });
86
+ console.log(\`Response Body for \${resolvedUrl}: \${res.body}\`);
87
+ check(res, {
88
+ "status is 2xx": (r) => r.status >= 200 && r.status < 300
89
+ });
90
+ `
91
+ }
92
+ }
93
+ `;
94
+ };
@@ -0,0 +1,29 @@
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, basic authentication, and no authentication.
6
+ * Generates HTTP headers based on the specified authentication type.
7
+ * Supported auth types: api_key, bearer_token, basic, none.
8
+ */
9
+ module.exports = function generateHeaders(authType, env) {
10
+ const headers = { "Content-Type": "application/json" };
11
+
12
+ if (authType === "api_key") {
13
+ headers["x-api-key"] = env.API_KEY || "";
14
+ } else if (authType === "bearer_token") {
15
+ headers["Authorization"] = `Bearer ${env.BEARER_TOKEN || ""}`;
16
+ } else if (authType === "basic") {
17
+ const base64 = Buffer.from(`${env.BASIC_USER}:${env.BASIC_PASS}`).toString(
18
+ "base64"
19
+ );
20
+ headers["Authorization"] = `Basic ${base64}`;
21
+ } else if (authType === "none") {
22
+ // No additional headers for "no auth"
23
+ // Default headers (e.g., Content-Type) are still included
24
+ } else {
25
+ throw new Error(`Unsupported authentication type: ${authType}`);
26
+ }
27
+
28
+ return headers;
29
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @module resolveBody
3
+ * @description
4
+ * This module resolves placeholders in a template string using environment variables,
5
+ * Faker templates, and JSON file includes.
6
+ * It supports the following types of placeholders:
7
+ * 1. Environment variables: {{username}} will be replaced with the value of process.env.username.
8
+ * 2. Faker templates: {{faker.internet.email}} will be replaced with a randomly generated email address.
9
+ * 3. JSON file includes: <address.json> will be replaced with the contents of the address.json file.
10
+ * */
11
+ const fs = require("fs");
12
+ const path = require("path");
13
+ const faker = require("@faker-js/faker");
14
+
15
+ module.exports = function resolveBody(template, env) {
16
+ let result = template;
17
+
18
+ // Replace env vars like {{username}}
19
+ result = result.replace(/{{(\w+)}}/g, (_, key) => {
20
+ if (!(key in env)) {
21
+ console.warn(`Missing environment variable for placeholder: {{${key}}}`);
22
+ }
23
+ return env[key] || "";
24
+ });
25
+
26
+ // Support faker templates like {{faker.internet.email}}
27
+ result = result.replace(/{{faker\.([\w.]+)}}/g, (_, methodPath) => {
28
+ const parts = methodPath.split(".");
29
+ let fn = faker;
30
+ for (const part of parts) {
31
+ fn = fn[part];
32
+ if (!fn) break;
33
+ }
34
+ if (typeof fn !== "function") {
35
+ throw new Error(`Invalid Faker template: {{faker.${methodPath}}}`);
36
+ }
37
+ return fn();
38
+ });
39
+
40
+ // Replace JSON file includes like <address.json>
41
+ result = result.replace(/<([\w.]+\.json)>/g, (_, fileName) => {
42
+ const filePath = path.join(__dirname, "../payloads", fileName);
43
+ if (!fs.existsSync(filePath)) {
44
+ throw new Error(`Payload file not found: ${fileName}`);
45
+ }
46
+ return JSON.stringify(JSON.parse(fs.readFileSync(filePath, "utf-8")));
47
+ });
48
+
49
+ try {
50
+ return JSON.parse(result);
51
+ } catch (error) {
52
+ console.error("Failed to parse resolved body to JSON:", result);
53
+ throw new Error("Invalid JSON body after resolving placeholders.");
54
+ }
55
+ };
@@ -0,0 +1,71 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { v4 as uuidv4 } from "uuid";
4
+ import { spawn } from "child_process";
5
+
6
+ /**
7
+ * Generates a temporary k6 script file.
8
+ * @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.
11
+ */
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
+ }
21
+
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.
26
+ */
27
+
28
+ export async function runK6Script(scriptPath) {
29
+ return new Promise((resolve, reject) => {
30
+ const k6Process = spawn("k6", ["run", scriptPath]);
31
+
32
+ let stdout = "";
33
+ let stderr = "";
34
+
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
+ });
40
+
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
+ });
46
+
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}`);
53
+ }
54
+ });
55
+
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);
62
+ }
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
+ });
70
+ });
71
+ }
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "k6-cucumber-steps",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/qaPaschalE/k6-cucumber-steps.git"
8
+ },
9
+ "bugs": {
10
+ "url": "https://github.com/qaPaschalE/k6-cucumber-steps/issues"
11
+ },
12
+ "homepage": "https://github.com/qaPaschalE/k6-cucumber-steps#readme",
13
+ "scripts": {
14
+ "stress": "npx cucumber-js --format json:stress-results.json --tags @stress",
15
+ "stress:report": "cucumber-html-reporter --jsonFile=stress-results.json --output=stress-report.html",
16
+ "loadTest": "npx cucumber-js --format json:reports/load-results.json --tags @loadTest",
17
+ "load:report": "cucumber-html-reporter --jsonFile=load-results.json --output=load-report.html",
18
+ "test": "cucumber-js features/ --require-module @babel/register --require step_definitions/",
19
+ "build": "npm run clean && npm run compile",
20
+ "clean": "rm -rf dist/",
21
+ "compile": "babel src/ -d dist/"
22
+ },
23
+ "cucumber": {
24
+ "require": [
25
+ "step_definitions/**/*.js"
26
+ ]
27
+ },
28
+ "keywords": [
29
+ "k6",
30
+ "cucumber",
31
+ "bdd",
32
+ "performance-testing",
33
+ "api-testing",
34
+ "load-testing",
35
+ "stress-testing",
36
+ "steps",
37
+ "test-automation"
38
+ ],
39
+ "engines": {
40
+ "node": ">=18"
41
+ },
42
+ "author": "Enyimiri Chetachi Paschal",
43
+ "license": "ISC",
44
+ "description": "Cucumber step definitions for running k6 performance tests.",
45
+ "devDependencies": {
46
+ "@babel/cli": "^7.27.0",
47
+ "@babel/core": "^7.26.10",
48
+ "@babel/preset-env": "^7.26.9",
49
+ "@cucumber/cucumber": "^11.2.0",
50
+ "@faker-js/faker": "^9.7.0",
51
+ "@types/k6": "^1.0.2",
52
+ "child_process": "^1.0.2",
53
+ "cucumber-html-reporter": "^6.0.0",
54
+ "dotenv": "^16.5.0",
55
+ "esbuild": "^0.25.3",
56
+ "form-data": "^4.0.2",
57
+ "k6": "^0.0.0",
58
+ "tsconfig-paths": "^4.2.0"
59
+ }
60
+ }