@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
package/README.md
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# Perfornium
|
|
2
|
+
|
|
3
|
+
> A powerful, flexible, and easy-to-use performance testing framework for REST APIs, SOAP services, and web applications.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@testsmith/perfornium)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
[](https://github.com/testsmith-io/perfornium/actions/workflows/ci.yml)
|
|
9
|
+
|
|
10
|
+
## ✨ Features
|
|
11
|
+
|
|
12
|
+
- 🚀 **Easy to Use** - Simple YAML syntax or powerful TypeScript DSL
|
|
13
|
+
- 🔧 **Highly Extensible** - Plugin architecture for protocols and outputs
|
|
14
|
+
- 🌐 **Multi-Protocol** - REST, SOAP, and Web (Playwright) support
|
|
15
|
+
- 📊 **Rich Reporting** - JSON, CSV, InfluxDB, Graphite, HTML reports
|
|
16
|
+
- ⚡ **High Performance** - Efficient load generation with virtual users
|
|
17
|
+
- 🎯 **Flexible Load Patterns** - Basic, stepping, arrivals, and custom patterns
|
|
18
|
+
- 📈 **Real-time Metrics** - Monitor performance as tests run
|
|
19
|
+
- 🔄 **Data-Driven** - CSV data support for realistic test scenarios
|
|
20
|
+
|
|
21
|
+
## 🚀 Quick Start
|
|
22
|
+
|
|
23
|
+
### Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Global installation
|
|
27
|
+
npm install -g @testsmith/perfornium
|
|
28
|
+
|
|
29
|
+
# Or as a project dependency
|
|
30
|
+
npm install --save-dev @testsmith/perfornium
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Your First Test (YAML)
|
|
34
|
+
|
|
35
|
+
Create a file `my-test.yml`:
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
name: "Simple API Test"
|
|
39
|
+
global:
|
|
40
|
+
base_url: "https://jsonplaceholder.typicode.com"
|
|
41
|
+
|
|
42
|
+
load:
|
|
43
|
+
pattern: "basic"
|
|
44
|
+
virtual_users: 10
|
|
45
|
+
duration: "1m"
|
|
46
|
+
|
|
47
|
+
scenarios:
|
|
48
|
+
- name: "get_posts"
|
|
49
|
+
steps:
|
|
50
|
+
- method: "GET"
|
|
51
|
+
path: "/posts"
|
|
52
|
+
checks:
|
|
53
|
+
- type: "status"
|
|
54
|
+
value: 200
|
|
55
|
+
|
|
56
|
+
outputs:
|
|
57
|
+
- type: "json"
|
|
58
|
+
file: "results.json"
|
|
59
|
+
|
|
60
|
+
report:
|
|
61
|
+
generate: true
|
|
62
|
+
output: "report.html"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Run it:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
perfornium run my-test.yml
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Your First Test (TypeScript)
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { test } from '@testsmith/perfornium/dsl';
|
|
75
|
+
|
|
76
|
+
test('API Test')
|
|
77
|
+
.baseUrl('https://jsonplaceholder.typicode.com')
|
|
78
|
+
.scenario('Get Posts', 100)
|
|
79
|
+
.get('/posts')
|
|
80
|
+
.check('status', 200)
|
|
81
|
+
.done()
|
|
82
|
+
.withLoad({ pattern: 'basic', virtual_users: 10, duration: '1m' })
|
|
83
|
+
.run();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 📖 Documentation
|
|
87
|
+
|
|
88
|
+
Full documentation is available at [https://testsmith-io.github.io/perfornium](https://testsmith-io.github.io/perfornium)
|
|
89
|
+
|
|
90
|
+
- [Quick Start](https://testsmith-io.github.io/perfornium/#/quick-start) - Get started in minutes
|
|
91
|
+
- [Configuration Guide](https://testsmith-io.github.io/perfornium/#/config/yaml) - YAML and TypeScript configuration
|
|
92
|
+
- [Load Patterns](https://testsmith-io.github.io/perfornium/#/load-patterns/basic) - Basic, stepping, and arrival patterns
|
|
93
|
+
- [Examples](https://testsmith-io.github.io/perfornium/#/examples/rest-basic) - Real-world examples
|
|
94
|
+
|
|
95
|
+
## 🎯 Use Cases
|
|
96
|
+
|
|
97
|
+
### REST API Testing
|
|
98
|
+
|
|
99
|
+
Test any REST API with support for:
|
|
100
|
+
- All HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
|
|
101
|
+
- Authentication (Basic, Bearer, OAuth, Digest)
|
|
102
|
+
- All payload types (JSON, XML, Form, Multipart)
|
|
103
|
+
- Query parameters and custom headers
|
|
104
|
+
- Response validation and data extraction
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
steps:
|
|
108
|
+
- method: "POST"
|
|
109
|
+
path: "/api/users"
|
|
110
|
+
auth:
|
|
111
|
+
type: "bearer"
|
|
112
|
+
token: "your-token"
|
|
113
|
+
json:
|
|
114
|
+
name: "John Doe"
|
|
115
|
+
email: "john@example.com"
|
|
116
|
+
checks:
|
|
117
|
+
- type: "status"
|
|
118
|
+
value: 201
|
|
119
|
+
extract:
|
|
120
|
+
- name: "user_id"
|
|
121
|
+
type: "json_path"
|
|
122
|
+
expression: "$.id"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Web Application Testing
|
|
126
|
+
|
|
127
|
+
Test web applications with Playwright:
|
|
128
|
+
|
|
129
|
+
```yaml
|
|
130
|
+
global:
|
|
131
|
+
web:
|
|
132
|
+
type: "chromium"
|
|
133
|
+
headless: true
|
|
134
|
+
base_url: "https://example.com"
|
|
135
|
+
|
|
136
|
+
scenarios:
|
|
137
|
+
- name: "user_journey"
|
|
138
|
+
steps:
|
|
139
|
+
- type: "web"
|
|
140
|
+
action:
|
|
141
|
+
command: "goto"
|
|
142
|
+
url: "/"
|
|
143
|
+
- type: "web"
|
|
144
|
+
action:
|
|
145
|
+
command: "fill"
|
|
146
|
+
selector: "#email"
|
|
147
|
+
value: "test@example.com"
|
|
148
|
+
- type: "web"
|
|
149
|
+
action:
|
|
150
|
+
command: "click"
|
|
151
|
+
selector: "#submit"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### SOAP Service Testing
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
global:
|
|
158
|
+
wsdl_url: "http://example.com/service?WSDL"
|
|
159
|
+
|
|
160
|
+
scenarios:
|
|
161
|
+
- name: "soap_test"
|
|
162
|
+
steps:
|
|
163
|
+
- type: "soap"
|
|
164
|
+
operation: "GetUser"
|
|
165
|
+
args:
|
|
166
|
+
userId: 123
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## 🎨 Load Patterns
|
|
170
|
+
|
|
171
|
+
### Basic Pattern
|
|
172
|
+
Fixed number of virtual users for a duration:
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
load:
|
|
176
|
+
pattern: "basic"
|
|
177
|
+
virtual_users: 50
|
|
178
|
+
ramp_up: "30s"
|
|
179
|
+
duration: "5m"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Stepping Pattern
|
|
183
|
+
Gradually increase load:
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
load:
|
|
187
|
+
pattern: "stepping"
|
|
188
|
+
steps:
|
|
189
|
+
- users: 10
|
|
190
|
+
duration: "2m"
|
|
191
|
+
- users: 25
|
|
192
|
+
duration: "3m"
|
|
193
|
+
- users: 50
|
|
194
|
+
duration: "5m"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Arrivals Pattern
|
|
198
|
+
Constant arrival rate:
|
|
199
|
+
|
|
200
|
+
```yaml
|
|
201
|
+
load:
|
|
202
|
+
pattern: "arrivals"
|
|
203
|
+
rate: 10 # users per second
|
|
204
|
+
duration: "5m"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Multiple Profiles
|
|
208
|
+
Run different patterns concurrently:
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
load:
|
|
212
|
+
pattern: "mixed"
|
|
213
|
+
profiles:
|
|
214
|
+
- name: "readers"
|
|
215
|
+
pattern: "basic"
|
|
216
|
+
virtual_users: 100
|
|
217
|
+
scenarios: ["read_data"]
|
|
218
|
+
- name: "writers"
|
|
219
|
+
pattern: "stepping"
|
|
220
|
+
scenarios: ["write_data"]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## 📊 Outputs and Reporting
|
|
224
|
+
|
|
225
|
+
Perfornium supports multiple output formats:
|
|
226
|
+
|
|
227
|
+
```yaml
|
|
228
|
+
outputs:
|
|
229
|
+
# Raw metrics
|
|
230
|
+
- type: "csv"
|
|
231
|
+
file: "results/metrics.csv"
|
|
232
|
+
|
|
233
|
+
# Structured results
|
|
234
|
+
- type: "json"
|
|
235
|
+
file: "results/results.json"
|
|
236
|
+
|
|
237
|
+
# Time-series databases
|
|
238
|
+
- type: "influxdb"
|
|
239
|
+
url: "http://localhost:8086"
|
|
240
|
+
database: "perfornium"
|
|
241
|
+
|
|
242
|
+
# Metrics backends
|
|
243
|
+
- type: "graphite"
|
|
244
|
+
url: "localhost:2003"
|
|
245
|
+
|
|
246
|
+
# Webhooks
|
|
247
|
+
- type: "webhook"
|
|
248
|
+
url: "https://example.com/webhook"
|
|
249
|
+
|
|
250
|
+
# Beautiful HTML reports
|
|
251
|
+
report:
|
|
252
|
+
generate: true
|
|
253
|
+
output: "results/report.html"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## 💡 TypeScript DSL
|
|
257
|
+
|
|
258
|
+
For complex tests, use the TypeScript DSL:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { test, load, testData } from '@testsmith/perfornium/dsl';
|
|
262
|
+
|
|
263
|
+
const config = test('E-Commerce Test')
|
|
264
|
+
.description('User shopping journey')
|
|
265
|
+
.baseUrl('https://api.shop.com')
|
|
266
|
+
.variables({ environment: 'staging' })
|
|
267
|
+
|
|
268
|
+
.withLoad({
|
|
269
|
+
pattern: 'stepping',
|
|
270
|
+
duration: '10m',
|
|
271
|
+
steps: [
|
|
272
|
+
{ users: 10, duration: '3m' },
|
|
273
|
+
{ users: 25, duration: '4m' },
|
|
274
|
+
{ users: 50, duration: '3m' }
|
|
275
|
+
]
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
.scenario('Shopping Flow', 100)
|
|
279
|
+
.beforeScenario(async (context) => {
|
|
280
|
+
context.variables.userId = testData.uuid();
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
.get('/products')
|
|
284
|
+
.check('status', 200)
|
|
285
|
+
.extract('product_id', '$.products[0].id')
|
|
286
|
+
|
|
287
|
+
.post('/cart', {
|
|
288
|
+
product_id: '{{product_id}}',
|
|
289
|
+
quantity: 1
|
|
290
|
+
})
|
|
291
|
+
.withBearerToken('{{auth_token}}')
|
|
292
|
+
.check('status', 201)
|
|
293
|
+
|
|
294
|
+
.done()
|
|
295
|
+
|
|
296
|
+
.withJSONOutput('results/shopping.json')
|
|
297
|
+
.withReport('results/shopping-report.html')
|
|
298
|
+
|
|
299
|
+
.build();
|
|
300
|
+
|
|
301
|
+
// Run it
|
|
302
|
+
import { TestRunner } from '@testsmith/perfornium';
|
|
303
|
+
await new TestRunner(config).run();
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## 🛠️ CLI Commands
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# Run a test
|
|
310
|
+
perfornium run test.yml
|
|
311
|
+
|
|
312
|
+
# Validate configuration
|
|
313
|
+
perfornium validate test.yml
|
|
314
|
+
|
|
315
|
+
# Run distributed test
|
|
316
|
+
perfornium distributed --config test.yml --workers 4
|
|
317
|
+
|
|
318
|
+
# Generate report from results
|
|
319
|
+
perfornium report --results results.json --output report.html
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## 🏗️ Architecture
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
perfornium/
|
|
326
|
+
├── src/
|
|
327
|
+
│ ├── protocols/ # Protocol handlers (REST, SOAP, Web)
|
|
328
|
+
│ ├── load-patterns/ # Load generation patterns
|
|
329
|
+
│ ├── core/ # Test runner and execution engine
|
|
330
|
+
│ ├── outputs/ # Output handlers
|
|
331
|
+
│ ├── reporting/ # HTML report generation
|
|
332
|
+
│ ├── dsl/ # TypeScript DSL
|
|
333
|
+
│ └── config/ # Configuration types
|
|
334
|
+
│
|
|
335
|
+
├── examples/ # Example configurations
|
|
336
|
+
├── tmp/test-project/ # Sample test project
|
|
337
|
+
└── docs/ # Documentation
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## 🤝 Contributing
|
|
341
|
+
|
|
342
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
343
|
+
|
|
344
|
+
## 📝 License
|
|
345
|
+
|
|
346
|
+
MIT
|
|
347
|
+
|
|
348
|
+
## 🙏 Acknowledgments
|
|
349
|
+
|
|
350
|
+
Built with:
|
|
351
|
+
- [Axios](https://axios-http.com/) - HTTP client
|
|
352
|
+
- [Playwright](https://playwright.dev/) - Web testing
|
|
353
|
+
- [Commander](https://github.com/tj/commander.js) - CLI framework
|
|
354
|
+
- [Handlebars](https://handlebarsjs.com/) - Templating
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
**Happy Load Testing!** 🚀
|
|
359
|
+
|
|
360
|
+
For more information, see the [documentation](https://testsmith-io.github.io/perfornium).
|
package/dist/cli/cli.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const run_1 = require("./commands/run");
|
|
6
|
+
const validate_1 = require("./commands/validate");
|
|
7
|
+
const report_1 = require("./commands/report");
|
|
8
|
+
const worker_1 = require("./commands/worker");
|
|
9
|
+
const init_1 = require("./commands/init");
|
|
10
|
+
const mock_1 = require("./commands/mock");
|
|
11
|
+
const native_recorder_1 = require("../recorder/native-recorder");
|
|
12
|
+
const distributed_1 = require("./commands/distributed");
|
|
13
|
+
// Add new import commands
|
|
14
|
+
const import_1 = require("./commands/import");
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
16
|
+
const packageJson = require('../../package.json');
|
|
17
|
+
const program = new commander_1.Command();
|
|
18
|
+
program
|
|
19
|
+
.name('perfornium')
|
|
20
|
+
.description(packageJson.description)
|
|
21
|
+
.version(packageJson.version);
|
|
22
|
+
program
|
|
23
|
+
.command('run')
|
|
24
|
+
.description('Run a performance test')
|
|
25
|
+
.argument('<config>', 'Test configuration file')
|
|
26
|
+
.option('-e, --env <environment>', 'Environment configuration')
|
|
27
|
+
.option('-w, --workers <workers>', 'Comma-separated list of worker addresses')
|
|
28
|
+
.option('-o, --output <directory>', 'Output directory for results')
|
|
29
|
+
.option('-r, --report', 'Generate HTML report after test')
|
|
30
|
+
.option('--dry-run', 'Validate configuration without running test')
|
|
31
|
+
.option('-v, --verbose', 'Enable verbose logging (info level)')
|
|
32
|
+
.option('-d, --debug', 'Enable debug logging (very detailed)')
|
|
33
|
+
.option('--max-users <number>', 'Maximum virtual users override')
|
|
34
|
+
.option('-g, --global <key=value>', 'Override global config (supports dot notation: browser.headless=false)', collectGlobals, [])
|
|
35
|
+
.action(run_1.runCommand);
|
|
36
|
+
// Helper function to collect --global options
|
|
37
|
+
function collectGlobals(value, previous) {
|
|
38
|
+
previous.push(value);
|
|
39
|
+
return previous;
|
|
40
|
+
}
|
|
41
|
+
program
|
|
42
|
+
.command('distributed')
|
|
43
|
+
.description('Run a distributed performance test across multiple workers')
|
|
44
|
+
.argument('<config>', 'Test configuration file')
|
|
45
|
+
.option('-e, --env <environment>', 'Environment configuration')
|
|
46
|
+
.option('-w, --workers <workers>', 'Comma-separated list of worker addresses (host:port)')
|
|
47
|
+
.option('--workers-file <file>', 'JSON file containing worker configurations')
|
|
48
|
+
.option('-s, --strategy <strategy>', 'Load distribution strategy (even|capacity_based|round_robin|geographic)', 'capacity_based')
|
|
49
|
+
.option('--sync-start', 'Synchronize test start across all workers')
|
|
50
|
+
.option('-o, --output <directory>', 'Output directory for results')
|
|
51
|
+
.option('-r, --report', 'Generate HTML report after test')
|
|
52
|
+
.option('-v, --verbose', 'Enable verbose logging (info level)')
|
|
53
|
+
.option('-d, --debug', 'Enable debug logging (very detailed)')
|
|
54
|
+
.action(distributed_1.distributedCommand);
|
|
55
|
+
program
|
|
56
|
+
.command('validate')
|
|
57
|
+
.description('Validate test configuration')
|
|
58
|
+
.argument('<config>', 'Test configuration file')
|
|
59
|
+
.option('-e, --env <environment>', 'Environment configuration')
|
|
60
|
+
.action(validate_1.validateCommand);
|
|
61
|
+
program
|
|
62
|
+
.command('report')
|
|
63
|
+
.description('Generate HTML report from results')
|
|
64
|
+
.argument('<results>', 'Results file (JSON or CSV)')
|
|
65
|
+
.option('-o, --output <file>', 'Output HTML file', 'report.html')
|
|
66
|
+
.option('-t, --template <template>', 'Custom report template')
|
|
67
|
+
.option('--title <title>', 'Custom report title')
|
|
68
|
+
.action(report_1.reportCommand);
|
|
69
|
+
// ============================================
|
|
70
|
+
// Record Command
|
|
71
|
+
// ============================================
|
|
72
|
+
program
|
|
73
|
+
.command('record')
|
|
74
|
+
.description('Record web interactions for test creation (Ctrl+W to add wait points)')
|
|
75
|
+
.argument('<url>', 'Starting URL for recording')
|
|
76
|
+
.option('-o, --output <file>', 'Output file for recorded scenario')
|
|
77
|
+
.option('--viewport <viewport>', 'Browser viewport size (e.g., 1920x1080)')
|
|
78
|
+
.option('--base-url <url>', 'Base URL to relativize recorded URLs')
|
|
79
|
+
.option('-f, --format <format>', 'Output format: yaml, json, or typescript', 'yaml')
|
|
80
|
+
.action(async (url, options) => {
|
|
81
|
+
// Auto-determine file extension if output not specified
|
|
82
|
+
// Save to tests/web directory by default
|
|
83
|
+
if (!options.output) {
|
|
84
|
+
const extensions = {
|
|
85
|
+
yaml: 'tests/web/recorded-scenario.yml',
|
|
86
|
+
json: 'tests/web/recorded-scenario.json',
|
|
87
|
+
typescript: 'tests/web/recorded-scenario.spec.ts'
|
|
88
|
+
};
|
|
89
|
+
options.output = extensions[options.format] || 'tests/web/recorded-scenario.yml';
|
|
90
|
+
}
|
|
91
|
+
await (0, native_recorder_1.startNativeRecording)(url, {
|
|
92
|
+
output: options.output,
|
|
93
|
+
format: options.format,
|
|
94
|
+
viewport: options.viewport,
|
|
95
|
+
baseUrl: options.baseUrl
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
// ============================================
|
|
99
|
+
// Import Commands
|
|
100
|
+
// ============================================
|
|
101
|
+
const importCmd = program
|
|
102
|
+
.command('import <type>')
|
|
103
|
+
.description('Import API definitions to generate test scenarios')
|
|
104
|
+
.argument('<source>', 'Source file to import');
|
|
105
|
+
// Common import options
|
|
106
|
+
const addImportOptions = (cmd) => {
|
|
107
|
+
return cmd
|
|
108
|
+
.option('-o, --output <dir>', 'Output directory', './tests')
|
|
109
|
+
.option('-f, --format <format>', 'Output format: yaml, json, or typescript', 'yaml')
|
|
110
|
+
.option('-i, --interactive', 'Interactive mode for selecting endpoints')
|
|
111
|
+
.option('--auto-correlate', 'Automatically detect and apply data correlations')
|
|
112
|
+
.option('--base-url <url>', 'Override base URL from specification')
|
|
113
|
+
.option('--scenarios-per-file <n>', 'Number of scenarios per output file', '10')
|
|
114
|
+
.option('-v, --verbose', 'Verbose output with detailed information');
|
|
115
|
+
};
|
|
116
|
+
// OpenAPI import
|
|
117
|
+
addImportOptions(importCmd
|
|
118
|
+
.command('openapi <file>')
|
|
119
|
+
.description('Import from OpenAPI/Swagger specification')
|
|
120
|
+
.option('--tags <tags>', 'Filter by tags (comma-separated)')
|
|
121
|
+
.option('--exclude-tags <tags>', 'Exclude specific tags (comma-separated)')
|
|
122
|
+
.option('--paths <patterns>', 'Filter by path patterns (comma-separated regex)')
|
|
123
|
+
.option('--methods <methods>', 'Filter by HTTP methods (comma-separated)')).action(async (file, options) => {
|
|
124
|
+
await (0, import_1.importCommand)('openapi', file, options);
|
|
125
|
+
});
|
|
126
|
+
// WSDL import
|
|
127
|
+
addImportOptions(importCmd
|
|
128
|
+
.command('wsdl <file>')
|
|
129
|
+
.description('Import from WSDL file')
|
|
130
|
+
.option('--services <names>', 'Filter by service names (comma-separated)')
|
|
131
|
+
.option('--operations <names>', 'Filter by operation names (comma-separated)')
|
|
132
|
+
.option('--soap-version <version>', 'SOAP version: 1.1, 1.2, or both', 'both')).action(async (file, options) => {
|
|
133
|
+
await (0, import_1.importCommand)('wsdl', file, options);
|
|
134
|
+
});
|
|
135
|
+
// HAR import
|
|
136
|
+
addImportOptions(importCmd
|
|
137
|
+
.command('har <file>')
|
|
138
|
+
.description('Import from HAR (HTTP Archive) file')
|
|
139
|
+
.option('--filter-domains <domains>', 'Include specific domains (comma-separated)')
|
|
140
|
+
.option('--exclude-domains <domains>', 'Exclude specific domains (comma-separated)')
|
|
141
|
+
.option('--methods <methods>', 'Filter by HTTP methods (comma-separated)')
|
|
142
|
+
.option('--skip-static', 'Skip static resources (images, CSS, JS)', true)).action(async (file, options) => {
|
|
143
|
+
await (0, import_1.importCommand)('har', file, options);
|
|
144
|
+
});
|
|
145
|
+
// importCmd
|
|
146
|
+
// .command('postman')
|
|
147
|
+
// .description('Import test scenarios from Postman collection')
|
|
148
|
+
// .argument('<collection-file>', 'Postman collection file (JSON)')
|
|
149
|
+
// .option('-o, --output <directory>', 'Output directory for generated tests', './tests')
|
|
150
|
+
// .option('-f, --format <format>', 'Output format (yaml|json)', 'yaml')
|
|
151
|
+
// .option('--environment <env-file>', 'Postman environment file')
|
|
152
|
+
// .option('--folders <folders>', 'Comma-separated list of folder names to include')
|
|
153
|
+
// .option('--auto-correlate', 'Automatically detect and apply data correlations', true)
|
|
154
|
+
// .option('--interactive', 'Interactive request selection', true)
|
|
155
|
+
// .option('-v, --verbose', 'Enable verbose logging')
|
|
156
|
+
// .action((collectionFile, options) => importCommand('postman', collectionFile, options));
|
|
157
|
+
// NEW: Correlate command
|
|
158
|
+
// program
|
|
159
|
+
// .command('correlate')
|
|
160
|
+
// .description('Analyze and apply data correlations to existing test configuration')
|
|
161
|
+
// .argument('<config-file>', 'Test configuration file to analyze')
|
|
162
|
+
// .option('-o, --output <file>', 'Output file for correlated configuration')
|
|
163
|
+
// .option('--report <file>', 'Generate correlation analysis report')
|
|
164
|
+
// .option('--auto-apply', 'Automatically apply detected correlations', true)
|
|
165
|
+
// .option('--confidence <threshold>', 'Minimum confidence threshold (0-1)', '0.6')
|
|
166
|
+
// .option('--interactive', 'Interactive correlation review and selection')
|
|
167
|
+
// .option('--patterns <file>', 'Custom correlation patterns file')
|
|
168
|
+
// .option('-v, --verbose', 'Enable verbose logging')
|
|
169
|
+
// .action(correlateCommand);
|
|
170
|
+
program
|
|
171
|
+
.command('worker')
|
|
172
|
+
.description('Start a worker node for distributed testing')
|
|
173
|
+
.option('-p, --port <port>', 'Port to listen on', '8080')
|
|
174
|
+
.option('--host <host>', 'Host to bind to', 'localhost')
|
|
175
|
+
.action(worker_1.workerCommand);
|
|
176
|
+
program
|
|
177
|
+
.command('init')
|
|
178
|
+
.description('Initialize a new test project')
|
|
179
|
+
.argument('[directory]', 'Project directory', '.')
|
|
180
|
+
.option('-t, --template <template>', 'Project template (basic|api|web|mixed)', 'basic')
|
|
181
|
+
.option('--examples', 'Include example test configurations')
|
|
182
|
+
.option('-f, --force', 'Overwrite existing project files')
|
|
183
|
+
.option('--dry-run', 'Preview files without creating them')
|
|
184
|
+
.action(init_1.initCommand);
|
|
185
|
+
program
|
|
186
|
+
.command('mock')
|
|
187
|
+
.description('Start a mock API server for testing')
|
|
188
|
+
.option('-p, --port <port>', 'Port to listen on', '3000')
|
|
189
|
+
.option('--host <host>', 'Host to bind to', 'localhost')
|
|
190
|
+
.option('-d, --delay <ms>', 'Add delay to all responses (ms)', '0')
|
|
191
|
+
.action(mock_1.mockCommand);
|
|
192
|
+
program.parse();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function distributedCommand(configPath: string, options: {
|
|
2
|
+
workers?: string;
|
|
3
|
+
workersFile?: string;
|
|
4
|
+
strategy?: string;
|
|
5
|
+
syncStart?: boolean;
|
|
6
|
+
env?: string;
|
|
7
|
+
output?: string;
|
|
8
|
+
report?: boolean;
|
|
9
|
+
verbose?: boolean;
|
|
10
|
+
debug?: boolean;
|
|
11
|
+
}): Promise<void>;
|