@testsmith/perfornium 0.1.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 +360 -0
- package/dist/cli/cli.d.ts +2 -0
- package/dist/cli/cli.js +192 -0
- package/dist/cli/commands/distributed.d.ts +11 -0
- package/dist/cli/commands/distributed.js +179 -0
- package/dist/cli/commands/import.d.ts +23 -0
- package/dist/cli/commands/import.js +461 -0
- package/dist/cli/commands/init.d.ts +7 -0
- package/dist/cli/commands/init.js +923 -0
- package/dist/cli/commands/mock.d.ts +7 -0
- package/dist/cli/commands/mock.js +281 -0
- package/dist/cli/commands/report.d.ts +5 -0
- package/dist/cli/commands/report.js +70 -0
- package/dist/cli/commands/run.d.ts +12 -0
- package/dist/cli/commands/run.js +260 -0
- package/dist/cli/commands/validate.d.ts +3 -0
- package/dist/cli/commands/validate.js +35 -0
- package/dist/cli/commands/worker.d.ts +27 -0
- package/dist/cli/commands/worker.js +320 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +20 -0
- package/dist/config/parser.d.ts +19 -0
- package/dist/config/parser.js +330 -0
- package/dist/config/types/global-config.d.ts +74 -0
- package/dist/config/types/global-config.js +2 -0
- package/dist/config/types/hooks.d.ts +58 -0
- package/dist/config/types/hooks.js +3 -0
- package/dist/config/types/import-types.d.ts +33 -0
- package/dist/config/types/import-types.js +2 -0
- package/dist/config/types/index.d.ts +11 -0
- package/dist/config/types/index.js +27 -0
- package/dist/config/types/load-config.d.ts +32 -0
- package/dist/config/types/load-config.js +9 -0
- package/dist/config/types/output-config.d.ts +10 -0
- package/dist/config/types/output-config.js +2 -0
- package/dist/config/types/report-config.d.ts +10 -0
- package/dist/config/types/report-config.js +2 -0
- package/dist/config/types/runtime-types.d.ts +6 -0
- package/dist/config/types/runtime-types.js +2 -0
- package/dist/config/types/scenario-config.d.ts +30 -0
- package/dist/config/types/scenario-config.js +2 -0
- package/dist/config/types/step-types.d.ts +139 -0
- package/dist/config/types/step-types.js +2 -0
- package/dist/config/types/test-configuration.d.ts +18 -0
- package/dist/config/types/test-configuration.js +2 -0
- package/dist/config/types/worker-config.d.ts +12 -0
- package/dist/config/types/worker-config.js +2 -0
- package/dist/config/validator.d.ts +19 -0
- package/dist/config/validator.js +198 -0
- package/dist/core/csv-data-provider.d.ts +47 -0
- package/dist/core/csv-data-provider.js +265 -0
- package/dist/core/hooks-manager.d.ts +33 -0
- package/dist/core/hooks-manager.js +129 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +11 -0
- package/dist/core/script-executor.d.ts +14 -0
- package/dist/core/script-executor.js +290 -0
- package/dist/core/step-executor.d.ts +41 -0
- package/dist/core/step-executor.js +680 -0
- package/dist/core/test-runner.d.ts +34 -0
- package/dist/core/test-runner.js +465 -0
- package/dist/core/threshold-evaluator.d.ts +43 -0
- package/dist/core/threshold-evaluator.js +170 -0
- package/dist/core/virtual-user-pool.d.ts +42 -0
- package/dist/core/virtual-user-pool.js +136 -0
- package/dist/core/virtual-user.d.ts +51 -0
- package/dist/core/virtual-user.js +488 -0
- package/dist/distributed/coordinator.d.ts +34 -0
- package/dist/distributed/coordinator.js +158 -0
- package/dist/distributed/health-monitor.d.ts +18 -0
- package/dist/distributed/health-monitor.js +72 -0
- package/dist/distributed/load-distributor.d.ts +17 -0
- package/dist/distributed/load-distributor.js +106 -0
- package/dist/distributed/remote-worker.d.ts +37 -0
- package/dist/distributed/remote-worker.js +241 -0
- package/dist/distributed/result-aggregator.d.ts +43 -0
- package/dist/distributed/result-aggregator.js +146 -0
- package/dist/dsl/index.d.ts +3 -0
- package/dist/dsl/index.js +11 -0
- package/dist/dsl/test-builder.d.ts +111 -0
- package/dist/dsl/test-builder.js +514 -0
- package/dist/importers/har-importer.d.ts +17 -0
- package/dist/importers/har-importer.js +172 -0
- package/dist/importers/open-api-importer.d.ts +23 -0
- package/dist/importers/open-api-importer.js +181 -0
- package/dist/importers/wsdl-importer.d.ts +42 -0
- package/dist/importers/wsdl-importer.js +440 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +17 -0
- package/dist/load-patterns/arrivals.d.ts +7 -0
- package/dist/load-patterns/arrivals.js +118 -0
- package/dist/load-patterns/base.d.ts +9 -0
- package/dist/load-patterns/base.js +2 -0
- package/dist/load-patterns/basic.d.ts +7 -0
- package/dist/load-patterns/basic.js +117 -0
- package/dist/load-patterns/stepping.d.ts +6 -0
- package/dist/load-patterns/stepping.js +122 -0
- package/dist/metrics/collector.d.ts +72 -0
- package/dist/metrics/collector.js +662 -0
- package/dist/metrics/types.d.ts +135 -0
- package/dist/metrics/types.js +2 -0
- package/dist/outputs/base.d.ts +7 -0
- package/dist/outputs/base.js +2 -0
- package/dist/outputs/csv.d.ts +13 -0
- package/dist/outputs/csv.js +163 -0
- package/dist/outputs/graphite.d.ts +13 -0
- package/dist/outputs/graphite.js +126 -0
- package/dist/outputs/influxdb.d.ts +12 -0
- package/dist/outputs/influxdb.js +82 -0
- package/dist/outputs/json.d.ts +14 -0
- package/dist/outputs/json.js +107 -0
- package/dist/outputs/streaming-csv.d.ts +37 -0
- package/dist/outputs/streaming-csv.js +254 -0
- package/dist/outputs/streaming-json.d.ts +43 -0
- package/dist/outputs/streaming-json.js +353 -0
- package/dist/outputs/webhook.d.ts +16 -0
- package/dist/outputs/webhook.js +96 -0
- package/dist/protocols/base.d.ts +33 -0
- package/dist/protocols/base.js +2 -0
- package/dist/protocols/rest/handler.d.ts +67 -0
- package/dist/protocols/rest/handler.js +776 -0
- package/dist/protocols/soap/handler.d.ts +12 -0
- package/dist/protocols/soap/handler.js +165 -0
- package/dist/protocols/web/core-web-vitals.d.ts +121 -0
- package/dist/protocols/web/core-web-vitals.js +373 -0
- package/dist/protocols/web/handler.d.ts +50 -0
- package/dist/protocols/web/handler.js +706 -0
- package/dist/recorder/native-recorder.d.ts +14 -0
- package/dist/recorder/native-recorder.js +533 -0
- package/dist/recorder/scenario-recorder.d.ts +55 -0
- package/dist/recorder/scenario-recorder.js +296 -0
- package/dist/reporting/constants.d.ts +94 -0
- package/dist/reporting/constants.js +82 -0
- package/dist/reporting/enhanced-html-generator.d.ts +55 -0
- package/dist/reporting/enhanced-html-generator.js +965 -0
- package/dist/reporting/generator.d.ts +42 -0
- package/dist/reporting/generator.js +1217 -0
- package/dist/reporting/statistics.d.ts +144 -0
- package/dist/reporting/statistics.js +742 -0
- package/dist/reporting/templates/enhanced-report.hbs +2812 -0
- package/dist/reporting/templates/html.hbs +2453 -0
- package/dist/utils/faker-manager.d.ts +55 -0
- package/dist/utils/faker-manager.js +166 -0
- package/dist/utils/file-manager.d.ts +33 -0
- package/dist/utils/file-manager.js +154 -0
- package/dist/utils/handlebars-manager.d.ts +42 -0
- package/dist/utils/handlebars-manager.js +172 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.js +46 -0
- package/dist/utils/template.d.ts +80 -0
- package/dist/utils/template.js +513 -0
- package/dist/utils/test-output-writer.d.ts +56 -0
- package/dist/utils/test-output-writer.js +643 -0
- package/dist/utils/time.d.ts +3 -0
- package/dist/utils/time.js +23 -0
- package/dist/utils/timestamp-helper.d.ts +17 -0
- package/dist/utils/timestamp-helper.js +53 -0
- package/dist/workers/manager.d.ts +18 -0
- package/dist/workers/manager.js +95 -0
- package/dist/workers/server.d.ts +21 -0
- package/dist/workers/server.js +205 -0
- package/dist/workers/worker.d.ts +19 -0
- package/dist/workers/worker.js +147 -0
- package/package.json +102 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.CSVDataProvider = void 0;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const papaparse_1 = __importDefault(require("papaparse"));
|
|
43
|
+
const logger_1 = require("../utils/logger");
|
|
44
|
+
/** Apply variable name mapping to a row */
|
|
45
|
+
function applyVariableMapping(row, mapping) {
|
|
46
|
+
if (!mapping || Object.keys(mapping).length === 0) {
|
|
47
|
+
return row;
|
|
48
|
+
}
|
|
49
|
+
const mappedRow = {};
|
|
50
|
+
for (const [csvColumn, value] of Object.entries(row)) {
|
|
51
|
+
// Use mapped name if defined, otherwise keep original column name
|
|
52
|
+
const variableName = mapping[csvColumn] || csvColumn;
|
|
53
|
+
mappedRow[variableName] = value;
|
|
54
|
+
}
|
|
55
|
+
return mappedRow;
|
|
56
|
+
}
|
|
57
|
+
class CSVDataProvider {
|
|
58
|
+
// Remove test termination callback - we don't need it anymore
|
|
59
|
+
constructor(filePath, config) {
|
|
60
|
+
this.data = [];
|
|
61
|
+
this.originalData = [];
|
|
62
|
+
this.currentIndex = 0;
|
|
63
|
+
this.isLoaded = false;
|
|
64
|
+
this.isExhausted = false;
|
|
65
|
+
this.globalIndex = 0; // For sequential tracking across all modes
|
|
66
|
+
this.accessCount = 0; // For random mode tracking
|
|
67
|
+
this.filePath = filePath;
|
|
68
|
+
this.config = config;
|
|
69
|
+
}
|
|
70
|
+
static getInstance(config) {
|
|
71
|
+
const fullPath = path.resolve(CSVDataProvider.baseDir, config.file);
|
|
72
|
+
const key = `${fullPath}-${JSON.stringify(config)}`;
|
|
73
|
+
if (!CSVDataProvider.instances.has(key)) {
|
|
74
|
+
CSVDataProvider.instances.set(key, new CSVDataProvider(fullPath, config));
|
|
75
|
+
}
|
|
76
|
+
return CSVDataProvider.instances.get(key);
|
|
77
|
+
}
|
|
78
|
+
static setBaseDir(dir) {
|
|
79
|
+
CSVDataProvider.baseDir = dir;
|
|
80
|
+
}
|
|
81
|
+
// ... existing loadData method stays the same ...
|
|
82
|
+
async loadData() {
|
|
83
|
+
if (this.isLoaded) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const fullPath = path.resolve(CSVDataProvider.baseDir, this.config.file);
|
|
87
|
+
if (!fs.existsSync(fullPath)) {
|
|
88
|
+
throw new Error(`CSV file not found: ${fullPath}`);
|
|
89
|
+
}
|
|
90
|
+
logger_1.logger.info(`📊 Loading CSV data from: ${this.config.file}`);
|
|
91
|
+
const encoding = this.config.encoding || 'utf8';
|
|
92
|
+
const csvContent = fs.readFileSync(fullPath, encoding);
|
|
93
|
+
const parseConfig = {
|
|
94
|
+
header: true,
|
|
95
|
+
delimiter: this.config.delimiter || ',',
|
|
96
|
+
skipEmptyLines: this.config.skipEmptyLines !== false,
|
|
97
|
+
dynamicTyping: true,
|
|
98
|
+
delimitersToGuess: [',', '\t', '|', ';']
|
|
99
|
+
};
|
|
100
|
+
const parseResult = papaparse_1.default.parse(csvContent, parseConfig);
|
|
101
|
+
if (parseResult.errors.length > 0) {
|
|
102
|
+
logger_1.logger.warn('CSV parsing warnings:', parseResult.errors);
|
|
103
|
+
}
|
|
104
|
+
this.originalData = parseResult.data;
|
|
105
|
+
if (this.config.skipFirstLine) {
|
|
106
|
+
this.originalData = this.originalData.slice(1);
|
|
107
|
+
}
|
|
108
|
+
if (this.config.columns && this.config.columns.length > 0) {
|
|
109
|
+
this.originalData = this.originalData.map(row => {
|
|
110
|
+
const filteredRow = {};
|
|
111
|
+
for (const col of this.config.columns) {
|
|
112
|
+
if (row.hasOwnProperty(col)) {
|
|
113
|
+
filteredRow[col] = row[col];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return filteredRow;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (this.config.filter) {
|
|
120
|
+
this.originalData = this.filterData(this.originalData, this.config.filter);
|
|
121
|
+
}
|
|
122
|
+
if (this.config.randomize) {
|
|
123
|
+
this.originalData = this.shuffleArray([...this.originalData]);
|
|
124
|
+
}
|
|
125
|
+
this.data = [...this.originalData];
|
|
126
|
+
this.isLoaded = true;
|
|
127
|
+
logger_1.logger.info(`📊 Loaded ${this.data.length} rows from CSV: ${this.config.file}`);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Enhanced getNextRow - returns null when exhausted if cycleOnExhaustion is false
|
|
131
|
+
*/
|
|
132
|
+
async getNextRow(vuId) {
|
|
133
|
+
await this.loadData();
|
|
134
|
+
if (this.originalData.length === 0) {
|
|
135
|
+
logger_1.logger.warn(`📊 No data available in CSV: ${this.config.file}`);
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
// If cycling is disabled, use sequential exhaustible access
|
|
139
|
+
if (this.config.cycleOnExhaustion === false) {
|
|
140
|
+
if (this.globalIndex >= this.originalData.length) {
|
|
141
|
+
logger_1.logger.warn(`📊 VU${vuId}: CSV data exhausted in file: ${this.config.file} (next mode, cycling disabled)`);
|
|
142
|
+
return null; // Just return null, don't terminate test
|
|
143
|
+
}
|
|
144
|
+
const row = this.originalData[this.globalIndex];
|
|
145
|
+
this.globalIndex++;
|
|
146
|
+
logger_1.logger.info(`📊 VU${vuId} using sequential CSV row ${this.globalIndex}/${this.originalData.length}:`, Object.keys(row));
|
|
147
|
+
return applyVariableMapping({ ...row }, this.config.variables);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// Normal round-robin behavior
|
|
151
|
+
const index = (vuId - 1) % this.originalData.length;
|
|
152
|
+
const row = this.originalData[index];
|
|
153
|
+
logger_1.logger.debug(`📊 VU${vuId} using CSV row ${index + 1}/${this.originalData.length}:`, Object.keys(row));
|
|
154
|
+
return applyVariableMapping({ ...row }, this.config.variables);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Enhanced getUniqueRow - returns null when exhausted if cycleOnExhaustion is false
|
|
159
|
+
*/
|
|
160
|
+
async getUniqueRow(vuId) {
|
|
161
|
+
await this.loadData();
|
|
162
|
+
if (this.data.length === 0) {
|
|
163
|
+
if (this.isExhausted && this.config.cycleOnExhaustion === false) {
|
|
164
|
+
logger_1.logger.warn(`📊 VU${vuId}: CSV data exhausted and cycling disabled: ${this.config.file}`);
|
|
165
|
+
return null; // Just return null, don't terminate test
|
|
166
|
+
}
|
|
167
|
+
logger_1.logger.warn(`📊 VU${vuId}: No more data available in CSV: ${this.config.file}`);
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
const row = this.data.shift();
|
|
171
|
+
logger_1.logger.info(`📊 VU${vuId} using unique CSV row (${this.data.length} remaining):`, Object.keys(row));
|
|
172
|
+
if (this.data.length === 0) {
|
|
173
|
+
this.isExhausted = true;
|
|
174
|
+
if (this.config.cycleOnExhaustion !== false) {
|
|
175
|
+
logger_1.logger.info(`📊 CSV data exhausted, reloading: ${this.config.file}`);
|
|
176
|
+
this.data = [...this.originalData];
|
|
177
|
+
if (this.config.randomize) {
|
|
178
|
+
this.data = this.shuffleArray(this.data);
|
|
179
|
+
}
|
|
180
|
+
this.isExhausted = false;
|
|
181
|
+
logger_1.logger.info(`📊 CSV data reloaded: ${this.data.length} rows available`);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
logger_1.logger.warn(`📊 CSV data exhausted, cycling disabled: ${this.config.file} - future requests will return null`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return applyVariableMapping({ ...row }, this.config.variables);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Enhanced getRandomRow - returns null when exhausted if cycleOnExhaustion is false
|
|
191
|
+
*/
|
|
192
|
+
async getRandomRow(vuId = 0) {
|
|
193
|
+
await this.loadData();
|
|
194
|
+
if (this.originalData.length === 0) {
|
|
195
|
+
logger_1.logger.warn(`📊 No data available for random selection in CSV: ${this.config.file}`);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
// If cycling is disabled, track accesses and stop after using all data once
|
|
199
|
+
if (this.config.cycleOnExhaustion === false) {
|
|
200
|
+
this.accessCount++;
|
|
201
|
+
if (this.accessCount > this.originalData.length) {
|
|
202
|
+
logger_1.logger.warn(`📊 VU${vuId}: CSV data exhausted in file: ${this.config.file} (random mode, cycling disabled, ${this.accessCount} accesses)`);
|
|
203
|
+
return null; // Just return null, don't terminate test
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const randomIndex = Math.floor(Math.random() * this.originalData.length);
|
|
207
|
+
const row = this.originalData[randomIndex];
|
|
208
|
+
logger_1.logger.debug(`📊 VU${vuId} using random CSV row ${randomIndex + 1}/${this.originalData.length} (access ${this.accessCount}):`, Object.keys(row));
|
|
209
|
+
return applyVariableMapping({ ...row }, this.config.variables);
|
|
210
|
+
}
|
|
211
|
+
filterData(data, filterExpression) {
|
|
212
|
+
try {
|
|
213
|
+
const operators = ['!=', '>=', '<=', '=', '>', '<'];
|
|
214
|
+
let operator = '';
|
|
215
|
+
let parts = [];
|
|
216
|
+
for (const op of operators) {
|
|
217
|
+
if (filterExpression.includes(op)) {
|
|
218
|
+
operator = op;
|
|
219
|
+
parts = filterExpression.split(op).map(p => p.trim());
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (parts.length !== 2) {
|
|
224
|
+
logger_1.logger.warn(`Invalid filter expression: ${filterExpression}`);
|
|
225
|
+
return data;
|
|
226
|
+
}
|
|
227
|
+
const [column, value] = parts;
|
|
228
|
+
const filterValue = isNaN(Number(value)) ? value.replace(/['"]/g, '') : Number(value);
|
|
229
|
+
return data.filter(row => {
|
|
230
|
+
const rowValue = row[column];
|
|
231
|
+
switch (operator) {
|
|
232
|
+
case '=':
|
|
233
|
+
return rowValue == filterValue;
|
|
234
|
+
case '!=':
|
|
235
|
+
return rowValue != filterValue;
|
|
236
|
+
case '>':
|
|
237
|
+
return Number(rowValue) > Number(filterValue);
|
|
238
|
+
case '<':
|
|
239
|
+
return Number(rowValue) < Number(filterValue);
|
|
240
|
+
case '>=':
|
|
241
|
+
return Number(rowValue) >= Number(filterValue);
|
|
242
|
+
case '<=':
|
|
243
|
+
return Number(rowValue) <= Number(filterValue);
|
|
244
|
+
default:
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
logger_1.logger.warn(`Error applying filter "${filterExpression}":`, error);
|
|
251
|
+
return data;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
shuffleArray(array) {
|
|
255
|
+
const shuffled = [...array];
|
|
256
|
+
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
257
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
258
|
+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
|
259
|
+
}
|
|
260
|
+
return shuffled;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
exports.CSVDataProvider = CSVDataProvider;
|
|
264
|
+
CSVDataProvider.instances = new Map();
|
|
265
|
+
CSVDataProvider.baseDir = process.cwd();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { VUHooks, ScenarioHooks, LoopHooks, StepHooks, ScriptResult } from '../config/types/hooks';
|
|
2
|
+
export declare class VUHooksManager {
|
|
3
|
+
private vuHooks?;
|
|
4
|
+
private vuId;
|
|
5
|
+
private testName;
|
|
6
|
+
constructor(testName: string, vuId: number, vuHooks?: VUHooks);
|
|
7
|
+
executeBeforeVU(variables: Record<string, any>, extractedData: Record<string, any>): Promise<ScriptResult | null>;
|
|
8
|
+
executeTeardownVU(variables: Record<string, any>, extractedData: Record<string, any>): Promise<ScriptResult | null>;
|
|
9
|
+
}
|
|
10
|
+
export declare class ScenarioHooksManager {
|
|
11
|
+
private scenarioHooks?;
|
|
12
|
+
private vuId;
|
|
13
|
+
private testName;
|
|
14
|
+
private scenarioName;
|
|
15
|
+
private scenarioStartTime;
|
|
16
|
+
constructor(testName: string, vuId: number, scenarioName: string, hooks?: ScenarioHooks & LoopHooks);
|
|
17
|
+
executeBeforeScenario(variables: Record<string, any>, extractedData: Record<string, any>, csvData?: Record<string, any>): Promise<ScriptResult | null>;
|
|
18
|
+
executeTeardownScenario(variables: Record<string, any>, extractedData: Record<string, any>, csvData?: Record<string, any>): Promise<ScriptResult | null>;
|
|
19
|
+
executeBeforeLoop(loopIteration: number, variables: Record<string, any>, extractedData: Record<string, any>, csvData?: Record<string, any>): Promise<ScriptResult | null>;
|
|
20
|
+
executeAfterLoop(loopIteration: number, variables: Record<string, any>, extractedData: Record<string, any>, csvData?: Record<string, any>): Promise<ScriptResult | null>;
|
|
21
|
+
}
|
|
22
|
+
export declare class StepHooksManager {
|
|
23
|
+
private stepHooks?;
|
|
24
|
+
private vuId;
|
|
25
|
+
private testName;
|
|
26
|
+
private scenarioName;
|
|
27
|
+
private stepName;
|
|
28
|
+
private stepType;
|
|
29
|
+
constructor(testName: string, vuId: number, scenarioName: string, stepName: string, stepType: string, hooks?: StepHooks);
|
|
30
|
+
executeBeforeStep(variables: Record<string, any>, extractedData: Record<string, any>, csvData?: Record<string, any>): Promise<ScriptResult | null>;
|
|
31
|
+
executeOnStepError(error: Error, variables: Record<string, any>, extractedData: Record<string, any>, csvData?: Record<string, any>): Promise<ScriptResult | null>;
|
|
32
|
+
executeTeardownStep(variables: Record<string, any>, extractedData: Record<string, any>, csvData?: Record<string, any>, stepResult?: any): Promise<ScriptResult | null>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StepHooksManager = exports.ScenarioHooksManager = exports.VUHooksManager = void 0;
|
|
4
|
+
const script_executor_1 = require("./script-executor");
|
|
5
|
+
const logger_1 = require("../utils/logger");
|
|
6
|
+
class VUHooksManager {
|
|
7
|
+
constructor(testName, vuId, vuHooks) {
|
|
8
|
+
this.testName = testName;
|
|
9
|
+
this.vuId = vuId;
|
|
10
|
+
this.vuHooks = vuHooks;
|
|
11
|
+
}
|
|
12
|
+
async executeBeforeVU(variables, extractedData) {
|
|
13
|
+
if (!this.vuHooks?.beforeVU)
|
|
14
|
+
return null;
|
|
15
|
+
const context = script_executor_1.ScriptExecutor.createContext(this.testName, this.vuId, variables, extractedData);
|
|
16
|
+
return await script_executor_1.ScriptExecutor.executeHookScript(this.vuHooks.beforeVU, context, 'beforeVU');
|
|
17
|
+
}
|
|
18
|
+
async executeTeardownVU(variables, extractedData) {
|
|
19
|
+
if (!this.vuHooks?.teardownVU)
|
|
20
|
+
return null;
|
|
21
|
+
const context = script_executor_1.ScriptExecutor.createContext(this.testName, this.vuId, variables, extractedData);
|
|
22
|
+
return await script_executor_1.ScriptExecutor.executeHookScript(this.vuHooks.teardownVU, context, 'teardownVU');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.VUHooksManager = VUHooksManager;
|
|
26
|
+
class ScenarioHooksManager {
|
|
27
|
+
constructor(testName, vuId, scenarioName, hooks) {
|
|
28
|
+
this.scenarioStartTime = 0;
|
|
29
|
+
this.testName = testName;
|
|
30
|
+
this.vuId = vuId;
|
|
31
|
+
this.scenarioName = scenarioName;
|
|
32
|
+
this.scenarioHooks = hooks;
|
|
33
|
+
}
|
|
34
|
+
async executeBeforeScenario(variables, extractedData, csvData) {
|
|
35
|
+
if (!this.scenarioHooks?.beforeScenario)
|
|
36
|
+
return null;
|
|
37
|
+
this.scenarioStartTime = Date.now();
|
|
38
|
+
const context = script_executor_1.ScriptExecutor.createContext(this.testName, this.vuId, variables, extractedData, csvData, {
|
|
39
|
+
scenario_name: this.scenarioName,
|
|
40
|
+
scenario_start_time: this.scenarioStartTime
|
|
41
|
+
});
|
|
42
|
+
const result = await script_executor_1.ScriptExecutor.executeHookScript(this.scenarioHooks.beforeScenario, context, 'beforeScenario');
|
|
43
|
+
// CRITICAL FIX: Merge both returned variables AND the context's extracted_data
|
|
44
|
+
if (result?.success) {
|
|
45
|
+
// Merge variables returned from the hook
|
|
46
|
+
if (result.variables) {
|
|
47
|
+
Object.assign(variables, result.variables);
|
|
48
|
+
}
|
|
49
|
+
// IMPORTANT: Also merge the context's extracted_data back into the main extracted_data
|
|
50
|
+
Object.assign(extractedData, context.extracted_data);
|
|
51
|
+
logger_1.logger.debug(`VU${this.vuId}: beforeScenario extracted data: ${Object.keys(context.extracted_data).join(', ')}`);
|
|
52
|
+
logger_1.logger.debug(`VU${this.vuId}: beforeScenario extracted values: ${JSON.stringify(context.extracted_data)}`);
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
async executeTeardownScenario(variables, extractedData, csvData) {
|
|
57
|
+
if (!this.scenarioHooks?.teardownScenario)
|
|
58
|
+
return null;
|
|
59
|
+
const context = script_executor_1.ScriptExecutor.createContext(this.testName, this.vuId, variables, extractedData, csvData, {
|
|
60
|
+
scenario_name: this.scenarioName,
|
|
61
|
+
scenario_start_time: this.scenarioStartTime
|
|
62
|
+
});
|
|
63
|
+
return await script_executor_1.ScriptExecutor.executeHookScript(this.scenarioHooks.teardownScenario, context, 'teardownScenario');
|
|
64
|
+
}
|
|
65
|
+
async executeBeforeLoop(loopIteration, variables, extractedData, csvData) {
|
|
66
|
+
if (!this.scenarioHooks?.beforeLoop)
|
|
67
|
+
return null;
|
|
68
|
+
const context = script_executor_1.ScriptExecutor.createContext(this.testName, this.vuId, variables, extractedData, csvData, {
|
|
69
|
+
scenario_name: this.scenarioName,
|
|
70
|
+
loop_iteration: loopIteration,
|
|
71
|
+
loop_start_time: Date.now()
|
|
72
|
+
});
|
|
73
|
+
return await script_executor_1.ScriptExecutor.executeHookScript(this.scenarioHooks.beforeLoop, context, 'beforeLoop');
|
|
74
|
+
}
|
|
75
|
+
async executeAfterLoop(loopIteration, variables, extractedData, csvData) {
|
|
76
|
+
if (!this.scenarioHooks?.afterLoop)
|
|
77
|
+
return null;
|
|
78
|
+
const context = script_executor_1.ScriptExecutor.createContext(this.testName, this.vuId, variables, extractedData, csvData, {
|
|
79
|
+
scenario_name: this.scenarioName,
|
|
80
|
+
loop_iteration: loopIteration
|
|
81
|
+
});
|
|
82
|
+
return await script_executor_1.ScriptExecutor.executeHookScript(this.scenarioHooks.afterLoop, context, 'afterLoop');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.ScenarioHooksManager = ScenarioHooksManager;
|
|
86
|
+
class StepHooksManager {
|
|
87
|
+
constructor(testName, vuId, scenarioName, stepName, stepType, hooks) {
|
|
88
|
+
this.testName = testName;
|
|
89
|
+
this.vuId = vuId;
|
|
90
|
+
this.scenarioName = scenarioName;
|
|
91
|
+
this.stepName = stepName;
|
|
92
|
+
this.stepType = stepType;
|
|
93
|
+
this.stepHooks = hooks;
|
|
94
|
+
}
|
|
95
|
+
async executeBeforeStep(variables, extractedData, csvData) {
|
|
96
|
+
if (!this.stepHooks?.beforeStep)
|
|
97
|
+
return null;
|
|
98
|
+
const context = script_executor_1.ScriptExecutor.createContext(this.testName, this.vuId, variables, extractedData, csvData, {
|
|
99
|
+
scenario_name: this.scenarioName,
|
|
100
|
+
step_name: this.stepName,
|
|
101
|
+
step_type: this.stepType,
|
|
102
|
+
step_start_time: Date.now()
|
|
103
|
+
});
|
|
104
|
+
return await script_executor_1.ScriptExecutor.executeHookScript(this.stepHooks.beforeStep, context, 'beforeStep');
|
|
105
|
+
}
|
|
106
|
+
async executeOnStepError(error, variables, extractedData, csvData) {
|
|
107
|
+
if (!this.stepHooks?.onStepError)
|
|
108
|
+
return null;
|
|
109
|
+
const context = script_executor_1.ScriptExecutor.createContext(this.testName, this.vuId, variables, extractedData, csvData, {
|
|
110
|
+
scenario_name: this.scenarioName,
|
|
111
|
+
step_name: this.stepName,
|
|
112
|
+
step_type: this.stepType,
|
|
113
|
+
error
|
|
114
|
+
});
|
|
115
|
+
return await script_executor_1.ScriptExecutor.executeHookScript(this.stepHooks.onStepError, context, 'onStepError');
|
|
116
|
+
}
|
|
117
|
+
async executeTeardownStep(variables, extractedData, csvData, stepResult) {
|
|
118
|
+
if (!this.stepHooks?.teardownStep)
|
|
119
|
+
return null;
|
|
120
|
+
const context = script_executor_1.ScriptExecutor.createContext(this.testName, this.vuId, variables, extractedData, csvData, {
|
|
121
|
+
scenario_name: this.scenarioName,
|
|
122
|
+
step_name: this.stepName,
|
|
123
|
+
step_type: this.stepType,
|
|
124
|
+
last_step_result: stepResult
|
|
125
|
+
});
|
|
126
|
+
return await script_executor_1.ScriptExecutor.executeHookScript(this.stepHooks.teardownStep, context, 'teardownStep');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.StepHooksManager = StepHooksManager;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CSVDataProvider = exports.StepExecutor = exports.VirtualUser = exports.TestRunner = void 0;
|
|
4
|
+
var test_runner_1 = require("./test-runner");
|
|
5
|
+
Object.defineProperty(exports, "TestRunner", { enumerable: true, get: function () { return test_runner_1.TestRunner; } });
|
|
6
|
+
var virtual_user_1 = require("./virtual-user");
|
|
7
|
+
Object.defineProperty(exports, "VirtualUser", { enumerable: true, get: function () { return virtual_user_1.VirtualUser; } });
|
|
8
|
+
var step_executor_1 = require("./step-executor");
|
|
9
|
+
Object.defineProperty(exports, "StepExecutor", { enumerable: true, get: function () { return step_executor_1.StepExecutor; } });
|
|
10
|
+
var csv_data_provider_1 = require("./csv-data-provider");
|
|
11
|
+
Object.defineProperty(exports, "CSVDataProvider", { enumerable: true, get: function () { return csv_data_provider_1.CSVDataProvider; } });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HookScript, ScriptContext, ScriptResult } from '../config/types/hooks';
|
|
2
|
+
export declare class ScriptExecutor {
|
|
3
|
+
private static baseDir;
|
|
4
|
+
private static scriptCache;
|
|
5
|
+
private static stepExecutor?;
|
|
6
|
+
static setStepExecutor(stepExecutor: any): void;
|
|
7
|
+
static createContext(testName: string, vuId: number, variables: Record<string, any>, extractedData: Record<string, any>, csvData?: Record<string, any>, additionalContext?: Partial<ScriptContext>): ScriptContext;
|
|
8
|
+
static executeHookScript(script: HookScript, context: ScriptContext, hookName: string): Promise<ScriptResult>;
|
|
9
|
+
private static executeInlineScript;
|
|
10
|
+
private static executeFileScript;
|
|
11
|
+
private static executeStepsScript;
|
|
12
|
+
private static transpileTypeScript;
|
|
13
|
+
static clearCache(): void;
|
|
14
|
+
}
|