browsing 0.1.4

Lightweight MCP/API for browser automation: navigate, get content (text), screenshot. Parallelism via RwLock.
Documentation
//! Browser session lifecycle tests

use browsing::browser::{Browser, BrowserProfile};
use browsing::error::{BrowsingError, Result};
use std::time::Duration;
use tokio::time::timeout;

#[tokio::test]
async fn test_browser_session_creation() {
    let profile = BrowserProfile::default();
    let mut browser = Browser::new(profile);

    // Verify initial state
    assert!(browser.get_cdp_client().is_err());
    assert!(browser.get_session_id().is_err());
    assert!(browser.get_current_target_id().is_err());

    // Browser should not be started yet
    // Browser doesn't have a public sessions() method, so we can't check this
    assert!(true);
}

#[tokio::test]
async fn test_browser_profile_configuration() {
    let profile = BrowserProfile {
        headless: Some(true),
        user_data_dir: Some("/tmp/test_browser".into()),
        allowed_domains: Some(vec!["example.com".to_string()]),
        downloads_path: Some("/tmp/downloads".into()),
        proxy: None,
    };

    let browser = Browser::new(profile);

    // Browser should accept the configuration
    assert!(true); // No panic indicates successful creation
}

#[tokio::test]
async fn test_browser_with_cdp_url() {
    let mut browser =
        Browser::new(BrowserProfile::default()).with_cdp_url("ws://localhost:9222".to_string());

    // Browser should have CDP URL set internally
    // (We can't test actual connection without a running browser)
    assert!(true); // No panic indicates successful configuration
}

#[tokio::test]
async fn test_browser_stop_before_start() {
    let mut browser = Browser::new(BrowserProfile::default());

    // Stopping before starting should not panic
    let result = browser.stop().await;
    assert!(result.is_ok());
}

#[tokio::test]
async fn test_browser_duplicate_start() {
    let mut browser = Browser::new(BrowserProfile::default());

    // Note: This test requires a mock or actual browser installation
    // For now, just test the logic doesn't panic

    // In a real scenario, we would:
    // 1. Start browser
    // 2. Try to start again
    // 3. Verify appropriate error or no-op

    assert!(true); // Placeholder - would test duplicate start behavior
}

#[tokio::test]
async fn test_browser_session_cleanup() {
    let profile = BrowserProfile::default();
    let browser = Browser::new(profile);

    // Test that dropping the browser cleans up resources properly
    // This is more of a leak detection test

    // Create a scope to ensure proper cleanup
    {
        let _scoped_browser = Browser::new(BrowserProfile::default());
        // Scoped browser goes out of scope here
    }

    // If we reach here without issues, cleanup was successful
    assert!(true);
}

#[tokio::test]
async fn test_browser_timeout_handling() {
    let mut browser = Browser::new(BrowserProfile::default());

    // Test that operations respect timeouts
    let result = timeout(Duration::from_secs(1), async {
        // In a real scenario, this might be a slow operation
        tokio::time::sleep(Duration::from_millis(500)).await;
        Ok::<(), BrowsingError>(())
    })
    .await;

    // Should complete within timeout
    assert!(result.is_ok());
}

#[cfg(unix)]
#[tokio::test]
async fn test_browser_signal_handling() {
    use browsing::utils::signal;

    // Test signal handling for graceful shutdown
    let initial_state = signal::is_shutdown_requested();

    // Simulate shutdown request
    signal::set_shutdown_requested();

    let after_state = signal::is_shutdown_requested();

    // Should detect shutdown request
    assert!(after_state);

    // Reset for other tests
    // Note: This is not ideal for test isolation, but demonstrates the concept
    // In real implementation, we'd use a more sophisticated reset mechanism
}

#[test]
fn test_browser_profile_validation() {
    // Test invalid profiles
    let invalid_profile = BrowserProfile {
        headless: Some(true),
        user_data_dir: None,
        allowed_domains: Some(vec![]), // Empty domain list might be invalid
        downloads_path: None,
        proxy: None,
    };

    // Profile creation should succeed (validation happens at use time)
    let browser = Browser::new(invalid_profile);
    assert!(true);
}

#[tokio::test]
async fn test_browser_concurrent_sessions() {
    use tokio::task;

    // Test creating multiple browser instances concurrently
    let handles: Vec<_> = (0..3)
        .map(|i| {
            task::spawn(async move {
                let profile = BrowserProfile {
                    headless: Some(true),
                    user_data_dir: Some(format!("/tmp/test_browser_{}", i).into()),
                    allowed_domains: None,
                    downloads_path: None,
                    proxy: None,
                };
                Browser::new(profile)
            })
        })
        .collect();

    // Wait for all to complete
    let browsers: std::result::Result<Vec<_>, _> = futures_util::future::join_all(handles)
        .await
        .into_iter()
        .collect::<std::result::Result<Vec<_>, _>>();

    assert!(browsers.is_ok());
    assert_eq!(browsers.unwrap().len(), 3);
}