behave-trace
August 5, 2026 · View on GitHub
Trace viewer and step-by-step debugger for Behave BDD.
Captures execution data (steps, statuses, durations, screenshots, DOM snapshots, logs) and visualizes them in a Playwright-inspired web viewer with timeline, filmstrip, per-step detail tabs, before/after DOM diff, and live progress updates.
Quickstart
# 1. Install
pip install behave-trace
# 2. Register the formatter — add to behave.ini in your project root:
# [behave.formatters]
# behave-trace = behave_trace.formatter:TraceFormatter
# 3. Capture — run Behave with the formatter
behave --format behave-trace -o trace.json
# 4. Visualize — open the viewer
behave-trace show trace.json
The viewer opens in your browser at http://127.0.0.1:<port> with a dark-themed
SPA showing features, scenarios, steps, screenshots, and errors.
How it works
┌──────────┐ ┌──────────────┐ ┌───────────┐ ┌──────────────┐
│ Behave │────▶│ Formatter │────▶│ Serializer │────▶│ trace.json │
│ runner │ │ (collector) │ │ (JSON) │ │ │
└──────────┘ └──────────────┘ └───────────┘ └──────┬───────┘
│
┌────────────────────────────────────────┘
▼
┌──────────────┐ ┌──────────────────┐
│ behave-trace │────▶│ Browser SPA │
│ show │ │ (Alpine.js) │
│ (HTTP server)│ │ Dark theme │
└──────────────┘ └──────────────────┘
Two-phase model (like Playwright Trace Viewer):
-
Capture — The
TraceFormatterhooks into Behave's formatter API and collects execution events into aTracedata model. Attachments (screenshots, DOM, logs) are captured viaattach_screenshot(),attach_dom(), andlog()helpers inenvironment.py. -
Visualize —
behave-trace showloads the trace JSON, starts a local HTTP server (stdlib only, no dependencies), and opens the viewer SPA in a browser.
Viewer features
- Visual DOM diff — compare before/after DOM snapshots with added and removed elements highlighted in split, diff, or before/after view modes.
- Collapse/Expand all — expand or collapse the entire feature tree with one click.
- Scenario sorting — sort scenarios by name, duration, or status; the selected
sort is persisted in
localStorage. - Feature → Scenario breadcrumb — shows the current feature and scenario above the step list; clicking the feature opens it in the sidebar.
- Live progress — real-time status updates via Server-Sent Events while tests are running from the viewer.
- Theme and state persistence — sidebar, sort, and snapshot diff mode are remembered across sessions.
- Port conflict detection — clear error message instead of hanging when the requested port is already in use (especially on Windows).
Capturing attachments
Add to your environment.py:
from behave_trace import attach_screenshot, attach_dom, attach_text, attach_network, log
def after_step(context, step):
# Log the current URL after every step
log(context, f"URL: {context.driver.current_url}")
if step.status == "failed":
attach_screenshot(context, context.driver, name="failure.png")
attach_dom(context, context.driver, name="dom.html")
log(context, f"Step failed: {step.name}", level="error")
The viewer will show screenshots in the filmstrip and detail tabs, with before/after DOM snapshot toggling. See the attachments guide for the full API.
CLI
# Show trace in browser
behave-trace show trace.json
# Show on specific port, don't open browser
behave-trace show trace.json --port 8080 --no-browser
# Run behave with the trace formatter, then open the viewer
behave-trace run features/
# Run with tags and watch mode
behave-trace run features/ --tags @smoke --watch
# Run from the UI (no initial trace required)
# The viewer opens even if behave fails. A "Run all" button lets you
# execute tests from scratch; selected scenarios can also be re-run.
behave-trace run --no-browser
# Version
behave-trace --version
Run from the UI
behave-trace run starts the viewer even if the initial Behave run fails or no
features have been executed yet. The viewer then shows a "Run all" button in
the header (and in the empty state) that triggers a fresh Behave execution
(POST /api/run).
While tests are running the viewer receives real-time status updates via Server-Sent Events (SSE), and the trace is reloaded automatically when the run finishes. You can also select one or more scenarios and re-run only those with "Run selected".
When watch mode is active, the viewer header shows an "Auto-run" toggle.
Enable it to re-execute Behave automatically whenever the watched *.feature or
*.py files change (debounced 500ms). Disable it to keep the viewer running and
reload the trace manually.
Development
# Install in editable mode with dev dependencies
pip install -e ".[dev]"
# Or use the Makefile shortcut
make dev
# Lint
ruff check .
ruff format --check .
# Type check
mypy --strict behave_trace
# Run tests
pytest tests/ -v
# E2E tests (meta: Behave testing Behave)
behave tests/e2e/
# Build
python -m build
Requirements
- Python 3.11+ (tested on 3.11, 3.12, 3.13)
behave >= 1.2.6(installed automatically)- No other runtime dependencies (viewer uses only Python stdlib)
Project structure
behave_trace/
__init__.py # Public API, formatter registration
__main__.py # python -m behave_trace entry point
formatter.py # Behave formatter (TraceFormatter)
collector.py # Event collector → Trace model
models.py # Dataclasses: Trace, Feature, Scenario, Step, etc.
serializer.py # JSON load/save
attach.py # Attachment helpers (screenshot, DOM, text, network, log)
runner.py # Behave runner (subprocess wrapper)
watcher.py # File watcher for --watch mode
utils.py # Utilities (format_duration, safe_str)
cli/
app.py # argparse CLI with `show` and `run` subcommands
viewer/
server.py # stdlib HTTP server (ThreadingHTTPServer)
browser.py # Browser opener (Chrome app mode)
assets/
index.html # SPA shell (Alpine.js from CDN)
css/viewer.css # Dark theme styles
js/viewer.js # Alpine.js component logic
Documentation
Full documentation is available at mathiaspaulenko.github.io/behave-trace.
Contributing
Contributions are welcome! See CONTRIBUTING.md for setup, commands, and the release process.
License
MIT — see LICENSE.