Files
ui-agregator/docs/testing-possible-solutions.md
Alexander 5bee7092d3 feat: add insta snapshot testing for TUI components
- Add insta dev-dependency for visual regression testing
- Create lib.rs to expose modules for integration tests
- Add snapshot tests for progress_bar, topbar, library, help modal
- Add unit tests for LibraryState navigation
- Move all tests to tests/ directory (proper Rust convention)
- Make build.rs skip proto compilation when protoc unavailable
- Add docs/testing-possible-solutions.md with testing strategies
2026-05-09 11:35:10 +02:00

187 lines
4.7 KiB
Markdown

# Testing Strategies for Ratatui TUI Applications
Research summary for testing the ui-agregator TUI application.
## 1. TestBackend + Buffer Assertions (Built-in)
Ratatui provides `TestBackend` - an in-memory terminal mock for testing without a real TTY.
```rust
use ratatui::{backend::TestBackend, Terminal};
#[test]
fn test_widget_renders() {
let mut terminal = Terminal::new(TestBackend::new(80, 24)).unwrap();
terminal.draw(|frame| {
frame.render_widget(MyWidget::new(), frame.area());
}).unwrap();
terminal.backend().assert_buffer_lines([
"Expected line 1",
"Expected line 2",
]);
}
```
**Best for**: Unit testing widgets, layout logic, pure rendering functions.
**Key Methods**:
- `TestBackend::new(width, height)` - Create in-memory terminal
- `backend.buffer()` - Access rendered buffer
- `backend.assert_buffer(&expected)` - Assert buffer equality
- `backend.assert_buffer_lines(lines)` - Assert against string lines
---
## 2. Snapshot Testing with `insta` (Visual Regression)
Captures rendered output to `.snap` files; detects unexpected visual changes.
**Official Recipe**: https://ratatui.rs/recipes/testing/snapshots/
### Setup
```toml
[dev-dependencies]
insta = "1.40.0"
```
```bash
cargo install cargo-insta
```
### Usage Pattern
```rust
#[test]
fn test_library_view_snapshot() {
let mut terminal = Terminal::new(TestBackend::new(80, 40)).unwrap();
let mut state = LibraryState::new(vec![/* test data */]);
terminal.draw(|f| render_library(f, f.area(), &mut state)).unwrap();
insta::assert_snapshot!(terminal.backend());
}
```
### Workflow
1. **First run**: Creates `.snap` file in `snapshots/` directory
2. **Subsequent runs**: Compares against snapshot
3. **Review changes**: `cargo insta review` - interactive diff viewer
4. **Update snapshots**: `cargo insta test --review`
**Best for**: Catching visual regressions, complex layouts, multi-component views.
**Note**: Color/style information is not currently captured in snapshots.
---
## 3. Direct Unit Tests (State Logic, No Rendering)
Test state machines and business logic without rendering.
```rust
#[test]
fn test_library_navigation() {
let mut state = LibraryState::new(test_artists());
state.move_down();
assert_eq!(state.selected_artist_index(), Some(1));
state.focus_right();
assert_eq!(state.focus, LibraryFocus::Albums);
}
```
**Best for**: State transitions, event handling logic, data transformations.
---
## 4. PTY-Based Integration Tests (`ratatui-testlib`)
Real terminal emulation with event simulation for end-to-end testing.
```toml
[dev-dependencies]
ratatui-testlib = "0.1"
```
```rust
#[test]
fn test_tab_switching_integration() -> Result<()> {
let mut harness = TuiTestHarness::new(80, 24)?;
harness.spawn(CommandBuilder::new("./ui-agregator"))?;
harness.wait_for(|s| s.contents().contains("Library"))?;
harness.send_key(KeyCode::Char('2'))?;
harness.wait_for(|s| s.contents().contains("Wanted"))?;
Ok(())
}
```
**Best for**: Full E2E scenarios, keyboard/mouse flow testing, CI validation.
---
## 5. Property-Based Testing (`proptest`)
Test invariants across random inputs - excellent for coordinate math and bounds checking.
```toml
[dev-dependencies]
proptest = "1.4"
```
```rust
proptest! {
#[test]
fn click_never_panics(x in 0u16..200, y in 0u16..100) {
let mut app = App::new();
app.size = Rect::new(0, 0, 80, 24);
app.handle_click(x, y, MouseButton::Left);
}
}
```
**Best for**: Click handling, scroll bounds, layout calculations.
---
## Testing Plan for ui-agregator
| Component | Strategy | Priority |
|-----------|----------|----------|
| `LibraryState` navigation | Unit tests | High |
| `NotificationManager` TTL/history | Unit tests | High |
| `App.handle_click()` routing | Unit + proptest | High |
| Tab views (wanted, queue, history) | Snapshot tests (insta) | Medium |
| `progress_bar.rs` | Already has 3 tests | Done |
| Modals (help, quit) | Snapshot tests | Medium |
| gRPC response → model conversion | Unit tests | Medium |
| Full app E2E flows | ratatui-testlib | Low |
---
## Recommended Dependencies
```toml
[dev-dependencies]
insta = "1.40.0"
rstest = "0.22" # Parameterized tests
proptest = "1.4" # Property-based testing
# ratatui-testlib = "0.1" # Optional: PTY integration tests
```
---
## Resources
- **Official Testing Docs**: https://ratatui.rs/recipes/testing/
- **Snapshot Testing Recipe**: https://ratatui.rs/recipes/testing/snapshots/
- **TestBackend API**: https://docs.rs/ratatui/latest/ratatui/backend/struct.TestBackend.html
- **insta Documentation**: https://insta.rs/docs/
- **ratatui-testlib**: https://docs.rs/ratatui-testlib/