k6-cucumber-steps
Version:
Generate k6 test scripts from Cucumber feature files
1,245 lines (1,085 loc) • 42.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SampleStepsGenerator = void 0;
// src/generators/samples/sample-steps.generator.ts
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const steps_metadata_generator_1 = require("./steps-metadata.generator");
class SampleStepsGenerator {
generate(outputPath, config) {
const isTS = config.language === "ts";
const stepExtension = isTS ? ".ts" : ".js";
const sampleSteps = this.buildSampleStepsContent(isTS);
fs_1.default.writeFileSync(path_1.default.join(outputPath, "steps", `sample.steps${stepExtension}`), sampleSteps);
// Generate metadata.json for step autocomplete
const metadataGenerator = new steps_metadata_generator_1.StepsMetadataGenerator();
metadataGenerator.generate(outputPath);
}
buildSampleStepsContent(isTS) {
return `import http from "k6/http";
import { check, sleep, group } from "k6";
let baseUrl = "";
let defaultHeaders = {
'Content-Type': 'application/json'
} as Record<string, string>;
// Replace {{VARIABLE_NAME}} placeholders with environment values
// k6 uses __ENV global object instead of process.env
function replaceEnvVariables(text: string): string {
return text.replace(/\\{\\{([^}]+)\\}\\}/g, (match, key) => {
const value = (globalThis as any)[key] || (__ENV as any)[key] || (__ENV as any)[\`K6_\${key.toUpperCase()}\`];
if (value === undefined) {
console.warn(\`⚠️ Environment variable "\${key}" not found, using literal value\`);
return match;
}
return value;
});
}
/* ===== HTTP / API STEPS ===== */
/**
* Loads request body from a payload.json file.
* Supports {{VARIABLE_NAME}} for env vars and {{alias:NAME}} for stored aliases.
*/
export function k6IUsePayloadJsonFromFile(fileName: string) {
const fs = require('fs');
const path = require('path');
// Resolve path relative to current working directory or data folder
let filePath = fileName;
if (!path.isAbsolute(fileName)) {
// Try data/ folder first, then root
if (fs.existsSync(path.join(process.cwd(), 'data', fileName))) {
filePath = path.join(process.cwd(), 'data', fileName);
} else if (fs.existsSync(path.join(process.cwd(), fileName))) {
filePath = path.join(process.cwd(), fileName);
} else {
filePath = path.join(process.cwd(), 'payload.json');
}
}
if (!fs.existsSync(filePath)) {
console.error(\`❌ Payload file not found: \${filePath}\`);
return;
}
let payloadContent = fs.readFileSync(filePath, 'utf8');
// Replace environment variables {{VARIABLE_NAME}}
payloadContent = replaceEnvVariables(payloadContent);
// Replace alias references {{alias:NAME}}
payloadContent = replaceAliasVariables(payloadContent);
globalThis.lastPostData = payloadContent;
console.log(\`📄 Loaded payload from: \${filePath}\`);
}
/**
* Helper: Replace {{alias:NAME}} with stored alias values
*/
function replaceAliasVariables(text: string): string {
return text.replace(/\{\{alias:([^}]+)\}\}/g, (match, aliasName) => {
const value = globalThis.storedAliases?.[aliasName];
if (value === undefined) {
console.warn(\`⚠️ Alias "\${aliasName}" not found, using literal value\`);
return match;
}
return typeof value === 'string' ? value : JSON.stringify(value);
});
}
export function k6TheBaseUrlIs(url: string) {
baseUrl = replaceEnvVariables(url.trim());
console.log(\`📍 Base URL set to: \${baseUrl}\`);
}
export function k6IAuthenticateWithTheFollowingUrlAndRequestBodyAsWith(
context: string,
formatOrTable: any,
maybeTable: any
) {
let format = 'json';
let dataTable;
if (maybeTable === undefined) {
format = 'json';
dataTable = formatOrTable;
} else {
format = formatOrTable;
dataTable = maybeTable;
}
if (!dataTable || !dataTable[0]) return;
const row = dataTable[0];
const { endpoint, ...payload } = row;
const url = \`\${baseUrl}\${endpoint}\`;
let body: any;
let params = {
headers: {} as Record<string, string>
};
if (format === 'form') {
params.headers['Content-Type'] = 'application/x-www-form-urlencoded';
body = Object.assign({}, payload);
} else {
params.headers['Content-Type'] = 'application/json';
body = JSON.stringify(payload);
}
const response = http.post(url, body, params);
const success = check(response, {
[\`Auth successful (\${format})\`]: (r) => r.status === 200 || r.status === 201
});
if (success) {
globalThis.lastResponse = response;
try {
const parsed = response.json();
let keys: string[] = [];
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
keys = Object.keys(parsed);
}
console.log(\`✅ \${context} Response Captured. Keys: \${keys.join(', ')}\`);
} catch (e) {
console.error(\`❌ Failed to parse JSON response for \${context}: \${response.body}\`);
globalThis.lastResponse = null;
}
} else {
console.error(\`❌ Auth failed for \${context}. Status: \${response.status}\`);
globalThis.lastResponse = null;
}
}
export function k6IAuthenticateWithTheFollowingUrlAndRequestBodyAs(
context: string,
formatOrTable: any,
maybeTable?: any
) {
let format = 'json';
let dataTable;
if (maybeTable === undefined) {
dataTable = formatOrTable;
} else {
format = formatOrTable;
dataTable = maybeTable;
}
if (!dataTable || !dataTable[0]) return;
const row = dataTable[0];
const { endpoint, ...payload } = row;
const url = \`\${baseUrl}\${endpoint}\`;
let body: any;
let params = {
headers: {} as Record<string, string>
};
if (format === 'form') {
params.headers['Content-Type'] = 'application/x-www-form-urlencoded';
body = Object.assign({}, payload);
} else {
params.headers['Content-Type'] = 'application/json';
body = JSON.stringify(payload);
}
const response = http.post(url, body, params);
const success = check(response, {
[\`Auth successful(\${format})\`]: (r) => r.status === 200 || r.status === 201
});
if (success) {
globalThis.lastResponse = response;
try {
const parsed = response.json();
let keys: string[] = [];
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
keys = Object.keys(parsed);
}
console.log(\`✅ \${context} Response Captured. Keys: \${keys.join(', ')}\`);
} catch (e) {
console.error(\`❌ Failed to parse JSON response for \${context}: \${response.body}\`);
globalThis.lastResponse = null;
}
} else {
console.error(\`❌ Auth failed for \${context}. Status: \${response.status}\`);
globalThis.lastResponse = null;
}
}
export function k6IStoreIn(jsonPath: any, fileName: any) {
const responseData = globalThis.lastResponse;
if (!responseData) {
console.error('❌ No response data to store. Did an HTTP request run?');
return;
}
let parsedBody;
try {
if (typeof responseData.json === 'function') {
parsedBody = responseData.json();
} else {
parsedBody = responseData;
}
} catch (e: any) {
console.error('❌ Failed to parse response as JSON:', e.message || e);
return;
}
const value = jsonPath.split('.').reduce((acc: any, key: any) => {
return acc && acc[key] !== undefined ? acc[key] : undefined;
}, parsedBody);
if (value === undefined) {
console.error(\`❌ Path "\${jsonPath}" not found in response. Available keys:\`, Object.keys(parsedBody).join(', '));
return;
}
const alias = fileName.split(/[\\\\/]/).pop()?.replace(/\\.json$/, '') || fileName;
globalThis.storedAliases = globalThis.storedAliases || {};
globalThis.storedAliases[alias] = value;
globalThis.storedAliases[fileName] = value;
globalThis.savedTokens = globalThis.savedTokens || {};
globalThis.savedTokens[alias] = value;
globalThis.savedTokens[fileName] = value;
console.log(\`✅ Stored response "\${jsonPath}" as alias "\${alias}"\`);
console.log(\` File path: \${fileName}\`);
console.log(\` Value: \${typeof value === 'string' && value.length > 20 ? value.substring(0, 20) + '...' : JSON.stringify(value)}\`);
console.log(\` Aliases available: \${alias}, \${fileName}\`);
}
export function k6IAmAuthenticatedAsA(userType: any) {
const token = globalThis.savedTokens?.[\`data/\${userType}.json\`] ||
globalThis.savedTokens?.[userType];
if (token) {
defaultHeaders['Authorization'] = \`Bearer \${token}\`;
console.log(\`🔑 Using token for \${userType}\`);
} else {
console.warn(\`⚠️ No token found for \${userType}\`);
}
}
export function k6ISetTheDefaultHeaders(data: any) {
if (data && data.length > 0) {
Object.assign(defaultHeaders, data[0]);
}
}
export function k6IMakeAGetRequestTo(endpoint: any) {
return k6IMakeAGetRequestToWithHeaders(endpoint, []);
}
export function k6IMakeAGetRequestToWithHeaders(endpoint: any, headersTable: any) {
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
let requestHeaders = { ...defaultHeaders };
if (headersTable?.length > 0) {
Object.assign(requestHeaders, headersTable[0]);
}
const res = http.get(url, { headers: requestHeaders });
check(res, {
'headers sent correctly': (r) => {
const sent = r.request.headers;
return Object.keys(requestHeaders).every(k => {
const s = sent[k];
const e = requestHeaders[k];
return Array.isArray(s) ? s.includes(e) : s === e;
});
}
});
globalThis.lastResponse = res;
}
export function k6TheResponseStatusShouldBe(expectedStatus: any) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
const status = parseInt(expectedStatus, 10);
check(res, {
[\`status is \${expectedStatus}\`]: (r) => r.status === status
});
}
export function k6TheResponseShouldContain(field: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
try {
const body = res.json();
check(res, {
[\`response contains "\${field}"\`]: () => body[field] !== undefined
});
} catch (e: any) {
check(res, {
[\`response contains "\${field}"\`]: () => false
});
}
}
export function k6TheResponsePropertyShouldNotBeEmpty(propertyPath: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
try {
const body = res.json();
const value = getPropertyByPath(body, propertyPath);
const isEmpty = value === undefined || value === null || value === '' ||
(Array.isArray(value) && value.length === 0) ||
(typeof value === 'object' && Object.keys(value).length === 0);
check(res, {
[\`response property "\${propertyPath}" is not empty\`]: () => !isEmpty
});
if (!isEmpty) {
console.log(\`✅ Response property "\${propertyPath}" has value\`);
} else {
console.error(\`❌ Response property "\${propertyPath}" is empty\`);
}
} catch (err) {
const e = err as Error;
check(res, {
[\`response property "\${propertyPath}" is not empty\`]: () => false
});
console.error('Error checking property:', e.message);
}
}
export function k6TheResponsePropertyShouldBeTrue(propertyPath: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
try {
const body = res.json();
const value = getPropertyByPath(body, propertyPath);
check(res, {
[\`response property "\${propertyPath}" is true\`]: () => value === true || value === 'true'
});
if (value === true || value === 'true') {
console.log(\`✅ Response property "\${propertyPath}" is true\`);
} else {
console.error(\`❌ Response property "\${propertyPath}" is not true (got: \${value})\`);
}
} catch (err) {
const e = err as Error;
check(res, {
[\`response property "\${propertyPath}" is true\`]: () => false
});
console.error('Error checking property:', e.message);
}
}
export function k6TheResponsePropertyShouldBeFalse(propertyPath: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
try {
const body = res.json();
const value = getPropertyByPath(body, propertyPath);
check(res, {
[\`response property "\${propertyPath}" is false\`]: () => value === false || value === 'false'
});
if (value === false || value === 'false') {
console.log(\`✅ Response property "\${propertyPath}" is false\`);
} else {
console.error(\`❌ Response property "\${propertyPath}" is not false (got: \${value})\`);
}
} catch (err) {
const e = err as Error;
check(res, {
[\`response property "\${propertyPath}" is false\`]: () => false
});
console.error('Error checking property:', e.message);
}
}
export function k6IHaveTheFollowingPostData(data: string) {
globalThis.lastPostData = replaceEnvVariables(data);
console.log('📝 Post data stored with environment variables replaced');
}
export function k6IMakeAPostRequestTo(endpoint: string) {
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
const payload = globalThis.lastPostData ? replaceEnvVariables(globalThis.lastPostData) : '{}';
const response = http.post(url, payload, { headers: defaultHeaders });
globalThis.lastResponse = response;
}
/**
* Makes a POST request using a payload.json file.
* Supports {{VARIABLE_NAME}} for env vars and {{alias:NAME}} for stored aliases.
*/
export function k6IMakeAPostRequestToWithPayloadFile(endpoint: string, fileName: string) {
const fs = require('fs');
const path = require('path');
// Resolve payload file path
let filePath = fileName;
if (!path.isAbsolute(fileName)) {
if (fs.existsSync(path.join(process.cwd(), 'data', fileName))) {
filePath = path.join(process.cwd(), 'data', fileName);
} else if (fs.existsSync(path.join(process.cwd(), fileName))) {
filePath = path.join(process.cwd(), fileName);
} else {
filePath = path.join(process.cwd(), 'payload.json');
}
}
if (!fs.existsSync(filePath)) {
console.error(\`❌ Payload file not found: \${filePath}\`);
return;
}
let payloadContent = fs.readFileSync(filePath, 'utf8');
payloadContent = replaceEnvVariables(payloadContent);
payloadContent = replaceAliasVariables(payloadContent);
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
const response = http.post(url, payloadContent, { headers: defaultHeaders });
globalThis.lastResponse = response;
console.log(\`📤 POST \${url} with payload from \${filePath}\`);
}
export function k6IMakeAPostRequestToWithBody(endpoint: string, bodyData: any) {
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
let payload = '{}';
if (typeof bodyData === 'string') {
payload = replaceEnvVariables(bodyData);
} else if (Array.isArray(bodyData) && bodyData.length > 0) {
payload = replaceEnvVariables(JSON.stringify(bodyData[0]));
}
const response = http.post(url, payload, { headers: defaultHeaders });
globalThis.lastResponse = response;
}
export function k6IMakeAPutRequestTo(endpoint: string) {
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
const payload = globalThis.lastPostData ? replaceEnvVariables(globalThis.lastPostData) : '{}';
const response = http.put(url, payload, { headers: defaultHeaders });
globalThis.lastResponse = response;
}
export function k6IMakeAPutRequestToWithBody(endpoint: string, bodyData: any) {
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
let payload = '{}';
if (typeof bodyData === 'string') {
payload = replaceEnvVariables(bodyData);
} else if (Array.isArray(bodyData) && bodyData.length > 0) {
payload = replaceEnvVariables(JSON.stringify(bodyData[0]));
}
const response = http.put(url, payload, { headers: defaultHeaders });
globalThis.lastResponse = response;
}
export function k6IMakeAPatchRequestTo(endpoint: string) {
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
const payload = globalThis.lastPostData ? replaceEnvVariables(globalThis.lastPostData) : '{}';
const response = http.patch(url, payload, { headers: defaultHeaders });
globalThis.lastResponse = response;
}
export function k6IMakeAPatchRequestToWithBody(endpoint: string, bodyData: any) {
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
let payload = '{}';
if (typeof bodyData === 'string') {
payload = replaceEnvVariables(bodyData);
} else if (Array.isArray(bodyData) && bodyData.length > 0) {
payload = replaceEnvVariables(JSON.stringify(bodyData[0]));
}
const response = http.patch(url, payload, { headers: defaultHeaders });
globalThis.lastResponse = response;
}
/**
* Makes a DELETE request to the specified endpoint.
* Supports {{VARIABLE_NAME}} for env vars in endpoint.
*/
export function k6IMakeADeleteRequestTo(endpoint: string) {
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
const response = http.del(url, null, { headers: defaultHeaders });
globalThis.lastResponse = response;
}
/**
* Makes a DELETE request with custom headers.
* Supports {{VARIABLE_NAME}} for env vars in endpoint.
*/
export function k6IMakeADeleteRequestToWithHeaders(endpoint: string, headersTable: any) {
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
let requestHeaders = { ...defaultHeaders };
if (headersTable?.length > 0) {
Object.assign(requestHeaders, headersTable[0]);
}
const response = http.del(url, null, { headers: requestHeaders });
globalThis.lastResponse = response;
}
/**
* Makes a DELETE request using a payload.json file.
* Supports {{VARIABLE_NAME}} for env vars and {{alias:NAME}} for stored aliases.
*/
export function k6IMakeADeleteRequestToWithPayloadFile(endpoint: string, fileName: string) {
const fs = require('fs');
const path = require('path');
// Resolve payload file path
let filePath = fileName;
if (!path.isAbsolute(fileName)) {
if (fs.existsSync(path.join(process.cwd(), 'data', fileName))) {
filePath = path.join(process.cwd(), 'data', fileName);
} else if (fs.existsSync(path.join(process.cwd(), fileName))) {
filePath = path.join(process.cwd(), fileName);
} else {
filePath = path.join(process.cwd(), 'payload.json');
}
}
if (!fs.existsSync(filePath)) {
console.error(\`❌ Payload file not found: \${filePath}\`);
return;
}
let payloadContent = fs.readFileSync(filePath, 'utf8');
payloadContent = replaceEnvVariables(payloadContent);
payloadContent = replaceAliasVariables(payloadContent);
const resolvedEndpoint = replaceEnvVariables(endpoint);
const url = \`\${baseUrl}\${resolvedEndpoint}\`;
const response = http.del(url, payloadContent, { headers: defaultHeaders });
globalThis.lastResponse = response;
console.log(\`🗑️ DELETE \${url} with payload from \${filePath}\`);
}
export function k6TheResponsePropertyShouldBe(propertyPath: string, expectedValue: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
try {
const body = res.json();
const actualValue = getPropertyByPath(body, propertyPath);
check(res, {
[\`response property "\${propertyPath}" is "\${expectedValue}"\`]: () => String(actualValue) === expectedValue
});
} catch (e: any) {
check(res, {
[\`response property "\${propertyPath}" is "\${expectedValue}"\`]: () => false
});
}
}
export function k6TheResponsePropertyShouldHaveProperty(parentPath: string, childProperty: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
try {
const body = res.json();
const parentValue = getPropertyByPath(body, parentPath);
if (parentValue === undefined || parentValue === null) {
console.error(\`❌ Parent property "\${parentPath}" not found or null\`);
check(res, {
[\`response property "\${parentPath}" has property "\${childProperty}"\`]: () => false
});
return;
}
if (typeof parentValue !== 'object') {
console.error(\`❌ Parent property "\${parentPath}" is not an object\`);
check(res, {
[\`response property "\${parentPath}" has property "\${childProperty}"\`]: () => false
});
return;
}
const hasProperty = childProperty in parentValue;
check(res, {
[\`response property "\${parentPath}" has property "\${childProperty}"\`]: () => hasProperty
});
if (hasProperty) {
console.log(\`✅ Response property "\${parentPath}" has property "\${childProperty}"\`);
} else {
console.error(\`❌ Response property "\${parentPath}" does not have property "\${childProperty}". Available keys:\`, Object.keys(parentValue).join(', '));
}
} catch (err) {
const e = err as Error;
check(res, {
[\`response property "\${parentPath}" has property "\${childProperty}"\`]: () => false
});
console.error('Error checking property:', e.message);
}
}
export function k6TheResponsePropertyShouldContain(propertyPath: string, expectedText: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
try {
const body = res.json();
const actualValue = getPropertyByPath(body, propertyPath);
check(res, {
[\`response property "\${propertyPath}" contains "\${expectedText}"\`]: () => String(actualValue).includes(expectedText)
});
} catch (e: any) {
check(res, {
[\`response property "\${propertyPath}" contains "\${expectedText}"\`]: () => false
});
}
}
export function k6TheResponseTimeShouldBeLessThanMilliseconds(milliseconds: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
const maxMs = parseInt(milliseconds, 10);
const actualMs = res.timings?.duration || res.timings?.end - res.timings?.start || 0;
check(res, {
[\`response time is less than \${milliseconds}ms\`]: () => actualMs < maxMs
});
if (actualMs < maxMs) {
console.log(\`✅ Response time: \${actualMs}ms (< \${maxMs}ms)\`);
} else {
console.error(\`❌ Response time: \${actualMs}ms (>= \${maxMs}ms threshold)\`);
}
}
export function k6TheResponseTimeShouldBeLessThanSeconds(seconds: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
const maxSeconds = parseInt(seconds, 10);
const maxMs = maxSeconds * 1000;
const actualMs = res.timings?.duration || res.timings?.end - res.timings?.start || 0;
check(res, {
[\`response time is less than \${seconds}s\`]: () => actualMs < maxMs
});
if (actualMs < maxMs) {
console.log(\`✅ Response time: \${actualMs}ms (< \${maxSeconds}s)\`);
} else {
console.error(\`❌ Response time: \${actualMs}ms (>= \${maxSeconds}s threshold)\`);
}
}
function getPropertyByPath(obj: any, path: string): any {
return path.split('.').reduce((acc: any, key: string) => {
return acc && acc[key] !== undefined ? acc[key] : undefined;
}, obj);
}
export function k6IClearAuthToken() {
delete defaultHeaders['Authorization'];
console.log('🔑 Cleared Authorization header');
}
export function k6IStoreResponseAs(propertyPath: string, alias: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found! Cannot store response.');
return;
}
try {
const body = res.json();
const value = getPropertyByPath(body, propertyPath);
if (value === undefined) {
console.error(\`❌ Path "\${propertyPath}" not found in response. Available keys:\`, Object.keys(body));
return;
}
if (!globalThis.storedAliases) {
globalThis.storedAliases = {};
}
globalThis.storedAliases[alias] = value;
const displayValue = typeof value === 'string' && value.length > 20
? value.substring(0, 20) + '...'
: value;
console.log(\`✅ Stored response "\${propertyPath}" as "\${alias}": \${JSON.stringify(displayValue)}\`);
} catch (err) {
const e = err as Error;
console.error('❌ Failed to parse response as JSON:', e.message || e);
}
}
export function k6IStoreResponseDataAs(propertyPath: string, alias: string) {
return k6IStoreResponseAs(propertyPath, alias);
}
export function k6TheResponsePropertyShouldBeAlias(propertyPath: string, alias: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
const storedValue = globalThis.storedAliases?.[alias];
if (storedValue === undefined) {
console.error(\`❌ Alias "\${alias}" not found. Available aliases:\`, globalThis.storedAliases ? Object.keys(globalThis.storedAliases) : 'none');
return;
}
try {
const body = res.json();
const actualValue = getPropertyByPath(body, propertyPath);
check(res, {
[\`response property "\${propertyPath}" matches alias "\${alias}"\`]: () => String(actualValue) === String(storedValue)
});
} catch (err) {
const e = err as Error;
check(res, {
[\`response property "\${propertyPath}" matches alias "\${alias}"\`]: () => false
});
console.error('Error parsing response:', e.message);
}
}
export function k6TheResponsePropertyShouldContainAlias(propertyPath: string, alias: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
const storedValue = globalThis.storedAliases?.[alias];
if (storedValue === undefined) {
console.error(\`❌ Alias "\${alias}" not found. Available aliases:\`, globalThis.storedAliases ? Object.keys(globalThis.storedAliases) : 'none');
return;
}
try {
const body = res.json();
const actualValue = getPropertyByPath(body, propertyPath);
check(res, {
[\`response property "\${propertyPath}" contains alias "\${alias}"\`]: () => String(actualValue).includes(String(storedValue))
});
} catch (err) {
const e = err as Error;
check(res, {
[\`response property "\${propertyPath}" contains alias "\${alias}"\`]: () => false
});
console.error('Error parsing response:', e.message);
}
}
export function k6TheResponsePropertyShouldNotBeAlias(propertyPath: string, alias: string) {
const res = globalThis.lastResponse;
if (!res) {
console.error('❌ No lastResponse found!');
return;
}
const storedValue = globalThis.storedAliases?.[alias];
if (storedValue === undefined) {
console.error(\`❌ Alias "\${alias}" not found. Available aliases:\`, globalThis.storedAliases ? Object.keys(globalThis.storedAliases) : 'none');
return;
}
try {
const body = res.json();
const actualValue = getPropertyByPath(body, propertyPath);
check(res, {
[\`response property "\${propertyPath}" does not match alias "\${alias}"\`]: () => String(actualValue) !== String(storedValue)
});
} catch (err) {
const e = err as Error;
check(res, {
[\`response property "\${propertyPath}" does not match alias "\${alias}"\`]: () => false
});
console.error('Error parsing response:', e.message);
}
}
export function k6TheAliasShouldNotBeEmpty(alias: string) {
const storedValue = globalThis.storedAliases?.[alias];
if (storedValue === undefined) {
console.error(\`❌ Alias "\${alias}" not found. Available aliases:\`, globalThis.storedAliases ? Object.keys(globalThis.storedAliases) : 'none');
check({ value: null }, {
[\`alias "\${alias}" exists and is not empty\`]: () => false
});
return;
}
const isEmpty = storedValue === null || storedValue === undefined || storedValue === '' ||
(Array.isArray(storedValue) && storedValue.length === 0) ||
(typeof storedValue === 'object' && Object.keys(storedValue).length === 0);
check({ value: storedValue }, {
[\`alias "\${alias}" is not empty\`]: () => !isEmpty
});
if (!isEmpty) {
console.log(\`✅ Alias "\${alias}" has value: \${typeof storedValue === 'string' && storedValue.length > 20 ? storedValue.substring(0, 20) + '...' : storedValue}\`);
}
}
export function k6TheAliasShouldBeEqualTo(alias: string, expectedValue: string) {
const storedValue = globalThis.storedAliases?.[alias];
if (storedValue === undefined) {
console.error(\`❌ Alias "\${alias}" not found. Available aliases:\`, globalThis.storedAliases ? Object.keys(globalThis.storedAliases) : 'none');
check({ value: null }, {
[\`alias "\${alias}" equals "\${expectedValue}"\`]: () => false
});
return;
}
check({ value: storedValue }, {
[\`alias "\${alias}" equals "\${expectedValue}"\`]: () => String(storedValue) === expectedValue
});
}
export function k6IPrintAlias(alias: string) {
const storedValue = globalThis.storedAliases?.[alias];
if (storedValue === undefined) {
console.error(\`❌ Alias "\${alias}" not found. Available aliases:\`, globalThis.storedAliases ? Object.keys(globalThis.storedAliases) : 'none');
return;
}
console.log(\`📋 Alias "\${alias}" = \${JSON.stringify(storedValue, null, 2)}\`);
}
export function k6IPrintAllAliases() {
if (!globalThis.storedAliases) {
console.log('📋 No aliases stored yet.');
return;
}
const aliases = globalThis.storedAliases;
const keys = Object.keys(aliases);
if (keys.length === 0) {
console.log('📋 No aliases stored yet.');
return;
}
console.log('📋 Stored Aliases:');
keys.forEach(key => {
const value = aliases[key];
const displayValue = typeof value === 'string' && value.length > 50
? value.substring(0, 50) + '...'
: JSON.stringify(value);
console.log(\` \${key} = \${displayValue}\`);
});
}
/* ===== BROWSER STEPS ===== */
export async function k6INavigateToThePage(page: any, url: string) {
let effectiveBase = baseUrl;
if (typeof effectiveBase !== 'string' || effectiveBase.trim() === '') {
console.warn('Invalid baseUrl detected:', baseUrl, '— using fallback');
effectiveBase = 'https://test.k6.io';
}
const fullUrl = url.startsWith('http') ? url : \`\${effectiveBase}\${url.startsWith('/') ? '' : '/'}\${url}\`;
console.log(\`Navigating to: \${fullUrl} (base: \${effectiveBase})\`);
await page.goto(fullUrl, { waitUntil: 'networkidle', timeout: 60000 });
}
export async function k6IClickTheButton(page: any, selector: string) {
await page.locator(selector).click();
}
export async function k6IShouldSeeTheText(page: any, expectedText: string) {
let locator = page.getByRole('heading', { name: expectedText, exact: false });
if ((await locator.count()) === 0) {
locator = page.getByText(expectedText, { exact: false }).first();
}
try {
await locator.waitFor({ state: 'visible', timeout: 30000 });
const count = await locator.count();
console.log(\`Found \${count} visible elements matching "\${expectedText}"\`);
check(locator, {
[\`Text/heading containing "\${expectedText}" is visible\`]: () => count >= 1
});
} catch (e: any) {
console.error(\`Text wait failed for "\${expectedText}":\`, e.message || e);
check(locator, {
[\`Text/heading containing "\${expectedText}" is visible\`]: () => false
});
}
}
export async function k6IClickOnTheElement(page: any, selector: string, nth?: any) {
const locator = nth
? page.locator(selector).nth(parseInt(nth) - 1)
: page.locator(selector);
await locator.waitFor({ state: 'visible', timeout: 15000 });
await locator.click();
console.log(\`✅ Clicked element: \${selector}\`);
}
export async function k6IFillTheFieldWith(
page: any,
selector: string,
value: string,
nth?: any
) {
const locator = nth
? page.locator(selector).nth(parseInt(nth) - 1)
: page.locator(selector);
await locator.waitFor({ state: 'visible', timeout: 15000 });
await locator.fill(value);
console.log(\`✅ Filled field \${selector} with "\${value}"\`);
}
export async function k6IFill(page: any, value: string) {
await page.keyboard.type(value);
console.log(\`✅ Filled value: "\${value}" (using keyboard)\`);
}
export async function k6ThePageTitleShouldBe(page: any, expectedTitle: string) {
await page.waitForLoadState('networkidle');
const title = await page.title();
check(title, {
[\`Page title is "\${expectedTitle}"\`]: (t) => t === expectedTitle
});
}
export async function k6TheCurrentUrlShouldContain(page: any, expectedFragment: string) {
const url = page.url();
check(url, {
[\`URL contains "\${expectedFragment}"\`]: (u) => u.includes(expectedFragment)
});
}
export async function k6IShouldSeeTheElement(page: any, selector: string) {
const locator = page.locator(selector);
await locator.waitFor({ state: 'visible', timeout: 20000 });
const isVisible = await locator.isVisible();
if (!isVisible) throw new Error(\`Element not visible: \${selector}\`);
console.log(\`✅ Verified visibility of element: \${selector}\`);
}
export async function k6IShouldNotSeeTheText(page: any, text: string) {
const locator = page.getByText(text, { exact: false });
const isHidden = (await locator.count()) === 0 || !(await locator.isVisible());
check(isHidden, {
[\`Text "\${text}" is not visible\`]: (hidden) => hidden === true
});
}
export async function k6ISelectFromTheDropdown(page: any, option: string, selector: string) {
const locator = page.locator(selector);
await locator.selectOption(option);
console.log(\`Selected "\${option}" from dropdown "\${selector}"\`);
}
export async function k6IWaitForTheElementToBeVisible(page: any, selector: string) {
const locator = page.locator(selector);
await locator.waitFor({ state: 'visible', timeout: 30000 });
}
export async function k6IGetElementBySelector(page: any, selector: string) {
const locator = page.locator(selector);
await locator.waitFor({ state: 'visible', timeout: 15000 });
console.log(\`Found element by selector: \${selector}\`);
return locator;
}
export async function k6IFindElementByLabel(page: any, labelText: string) {
const locator = page.getByLabel(labelText, { exact: false });
await locator.waitFor({ state: 'visible', timeout: 15000 });
console.log(\`Found element by label: "\${labelText}"\`);
return locator;
}
export async function k6IFindElementByTextarea(page: any, placeholderOrLabel: string) {
let locator = page.getByPlaceholder(placeholderOrLabel, { exact: false });
if ((await locator.count()) === 0) {
locator = page.getByLabel(placeholderOrLabel, { exact: false })
.or(page.getByRole('textbox', { name: placeholderOrLabel }));
}
await locator.waitFor({ state: 'visible', timeout: 15000 });
console.log(\`Found textarea by placeholder / label: "\${placeholderOrLabel}"\`);
return locator;
}
export async function k6IClick(page: any) {
try {
const bbox = await page.evaluate(() => {
const el = document.activeElement;
if (!el || !el.getBoundingClientRect) return null;
const rect = el.getBoundingClientRect();
return {
x: rect.left + window.scrollX,
y: rect.top + window.scrollY,
width: rect.width,
height: rect.height
};
});
if (!bbox || bbox.width === 0 || bbox.height === 0) {
console.warn('No clickable focused element found');
return;
}
const x = bbox.x + bbox.width / 2;
const y = bbox.y + bbox.height / 2;
await page.mouse.click(x, y);
console.log('✅ Performed mouse click on focused element');
} catch (error: any) {
console.error('Click failed on focused element:', error.message || error);
throw error;
}
}
export async function k6IWaitSeconds(page: any, secondsStr: string) {
const seconds = parseFloat(secondsStr);
if (isNaN(seconds) || seconds < 0) {
throw new Error(\`Invalid wait time: "\${secondsStr}"\`);
}
await sleep(seconds);
}
export async function k6IWaitMilliseconds(page: any, milliseconds: string) {
const timeInMs = parseFloat(milliseconds);
if (isNaN(timeInMs) || timeInMs < 0) {
throw new Error(\`Invalid wait time: "\${milliseconds}" milliseconds\`);
}
console.log(\`Waiting for \${milliseconds} ms\`);
await page.waitForTimeout(timeInMs);
}
export async function k6IFindInputElementByPlaceholderText(page: any, placeholder: string) {
const locator = page.getByPlaceholder(placeholder, { exact: false });
await locator.waitFor({ state: 'visible', timeout: 20000 });
const count = await locator.count();
console.log(\`Found \${count} input(s) with placeholder "\${placeholder}"\`);
return locator;
}
export async function k6IFindElementByText(page: any, text: string) {
const locator = page.getByText(text, { exact: false });
await locator.waitFor({ state: 'visible', timeout: 20000 });
const count = await locator.count();
console.log(\`Found \${count} element(s) containing text "\${text}"\`);
return locator;
}
export async function k6IFindElementsByText(page: any, text: string) {
const locator = page.getByText(text, { exact: false });
await locator.waitFor({ state: 'visible', timeout: 20000 });
const count = await locator.count();
console.log(\`Found \${count} elements containing text "\${text}"\`);
return locator;
}
export async function k6IFindButtonByText(page: any, buttonText: string) {
const locator = page.getByText(buttonText, { exact: false });
await locator.waitFor({ state: 'visible', timeout: 20000 });
const count = await locator.count();
console.log(\`Found \${count} element(s) containing text "\${buttonText}"\`);
return locator;
}
export async function k6IFindElementByValue(page: any, valueText: string) {
const locator = page.locator(\`input[value="\${valueText}"], textarea[value="\${valueText}"]\`);
try {
await locator.waitFor({ state: 'visible', timeout: 20000 });
const count = await locator.count();
if (count === 0) {
console.warn(\`No element found with value attribute "\${valueText}"\`);
}
console.log(\`Found \${count} element(s) with value attribute "\${valueText}"\`);
if (count > 0) {
const tags = await locator.evaluateAll((els: Element[]) =>
els.map((el: Element) => el.tagName.toLowerCase())
);
console.log(\`Matching elements are: \${tags.join(', ')}\`);
}
return locator;
} catch (error: any) {
console.error(\`Could not find element by value "\${valueText}":\`, error.message || error);
check(locator, {
[\`Element with value "\${valueText}" is found\`]: () => false
});
throw error;
}
}
export async function k6IFindElementByRole(page: any, roleName: string, nameOrOptions?: string | object) {
let locator;
if (!nameOrOptions) {
locator = page.getByRole(roleName);
} else if (typeof nameOrOptions === 'string') {
locator = page.getByRole(roleName, { name: nameOrOptions, exact: false });
} else {
locator = page.getByRole(roleName, nameOrOptions);
}
try {
await locator.waitFor({ state: 'visible', timeout: 20000 });
const count = await locator.count();
console.log(\`Found \${count} element(s) by role "\${roleName}"\`);
if (typeof nameOrOptions === 'string') {
console.log(\` with name containing "\${nameOrOptions}"\`);
}
return locator;
} catch (error: any) {
console.error(\`Could not find element by role "\${roleName}":\`, error.message || error);
check(locator, {
[\`Element by role "\${roleName}" is found\`]: () => false
});
throw error;
}
}
export async function k6IFindButtonsByText(page: any, buttonText: string) {
const locator = page.getByRole('button', { name: buttonText, exact: false });
await locator.waitFor({ state: 'visible', timeout: 20000 });
const count = await locator.count();
console.log(\`Found \${count} button(s) with text "\${buttonText}"\`);
return locator;
}
export async function k6IFindElementByName(page: any, labelText: string) {
const locator = page.getByLabel(labelText, { exact: false });
await locator.waitFor({ state: 'visible', timeout: 20000 });
console.log(\`Found input by label: "\${labelText}"\`);
return locator;
}
export async function k6IFindElementById(page: any, id: string) {
const selector = id.startsWith('#') ? id : \`#\${id}\`;
const locator = page.locator(selector);
await locator.waitFor({ state: 'visible', timeout: 20000 });
console.log(\`Found element by ID: \${selector}\`);
return locator;
}
export async function k6IClickOnExactText(page: any, text: string) {
const locator = page.getByText(text, { exact: true });
try {
await locator.waitFor({ state: 'visible', timeout: 20000 });
const count = await locator.count();
if (count === 0) {
throw new Error(\`No element found with exact text: "\${text}"\`);
}
if (count > 1) {
console.warn(\`⚠️ Multiple (\${count}) elements found with exact text "\${text}". Clicking the first.\`);
}
await locator.first().click();
console.log(\`✅ Clicked element with exact text: "\${text}"\`);
} catch (error: any) {
console.error(\`Failed to click exact text "\${text}":\`, error.message || error);
throw error;
}
}
export async function k6IFillNthFieldBySelector(page: any, n: string, selector: string, value: string) {
const index = parseInt(n.replace(/\\D/g, '')) - 1;
if (isNaN(index)) throw new Error(\`Invalid nth value: \${n}\`);
const locator = page.locator(selector).nth(index);
await locator.waitFor({ state: 'visible', timeout: 15000 });
await locator.fill(value);
console.log(\`Filled the \${n} element matching "\${selector}" with "\${value}"\`);
}
`;
}
}
exports.SampleStepsGenerator = SampleStepsGenerator;
//# sourceMappingURL=sample-steps.generator.js.map