use actix_web::{test, App, http::StatusCode, web}; use rust_decimal::Decimal; use serde_json::json; use tera::Tera; use threefold_marketplace::routes::configure_routes; use threefold_marketplace::services::user_persistence::UserPersistence; use threefold_marketplace::utils; use threefold_marketplace::models::user::Service; fn sanitize(email: &str) -> String { email.replace("@", "_at_").replace(".", "_") } /// Helper to read a Set-Cookie header by name fn extract_cookie_value(resp: &actix_web::dev::ServiceResponse, name: &str) -> Option { for header in resp.headers().get_all(actix_web::http::header::SET_COOKIE) { if let Ok(s) = header.to_str() { if s.starts_with(&format!("{}=", name)) { // Take only the name=value part if let Some((prefix, _rest)) = s.split_once(';') { return Some(prefix.to_string()); } } } } None } #[actix_rt::test] async fn test_instant_purchase_persists_service_booking() { // Ensure clean user_data directory entries for test users let _ = std::fs::create_dir_all("user_data"); let customer_email = "instant_customer@example.com"; let provider_email = "provider_instant@example.com"; let product_id = "svc-test-123"; let customer_path = format!("user_data/{}.json", sanitize(customer_email)); let provider_path = format!("user_data/{}.json", sanitize(provider_email)); let _ = std::fs::remove_file(&customer_path); let _ = std::fs::remove_file(&provider_path); // Initialize Tera templates similar to main.rs let mut tera = Tera::new("src/views/**/*.html").expect("failed to load templates"); utils::register_tera_functions(&mut tera); // Start test app with configured routes (includes session middleware) let app = test::init_service( App::new() .app_data(web::Data::new(tera)) .configure(configure_routes) ).await; // 1) Register a new customer to obtain a valid session cookie let form = [ ("name", "Instant Customer"), ("email", customer_email), ("password", "secret123"), ("password_confirmation", "secret123"), ]; let req = test::TestRequest::post() .uri("/register") .set_form(&form) .to_request(); let resp = test::call_service(&app, req).await; assert!(resp.status().is_redirection()); // Extract session cookie set by session middleware let session_cookie = extract_cookie_value(&resp, "threefold_marketplace_session") .expect("session cookie should be set after registration"); // 2) Seed provider user_data with a service matching product_id let mut provider_data = UserPersistence::create_default_user_data(provider_email); provider_data.services.push(Service { id: product_id.to_string(), name: "Instant Test Service".to_string(), category: "service".to_string(), description: "test service".to_string(), price_per_hour_usd: 100, status: "active".to_string(), clients: 0, rating: 0.0, total_hours: 0, }); UserPersistence::save_user_data(&provider_data).expect("save provider data"); // 3) Increase customer's wallet balance so purchase can succeed let mut customer_data = UserPersistence::create_default_user_data(customer_email); customer_data.name = Some("Instant Customer".to_string()); customer_data.wallet_balance_usd = Decimal::from(500); UserPersistence::save_user_data(&customer_data).expect("save customer data"); // 4) Perform instant purchase let body = json!({ "product_id": product_id, "product_name": "Instant Test Service", "product_category": "service", "quantity": 1u32, "unit_price_usd": Decimal::from(100), "provider_id": provider_email, "provider_name": "Instant Provider", "specifications": json!({"note":"test"}), }); let req = test::TestRequest::post() .uri("/api/wallet/instant-purchase") .insert_header((actix_web::http::header::CONTENT_TYPE, "application/json")) .insert_header((actix_web::http::header::COOKIE, session_cookie.clone())) .set_payload(body.to_string()) .to_request(); let resp = test::call_service(&app, req).await; assert_eq!(resp.status(), StatusCode::OK); let resp_body: serde_json::Value = test::read_body_json(resp).await; assert!(resp_body.get("success").and_then(|v| v.as_bool()).unwrap_or(false)); // 5) Verify that a booking got persisted to the customer's file let persisted = UserPersistence::load_user_data(customer_email).expect("customer data should exist"); assert!(persisted.service_bookings.len() >= 1, "expected at least one service booking to be persisted"); assert!(persisted.service_bookings.iter().any(|b| b.service_name == "Instant Test Service")); // Also verify provider got a service request let provider_persisted = UserPersistence::load_user_data(provider_email).expect("provider data should exist"); assert!(provider_persisted.service_requests.len() >= 1, "expected at least one service request for provider"); }