Advanced Features Guide
This guide covers advanced Flow Test Engine features including dependencies, iterations, conditional execution, mocking, and complex scenarios.
Test Dependencies
Dependencies allow you to create relationships between test suites, ensuring prerequisite tests run before dependent ones.
Basic Dependencies
# Suite A (dependency)
node_id: "auth-setup"
suite_name: "Authentication Setup"
exports: ["auth_token", "user_id"]
steps:
- name: "Login user"
request:
method: "POST"
url: "/auth/login"
body:
email: "admin@example.com"
password: "password"
capture:
auth_token: "body.token"
user_id: "body.user.id"
---
# Suite B (dependent)
node_id: "user-operations"
suite_name: "User Operations"
depends:
- node_id: "auth-setup"
required: true
steps:
- name: "Get user profile"
request:
method: "GET"
url: "/users/{{user_id}}"
headers:
Authorization: "Bearer {{auth_token}}"
Advanced Dependency Configuration
depends:
- node_id: "database-seed"
required: true # Fail if dependency fails
cache: true # Cache results for multiple dependents
variables: # Override variables in dependency
environment: "test"
data_set: "minimal"
- node_id: "optional-setup"
required: false # Continue even if dependency fails
cache: false
Dependency Variable Scoping
Variables exported by dependencies are available globally using the pattern {dependency-node-id}.{variable-name}:
# In dependent suite
steps:
- name: "Use dependency variables"
request:
method: "GET"
url: "/api/data"
headers:
# Access variables from 'auth-setup' dependency
Authorization: "Bearer {{auth-setup.auth_token}}"
User-ID: "{{auth-setup.user_id}}"
Iterations
Execute the same step multiple times with different data using iterations.
Array Iteration
variables:
test_users:
- id: 1
name: "Alice"
email: "alice@example.com"
- id: 2
name: "Bob"
email: "bob@example.com"
steps:
- name: "Create user {{item.name}}"
iterate:
over: "{{test_users}}"
as: "item"
request:
method: "POST"
url: "/api/users"
body:
name: "{{item.name}}"
email: "{{item.email}}"
assert:
status_code: 201
body:
id: { exists: true }
name: { equals: "{{item.name}}" }
Range Iteration
steps:
- name: "Test pagination page {{index}}"
iterate:
range:
start: 1
end: 10
step: 1
as: "index"
request:
method: "GET"
url: "/api/items?page={{index}}&limit=20"
assert:
status_code: 200
body:
page: { equals: "{{index}}" }
items: { length: { max: 20 } }
Dynamic Iteration
steps:
- name: "Get all users"
request:
method: "GET"
url: "/api/users"
capture:
users_list: "body.users"
- name: "Process each user"
iterate:
over: "{{users_list}}"
as: "user"
request:
method: "GET"
url: "/api/users/{{user.id}}/profile"
assert:
status_code: 200
Conditional Execution
Control test execution based on conditions, variables, or previous results.
Step-Level Conditions
variables:
environment: "production"
feature_enabled: true
steps:
- name: "Conditional database cleanup"
metadata:
skip: "{{environment}} !== 'test'" # Skip in production
request:
method: "POST"
url: "/api/cleanup"
- name: "Feature-specific test"
metadata:
skip: "{{feature_enabled}} === false"
request:
method: "GET"
url: "/api/new-feature"
Dynamic Conditions
steps:
- name: "Check feature availability"
request:
method: "GET"
url: "/api/features"
capture:
feature_x_enabled: "body.features.feature_x"
- name: "Test feature X"
metadata:
skip: "{{feature_x_enabled}} === false"
request:
method: "POST"
url: "/api/feature-x"
Advanced Assertions
Complex validation rules beyond basic equality checks.
Complex Body Assertions
assert:
body:
# Nested object validation
user:
id: { type: "number", min: 1 }
name: { type: "string", min_length: 2, max_length: 100 }
email: { matches: "^[^@]+@[^@]+\\.[^@]+$" }
roles: { length: { min: 1 } }
# Array validations
permissions:
- { equals: "read" }
- { one_of: ["write", "admin"] }
# Conditional assertions
metadata:
created_at: { exists: true }
updated_at: { exists: "{{user.id}} > 100" } # Exists only for certain users
Response Time Assertions
assert:
response_time_ms:
max: 1000 # Fail if response takes longer than 1 second
min: 10 # Fail if response is suspiciously fast
Header Assertions
assert:
headers:
"content-type": { contains: "application/json" }
"x-api-version": { equals: "2.1" }
"cache-control": { exists: true }
"x-request-id": { matches: "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$" }
Mocking and Data Generation
Faker.js Integration
Generate realistic test data using Faker.js:
variables:
test_user:
name: "{{$faker.name.fullName}}"
email: "{{$faker.internet.email}}"
phone: "{{$faker.phone.number}}"
address:
street: "{{$faker.address.streetAddress}}"
city: "{{$faker.address.city}}"
zipcode: "{{$faker.address.zipCode}}"
company: "{{$faker.company.name}}"
job_title: "{{$faker.name.jobTitle}}"
steps:
- name: "Create test user"
request:
method: "POST"
url: "/api/users"
body: "{{test_user}}"
Dynamic Data Generation
steps:
- name: "Create multiple test records"
iterate:
range:
start: 1
end: 5
as: "i"
request:
method: "POST"
url: "/api/records"
body:
name: "Test Record {{i}}"
email: "{{$faker.internet.email}}"
created_at: "{{$faker.date.recent}}"
metadata:
batch_id: "{{i}}"
random_value: "{{$faker.number.int}}"
Retry Logic and Error Handling
Automatic Retries
steps:
- name: "Unstable API call"
request:
method: "GET"
url: "/api/unstable"
metadata:
retry:
max_attempts: 3
delay_ms: 1000
backoff: "exponential" # linear, exponential, or fixed
assert:
status_code: 200
Conditional Retries
steps:
- name: "Retry on specific errors"
request:
method: "POST"
url: "/api/process"
metadata:
retry:
max_attempts: 5
delay_ms: 2000
retry_on:
- status_code: 429 # Too Many Requests
- status_code: 502 # Bad Gateway
- status_code: 503 # Service Unavailable
assert:
status_code: 201
Complex Scenarios
Multi-Step Workflows
suite_name: "E-commerce Purchase Flow"
variables:
product_id: null
cart_id: null
order_id: null
steps:
- name: "Browse products"
request:
method: "GET"
url: "/api/products"
assert:
status_code: 200
body:
products: { length: { min: 1 } }
capture:
product_id: "body.products[0].id"
- name: "Add to cart"
request:
method: "POST"
url: "/api/cart"
body:
product_id: "{{product_id}}"
quantity: 1
assert:
status_code: 201
capture:
cart_id: "body.cart_id"
- name: "Checkout"
request:
method: "POST"
url: "/api/checkout"
body:
cart_id: "{{cart_id}}"
payment_method: "credit_card"
shipping_address: "{{$faker.address.streetAddress}}"
assert:
status_code: 201
capture:
order_id: "body.order_id"
- name: "Verify order"
request:
method: "GET"
url: "/api/orders/{{order_id}}"
assert:
status_code: 200
body:
id: { equals: "{{order_id}}" }
status: { equals: "confirmed" }
Load Testing Patterns
suite_name: "Load Testing Scenario"
metadata:
priority: "medium"
tags: ["load", "performance"]
steps:
- name: "Concurrent user simulation"
iterate:
range:
start: 1
end: 50 # Simulate 50 concurrent users
as: "user_id"
request:
method: "GET"
url: "/api/dashboard"
headers:
Authorization: "Bearer user_{{user_id}}_token"
assert:
status_code: 200
response_time_ms: { max: 500 } # Max 500ms response time
API Contract Testing
suite_name: "API Contract Validation"
variables:
api_spec_version: "2.1"
steps:
- name: "Validate response schema"
request:
method: "GET"
url: "/api/users"
assert:
status_code: 200
headers:
"content-type": { equals: "application/json" }
"x-api-version": { equals: "{{api_spec_version}}" }
body:
# Strict schema validation
type: "object"
properties:
users: { type: "array" }
pagination: { type: "object" }
required: ["users", "pagination"]
- name: "Validate error responses"
request:
method: "GET"
url: "/api/users/99999"
assert:
status_code: 404
body:
error: { exists: true }
message: { type: "string" }
code: { equals: "USER_NOT_FOUND" }
Performance Monitoring
Response Time Tracking
steps:
- name: "Performance-critical endpoint"
request:
method: "GET"
url: "/api/dashboard"
assert:
status_code: 200
response_time_ms:
max: 200
warning_threshold: 100 # Log warning if over 100ms
metadata:
performance_critical: true
Throughput Testing
suite_name: "API Throughput Test"
metadata:
tags: ["performance", "throughput"]
steps:
- name: "High-frequency requests"
iterate:
range:
start: 1
end: 100
as: "request_id"
request:
method: "GET"
url: "/api/status?request={{request_id}}"
assert:
status_code: 200
response_time_ms: { max: 50 }
metadata:
parallel: true # Execute in parallel for throughput testing
Environment-Specific Testing
Configuration-Based Execution
variables:
environment: "{{$env.NODE_ENV}}"
base_urls:
development: "http://localhost:3000"
staging: "https://api-staging.example.com"
production: "https://api.example.com"
base_url: "{{base_urls[environment]}}"
steps:
- name: "Environment-specific test"
metadata:
skip: "{{environment}} === 'production'" # Skip destructive tests in prod
request:
method: "DELETE"
url: "/api/test-data"
Feature Flags
variables:
features:
new_api: "{{$env.FEATURE_NEW_API}}"
beta_feature: "{{$env.FEATURE_BETA}}"
steps:
- name: "Test new API"
metadata:
skip: "{{features.new_api}} !== 'true'"
request:
method: "GET"
url: "/api/v2/endpoint"
- name: "Test beta feature"
metadata:
skip: "{{features.beta_feature}} !== 'enabled'"
request:
method: "POST"
url: "/api/beta/feature"
Debugging Advanced Scenarios
Verbose Logging
steps:
- name: "Debug complex request"
request:
method: "POST"
url: "/api/complex"
headers:
"X-Debug": "true"
body:
complex_data: "..."
metadata:
log_request: true
log_response: true
assert:
status_code: 200
Conditional Debugging
variables:
debug_mode: "{{$env.DEBUG_MODE}}"
steps:
- name: "Conditional debug logging"
metadata:
log_request: "{{debug_mode}} === 'true'"
log_response: "{{debug_mode}} === 'true'"
request:
method: "GET"
url: "/api/debug"
This covers the most advanced features of the Flow Test Engine. For more examples, check the tests/ directory for comprehensive test suites demonstrating these patterns.