Complete reference for ENE test suite configuration files (suite.yml).
ENE uses YAML format for test configuration. Each test suite must have a suite.yml file.
kind: e2e_test:v1
name: my-test-suite
# Fixtures can be either array or map format
fixtures:
- fixture_name: fixture_value # Array format
# OR
fixtures:
fixture_name: fixture_value # Map format
units:
- name: service_name
kind: service_type
target: target_service_name
tests:
- name: test_name
kind: test_typeSpecifies the configuration version.
- Type:
string - Required: Yes
- Valid Values:
e2e_test:v1
kind: e2e_test:v1Name of the test suite. Should be descriptive and unique.
- Type:
string - Required: Yes
- Min Length: 1
name: user-api-testsArray of reusable data fixtures that can be interpolated throughout the configuration.
- Type:
array - Required: No
- Default:
[]
See Fixtures section for details.
Array of service/container definitions that make up the test environment.
- Type:
array - Required: Yes
- Min Items: 1
See Units section for details.
Name of the unit that tests should target by default.
- Type:
string - Required: Yes
- Must Reference: An existing unit name
target: my-appArray of test cases to execute.
- Type:
array - Required: Yes
- Min Items: 1
See Tests section for details.
Fixtures are reusable values that can be referenced throughout the configuration using {{ fixture_name }} syntax.
fixtures:
- api_key: test-key-12345Fields:
name(required): Unique identifier for the fixturevalue(required): The value to use (string, number, boolean, or object)
fixtures:
- test_user: { file: ./testdata/user.json }Fields:
name(required): Unique identifier for the fixturefile(required): Path to file containing the fixture value (relative to suite directory)
Array format:
fixtures:
- content_type: application/json; charset=utf-8
- test_payload: { file: ./data/payload.json }
tests:
- name: create resource
kind: http
request:
headers:
Content-Type: "{{ content_type }}"
body: "{{ test_payload }}"Map format:
fixtures:
content_type: application/json; charset=utf-8
test_payload: { file: ./data/payload.json }
tests:
- name: create resource
kind: http
request:
headers:
Content-Type: "{{ content_type }}"
body: "{{ test_payload }}"Units define the services/containers that make up your test environment.
units:
- name: my-service
kind: http
app_port: 8080
startup_timeout: 30s
env_file: .env
env:
- KEY=valueCommon Fields:
name(required): Unique identifier for this unitkind(required): Type of unit (see unit types below)app_port(required): Port the service listens onstartup_timeout(optional): Maximum time to wait for startup (default: 30s)env_file(optional): Path to environment file (relative to suite directory)env(optional): Array of environment variables inKEY=valueformat
Mock HTTP server for testing without real services.
- name: mock-api
kind: httpmock
app_port: 8080
routes:
- path: /api/users
method: GET
response:
status: 200
body:
users: []
headers:
Content-Type: application/json
- path: /api/users
method: POST
response:
status: 201
body:
id: "123"
created: true
- path: /api/slow-endpoint
method: GET
response:
status: 200
delay: "5s" # Simulates a slow endpoint
body:
message: "This took a while"
headers:
Content-Type: application/jsonFields:
routes(required): Array of mock route definitionspath(required): URL path to matchmethod(required): HTTP method (GET, POST, PUT, DELETE, PATCH, etc.)response(required): Response configurationstatus(required): HTTP status codebody(optional): Response body (can be object or string)headers(optional): Response headers (key-value pairs)delay(optional): Delay before responding (e.g., '2s', '500ms'). Simulates slow endpoints.
Supported Methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
Delay Format: Duration string following Go's time.ParseDuration format
500ms- 500 milliseconds2s- 2 seconds1m30s- 1 minute and 30 seconds- Use cases: Testing timeout configuration, simulating slow external services, demonstrating timeout failures
Your actual application service running in a container.
- name: my-app
kind: http
dockerfile: Dockerfile
# OR
image: myapp:latest
app_port: 8080
healthcheck: /health
startup_timeout: 2m
env_file: .env
env:
- DATABASE_URL={{ mongodb.dsn }}
- LOG_LEVEL=debug
cmd:
- ./server
- --port=8080Fields:
dockerfile(conditional): Path to Dockerfile (required ifimagenot specified)image(conditional): Docker image name (required ifdockerfilenot specified)healthcheck(optional): Health check endpoint pathcmd(optional): Override container command (array of strings)
Note: Either dockerfile or image must be specified, but not both.
MongoDB database service.
- name: mongodb
kind: mongo
image: mongo:6.0
app_port: 27017
database: testdb
user: testuser
password: testpass
migrations: db.js
startup_timeout: 30sFields:
image(required): MongoDB Docker imagedatabase(optional): Database name (default: test)user(optional): Database user (default: admin)password(optional): Database password (default: password)migrations(optional): Path to JavaScript migration file
Available Service Variables:
{{ mongodb.dsn }}- Full connection string{{ mongodb.host }}- Hostname{{ mongodb.port }}- Port number{{ mongodb.database }}- Database name
PostgreSQL database service.
- name: postgres
kind: postgres
image: postgres:14
app_port: 5432
database: testdb
user: testuser
password: testpass
migrations: ./migrations
startup_timeout: 30sFields:
image(required): PostgreSQL Docker imagedatabase(optional): Database name (default: test)user(optional): Database user (default: postgres)password(optional): Database password (default: postgres)migrations(optional): Path to SQL migration files directory
Available Service Variables:
{{ postgres.dsn }}- Full connection string{{ postgres.host }}- Hostname{{ postgres.port }}- Port number{{ postgres.database }}- Database name
MinIO S3-compatible object storage service.
- name: storage
kind: minio
image: minio/minio:latest
access_key: testuser
secret_key: testpass123
app_port: 9000
console_port: 9001
startup_timeout: 30s
buckets:
- uploads
- processed
- archived
env:
- MINIO_BROWSER=onFields:
image(required): MinIO Docker imageaccess_key(required): Access key for MinIOsecret_key(required): Secret key for MinIOconsole_port(optional): MinIO console port (default: 9001)buckets(optional): Array of bucket names to create on startup
Available Service Variables:
{{ storage.endpoint }}- External endpoint{{ storage.local_endpoint }}- Internal container endpoint{{ storage.access_key }}- Access key{{ storage.secret_key }}- Secret key
Test definitions specify what to test and what results to expect.
tests:
- name: my test
kind: http
target: payment-service # Optional: override suite-level target
timeout: 5sCommon Fields:
name(required): Descriptive test namekind(required): Test type (httporminio)target(optional): Override suite-level target for this specific testtimeout(optional): Maximum test execution time (default: 5s)
Override the suite-level target for this specific test.
Type: string (unit name)
Default: Uses suite-level target
Use cases:
- Testing external services directly (bypass gateway)
- Multi-service architectures where some tests hit different services
- Testing service-to-service communication
Example:
# Suite-level target
target: api-gateway
tests:
# This test uses api-gateway (default)
- name: test gateway endpoint
kind: http
request:
path: /api/users
# This test overrides to call payment service directly
- name: test payment service
kind: http
target: payment-service # Override
request:
path: /v1/chargeHTTP request/response test.
- name: create user
kind: http
timeout: 10s
request:
method: POST
path: /api/users
headers:
Content-Type: application/json
Authorization: Bearer {{ token }}
query_params:
include: profile
body:
name: John Doe
email: john@example.com
expect:
status_code: 201
body_asserts:
id:
present: true
name: John Doe
header_asserts:
Location:
present: trueFields:
method(required): HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)path(required): Request path (can include variables)timeout(optional): Request timeout (default: 5s)headers(optional): Request headers (key-value pairs)query_params(optional): Query parameters (key-value pairs)body(optional): Request body (can be object or string)
Fields:
status_code(optional): Expected HTTP status code (default: 200)body_asserts(optional): Array of body assertions (see Body Assertions)header_asserts(optional): Array of header assertions (see Header Assertions)
PostgreSQL database query test.
- name: "Check user count"
kind: postgres
query: "SELECT COUNT(*) as count FROM users WHERE status = 'active'"
expect:
row_count: 1
column_values:
count: 5| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique test identifier |
kind |
string | Yes | Must be "postgres" |
query |
string | Conditional | SQL query to execute (required unless only checking table_exists) |
expect |
object | Yes | Expectations to verify |
target |
string | Optional | Override suite-level target unit |
debug |
boolean | Optional | Enable debug output for this test |
| Field | Type | Description |
|---|---|---|
table_exists |
string | Verify a table exists |
row_count |
integer | Assert exact row count |
min_row_count |
integer | Assert minimum row count |
max_row_count |
integer | Assert maximum row count |
no_rows |
boolean | Assert query returns zero rows |
rows |
array[object] | Assert exact row data matches |
column_values |
object | Assert column values (single row only) |
contains |
array[object] | Assert results contain these rows |
not_contains |
array[object] | Assert results don't contain these rows |
Table Existence Check:
- name: "Verify users table exists"
kind: postgres
expect:
table_exists: "users"Row Count Assertions:
# Exact count
- name: "Verify 5 active users"
kind: postgres
query: "SELECT * FROM users WHERE status = 'active'"
expect:
row_count: 5
# Range
- name: "Verify user count in range"
kind: postgres
query: "SELECT * FROM users"
expect:
min_row_count: 1
max_row_count: 100
# No rows
- name: "No orphaned orders"
kind: postgres
query: "SELECT * FROM orders WHERE user_id NOT IN (SELECT id FROM users)"
expect:
no_rows: trueExact Row Data:
- name: "Verify user details"
kind: postgres
query: "SELECT id, name, email FROM users WHERE id = 1"
expect:
row_count: 1
rows:
- id: 1
name: "Alice"
email: "alice@example.com"Column Values (Single Row):
- name: "Check aggregate values"
kind: postgres
query: "SELECT COUNT(*) as total, SUM(amount) as sum FROM orders"
expect:
column_values:
total: 42
sum: 1500Contains/Not Contains:
# Verify specific rows exist
- name: "Admin users exist"
kind: postgres
query: "SELECT email, role FROM users WHERE role = 'admin'"
expect:
contains:
- email: "admin@example.com"
role: "admin"
# Verify specific rows don't exist
- name: "Deleted user is gone"
kind: postgres
query: "SELECT * FROM users"
expect:
not_contains:
- email: "deleted@example.com"Fixture Interpolation:
fixtures:
- user_id: 123
tests:
- name: "Query specific user"
kind: postgres
query: "SELECT * FROM users WHERE id = {{ user_id }}"
expect:
row_count: 1📖 More details: See PostgreSQL Test Plugin README and POSTGRES_TESTS.md
MongoDB database query test.
- name: "Check active users"
kind: mongo
collection: users
filter: '{"status": "active"}'
expect:
document_count: 5| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique test identifier |
kind |
string | Yes | Must be "mongo" |
collection |
string | Conditional | MongoDB collection name (required unless only checking collection_exists) |
filter |
string/object | Optional | MongoDB filter for find operations (JSON string or YAML structure) |
pipeline |
string/array | Optional | MongoDB aggregation pipeline (JSON string or YAML array) |
expect |
object | Yes | Expectations to verify |
target |
string | Optional | Override suite-level target unit |
debug |
boolean | Optional | Enable debug output for this test |
| Field | Type | Description |
|---|---|---|
collection_exists |
string | Verify a collection exists |
document_count |
integer | Assert exact document count |
min_document_count |
integer | Assert minimum document count |
max_document_count |
integer | Assert maximum document count |
no_documents |
boolean | Assert query returns zero documents |
documents |
array[object] | Assert exact document data matches |
field_values |
object | Assert field values (single document only) |
contains |
array[object] | Assert results contain these documents |
not_contains |
array[object] | Assert results don't contain these documents |
The plugin supports both JSON strings and YAML structures.
Filter (Find) Operations:
# JSON String Format
- name: "Find active users"
kind: mongo
collection: users
filter: '{"status": "active", "age": {"$gte": 18}}'
expect:
min_document_count: 1
# YAML Structure Format
- name: "Find active users"
kind: mongo
collection: users
filter:
status: active
age:
$gte: 18
expect:
min_document_count: 1Pipeline (Aggregation) Operations:
# JSON String Format
- name: "Aggregate by status"
kind: mongo
collection: orders
pipeline: '[{"$group": {"_id": "$status", "count": {"$sum": 1}}}]'
expect:
min_document_count: 1
# YAML Array Format
- name: "Aggregate by status"
kind: mongo
collection: orders
pipeline:
- $match:
year: 2024
- $group:
_id: "$status"
count: { $sum: 1 }
- $sort:
count: -1
expect:
min_document_count: 1Collection Existence Check:
- name: "Verify users collection exists"
kind: mongo
expect:
collection_exists: "users"Document Count Assertions:
# Exact count
- name: "Verify 5 users"
kind: mongo
collection: users
filter: '{}'
expect:
document_count: 5
# Range
- name: "Verify user count in range"
kind: mongo
collection: users
filter: '{}'
expect:
min_document_count: 1
max_document_count: 100
# No documents
- name: "No orphaned records"
kind: mongo
collection: orders
filter:
user_id:
$nin: [1, 2, 3]
expect:
no_documents: trueExact Document Data:
- name: "Verify user details"
kind: mongo
collection: users
filter:
_id: 1
expect:
document_count: 1
documents:
- _id: 1
name: "Alice"
email: "alice@example.com"Field Values (Single Document):
- name: "Check aggregate values"
kind: mongo
collection: orders
pipeline:
- $group:
_id: null
total: { $sum: 1 }
total_amount: { $sum: "$amount" }
expect:
field_values:
total: 42
total_amount: 1500Contains/Not Contains:
# Verify specific documents exist
- name: "Admin users exist"
kind: mongo
collection: users
filter:
role: admin
expect:
contains:
- email: "admin@example.com"
role: "admin"
# Verify specific documents don't exist
- name: "Deleted user is gone"
kind: mongo
collection: users
filter: '{}'
expect:
not_contains:
- email: "deleted@example.com"Fixture Interpolation:
fixtures:
- user_id: "123"
- user_email: "test@example.com"
tests:
- name: "Query specific user by ID"
kind: mongo
collection: users
filter: '{"_id": "{{ user_id }}"}'
expect:
document_count: 1
- name: "Query by email"
kind: mongo
collection: users
filter:
email: "{{ user_email }}"
expect:
document_count: 1📖 More details: See MongoDB Test Plugin README and MONGO_QUICK_REFERENCE.md
MinIO state verification test.
- name: verify upload
kind: minio
verify_state:
files_exist:
- uploads/file1.txt
- uploads/file2.pdf
bucket_counts:
uploads: 2
processed: 0
required:
buckets:
uploads:
- path: file1.txt
min_size: 10B
max_size: 10MB
content_type: text/plain
max_age: 5m
forbidden:
buckets:
uploads:
- "*.tmp"
- "temp_*"
constraints:
- bucket: uploads
file_count: 2
max_total_size: 100MBFields:
files_exist(optional): Array of file paths that must existbucket_counts(optional): Expected file counts per bucket (key-value pairs)required(optional): Required file specificationsforbidden(optional): Patterns/files that must not existconstraints(optional): Bucket-level constraints
required:
buckets:
bucket_name:
- path: relative/path/to/file
min_size: 1B
max_size: 10MB
content_type: image/jpeg
max_age: 5m
pattern: "^user-.*\\.jpg$"Fields:
path(required): Relative path to file in bucketmin_size(optional): Minimum file size (e.g., "1B", "1KB", "1MB")max_size(optional): Maximum file sizemax_age(optional): Maximum file age (e.g., "5m", "1h", "2d")content_type(optional): Expected MIME typepattern(optional): Regex pattern for file path
forbidden:
buckets:
bucket_name:
- "*.tmp" # Wildcard patterns
- "temp_*"
- "debug/**"
files:
- "uploads/sensitive.txt"
- "bucket/admin/*"constraints:
- bucket: uploads
file_count: 5 # Exact count
# OR
file_count: ">= 5" # Comparison
max_total_size: 100MB
min_total_size: 1MB
- bucket: archived
file_count: 0 # Must be empty
- total_buckets: 3 # Total bucket count
- empty_buckets: "<= 1" # Empty bucket limitConstraint Types:
bucket(optional): Specific bucket namefile_count(optional): Expected file count (number or comparison string)max_total_size(optional): Maximum total size of filesmin_total_size(optional): Minimum total size of filestotal_buckets(optional): Total number of bucketsempty_buckets(optional): Number of empty buckets allowed
Comparison Operators: =, !=, >, <, >=, <=, ≤, ≥
ENE provides detailed error messages when assertions fail, showing both the expected and actual values to help you quickly diagnose issues.
Example Error Messages:
- Header assertion:
header "Content-Type": expected "application/json" but got "text/plain" - Body equals:
expected "John Doe" but got "Jane Smith" - Body comparison:
expected value > 18 but got 15 - Body size:
expected array size 5 but got 3
Assertions on response body content using JSONPath. Uses a map-based format where keys are JSON paths and values are either strings (shorthand for equals) or objects with explicit assertions.
body_asserts:
# String shorthand for equals
user.name: John Doe
# Explicit assertions with object
user.email:
matches: "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$"
# Comparison operators with symbols
user.age:
">": 18 # greater_than
"<": 100 # less_than
# Type and length checking
user.tags:
length: 3 # or 'size'
type: array
# Multiple assertions on same field
user.active:
type: boolean
equals: trueMap Key: JSONPath to the field (use $ for root document)
Map Value: Either a string (shorthand for equals) or an object with one or more assertions:
Comparison Assertions:
- String value: Shorthand for equals assertion (e.g.,
name: "John") equals: Exact value match- Error format:
expected "X" but got "Y"
- Error format:
not_equals: Value must not match- Error format:
value equals "X" (should not equal, but got: "X")
- Error format:
contains: String/array must contain substring/element- Error format:
value does not contain "X" (got: "Y")
- Error format:
not_contains: Must not contain substring/element- Error format:
value contains "X" (got: "Y")
- Error format:
matches: Regex pattern match- Error format:
value does not match regex "pattern" (got: "Y")
- Error format:
not_matches: Must not match regex pattern- Error format:
value matches regex "pattern" (should not match, but got: "Y")
- Error format:
>: Numeric comparison (value > threshold)- Error format:
expected value > X but got Y
- Error format:
<: Numeric comparison (value < threshold)- Error format:
expected value < X but got Y
- Error format:
greater_than: Alias for>less_than: Alias for<
Presence Assertion:
present: Boolean - field must exist (true) or not exist (false)
Type Assertion:
type: Expected type (string,int,float,bool,array,object)- Error format:
expected type 'string' but got type 'number' at path: user.age (value: "25")
- Error format:
Size/Length Assertion:
length: Expected length for strings/arrays or key count for objects- Error format:
expected size X but got Yorexpected array size X but got Y
- Error format:
size: Alias forlength
Array Containment Assertions:
contains_where: Check if array contains at least one item matching all conditionsall_match: Check if all array items match conditionsnone_match: Check if no array items match conditions
Note: Some assertions conflict (e.g., equals with contains, >, <). Compatible combinations include > and < for range checks, present with any other assertion, and type with any other assertion. Array containment assertions can be combined with type and length checks.
body_asserts:
# Root document
$:
type: object
# Top-level field with shorthand
status: success
# Nested field
data.user.email:
present: true
# Array element with shorthand
items.0.name: First Item
# Array length
items:
length: 5
# Range checking
score:
">": 0
"<": 100
# Array containment - check if array contains item matching conditions
products:
contains_where:
name: "iPhone"
price:
">": 900
# All items must match conditions
items:
all_match:
in_stock: true
price:
">": 0
# No items should match conditions
errors:
none_match:
severity: "critical"Assertions on response headers. Uses a map-based format where keys are header names and values are either strings (shorthand for equals) or objects with explicit assertions.
header_asserts:
# String shorthand for equals
Content-Type: application/json
# Explicit assertions with object
X-Request-ID:
present: true
matches: "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
# String operations
Cache-Control:
contains: no-cache
Set-Cookie:
not_contains: secure=falseMap Key: HTTP header name (case-insensitive)
Map Value: Either a string (shorthand for equals) or an object with one or more assertions:
Comparison Assertions:
- String value: Shorthand for equals assertion (e.g.,
Content-Type: application/json) equals: Exact value match- Error format:
header "Content-Type": expected "application/json" but got "text/plain"
- Error format:
not_equals: Value must not match- Error format:
header "X-Custom" equals "value" (should not equal, but got: "value")
- Error format:
contains: Header value must contain substring- Error format:
header "Cache-Control" does not contain "no-cache" (got: "public, max-age=3600")
- Error format:
not_contains: Must not contain substring- Error format:
header "Set-Cookie" contains "secure=false" (got: "session=abc; secure=false")
- Error format:
matches: Regex pattern match- Error format:
header "X-Request-ID" does not match pattern "^[0-9a-f-]+$" (got: "invalid_id")
- Error format:
not_matches: Must not match regex pattern- Error format:
header "X-Token" matches pattern "^Bearer" (should not match, but got: "Bearer token123")
- Error format:
Presence Assertion:
present: Boolean - header must exist (true) or not exist (false)
Note: equals conflicts with other comparison assertions. Compatible combinations include present with any other assertion, contains with matches, etc.
ENE supports variable interpolation using {{ variable_name }} syntax.
Array format:
fixtures:
- api_key: test-key-123
tests:
- name: test
kind: http
request:
headers:
Authorization: "Bearer {{ api_key }}"Map format:
fixtures:
api_key: test-key-123
tests:
- name: test
kind: http
request:
headers:
Authorization: "Bearer {{ api_key }}"Reference properties of defined units using {{ unit_name.property }} syntax.
- name: mongodb
kind: mongo
# Available variables:
# {{ mongodb.dsn }} - mongodb://user:pass@host:port/database
# {{ mongodb.host }} - container hostname
# {{ mongodb.port }} - 27017
# {{ mongodb.database }} - database name
# {{ mongodb.user }} - username
# {{ mongodb.password }} - password- name: postgres
kind: postgres
# Available variables:
# {{ postgres.dsn }} - postgres://user:pass@host:port/database
# {{ postgres.host }} - container hostname
# {{ postgres.port }} - 5432
# {{ postgres.database }} - database name
# {{ postgres.user }} - username
# {{ postgres.password }} - password- name: storage
kind: minio
# Available variables:
# {{ storage.endpoint }} - http://host:9000 (external)
# {{ storage.local_endpoint }} - host:9000 (internal)
# {{ storage.access_key }} - access key
# {{ storage.secret_key }} - secret key
# {{ storage.console_port }} - 9001- name: my-app
kind: http
# Available variables:
# {{ my-app.host }} - container hostname
# {{ my-app.port }} - service port
# {{ my-app.endpoint }} - http://host:portArray format:
fixtures:
- api_version: v1
units:
- name: database
kind: mongo
# ...
- name: app
kind: http
env:
- DB_URI: "{{ database.local_uri }}"
tests:
- name: test
kind: http
request:
path: /api/{{ api_version }}/users
headers:
X-Database: "{{ database.local_uri }}"Map format:
fixtures:
api_version: v1
units:
- name: database
kind: mongo
# ...
- name: app
kind: http
env:
- DB_URI: "{{ database.local_uri }}"
tests:
- name: test
kind: http
request:
path: /api/{{ api_version }}/users
headers:
X-Database: "{{ database.local_uri }}"Size values support the following units:
B- BytesKB- Kilobytes (1024 bytes)MB- Megabytes (1024 KB)GB- Gigabytes (1024 MB)
Examples: 100B, 1.5KB, 10MB, 2GB
Duration values use Go's duration format:
s- Secondsm- Minutesh- Hoursd- Days (custom extension)
Examples: 5s, 2m, 1h30m, 2d
kind: e2e_test:v1
name: complete-example
# Using map format (array format also works)
fixtures:
content_type: application/json; charset=utf-8
test_user: { file: ./testdata/user.json }
units:
- name: mongodb
kind: mongo
image: mongo:6.0
app_port: 27017
database: testdb
migrations: db.js
startup_timeout: 30s
- name: storage
kind: minio
image: minio/minio:latest
access_key: testkey
secret_key: testsecret
app_port: 9000
console_port: 9001
buckets:
- uploads
- name: app
kind: http
dockerfile: Dockerfile
app_port: 8080
healthcheck: /health
startup_timeout: 2m
env:
- DATABASE_URL={{ mongodb.dsn }}
- STORAGE_ENDPOINT={{ storage.local_endpoint }}
- STORAGE_ACCESS_KEY={{ storage.access_key }}
- STORAGE_SECRET_KEY={{ storage.secret_key }}
target: app
tests:
- name: health check
kind: http
request:
path: /health
method: GET
expect:
status_code: 200
body_asserts:
status: ok
- name: create user
kind: http
request:
path: /api/users
method: POST
headers:
Content-Type: "{{ content_type }}"
body: "{{ test_user }}"
expect:
status_code: 201
body_asserts:
id:
present: true
type: string
created: true
# Check if tags array contains specific value
tags:
contains_where:
name: "new"
header_asserts:
Location:
present: true
matches: "^/api/users/[0-9]+$"
- name: upload file
kind: http
request:
path: /api/upload
method: POST
headers:
Content-Type: multipart/form-data
body:
file: testfile.txt
expect:
status_code: 200
- name: verify file in storage
kind: minio
verify_state:
files_exist:
- uploads/testfile.txt
bucket_counts:
uploads: 1
required:
buckets:
uploads:
- path: testfile.txt
min_size: 1B
max_size: 10MB
max_age: 1mENE validates configuration against a JSON schema during load. Common validation errors:
- Missing Required Fields: Ensure all required fields are present
- Invalid Types: Check field types match specifications
- Invalid References: Ensure fixture/unit names exist before referencing
- Invalid Syntax: Verify YAML syntax is correct
Run ene dry-run to validate configuration without running tests.
- Use Descriptive Names: Make test and unit names clear and descriptive
- Organize Fixtures: Group related fixtures together
- Minimize Timeouts: Set appropriate timeouts to avoid slow tests
- Use Healthchecks: Define healthcheck endpoints for faster startup detection
- Leverage Interpolation: Use fixtures and service variables to avoid duplication
- Test Independently: Design tests to run independently without dependencies
- Clean Test Data: Use migrations to set up known test data state
- Document Tests: Use clear test names that describe what is being tested
Current schema version: e2e_test:v1
For schema updates and migration guides, see the CHANGELOG.