rust-actions
A BDD testing framework for Rust using GitHub Actions YAML syntax instead of Gherkin.
Features
- GitHub Actions YAML syntax - Write tests in familiar YAML format
- Typed step definitions - Full Rust type safety with
#[derive(Args)]and#[derive(Outputs)] - Auto-registration - Steps are automatically discovered via
#[step("name")]attribute - Inline assertions - Pre and post assertions with expression-based syntax
- Deterministic testing - Seeded RNG for reproducible tests
- Testcontainers support - Built-in Docker container management
Installation
Add to your Cargo.toml:
[]
= "0.1"
= { = "1", = ["full", "test-util"] }
Quick Start
1. Define your World
// tests/world.rs
use *;
2. Define your Steps
// tests/steps.rs
use *;
use crate;
pub async
3. Write your Feature File
# tests/features/user.yaml
name: User Management
scenarios:
- name: Create a new user
steps:
- name: Create user Alice
id: alice
uses: user/create
with:
username: alice
email: alice@example.com
post-assert:
- ${{ outputs.id != "" }}
- ${{ outputs.username == "alice" }}
4. Run the Tests
// tests/main.rs
use *;
use TestWorld;
async
YAML Syntax
Basic Structure
name: Feature Name
env:
DB_URL: postgres://localhost/test
containers:
postgres: postgres:15
redis: redis:7
scenarios:
- name: Scenario Name
steps:
- name: Step description
id: step_id # Optional: reference outputs later
uses: step/name # Required: step to execute
with: # Optional: step arguments
arg1: value1
arg2: ${{ steps.previous.outputs.field }}
continue-on-error: true # Optional: don't fail on error
pre-assert: # Optional: assertions before step
- ${{ env.DB_URL != "" }}
post-assert: # Optional: assertions after step
- ${{ outputs.id != "" }}
Expression Syntax
Access data using ${{ }} expressions:
# Environment variables
${{ env.DB_URL }}
# Previous step outputs
${{ steps.user.outputs.id }}
# Container info
${{ containers.postgres.url }}
${{ containers.postgres.host }}
${{ containers.postgres.port }}
# Current step outputs (in post-assert only)
${{ outputs.id }}
Assertions
Inline assertions support comparison operators and object matching:
post-assert:
# Scalar comparisons
- ${{ outputs.id != "" }}
- ${{ outputs.count > 0 }}
- ${{ outputs.status == "active" }}
# Object partial matching
- '${{ outputs contains { "username": "alice" } }}'
# Array contains
- '${{ outputs.tags contains "admin" }}'
- '${{ outputs.users contains { "name": "bob" } }}'
# Full object equality
- '${{ outputs == { "id": "123", "name": "alice" } }}'
Supported operators:
- Comparison:
==,!=,>,<,>=,<= - Subset matching:
contains
Step Definitions
Basic Step
async
Args and Outputs
Step without Args
async
Determinism
rust-actions provides helpers for deterministic testing:
SeededRng
use *;
async
Time Control
Uses tokio's test-util for time manipulation:
async
Output
Feature: User Management
✓ Create a new user (5ms)
✓ Create user Alice
1 scenarios ✓ (1 passed)
1 steps (1 passed, 0 failed)
License
MIT