Spex

Hex.pmDocumentation

Behavior-Driven Development (BDD) for AI-Driven Testing | Executable Specifications | Specification by Example

SexySpex is a behavior-driven development (BDD) framework for Elixir that enables executable specifications, specification by example, and AI-driven testing. Write Given-When-Then scenarios that serve as both living documentation and automated tests.

Features

Installation

Add sexy_spex to your list of dependencies in mix.exs:

def deps do
[
{:sexy_spex, "~> 0.1.0"}
]
end

Quick Start

1. Write Your First Spex

Create a file test/spex/user_registration_spex.exs:

defmodule MyApp.UserRegistrationSpex do
use SexySpex
setup_all do
# Start your application or setup shared state
{:ok, %{base_url: "http://localhost:4000"}}
end
spex "user can register successfully",
description: "Validates the user registration flow",
tags: [:user_management, :registration] do
scenario "with valid data" do
given_ "valid user registration data", context do
user_data = %{
email: "test@example.com",
password: "secure_password123",
name: "Test User"
}
assert valid_registration_data?(user_data)
{:ok, Map.put(context, :user_data, user_data)}
end
when_ "user submits registration", context do
{:ok, user} = MyApp.Users.register(context.user_data)
assert user.email == context.user_data.email
{:ok, Map.put(context, :user, user)}
end
then_ "user account is created and can login", context do
assert {:ok, _session} = MyApp.Auth.login(
context.user_data.email,
context.user_data.password
)
{:ok, context}
end
end
end
end

2. Run Your Spex

# Run all spex files
mix spex
# Run specific spex file
mix spex test/spex/user_registration_spex.exs
# Run with verbose output
mix spex --verbose
# Run in manual mode (step-by-step)
mix spex --manual

Important: Spex files can ONLY be run with mix spex, not mix test. This ensures proper compilation and application lifecycle management.

3. See Beautiful Output

🎯 Running Spex: user can register successfully
==================================================
Validates the user registration flow
Tags: #user_management #registration
📋 Scenario: with valid data
Given: valid user registration data
When: user submits registration
Then: user account is created and can login
Scenario passed: with valid data
Spex completed: user can register successfully

GUI Testing with Scenic

For Scenic applications, use the built-in helpers:

defmodule MyGUI.LoginSpex do
use SexySpex
setup_all do
# Start Scenic application with MCP server
SexySpex.Helpers.start_scenic_app(:my_gui_app)
end
spex "user can login via GUI" do
scenario "successful login flow" do
given_ "the application is running", context do
assert SexySpex.Helpers.application_running?(:my_gui_app)
assert SexySpex.Helpers.can_connect_to_scenic_mcp?(context.port)
{:ok, context}
end
when_ "user enters valid credentials", context do
ScenicMcp.send_keys(text: "user@example.com")
ScenicMcp.send_keys(key: "tab")
ScenicMcp.send_keys(text: "password123")
ScenicMcp.send_keys(key: "enter")
{:ok, context}
end
then_ "user is logged in successfully", context do
ScenicMcp.take_screenshot(filename: "logged_in_dashboard")
viewport_state = ScenicMcp.Probes.viewport_state()
assert viewport_state.name == :main_viewport
{:ok, context}
end
end
end
end

Framework Helpers

SexySpex provides semantic helpers for common patterns:

# Start Scenic applications with MCP server
SexySpex.Helpers.start_scenic_app(:quillex)
SexySpex.Helpers.start_scenic_app(:flamelex, port: 8888)
# Test connectivity
SexySpex.Helpers.can_connect_to_scenic_mcp?(9999)
SexySpex.Helpers.application_running?(:my_app)
# Automatically handles:
# - Compilation (Mix.Task.run("compile"))
# - Application startup and cleanup
# - MCP server waiting and connection testing

Manual Mode - Interactive Testing

Run spex in manual mode for step-by-step execution:

mix spex --manual

Manual mode gives you:

Perfect for:

Architecture

Built on ExUnit

SexySpex is 100% built on ExUnit but provides a controlled execution environment:

# When you write:
use SexySpex
# You get:
use ExUnit.Case, async: false # Standard ExUnit test case
import SexySpex.DSL # spex/scenario/given_/when_/then_

Execution Flow

mix spex → Mix.Tasks.Spex → ExUnit.start() → Load spex files → ExUnit.run()

Core Modules

Use Cases

Perfect for teams practicing:

Philosophy

Spex bridges the gap between business requirements and automated testing by providing:

This enables AI systems to write, execute, and understand tests while maintaining human readability and stakeholder collaboration.

📚 Documentation

Contributing

We welcome contributions! Please see the documentation in /docs for details.

License

This project is licensed under the MIT License.

Inspiration

Spex is inspired by:

Perfect for teams building the future of AI-assisted software development.