@voiden/runner 0.1.0-beta.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 +748 -0
- package/dist/blockSchemaRegistry.d.ts +49 -0
- package/dist/blockSchemaRegistry.d.ts.map +1 -0
- package/dist/blockSchemaRegistry.js +68 -0
- package/dist/blockSchemaRegistry.js.map +1 -0
- package/dist/cliElectron.d.ts +55 -0
- package/dist/cliElectron.d.ts.map +1 -0
- package/dist/cliElectron.js +120 -0
- package/dist/cliElectron.js.map +1 -0
- package/dist/headlessContext.d.ts +18 -0
- package/dist/headlessContext.d.ts.map +1 -0
- package/dist/headlessContext.js +85 -0
- package/dist/headlessContext.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +945 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +24 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +87 -0
- package/dist/parser.js.map +1 -0
- package/dist/parserRegistry.d.ts +17 -0
- package/dist/parserRegistry.d.ts.map +1 -0
- package/dist/parserRegistry.js +27 -0
- package/dist/parserRegistry.js.map +1 -0
- package/dist/plugins/community.d.ts +42 -0
- package/dist/plugins/community.d.ts.map +1 -0
- package/dist/plugins/community.js +105 -0
- package/dist/plugins/community.js.map +1 -0
- package/dist/plugins/loader.d.ts +17 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +120 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/registry.d.ts +30 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +52 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/store.d.ts +19 -0
- package/dist/plugins/store.d.ts.map +1 -0
- package/dist/plugins/store.js +68 -0
- package/dist/plugins/store.js.map +1 -0
- package/dist/report/csv.d.ts +6 -0
- package/dist/report/csv.d.ts.map +1 -0
- package/dist/report/csv.js +71 -0
- package/dist/report/csv.js.map +1 -0
- package/dist/report/mail.d.ts +17 -0
- package/dist/report/mail.d.ts.map +1 -0
- package/dist/report/mail.js +84 -0
- package/dist/report/mail.js.map +1 -0
- package/dist/runner.d.ts +41 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +193 -0
- package/dist/runner.js.map +1 -0
- package/dist/runtimeVars.d.ts +55 -0
- package/dist/runtimeVars.d.ts.map +1 -0
- package/dist/runtimeVars.js +248 -0
- package/dist/runtimeVars.js.map +1 -0
- package/dist/session.d.ts +10 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +32 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +45 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
# @voiden/runner
|
|
2
|
+
|
|
3
|
+
Headless CLI runner for [Voiden](https://voiden.app) — execute `.void` files
|
|
4
|
+
outside the app, in terminals, and CI/CD pipelines.
|
|
5
|
+
|
|
6
|
+
`.void` files are created and edited inside the **Voiden desktop app**.
|
|
7
|
+
This package runs them anywhere Node.js ≥ 18 is available: local terminals,
|
|
8
|
+
GitHub Actions, GitLab CI, Docker, and more.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of contents
|
|
13
|
+
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Quick start](#quick-start)
|
|
16
|
+
- [Commands](#commands)
|
|
17
|
+
- [run](#run)
|
|
18
|
+
- [env](#env)
|
|
19
|
+
- [session](#session)
|
|
20
|
+
- [report](#report)
|
|
21
|
+
- [plugin](#plugin)
|
|
22
|
+
- [Environment variables](#environment-variables)
|
|
23
|
+
- [Runtime variables](#runtime-variables)
|
|
24
|
+
- [Sessions & Persistence](#sessions--persistence)
|
|
25
|
+
- [Plugins](#plugins)
|
|
26
|
+
- [voiden-scripting](#voiden-scripting)
|
|
27
|
+
- [simple-assertions](#simple-assertions)
|
|
28
|
+
- [voiden-faker](#voiden-faker)
|
|
29
|
+
- [voiden-advanced-auth](#voiden-advanced-auth)
|
|
30
|
+
- [voiden-graphql](#voiden-graphql)
|
|
31
|
+
- [Output formats](#output-formats)
|
|
32
|
+
- [Reports — CSV and email](#reports--csv-and-email)
|
|
33
|
+
- [Exit codes](#exit-codes)
|
|
34
|
+
- [CI/CD](#cicd)
|
|
35
|
+
- [Supported protocols](#supported-protocols)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g @voiden/runner
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Requires Node.js 18 or later.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Quick start
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Run a single file
|
|
53
|
+
voiden-runner run auth.void
|
|
54
|
+
|
|
55
|
+
# Run an entire folder recursively
|
|
56
|
+
voiden-runner run ./requests/
|
|
57
|
+
|
|
58
|
+
# With environment variable substitution
|
|
59
|
+
voiden-runner run ./requests/ --env .env.staging
|
|
60
|
+
|
|
61
|
+
# Stop on first failure (CI-friendly)
|
|
62
|
+
voiden-runner run ./tests/ --env .env.ci --stop-on-failure
|
|
63
|
+
|
|
64
|
+
# Export report to CSV + send by email
|
|
65
|
+
# SMTP settings (host, user, etc.) are read from your .env file
|
|
66
|
+
voiden-runner run ./tests/ \
|
|
67
|
+
--env .env.staging \
|
|
68
|
+
--csv ./results/report.csv \
|
|
69
|
+
--mail-to team@company.com
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Commands
|
|
75
|
+
|
|
76
|
+
### `run`
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
voiden-runner run <paths...> [options]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`<paths...>` accepts any mix of files, directories (recursive), and glob patterns.
|
|
83
|
+
|
|
84
|
+
**Options**
|
|
85
|
+
|
|
86
|
+
| Flag | Description |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `-e, --env <path>` | Standard `.env` file (`KEY=VALUE`) — merged on top of system env |
|
|
89
|
+
| `--env-var <k=v>` | Individual environment variable override (can be used multiple times) |
|
|
90
|
+
| `--bail` | Stop on first failure, exit 1 |
|
|
91
|
+
| `--stop-on-failure` | Alias for `--bail` (shell `set -e` friendly) |
|
|
92
|
+
| `--fail-on-error` | Run all files first, then exit 1 if any failed |
|
|
93
|
+
| `--show-req` | Print sent request headers and body for each request |
|
|
94
|
+
| `--show-res` | Print response headers and body for each request |
|
|
95
|
+
| `--verbose` | Print script logs, plugin messages, and section dividers |
|
|
96
|
+
| `--json` | Machine-readable JSON output (suppresses normal output) |
|
|
97
|
+
| `--no-session` | Completely stateless run (do not load/save results or runtime variables) |
|
|
98
|
+
| `--output-json <file>` | Write the full result object to a JSON file — pass the whole response data to the next CLI or script |
|
|
99
|
+
| `--csv <path>` | Export full report to a CSV file. Use `.` for the current directory (auto-generates filename) |
|
|
100
|
+
| `--mail` | Send HTML summary + attached CSV using `VOIDEN_MAIL_TO` (requires `--csv`) |
|
|
101
|
+
| `--mail-to <address>` | Send HTML summary + attached CSV to this address (requires `--csv`) |
|
|
102
|
+
| `--mail-from <address>` | Sender address (default: `VOIDEN_MAIL_FROM` env) |
|
|
103
|
+
| `--mail-subject <text>` | Email subject (default: `VOIDEN_MAIL_SUBJECT` env or auto-summary) |
|
|
104
|
+
| `--smtp-host <host>` | SMTP server host (default: `VOIDEN_SMTP_HOST` env) |
|
|
105
|
+
| `--smtp-port <port>` | SMTP server port (default: `VOIDEN_SMTP_PORT` env) |
|
|
106
|
+
| `--smtp-secure` | Use TLS for SMTP (default: `VOIDEN_SMTP_SECURE` env) |
|
|
107
|
+
| `--smtp-user <user>` | SMTP username (default: `VOIDEN_SMTP_USER` env) |
|
|
108
|
+
| `--smtp-pass <pass>` | SMTP password (default: `VOIDEN_SMTP_PASS` env) |
|
|
109
|
+
|
|
110
|
+
### Environment Variables
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
voiden-runner session status
|
|
114
|
+
voiden-runner session vars
|
|
115
|
+
voiden-runner session clear
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`status` shows counts of stored variables and results. `vars` lists all currently
|
|
119
|
+
stored runtime variables and their values. `clear` wipes all session
|
|
120
|
+
state (results and runtime variables).
|
|
121
|
+
|
|
122
|
+
### `report`
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
voiden-runner report generate [--csv <path>] [--mail] [--mail-to <address>]
|
|
126
|
+
voiden-runner report clear
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`generate` (alias `gen`) creates a combined report from all accumulated results
|
|
130
|
+
in the current session. `clear` wipes the results history only (runtime
|
|
131
|
+
variables are preserved).
|
|
132
|
+
|
|
133
|
+
Accepts all mail and SMTP options listed above.
|
|
134
|
+
|
|
135
|
+
### `plugin`
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
voiden-runner plugin install [names...] [--all]
|
|
139
|
+
voiden-runner plugin uninstall <name>
|
|
140
|
+
voiden-runner plugin enable [name] [--all]
|
|
141
|
+
voiden-runner plugin disable [name] [--all]
|
|
142
|
+
voiden-runner plugin list
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Plugin state is persisted to `~/.voiden/plugins.json` and survives across sessions.
|
|
146
|
+
Core plugins are **enabled by default** but can be disabled individually or all at once.
|
|
147
|
+
Community plugins must be installed before they can be enabled.
|
|
148
|
+
|
|
149
|
+
**`install` Options**
|
|
150
|
+
|
|
151
|
+
| Flag | Description |
|
|
152
|
+
|---|---|
|
|
153
|
+
| `--all` | Install all core plugins (makes them explicit in the store). Community plugins must be installed by name. |
|
|
154
|
+
|
|
155
|
+
**`enable` Options**
|
|
156
|
+
|
|
157
|
+
| Flag | Description |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `--all` | Re-enable all disabled plugins (core and community). |
|
|
160
|
+
|
|
161
|
+
**`disable` Options**
|
|
162
|
+
|
|
163
|
+
| Flag | Description |
|
|
164
|
+
|---|---|
|
|
165
|
+
| `--all` | Disable all plugins (core and community). |
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Environment variables
|
|
170
|
+
|
|
171
|
+
Use `{{KEY}}` anywhere in a `.void` file — URL, headers, query params, body,
|
|
172
|
+
assertion expected values.
|
|
173
|
+
|
|
174
|
+
### Sources (lowest → highest priority)
|
|
175
|
+
|
|
176
|
+
1. **System environment** — `process.env`, including CI/CD platform variables
|
|
177
|
+
(GitHub Actions secrets, GitLab CI variables, etc.) — always available, no
|
|
178
|
+
flag needed
|
|
179
|
+
2. **`--env` file** — standard `.env` file, overrides system variables
|
|
180
|
+
3. **`--env-var` overrides** — per-run inline overrides, highest priority
|
|
181
|
+
|
|
182
|
+
### `--env` file format
|
|
183
|
+
|
|
184
|
+
Standard `KEY=VALUE` format only — one variable per line:
|
|
185
|
+
|
|
186
|
+
```env
|
|
187
|
+
# .env.staging
|
|
188
|
+
BASE_URL=https://staging.api.example.com
|
|
189
|
+
API_KEY=sk-staging-abc123
|
|
190
|
+
USER_ID=42
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
voiden-runner run ./requests/ --env .env.staging
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### CI/CD — no `--env` file needed
|
|
198
|
+
|
|
199
|
+
CI/CD platform variables are injected into `process.env` automatically and are
|
|
200
|
+
available as `{{KEY}}` without any `--env` file:
|
|
201
|
+
|
|
202
|
+
```yaml
|
|
203
|
+
# GitHub Actions
|
|
204
|
+
- run: voiden-runner run tests/
|
|
205
|
+
env:
|
|
206
|
+
BASE_URL: ${{ vars.BASE_URL }} # → {{BASE_URL}}
|
|
207
|
+
API_KEY: ${{ secrets.API_KEY }} # → {{API_KEY}}
|
|
208
|
+
|
|
209
|
+
# GitLab CI — CI_* variables available automatically
|
|
210
|
+
api-tests:
|
|
211
|
+
script: voiden-runner run tests/ # {{CI_COMMIT_SHA}}, {{API_KEY}} etc. just work
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Available inside scripts as `voiden.env.get('KEY')`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Runtime variables
|
|
219
|
+
|
|
220
|
+
Runtime variables let requests **chain** — a value extracted from one response
|
|
221
|
+
becomes available in the next request as `{{process.KEY}}`.
|
|
222
|
+
|
|
223
|
+
### How it works
|
|
224
|
+
|
|
225
|
+
1. Add a **runtime-variables block** to a `.void` file (use `/runtime-variables`
|
|
226
|
+
slash command in the Voiden app).
|
|
227
|
+
2. Each row maps a **variable name** to a **capture expression** — a
|
|
228
|
+
`{{$res.xxx}}` or `{{$req.xxx}}` path into the request or response.
|
|
229
|
+
3. After the request completes, the runner evaluates every enabled row and
|
|
230
|
+
stores the captured values **in memory** for the rest of the run.
|
|
231
|
+
4. In any subsequent request (same file or later files), use `{{process.KEY}}`
|
|
232
|
+
to substitute the captured value.
|
|
233
|
+
|
|
234
|
+
### Capture expression syntax
|
|
235
|
+
|
|
236
|
+
| Expression | Captures |
|
|
237
|
+
|---|---|
|
|
238
|
+
| `{{$res.body.access_token}}` | JSON field from response body |
|
|
239
|
+
| `{{$res.body.data.items[0].id}}` | Nested path with array index |
|
|
240
|
+
| `{{$res.headers.X-Request-Id}}` | Response header |
|
|
241
|
+
| `{{$res.status}}` | HTTP status code |
|
|
242
|
+
| `{{$res.statusText}}` | HTTP status text |
|
|
243
|
+
| `{{$res.time}}` | Response time in ms |
|
|
244
|
+
| `{{$req.headers.Authorization}}` | Header from the sent request |
|
|
245
|
+
| `{{$req.url}}` | Final URL (after variable substitution) |
|
|
246
|
+
|
|
247
|
+
### Substitution syntax
|
|
248
|
+
|
|
249
|
+
Use `{{process.KEY}}` in URLs, headers, query params, body, and path params:
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
GET {{process.baseUrl}}/users/{{process.userId}}
|
|
253
|
+
Authorization: Bearer {{process.token}}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Script access
|
|
257
|
+
|
|
258
|
+
Inside pre-request and post-response scripts:
|
|
259
|
+
|
|
260
|
+
```javascript
|
|
261
|
+
// Read a runtime variable
|
|
262
|
+
const token = voiden.variables.get('token')
|
|
263
|
+
|
|
264
|
+
// Write a runtime variable (available to all subsequent requests in this run)
|
|
265
|
+
voiden.variables.set('token', voiden.response.body.access_token)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Persistence
|
|
269
|
+
|
|
270
|
+
By default, runtime variables are **persisted to disk** at `~/.voiden/.process.env.json`.
|
|
271
|
+
This allows you to share state across multiple `voiden-runner` commands.
|
|
272
|
+
|
|
273
|
+
- **To disable persistence** (keep variables in-memory only for a single run), use the `--no-session` flag.
|
|
274
|
+
- **To clear variables**, delete the `.process.env.json` file or use `voiden-runner session clear`.
|
|
275
|
+
|
|
276
|
+
The `.void` files themselves are never modified. This ensures that your source
|
|
277
|
+
files remain clean while still allowing for stateful execution chains.
|
|
278
|
+
|
|
279
|
+
### Example — auth chain
|
|
280
|
+
|
|
281
|
+
**1. `login.void`** — POST /auth/login
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
runtime-variables block:
|
|
285
|
+
token → {{$res.body.access_token}}
|
|
286
|
+
userId → {{$res.body.user.id}}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**2. `get-profile.void`** — GET /users/{{process.userId}}
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
Authorization: Bearer {{process.token}}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Run them in order:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
voiden-runner run login.void get-profile.void --env .env
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The `token` and `userId` captured from `login.void` are automatically available
|
|
302
|
+
in `get-profile.void`.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Sessions & Persistence
|
|
307
|
+
|
|
308
|
+
By default, `voiden-runner` operates in a **stateful session**. This means it
|
|
309
|
+
persists captured runtime variables and run results across multiple command
|
|
310
|
+
invocations until you explicitly clear them.
|
|
311
|
+
|
|
312
|
+
### 1. Persistent State
|
|
313
|
+
Captured variables stay active until you clear the session. This is ideal for
|
|
314
|
+
multi-step workflows:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
voiden-runner run login.void # captures token
|
|
318
|
+
voiden-runner run get-profile.void # uses {{process.token}} automatically
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### 2. Accumulated Results & Reporting
|
|
322
|
+
|
|
323
|
+
Every time you call `run`, the results are appended to a session results file.
|
|
324
|
+
This allows you to generate a single report for a series of separate runs.
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
voiden-runner run login.void
|
|
328
|
+
voiden-runner run users.void
|
|
329
|
+
voiden-runner run posts.void
|
|
330
|
+
|
|
331
|
+
# Generate a combined CSV report for all 3 runs
|
|
332
|
+
voiden-runner report --csv ./session-report.csv
|
|
333
|
+
|
|
334
|
+
# Email the combined report
|
|
335
|
+
voiden-runner report --mail-to qa@company.com
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Managing the Session
|
|
339
|
+
|
|
340
|
+
Use the `session` command to check status or wipe all state.
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# See how many variables and results are stored
|
|
344
|
+
voiden-runner session status
|
|
345
|
+
|
|
346
|
+
# Wipe everything (results and runtime variables)
|
|
347
|
+
voiden-runner session clear
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Plugins
|
|
353
|
+
|
|
354
|
+
All core plugins are **enabled by default** — no `plugin install` step is needed.
|
|
355
|
+
They can be disabled individually (`plugin disable <name>`) or all at once (`plugin disable --all`).
|
|
356
|
+
The `plugin install` command is only required for community plugins.
|
|
357
|
+
|
|
358
|
+
### `voiden-scripting`
|
|
359
|
+
|
|
360
|
+
Executes **pre-request** (`pre_script`) and **post-response** (`post_script`)
|
|
361
|
+
scripts embedded in the `.void` file.
|
|
362
|
+
|
|
363
|
+
**Languages supported in the runner:**
|
|
364
|
+
|
|
365
|
+
| Language | How it runs |
|
|
366
|
+
|---|---|
|
|
367
|
+
| JavaScript | In-process `AsyncFunction` — zero overhead |
|
|
368
|
+
| Python | `python3` subprocess (detected at startup; clear error if missing) |
|
|
369
|
+
| Shell (bash) | `bash` subprocess with temp file isolation |
|
|
370
|
+
|
|
371
|
+
**voiden API inside scripts**
|
|
372
|
+
|
|
373
|
+
| Property / Method | Description |
|
|
374
|
+
|---|---|
|
|
375
|
+
| `voiden.request.url` | Request URL (read/write in pre-script) |
|
|
376
|
+
| `voiden.request.method` | HTTP method (read/write in pre-script) |
|
|
377
|
+
| `voiden.request.headers` | Headers array `[{key, value}]` (read/write) |
|
|
378
|
+
| `voiden.request.body` | Request body string (read/write) |
|
|
379
|
+
| `voiden.request.queryParams` | Query params array (read/write) |
|
|
380
|
+
| `voiden.request.pathParams` | Path params array (read/write) |
|
|
381
|
+
| `voiden.response` | Response object (post-script only) |
|
|
382
|
+
| `voiden.response.status` | HTTP status code |
|
|
383
|
+
| `voiden.response.body` | Parsed response body |
|
|
384
|
+
| `voiden.response.headers` | Response headers `{key: value}` |
|
|
385
|
+
| `voiden.env.get('KEY')` | Read from `--env` file |
|
|
386
|
+
| `voiden.variables.get('KEY')` | Read a runtime variable |
|
|
387
|
+
| `voiden.variables.set('KEY', val)` | Write a runtime variable (available to next request) |
|
|
388
|
+
| `voiden.assert(actual, op, expected, msg?)` | Emit a pass/fail assertion |
|
|
389
|
+
| `voiden.log(level?, ...args)` | Emit a log line (`--verbose` to see them) |
|
|
390
|
+
| `voiden.cancel()` | Cancel the request from a pre-script |
|
|
391
|
+
|
|
392
|
+
**Assertion operators:** `==` `===` `!=` `!==` `>` `>=` `<` `<=`
|
|
393
|
+
`contains` `includes` `matches` (regex) `truthy` `falsy`
|
|
394
|
+
`eq` `neq` `gte` `lte` `greater` `less`
|
|
395
|
+
|
|
396
|
+
**Example — pre-script adds a timestamp header:**
|
|
397
|
+
|
|
398
|
+
```javascript
|
|
399
|
+
voiden.request.headers.push({ key: 'X-Run-Ts', value: String(Date.now()), enabled: true })
|
|
400
|
+
voiden.log('info', 'Added X-Run-Ts')
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Example — post-script asserts and captures a token:**
|
|
404
|
+
|
|
405
|
+
```javascript
|
|
406
|
+
const body = voiden.response.body
|
|
407
|
+
voiden.assert(voiden.response.status, '==', 200, 'status is 200')
|
|
408
|
+
voiden.assert(body.access_token, 'truthy', null, 'token present')
|
|
409
|
+
voiden.variables.set('token', body.access_token)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
### `simple-assertions`
|
|
415
|
+
|
|
416
|
+
Evaluates assertion rows from an `assertions-table` block against the response.
|
|
417
|
+
|
|
418
|
+
**Field path syntax** (the `field` column):
|
|
419
|
+
|
|
420
|
+
| Path | Resolves to |
|
|
421
|
+
|---|---|
|
|
422
|
+
| `status` | HTTP status code |
|
|
423
|
+
| `statusText` | HTTP status text |
|
|
424
|
+
| `responseTime` | Response time in ms |
|
|
425
|
+
| `header.<Name>` | A response header value |
|
|
426
|
+
| `body.data.id` | JSON path into the parsed body |
|
|
427
|
+
| `body.items[0].name` | Array index access |
|
|
428
|
+
|
|
429
|
+
**Operators:** `equals` `notEquals` `contains` `notContains` `startsWith`
|
|
430
|
+
`endsWith` `greaterThan` `lessThan` `gte` `lte` `isEmpty` `isNotEmpty`
|
|
431
|
+
`isNull` `isNotNull` `matches` `exists` `notExists`
|
|
432
|
+
|
|
433
|
+
Assertion results appear under the request result line and in CSV/email reports.
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
### `voiden-faker`
|
|
438
|
+
|
|
439
|
+
Replaces `{{$faker.category.method(args)}}` patterns before the request is sent.
|
|
440
|
+
|
|
441
|
+
```
|
|
442
|
+
{{$faker.person.firstName()}}
|
|
443
|
+
{{$faker.internet.email()}}
|
|
444
|
+
{{$faker.string.uuid()}}
|
|
445
|
+
{{$faker.number.int({"min":1,"max":100})}}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
### `voiden-advanced-auth`
|
|
451
|
+
|
|
452
|
+
Reads the `auth` block and injects authentication into the request.
|
|
453
|
+
|
|
454
|
+
**Auth types in the runner:** `bearer` `basic` `apiKey` (header or query)
|
|
455
|
+
|
|
456
|
+
OAuth 2.0, OAuth 1.0, AWS SigV4, Digest, NTLM — require the desktop app and
|
|
457
|
+
emit a warning when encountered in the runner.
|
|
458
|
+
|
|
459
|
+
`{{KEY}}` patterns in token/key/value fields are resolved from system env and the `--env` file.
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
### `voiden-graphql`
|
|
464
|
+
|
|
465
|
+
Rewrites `gqlquery` + `gqlvariables` blocks as a standard GraphQL-over-HTTP
|
|
466
|
+
POST (`Content-Type: application/json`, body `{query, variables}`).
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## Output formats
|
|
471
|
+
|
|
472
|
+
### Default (human-readable)
|
|
473
|
+
|
|
474
|
+
```
|
|
475
|
+
voiden-runner · 3 files · 5 plugins active
|
|
476
|
+
────────────────────────────────────────────────────────────────
|
|
477
|
+
|
|
478
|
+
[1/3] auth.void
|
|
479
|
+
✓ REST POST https://api.example.com/auth 200 OK 342ms 1.2KB
|
|
480
|
+
|
|
481
|
+
[2/3] users.void
|
|
482
|
+
✓ REST GET https://api.example.com/users 200 OK 128ms
|
|
483
|
+
assertions: 3 passed
|
|
484
|
+
✓ status is 200
|
|
485
|
+
✓ body has items
|
|
486
|
+
✓ items count > 0
|
|
487
|
+
|
|
488
|
+
[3/3] delete-missing.void
|
|
489
|
+
✗ REST DELETE https://api.example.com/users/999 404 Not Found 89ms
|
|
490
|
+
assertions: 1 passed · 1 failed
|
|
491
|
+
✗ status is 200 (got 404, expected == 200)
|
|
492
|
+
|
|
493
|
+
────────────────────────────────────────────────────────────────
|
|
494
|
+
Summary 3 requests · 2 passed · 1 failed · 559ms total
|
|
495
|
+
────────────────────────────────────────────────────────────────
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### `--json`
|
|
499
|
+
|
|
500
|
+
```json
|
|
501
|
+
{
|
|
502
|
+
"summary": { "total": 3, "passed": 2, "failed": 1, "totalDurationMs": 559, "activePlugins": ["..."] },
|
|
503
|
+
"requests": [
|
|
504
|
+
{
|
|
505
|
+
"file": "/path/to/auth.void",
|
|
506
|
+
"protocol": "rest", "method": "POST", "url": "...",
|
|
507
|
+
"success": true, "status": 200, "durationMs": 342,
|
|
508
|
+
"requestHeaders": { "Content-Type": "application/json" },
|
|
509
|
+
"requestBody": "{\"email\":\"...\"}",
|
|
510
|
+
"responseHeaders": { "content-type": "application/json" },
|
|
511
|
+
"body": "{\"access_token\":\"...\"}",
|
|
512
|
+
"reportEntries": []
|
|
513
|
+
}
|
|
514
|
+
]
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## Reports — CSV and email
|
|
521
|
+
|
|
522
|
+
### CSV
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
# Write to a specific file
|
|
526
|
+
voiden-runner run ./tests/ --csv ./results/report.csv
|
|
527
|
+
|
|
528
|
+
# Write to the current directory (auto-generates filename: voiden-report-<timestamp>.csv)
|
|
529
|
+
voiden-runner run ./tests/ --csv .
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
CSV columns: `File`, `Protocol`, `Method`, `URL`, `Success`, `Status`,
|
|
533
|
+
`StatusText`, `DurationMs`, `SizeBytes`, `Error`, `RequestHeaders`,
|
|
534
|
+
`RequestBody`, `ResponseHeaders`, `ResponseBody`, `AssertionsPassed`,
|
|
535
|
+
`AssertionsFailed`, `AssertionDetail`
|
|
536
|
+
|
|
537
|
+
### Email
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
voiden-runner run ./tests/ \
|
|
541
|
+
--env .env.ci \
|
|
542
|
+
--mail-to qa@company.com
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Sends a dark-themed HTML report with per-request cards showing request/response
|
|
546
|
+
headers, bodies, and assertion results. Subject line is auto-generated from the
|
|
547
|
+
pass/fail summary unless `--mail-subject` is provided.
|
|
548
|
+
|
|
549
|
+
**SMTP Configuration**
|
|
550
|
+
|
|
551
|
+
The runner reads SMTP settings from your `.env` file (passed via `--env`) or
|
|
552
|
+
the system environment.
|
|
553
|
+
|
|
554
|
+
| Variable | Description |
|
|
555
|
+
|---|---|
|
|
556
|
+
| `VOIDEN_SMTP_HOST` | **Required** for email. SMTP server hostname (e.g., `smtp.gmail.com`). |
|
|
557
|
+
| `VOIDEN_SMTP_PORT` | SMTP port. Defaults to `587` (or `465` if secure). |
|
|
558
|
+
| `VOIDEN_SMTP_SECURE` | Set to `true` to use TLS/SSL (port 465). |
|
|
559
|
+
| `VOIDEN_SMTP_USER` | SMTP login username. |
|
|
560
|
+
| `VOIDEN_SMTP_PASS` | SMTP login password. |
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## Exit codes
|
|
565
|
+
|
|
566
|
+
| Code | Condition |
|
|
567
|
+
|---|---|
|
|
568
|
+
| `0` | Run completed — unless `--fail-on-error` or `--bail`/`--stop-on-failure` is set |
|
|
569
|
+
| `1` | Any request failed and `--fail-on-error`, `--bail`, or `--stop-on-failure` is set |
|
|
570
|
+
| `1` | Usage error (bad flag, no files found, missing SMTP config, etc.) |
|
|
571
|
+
|
|
572
|
+
When exiting with code `1` due to failures, a final message is printed:
|
|
573
|
+
|
|
574
|
+
```
|
|
575
|
+
✗ Run failed — 3 requests failed. Exiting with code 1.
|
|
576
|
+
(use this exit code in your shell script to abort on failure)
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
This exit code works universally — bash (`$?`), PowerShell (`$LASTEXITCODE`),
|
|
580
|
+
`set -e`, `&&`/`||` chains, GitHub Actions, GitLab CI, Jenkins, CircleCI, and
|
|
581
|
+
any other CI/CD system.
|
|
582
|
+
|
|
583
|
+
## Passing results to other CLI commands
|
|
584
|
+
|
|
585
|
+
### `--output-json <file>`
|
|
586
|
+
|
|
587
|
+
Writes the full result — the whole response object and array — to a JSON file.
|
|
588
|
+
Normal terminal output still shows. The next CLI, script, or tool reads the file
|
|
589
|
+
and gets everything: status, headers, body, assertions, duration.
|
|
590
|
+
|
|
591
|
+
```bash
|
|
592
|
+
# Write results to a file, then pass the whole object to the next tool
|
|
593
|
+
voiden-runner run auth.void --output-json result.json
|
|
594
|
+
my-deploy-cli --data result.json
|
|
595
|
+
|
|
596
|
+
# Chain multiple runs — each appends its own file
|
|
597
|
+
voiden-runner run login.void --output-json login.json
|
|
598
|
+
voiden-runner run users.void --output-json users.json
|
|
599
|
+
my-report-tool login.json users.json
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
The JSON structure written to the file is the same as `--json` stdout output:
|
|
603
|
+
|
|
604
|
+
```json
|
|
605
|
+
{
|
|
606
|
+
"summary": { "total": 1, "passed": 1, "failed": 0, "totalDurationMs": 342 },
|
|
607
|
+
"requests": [
|
|
608
|
+
{
|
|
609
|
+
"file": "/path/to/auth.void",
|
|
610
|
+
"protocol": "rest",
|
|
611
|
+
"method": "POST",
|
|
612
|
+
"url": "https://api.example.com/auth",
|
|
613
|
+
"success": true,
|
|
614
|
+
"status": 200,
|
|
615
|
+
"durationMs": 342,
|
|
616
|
+
"body": "{\"access_token\":\"sk-abc\",\"user\":{\"id\":42}}",
|
|
617
|
+
"requestHeaders": { "Content-Type": "application/json" },
|
|
618
|
+
"responseHeaders": { "content-type": "application/json" }
|
|
619
|
+
}
|
|
620
|
+
]
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### `--json` stdout pipe
|
|
625
|
+
|
|
626
|
+
Use `--json` to pipe the same structure directly to another command:
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
voiden-runner run auth.void --json | jq .
|
|
630
|
+
voiden-runner run tests/ --json | my-cli --stdin
|
|
631
|
+
voiden-runner run tests/ --json > results.json && python3 analyse.py results.json
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Runtime variable chaining
|
|
635
|
+
|
|
636
|
+
Variables captured via `{{$res.body.xxx}}` blocks persist to
|
|
637
|
+
`~/.voiden/.process.env.json` between separate `voiden-runner run` calls —
|
|
638
|
+
no piping or files needed:
|
|
639
|
+
|
|
640
|
+
```bash
|
|
641
|
+
voiden-runner run login.void # captures token via runtime-variables block
|
|
642
|
+
voiden-runner run users.void # uses {{process.token}} automatically
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
## CI/CD
|
|
648
|
+
|
|
649
|
+
Works on every CI/CD platform that supports Node.js — GitHub Actions, GitLab CI,
|
|
650
|
+
CircleCI, Jenkins, Azure Pipelines, Bitbucket Pipelines, and more. Install once,
|
|
651
|
+
run anywhere:
|
|
652
|
+
|
|
653
|
+
```bash
|
|
654
|
+
npm install -g @voiden/runner # bash / macOS / Linux
|
|
655
|
+
npm install -g @voiden/runner # PowerShell / Windows cmd — identical
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
**Windows (cmd.exe / PowerShell)**
|
|
659
|
+
|
|
660
|
+
```batch
|
|
661
|
+
:: cmd.exe
|
|
662
|
+
voiden-runner run tests\ --env .env.ci --stop-on-failure
|
|
663
|
+
if %ERRORLEVEL% neq 0 exit /b 1
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
```powershell
|
|
667
|
+
# PowerShell
|
|
668
|
+
voiden-runner run tests/ --env .env.ci --stop-on-failure
|
|
669
|
+
if ($LASTEXITCODE -ne 0) { exit 1 }
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### GitHub Actions
|
|
673
|
+
|
|
674
|
+
```yaml
|
|
675
|
+
jobs:
|
|
676
|
+
api-tests:
|
|
677
|
+
runs-on: ubuntu-latest
|
|
678
|
+
steps:
|
|
679
|
+
- uses: actions/checkout@v4
|
|
680
|
+
- uses: actions/setup-node@v4
|
|
681
|
+
with: { node-version: '20' }
|
|
682
|
+
|
|
683
|
+
- run: npm install -g @voiden/runner
|
|
684
|
+
|
|
685
|
+
- name: Write env
|
|
686
|
+
run: |
|
|
687
|
+
echo "BASE_URL=${{ secrets.BASE_URL }}" >> .env.ci
|
|
688
|
+
echo "API_KEY=${{ secrets.API_KEY }}" >> .env.ci
|
|
689
|
+
|
|
690
|
+
- name: Run tests
|
|
691
|
+
run: |
|
|
692
|
+
voiden-runner run ./tests/ \
|
|
693
|
+
--env .env.ci \
|
|
694
|
+
--stop-on-failure \
|
|
695
|
+
--json | tee results.json
|
|
696
|
+
|
|
697
|
+
- uses: actions/upload-artifact@v4
|
|
698
|
+
if: always()
|
|
699
|
+
with: { name: api-test-results, path: results.json }
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
### GitLab CI
|
|
703
|
+
|
|
704
|
+
```yaml
|
|
705
|
+
api-tests:
|
|
706
|
+
image: node:20
|
|
707
|
+
script:
|
|
708
|
+
- npm install -g @voiden/runner
|
|
709
|
+
- echo "BASE_URL=$BASE_URL" >> .env.ci
|
|
710
|
+
- echo "API_KEY=$API_KEY" >> .env.ci
|
|
711
|
+
- voiden-runner run ./tests/ --env .env.ci --stop-on-failure
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### With scripting enabled
|
|
715
|
+
|
|
716
|
+
If your `.void` files use `voiden-scripting` blocks and you trust the content:
|
|
717
|
+
|
|
718
|
+
```bash
|
|
719
|
+
# JavaScript only (no Python/Shell risk)
|
|
720
|
+
voiden-runner run ./tests/ --env .env.ci --stop-on-failure
|
|
721
|
+
|
|
722
|
+
# With Python — ensure python3 is available in the runner image
|
|
723
|
+
# python3 --version → Python 3.x.x
|
|
724
|
+
voiden-runner run ./tests/ --env .env.ci --stop-on-failure
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
### Request chaining in CI
|
|
728
|
+
|
|
729
|
+
Variables captured via runtime-variable blocks are shared across all files in a
|
|
730
|
+
single `voiden-runner run` invocation:
|
|
731
|
+
|
|
732
|
+
```bash
|
|
733
|
+
# login.void captures {{token}}, get-users.void uses {{process.token}}
|
|
734
|
+
voiden-runner run login.void get-users.void create-post.void \
|
|
735
|
+
--env .env.ci \
|
|
736
|
+
--stop-on-failure
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
---
|
|
740
|
+
|
|
741
|
+
## Supported protocols
|
|
742
|
+
|
|
743
|
+
| Protocol | Block types |
|
|
744
|
+
|---|---|
|
|
745
|
+
| REST (HTTP/HTTPS) | `method`, `url`, `headers-table`, `query-table`, `json_body`, … |
|
|
746
|
+
| WebSocket (`ws://` / `wss://`) | `socket-request`, `surl`, `smethod` |
|
|
747
|
+
| gRPC (`grpc://` / `grpcs://`) | `socket-request`, `proto`, `grpc-messages-node` |
|
|
748
|
+
| GraphQL | `gqlquery`, `gqlvariables` |
|