AI and Machine-Readable Reference
This page is the compact reference for generating valid Gherkio tests. The detailed DSL chapters remain canonical for explanations and edge cases. Historical RFCs are not current syntax references.
Minimal Scenario
scenario: Fetch user
tags: [smoke, users]
steps:
- name: Fetch users
request:
method: GET
url: /users
query:
page: 1
expect:
status: 200
body.data: array
save:
users: body.data
- name: Select a user
set:
SELECTED_USER: ${randomItem(users)}
- name: Fetch selected user
if: $SELECTED_USER.id
request:
method: GET
url: /users/$SELECTED_USER.id
expect:
status: 200
```text
Top-level fields are `scenario`, `description`, `tags`, `setup`, `steps`, `teardown`, and `examples`. `steps` is required. Setup runs before the main workflow; failed setup skips the main workflow; teardown always runs.
## Step Operations
A step performs one primary operation:
- `request:` sends HTTP.
- `redis:` runs one controlled read-only Redis command.
- `set:` assigns variables without I/O; only `name` and `if` may accompany it.
- `use:` composes another scenario; `with:` supplies local overrides.
- `repeat:` runs nested `steps` up to `attempts` times and checks `until` after each successful block.
- `for_each:` runs nested `steps` once per item in a source collection array.
- `export:` materializes a saved collection into an Excel (`.xlsx`) file.
- `import:` reads an Excel (`.xlsx`) file from disk into runtime variables.
All operation types support `name` and `if`. Request and Redis steps also support `expect`, `save`, `timing`, and `retry` where applicable.
For a multi-step polling cycle, use a bounded repeat block:
```yaml
- name: Find unused candidate
repeat:
attempts: 20
until: $existingCount == 0
steps:
- set:
candidate: ${randomItem(candidates)}
- request:
method: GET
url: /items
query: { candidate_id: $candidate.id }
expect: { status: 200 }
save: { existingCount: count(body.data) }
```text
Variables written by nested steps remain available after success. Any nested
failure stops the loop, and unmet `until` after the final attempt fails it.
Negate a simple condition by quoting it:
```yaml
- name: Authenticate when token is absent
if: "!$accessToken"
use: shared/auth/auth.yaml
```text
Combine conditions with `&&` and `||`; `&&` binds more tightly. Parentheses
control grouping, and `!` negates a truthiness check or parenthesized expression:
```yaml
- name: Process complete ticket
if: $item.ticket_name && $item.customer_name && $item.ticket_code
request:
method: POST
url: /tickets
```text
## Excel Export (`export`)
The `export` step writes a saved collection directly into an Excel (`.xlsx`) file on disk without making HTTP requests:
```yaml
- name: Export products to Excel
export:
file: fixtures/products.xlsx # Target file path (relative to export.path or project root)
from: $products # Source collection variable (must start with $)
sheet: "Products" # Optional worksheet name (defaults to Sheet1)
columns:
- header: "ID"
value: "$string(item.id)"
- header: "Title"
value: "$string(item.title)"
- header: "Price"
value: "$float(item.price)"
- header: "Tier"
value: "$if(item.price > 100, 'Premium', 'Standard')"
```text
Each column expression supports casting (`$string`, `$int`, `$float`, `$bool`), `$if(condition, then, else)`, and access to `item.<field>` or runtime variables.
## Excel Import (`import`)
The `import` step reads an Excel (`.xlsx`) file from disk into a runtime array variable without making HTTP requests:
```yaml
- name: Ingest customers from spreadsheet
import:
file: fixtures/customers.xlsx # Path to .xlsx file
sheet: "Sheet1" # Optional worksheet name
as: customers # Variable name storing array of row objects
columns: # Optional explicit aliases; headers default to snake_case
- header: "Customer Name"
as: full_name
```text
Headers with spaces are auto-normalized to `snake_case` (e.g. `$customer.customer_name`).
## Loops (`for_each`)
```yaml
- name: Process each created item
for_each:
from: $createdItems
as: item
steps:
- name: Verify item status
request:
method: GET
url: /items/$item.id
expect:
status: 200
```text
## HTTP Request
```yaml
request:
service: billing # optional named environment service
method: POST # GET, POST, PUT, DELETE, PATCH
url: /v1/orders
query:
include: [customer, items] # arrays create repeated query keys
headers:
Authorization: Bearer $accessToken
body:
user_id: $SELECTED_USER.id
timeout: 30s
```text
Use `multipart` instead of `body` for uploads:
```yaml
request:
method: POST
url: /attachments
multipart:
fields:
title: evidence
files:
attachment:
path: documents/evidence.pdf
contentType: application/pdf
filename: evidence.pdf
```text
Relative file names are checked against `assets.path` after the project-relative path. When `contentType` is omitted, the multipart writer uses `application/octet-stream`.
## Variables and Functions
- `$name`, `${name}`: variable reference.
- `${name:default}`: fallback when missing.
- `$accounts.<name>.<field>`: credential value.
- `$value.path`, `$items[0].id`: nested paths.
- `$string(value)`, `$int(value)`, `$float(value)`, `$bool(value)`: request-body casts.
- `$uuid`, `$ulid`, `$randomInt`, `$randomEmail`, `$randomPhone`, `$timestamp`, `$timestampMs`.
- `${randomInt(min,max)}`.
- `${randomItem(array[,field])}`; an exact `${randomItem(array)}` in `set:` preserves the selected object.
- `${dateNow(format)}`, `${dateOffset(duration,format)}`.
- `${base64(string)}`, `${base64Decode(encoded)}`, `${urlencode(string)}`, `${urldecode(encoded)}`.
- `${hash(algo,data)}`, `${hmac(algo,key,message)}`.
- `${randomString(length,charset)}`, `${toUpper(string)}`, `${toLower(string)}`, `${trim(string)}`.
- `${trimPrefix(value,prefix)}`, `${trimSuffix(value,suffix)}`, `${split(value,delimiter,index)}`.
- `$if(condition,thenValue,elseValue)` inside transform selections.
## Assertions and Saved Values
```yaml
expect:
status: 200
body.id: uuid
body.email: email
body.name: contains Gramedia
body.role: oneOf admin,manager
body.deleted_at: not exists
count(body.items): 3
all(body.items): object
timing:
max: 500ms
save:
userId: body.id
itemCount: count(body.items)
```text
Canonical paths include `body.<field>`, `headers.<name>`, `jwt.<claim>`, and `redis.<field>`. Supported matchers include `exists`, `not exists`, `uuid`, `email`, `datetime`, `uri`, `string`, `number`, `boolean`, `array`, `object`, `null`, `true`, `false`, `contains`, `startsWith`, `endsWith`, `regex`, `oneOf`, `in`, `gt`, `gte`, `lt`, `lte`, `empty`, `ipv4`, `ipv6`, `base64`, and `mac`.
In `save:`, `count(body.<path>)` stores an array length. Empty arrays and explicit `null` values store `0`; missing paths and non-array values warn and are not stored.
## Retry
```yaml
retry:
attempts: 5
interval: 500
backoff: exponential # constant, linear, exponential
maxDuration: 15s
onStatus: [404, 409]
```text
## Redis
Environment:
```yaml
connections:
cache:
type: redis
sentinel:
master: mymaster
addresses: [sentinel-1:26379, sentinel-2:26379]
username: $REDIS_USERNAME
password: $REDIS_PASSWORD
database: 0
```text
Step:
```yaml
- name: Verify cached user
redis:
connection: cache
command: get # get, exists, ttl, hgetall
key: user:$userId
expect:
redis.exists: true
redis.value.id: $userId
```text
## Execution Models
```bash
# Different test files concurrently
gherkio run .gherkio/tests --parallel 4
# Same workflow: two isolated users, three sequential iterations each
gherkio run workflow.yaml --virtual-users 2 --iterations-per-user 3
# Reports
gherkio run workflow.yaml --report html,json
```text
`examples:` is data-driven scenario iteration. Virtual-user mode cannot be combined with `examples`, directory runs, `--parallel`, `--all-accounts`, or partial-step selection.
## Common Invalid Syntax
- Do not use unsupported report flags such as `--report-html`, `--report-json`, or `--report-junit`; use `--report`.
- Do not use a fixed random index when the array length comes from a response; use `randomItem`.
- Do not select an object twice to obtain related fields; store one `${randomItem(array)}` object and access its fields.
- Do not configure both `address` and `sentinel` for one Redis connection.
- Do not use Redis mutation commands; Redis steps are intentionally read-only.
- Do not combine `export` or `import` with `request`, `redis`, `use`, `set`, `repeat`, `for_each`, `expect`, `save`, `retry`, or `timing` in the same step.
- Do not combine `set` with `request`, `redis`, `use`, `repeat`, `for_each`, `export`, or `import` in the same step (validation error `mutually_exclusive`); `expect`, `save`, `retry`, `timing`, and `with` on a `set` step do not error but are ignored.