Skip to main content

Module testing

Module testing 

Source
Expand description

Pilot testing framework for automated UI tests.

Test your TUI applications with simulated user interactions, assertions on rendered output, and snapshot testing.

§Features

FeatureDescription
Key SimulationSimulate keyboard input
Text SearchAssert on rendered text
Snapshot TestingCompare against golden files
Visual RegressionColor & style comparison
CI IntegrationGitHub Actions, GitLab CI
Async SupportTest async operations
Action SequencesChain multiple actions

§Quick Start

use revue::testing::{Pilot, TestApp};
use revue::event::Key;

#[test]
fn test_counter() {
    let mut app = TestApp::new(Counter::new());
    let mut pilot = Pilot::new(&mut app);

    pilot
        .press(Key::Up)
        .press(Key::Up)
        .assert_contains("Count: 2")
        .snapshot("counter_at_2");
}

§Pilot API

§Key Simulation

pilot
    .press(Key::Enter)           // Press Enter
    .press(Key::Char('a'))       // Type 'a'
    .type_text("hello")          // Type string
    .press(Key::Escape);         // Press Escape

§Assertions

pilot
    .assert_contains("Welcome")          // Text exists
    .assert_not_contains("Error")        // Text doesn't exist
    .assert_focused(".input")            // Element is focused
    .assert_visible(".modal");           // Element is visible

§Snapshot Testing

pilot
    .snapshot("initial_state")           // Save/compare snapshot
    .press(Key::Enter)
    .snapshot("after_enter");

Snapshots are stored in tests/snapshots/ and can be updated with:

REVUE_UPDATE_SNAPSHOTS=1 cargo test

§Waiting

pilot
    .wait_ms(100)                        // Wait 100ms
    .wait_until(|screen| {               // Wait for condition
        screen.contains("Loaded")
    });

§TestApp

TestApp wraps your view for testing:

use revue::testing::{TestApp, TestConfig};

// Default 80x24 terminal
let app = TestApp::new(MyView::new());

// Custom size
let config = TestConfig {
    width: 120,
    height: 40,
    ..Default::default()
};
let app = TestApp::with_config(MyView::new(), config);

§Action Sequences

Build reusable action sequences:

use revue::testing::{ActionSequence, Action};

let login_sequence = ActionSequence::new()
    .action(Action::Type("admin".into()))
    .action(Action::Press(Key::Tab))
    .action(Action::Type("password".into()))
    .action(Action::Press(Key::Enter));

pilot.run_sequence(&login_sequence);

§Async Testing

For testing async operations:

use revue::testing::AsyncPilot;

#[tokio::test]
async fn test_async_load() {
    let app = TestApp::new(MyAsyncView::new());

    AsyncPilot::run(app, |pilot| async move {
        pilot.press(Key::Enter).await;
        pilot.wait_until_async(|s| s.contains("Loaded")).await;
        pilot.assert_contains("Data loaded");
    }).await;
}

§Visual Regression Testing

For pixel-perfect UI testing with color and style comparison:

use revue::testing::{VisualTest, VisualTestConfig};

#[test]
fn test_button_styles() {
    let test = VisualTest::new("button_normal")
        .group("buttons");

    let buffer = render_my_widget();
    test.assert_matches(&buffer);
}

Update golden files:

REVUE_UPDATE_VISUALS=1 cargo test

§CI Integration

Detect CI environments and generate reports:

use revue::testing::{CiEnvironment, TestReport};

let ci = CiEnvironment::detect();
let mut report = TestReport::new();

// Run tests...
report.add_passed("button_test");
report.add_failed("modal_test", "Size mismatch");

// Generate CI-specific output
report.write_summary(&ci);
report.save_artifacts(&ci).ok();

§Best Practices

  1. Name snapshots descriptively: "login_form_with_error" not "test1"
  2. Test user flows: Simulate realistic user interactions
  3. Keep tests focused: One behavior per test
  4. Use wait_until for async: Don’t rely on fixed delays
  5. Use visual tests for styling: Catch color and layout regressions
  6. Run in CI: Use CiEnvironment for portable test reports

Re-exports§

pub use mock::capture_render;
pub use mock::mock_alt_key;
pub use mock::mock_click;
pub use mock::mock_ctrl_key;
pub use mock::mock_key;
pub use mock::mock_mouse;
pub use mock::mock_terminal;
pub use mock::mock_time;
pub use mock::simulate_user;
pub use mock::EventSimulator;
pub use mock::MockState;
pub use mock::MockTerminal;
pub use mock::MockTime;
pub use mock::RenderCapture;
pub use mock::SimulatedEvent;
pub use visual::CapturedCell;
pub use visual::CellDiff;
pub use visual::VisualCapture;
pub use visual::VisualDiff;
pub use visual::VisualTest;
pub use visual::VisualTestConfig;
pub use visual::VisualTestResult;
pub use ci::CiEnvironment;
pub use ci::CiProvider;
pub use ci::TestReport;
pub use ci::TestResult;

Modules§

ci
CI integration helpers for visual regression testing
mock
Mocking utilities for testing Revue applications
visual
Visual regression testing for TUI applications

Structs§

ActionSequence
A sequence of actions that can be replayed
AsyncPilot
Async test runner for Pilot
Pilot
Pilot controller for automated testing
SnapshotManager
Snapshot manager for storing and comparing test snapshots
TestApp
A test application that can run views without a real terminal
TestConfig
Test configuration

Enums§

Action
A recorded test action
AssertionResult
Result of an assertion
KeyAction
Key-related actions
MouseAction
Mouse-related actions

Traits§

Assertion
An assertion that can be run against a buffer