use portable_pty::CommandBuilder;
use ratatui_testlib::{Result, TuiTestHarness};
use std::time::Duration;
fn main() -> Result<()> {
println!("=== Snapshot Testing Example with insta ===\n");
println!("Note: This example demonstrates snapshot testing patterns.");
println!("In a real test file, you would use #[test] functions and");
println!("the insta::assert_snapshot!() macro.\n");
example_1_basic_snapshot()?;
example_2_named_snapshots()?;
example_3_multi_step_flow()?;
example_4_snapshot_settings()?;
example_5_error_states()?;
println!("\n=== All Snapshot Examples Completed ===");
println!("\nTo use in real tests:");
println!("1. Add to your test file: use insta::assert_snapshot;");
println!("2. Replace println!() with assert_snapshot!()");
println!("3. Run: cargo test");
println!("4. Review snapshots: cargo insta review");
Ok(())
}
fn example_1_basic_snapshot() -> Result<()> {
println!("--- Example 1: Basic Snapshot Capture ---");
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("echo");
cmd.arg("Hello, Snapshot Testing!");
harness.spawn(cmd)?;
std::thread::sleep(Duration::from_millis(100));
harness.update_state()?;
let contents = harness.screen_contents();
println!("Captured screen contents:");
println!("┌{:─<78}┐", "");
for (i, line) in contents.lines().take(5).enumerate() {
println!("│ {:2} {:<74}│", i, line);
}
println!("└{:─<78}┘", "");
println!("\nIn a real test file:");
println!(" #[test]");
println!(" fn test_welcome_message() -> Result<()> {{");
println!(" let mut harness = TuiTestHarness::new(80, 24)?;");
println!(" // ... spawn and capture ...");
println!(" insta::assert_snapshot!(harness.screen_contents());");
println!(" Ok(())");
println!(" }}");
println!();
Ok(())
}
fn example_2_named_snapshots() -> Result<()> {
println!("--- Example 2: Named Snapshots ---");
println!("Testing multiple scenarios with descriptive names:\n");
let mut harness1 = TuiTestHarness::new(80, 24)?;
let mut cmd1 = CommandBuilder::new("echo");
cmd1.arg("");
harness1.spawn(cmd1)?;
std::thread::sleep(Duration::from_millis(100));
harness1.update_state()?;
let empty_state = harness1.screen_contents();
println!("Scenario: empty_state");
println!(" Would save as: snapshots/snapshot_test__empty_state.snap");
let mut harness2 = TuiTestHarness::new(80, 24)?;
let mut cmd2 = CommandBuilder::new("echo");
cmd2.arg("Single line of text");
harness2.spawn(cmd2)?;
std::thread::sleep(Duration::from_millis(100));
harness2.update_state()?;
let single_line = harness2.screen_contents();
println!("Scenario: single_line");
println!(" Would save as: snapshots/snapshot_test__single_line.snap");
let mut harness3 = TuiTestHarness::new(80, 24)?;
let mut cmd3 = CommandBuilder::new("printf");
cmd3.arg("Line 1\\nLine 2\\nLine 3");
harness3.spawn(cmd3)?;
std::thread::sleep(Duration::from_millis(100));
harness3.update_state()?;
let multi_line = harness3.screen_contents();
println!("Scenario: multi_line");
println!(" Would save as: snapshots/snapshot_test__multi_line.snap");
println!("\nBenefit: Each scenario has its own snapshot file,");
println!(" making it easy to review changes.");
println!();
Ok(())
}
fn example_3_multi_step_flow() -> Result<()> {
println!("--- Example 3: Multi-step UI Flow ---");
println!("Testing a multi-step interaction flow:\n");
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("sh");
cmd.arg("-c");
cmd.arg("echo 'Step 1: Initializing...' && sleep 0.1 && echo 'Step 2: Loading...' && sleep 0.1 && echo 'Step 3: Ready!'");
harness.spawn(cmd)?;
std::thread::sleep(Duration::from_millis(50));
harness.update_state()?;
let state_1 = harness.screen_contents();
println!("Capturing state 1 (early):");
println!(" insta::assert_snapshot!(\"flow_step_1\", contents);");
std::thread::sleep(Duration::from_millis(150));
harness.update_state()?;
let state_2 = harness.screen_contents();
println!("Capturing state 2 (mid):");
println!(" insta::assert_snapshot!(\"flow_step_2\", contents);");
std::thread::sleep(Duration::from_millis(150));
harness.update_state()?;
let state_3 = harness.screen_contents();
println!("Capturing state 3 (final):");
println!(" insta::assert_snapshot!(\"flow_step_3\", contents);");
println!("\nFinal state preview:");
println!("┌{:─<78}┐", "");
for line in state_3.lines().take(5) {
println!("│ {:<77}│", line);
}
println!("└{:─<78}┘", "");
println!("\nUse case: Verify each step of a wizard or loading sequence");
println!();
Ok(())
}
fn example_4_snapshot_settings() -> Result<()> {
println!("--- Example 4: Snapshot Settings ---");
println!("Handling dynamic content with insta settings:\n");
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("date");
cmd.arg("+%Y-%m-%d %H:%M:%S");
harness.spawn(cmd)?;
std::thread::sleep(Duration::from_millis(100));
harness.update_state()?;
let contents = harness.screen_contents();
println!("Raw output (contains timestamp):");
println!("┌{:─<78}┐", "");
for line in contents.lines().take(3) {
println!("│ {:<77}│", line);
}
println!("└{:─<78}┘", "");
println!("\nProblem: Timestamps change every run, breaking snapshots");
println!("\nSolution: Use insta settings with redactions:");
println!("
let mut settings = insta::Settings::clone_current();
settings.add_filter(r\"\\d{{4}}-\\d{{2}}-\\d{{2}}\", \"[DATE]\");
settings.add_filter(r\"\\d{{2}}:\\d{{2}}:\\d{{2}}\", \"[TIME]\");
let _guard = settings.bind_to_scope();
insta::assert_snapshot!(contents);
");
println!("Result: Snapshot contains [DATE] [TIME] instead of actual values");
println!("\nOther common redactions:");
println!(" - Process IDs: add_filter(r\"pid: \\d+\", \"pid: [PID]\")");
println!(" - Memory addresses: add_filter(r\"0x[0-9a-f]+\", \"0x[ADDR]\")");
println!(" - UUIDs: add_filter(r\"[0-9a-f-]{{36}}\", \"[UUID]\")");
println!();
Ok(())
}
fn example_5_error_states() -> Result<()> {
println!("--- Example 5: Testing Error States ---");
println!("Capturing error messages and edge cases:\n");
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("sh");
cmd.arg("-c");
cmd.arg("echo 'Error: File not found' >&2");
harness.spawn(cmd)?;
std::thread::sleep(Duration::from_millis(100));
harness.update_state()?;
let error_contents = harness.screen_contents();
println!("Error state captured:");
println!("┌{:─<78}┐", "");
for line in error_contents.lines().take(5) {
println!("│ {:<77}│", line);
}
println!("└{:─<78}┘", "");
println!("\nIn a real test:");
println!(" #[test]");
println!(" fn test_file_not_found_error() -> Result<()> {{");
println!(" // ... trigger error condition ...");
println!(" insta::assert_snapshot!(\"error_file_not_found\", contents);");
println!(" Ok(())");
println!(" }}");
println!("\nBenefits:");
println!(" - Catch regressions in error message formatting");
println!(" - Document expected error states");
println!(" - Ensure helpful error messages");
println!();
Ok(())
}