Snapshot testing for Ratatui TUIs. Declare the canonical screens of your TUI
as an enum, derive Tuishot, and capture them as SVG. Wire the capture step
into cargo test or CI and your documentation screenshots can never drift
from reality.
1. Add tuishot as a dev-dependency:
[dev-dependencies]
tuishot = "20260415.0.0"2. Create tuishot.toml at your crate root (all fields optional):
output = "docs/screens"
size = "100x30"
background = "#0d1117"
foreground = "#d0d0d0"3. Declare shots next to the screen they capture, inside a
#[cfg(test)] mod shots — same pattern as unit tests, so you get access to
your screen's private state:
#[cfg(test)]
mod shots {
use super::*;
use tuishot::Tuishot;
#[derive(Tuishot)]
enum HomeShot {
#[tuishot(name = "home", description = "Initial view on launch")]
Home,
#[tuishot(name = "about", description = "About panel")]
About,
}
// The derive emits a per-enum `{Name}Render` trait + a blanket `Capture`
// impl that forwards to it. You write just the render logic.
impl HomeShotRender for HomeShot {
fn render(&self, buf: &mut ratatui::buffer::Buffer, area: ratatui::layout::Rect) {
match self {
HomeShot::Home => { /* draw home into buf */ }
HomeShot::About => { /* draw about into buf */ }
}
}
}
#[test]
fn capture() {
HomeShot::check_all().unwrap();
}
}4. Run it:
cargo test— fails if a screenshot has drifted.TUISHOT_UPDATE=1 cargo test— accept the new output.
Captures need access to your screen's internal state to construct specific
states (mid-stream, error mode, prompt open, ...). That's the same reason
Rust unit tests live inside src/ rather than tests/ — access to private
items. tuishot captures are unit tests for what your TUI looks like, so
they live in the same neighborhood.
- Derive attrs are for identity only —
name,descriptionon variants. - Visual config lives in
tuishot.toml— output dir, size, colors. - Rendering is pure — no PTY, no timing, no flakiness. You construct the
screen state, tuishot renders it into a
ratatui::Buffer, and serializes to SVG.
Early. Working on Ratatui, Ratatui-only. First dogfood: claux.
MIT