use portable_pty::CommandBuilder;
use ratatui_testlib::{Result, TuiTestHarness};
use tokio::time::{timeout, Duration};
#[tokio::main]
async fn main() -> Result<()> {
println!("=== Async Testing with Tokio Example ===\n");
println!("Note: Currently using sync TuiTestHarness in async context");
println!("Phase 2 will implement AsyncTuiTestHarness with native async/await\n");
example_1_basic_async().await?;
example_2_async_wait().await?;
example_3_concurrent_operations().await?;
example_4_timeout_handling().await?;
example_5_practical_scenario().await?;
println!("\n=== All Async Examples Completed ===");
Ok(())
}
async fn example_1_basic_async() -> Result<()> {
println!("--- Example 1: Basic Async Testing ---");
let mut harness = TuiTestHarness::new(80, 24)?;
println!("Created harness in async context");
let mut cmd = CommandBuilder::new("echo");
cmd.arg("Hello from async!");
harness.spawn(cmd)?;
println!("Spawned command");
println!("Waiting asynchronously...");
tokio::time::sleep(Duration::from_millis(100)).await;
harness.update_state()?;
let contents = harness.screen_contents();
println!("\nScreen contents:");
println!("┌{:─<78}┐", "");
for line in contents.lines().take(3) {
println!("│ {:<77}│", line);
}
println!("└{:─<78}┘", "");
assert!(contents.contains("Hello from async!"));
println!("✓ Async test passed");
println!();
Ok(())
}
async fn example_2_async_wait() -> Result<()> {
println!("--- Example 2: Async Wait Patterns ---");
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("sh");
cmd.arg("-c");
cmd.arg("sleep 0.2 && echo 'Ready!'");
harness.spawn(cmd)?;
println!("Spawned delayed command");
println!("\nPattern 1: Simple async polling");
let start = std::time::Instant::now();
loop {
harness.update_state()?;
if harness.screen_contents().contains("Ready!") {
println!("✓ Found expected text after {:?}", start.elapsed());
break;
}
if start.elapsed() > Duration::from_secs(5) {
return Err(ratatui_testlib::TermTestError::Timeout { timeout_ms: 5000 });
}
tokio::time::sleep(Duration::from_millis(50)).await;
}
println!("\nFinal output:");
println!("{}", harness.screen_contents().lines().next().unwrap_or(""));
println!();
Ok(())
}
async fn example_3_concurrent_operations() -> Result<()> {
println!("--- Example 3: Concurrent Operations ---");
println!("Running 3 tests concurrently with tokio::join!\n");
let task1 = async {
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("echo");
cmd.arg("Task 1");
harness.spawn(cmd)?;
tokio::time::sleep(Duration::from_millis(100)).await;
harness.update_state()?;
let result = harness.screen_contents().contains("Task 1");
Ok::<bool, ratatui_testlib::TermTestError>(result)
};
let task2 = async {
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("echo");
cmd.arg("Task 2");
harness.spawn(cmd)?;
tokio::time::sleep(Duration::from_millis(100)).await;
harness.update_state()?;
let result = harness.screen_contents().contains("Task 2");
Ok::<bool, ratatui_testlib::TermTestError>(result)
};
let task3 = async {
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("echo");
cmd.arg("Task 3");
harness.spawn(cmd)?;
tokio::time::sleep(Duration::from_millis(100)).await;
harness.update_state()?;
let result = harness.screen_contents().contains("Task 3");
Ok::<bool, ratatui_testlib::TermTestError>(result)
};
let start = std::time::Instant::now();
let (result1, result2, result3) = tokio::join!(task1, task2, task3);
println!("All tasks completed in {:?}", start.elapsed());
println!(" Task 1 passed: {}", result1?);
println!(" Task 2 passed: {}", result2?);
println!(" Task 3 passed: {}", result3?);
println!("\n✓ Concurrent testing successful");
println!(" Benefit: Tests run in parallel, reducing total test time");
println!();
Ok(())
}
async fn example_4_timeout_handling() -> Result<()> {
println!("--- Example 4: Timeout Handling ---");
println!("Test 1: Fast operation (should succeed)");
let result = timeout(Duration::from_secs(2), async {
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("echo");
cmd.arg("Quick!");
harness.spawn(cmd)?;
tokio::time::sleep(Duration::from_millis(100)).await;
harness.update_state()?;
let contents = harness.screen_contents();
Ok::<String, ratatui_testlib::TermTestError>(contents)
})
.await;
match result {
Ok(Ok(contents)) => {
println!(" ✓ Operation completed: {}",
contents.lines().next().unwrap_or("").trim());
}
Ok(Err(e)) => println!(" ✗ Operation failed: {}", e),
Err(_) => println!(" ✗ Operation timed out"),
}
println!("\nTest 2: Slow operation (will timeout)");
let result = timeout(Duration::from_millis(50), async {
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("sleep");
cmd.arg("1");
harness.spawn(cmd)?;
tokio::time::sleep(Duration::from_secs(2)).await;
Ok::<(), ratatui_testlib::TermTestError>(())
})
.await;
match result {
Ok(_) => println!(" ✗ Unexpected: Operation completed"),
Err(_) => println!(" ✓ Expected: Operation timed out after 50ms"),
}
println!("\nTimeout patterns are essential for:");
println!(" - Preventing hung tests");
println!(" - Testing timeout behavior");
println!(" - Enforcing performance requirements");
println!();
Ok(())
}
async fn example_5_practical_scenario() -> Result<()> {
println!("--- Example 5: Practical Async Scenario ---");
println!("Scenario: Testing an async data loader TUI\n");
let mut harness = TuiTestHarness::new(80, 24)?;
let mut cmd = CommandBuilder::new("sh");
cmd.arg("-c");
cmd.arg(
"echo 'Loading...' && \
sleep 0.1 && \
echo 'Fetching data...' && \
sleep 0.1 && \
echo 'Processing...' && \
sleep 0.1 && \
echo 'Complete!'"
);
harness.spawn(cmd)?;
println!("Spawned simulated async TUI app");
println!("\nStep 1: Wait for loading message");
let result = timeout(Duration::from_secs(1), async {
loop {
harness.update_state()?;
if harness.screen_contents().contains("Loading") {
break;
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
Ok::<(), ratatui_testlib::TermTestError>(())
})
.await;
match result {
Ok(Ok(())) => println!(" ✓ Loading message appeared"),
_ => println!(" ✗ Failed to detect loading message"),
}
println!("\nStep 2: Wait for completion message");
let result = timeout(Duration::from_secs(2), async {
loop {
harness.update_state()?;
if harness.screen_contents().contains("Complete!") {
break;
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
Ok::<(), ratatui_testlib::TermTestError>(())
})
.await;
match result {
Ok(Ok(())) => println!(" ✓ Completion message appeared"),
_ => println!(" ✗ Failed to detect completion message"),
}
harness.update_state()?;
let final_state = harness.screen_contents();
println!("\nFinal state:");
println!("┌{:─<78}┐", "");
for line in final_state.lines().take(6) {
println!("│ {:<77}│", line);
}
println!("└{:─<78}┘", "");
assert!(final_state.contains("Loading"));
assert!(final_state.contains("Fetching"));
assert!(final_state.contains("Processing"));
assert!(final_state.contains("Complete"));
println!("\n✓ All stages verified");
println!("\nThis pattern works well for:");
println!(" - Testing async loading sequences");
println!(" - Verifying progress indicators");
println!(" - Testing timeout behavior");
println!(" - Integration testing with async libraries");
println!();
Ok(())
}