init projectmycelium
This commit is contained in:
249
tests/tests_archive/ux_suite/environment/api_client.rs
Normal file
249
tests/tests_archive/ux_suite/environment/api_client.rs
Normal file
@@ -0,0 +1,249 @@
|
||||
//! API Test Client
|
||||
//!
|
||||
//! Validates API responses alongside UX interactions
|
||||
|
||||
use reqwest;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// API test client for validating backend responses
|
||||
#[derive(Clone)]
|
||||
pub struct APITestClient {
|
||||
client: reqwest::Client,
|
||||
base_url: String,
|
||||
session_cookies: Option<String>,
|
||||
}
|
||||
|
||||
impl APITestClient {
|
||||
/// Create a new API test client
|
||||
pub fn new(test_port: u16) -> Self {
|
||||
Self {
|
||||
client: reqwest::Client::builder()
|
||||
.cookie_store(true)
|
||||
.build()
|
||||
.expect("Failed to create HTTP client"),
|
||||
base_url: format!("http://localhost:{}", test_port),
|
||||
session_cookies: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Make a GET request to an API endpoint
|
||||
pub async fn get(&self, path: &str) -> Result<ApiResponse, Box<dyn std::error::Error>> {
|
||||
let url = format!("{}{}", self.base_url, path);
|
||||
log::info!("API GET: {}", url);
|
||||
|
||||
let mut request = self.client.get(&url);
|
||||
|
||||
if let Some(cookies) = &self.session_cookies {
|
||||
request = request.header("Cookie", cookies);
|
||||
}
|
||||
|
||||
let response = request.send().await?;
|
||||
let status = response.status();
|
||||
let headers = response.headers().clone();
|
||||
let body: Value = response.json().await?;
|
||||
|
||||
Ok(ApiResponse {
|
||||
status: status.as_u16(),
|
||||
headers: headers.iter().map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string())).collect(),
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
/// Make a POST request to an API endpoint
|
||||
pub async fn post(&self, path: &str, data: Value) -> Result<ApiResponse, Box<dyn std::error::Error>> {
|
||||
let url = format!("{}{}", self.base_url, path);
|
||||
log::info!("API POST: {}", url);
|
||||
|
||||
let mut request = self.client.post(&url).json(&data);
|
||||
|
||||
if let Some(cookies) = &self.session_cookies {
|
||||
request = request.header("Cookie", cookies);
|
||||
}
|
||||
|
||||
let response = request.send().await?;
|
||||
let status = response.status();
|
||||
let headers = response.headers().clone();
|
||||
let body: Value = response.json().await?;
|
||||
|
||||
Ok(ApiResponse {
|
||||
status: status.as_u16(),
|
||||
headers: headers.iter().map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string())).collect(),
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
/// Make a PUT request to an API endpoint
|
||||
pub async fn put(&self, path: &str, data: Value) -> Result<ApiResponse, Box<dyn std::error::Error>> {
|
||||
let url = format!("{}{}", self.base_url, path);
|
||||
log::info!("API PUT: {}", url);
|
||||
|
||||
let mut request = self.client.put(&url).json(&data);
|
||||
|
||||
if let Some(cookies) = &self.session_cookies {
|
||||
request = request.header("Cookie", cookies);
|
||||
}
|
||||
|
||||
let response = request.send().await?;
|
||||
let status = response.status();
|
||||
let headers = response.headers().clone();
|
||||
let body: Value = response.json().await?;
|
||||
|
||||
Ok(ApiResponse {
|
||||
status: status.as_u16(),
|
||||
headers: headers.iter().map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string())).collect(),
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
/// Make a DELETE request to an API endpoint
|
||||
pub async fn delete(&self, path: &str) -> Result<ApiResponse, Box<dyn std::error::Error>> {
|
||||
let url = format!("{}{}", self.base_url, path);
|
||||
log::info!("API DELETE: {}", url);
|
||||
|
||||
let mut request = self.client.delete(&url);
|
||||
|
||||
if let Some(cookies) = &self.session_cookies {
|
||||
request = request.header("Cookie", cookies);
|
||||
}
|
||||
|
||||
let response = request.send().await?;
|
||||
let status = response.status();
|
||||
let headers = response.headers().clone();
|
||||
let body: Value = response.json().await?;
|
||||
|
||||
Ok(ApiResponse {
|
||||
status: status.as_u16(),
|
||||
headers: headers.iter().map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string())).collect(),
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
/// Validate authentication status
|
||||
pub async fn validate_auth_status(&self) -> Result<AuthStatus, Box<dyn std::error::Error>> {
|
||||
let response = self.get("/api/auth/status").await?;
|
||||
|
||||
// Validate ResponseBuilder envelope format
|
||||
self.assert_response_envelope(&response.body)?;
|
||||
|
||||
let authenticated = response.body["data"]["authenticated"].as_bool().unwrap_or(false);
|
||||
let user_email = response.body["data"]["user"]["email"].as_str().map(|s| s.to_string());
|
||||
|
||||
Ok(AuthStatus {
|
||||
authenticated,
|
||||
user_email,
|
||||
})
|
||||
}
|
||||
|
||||
/// Validate cart state
|
||||
pub async fn validate_cart_state(&self) -> Result<CartState, Box<dyn std::error::Error>> {
|
||||
let response = self.get("/api/cart").await?;
|
||||
|
||||
self.assert_response_envelope(&response.body)?;
|
||||
|
||||
let items = response.body["data"]["items"].as_array()
|
||||
.map(|arr| arr.len())
|
||||
.unwrap_or(0);
|
||||
|
||||
let total = response.body["data"]["total"]["amount"].as_f64().unwrap_or(0.0);
|
||||
|
||||
Ok(CartState {
|
||||
item_count: items,
|
||||
total_amount: total,
|
||||
})
|
||||
}
|
||||
|
||||
/// Validate wallet balance
|
||||
pub async fn get_wallet_balance(&self) -> Result<WalletBalance, Box<dyn std::error::Error>> {
|
||||
let response = self.get("/api/wallet/balance").await?;
|
||||
|
||||
self.assert_response_envelope(&response.body)?;
|
||||
|
||||
let balance = response.body["data"]["balance"]["amount"].as_f64().unwrap_or(0.0);
|
||||
let currency = response.body["data"]["balance"]["currency"].as_str().unwrap_or("TFC").to_string();
|
||||
|
||||
Ok(WalletBalance {
|
||||
balance,
|
||||
currency,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get user dashboard data
|
||||
pub async fn get_dashboard_data(&self, dashboard_type: &str) -> Result<Value, Box<dyn std::error::Error>> {
|
||||
let path = format!("/api/dashboard/{}-data", dashboard_type);
|
||||
let response = self.get(&path).await?;
|
||||
|
||||
self.assert_response_envelope(&response.body)?;
|
||||
|
||||
Ok(response.body["data"].clone())
|
||||
}
|
||||
|
||||
/// Validate products API
|
||||
pub async fn get_products(&self, category: Option<&str>) -> Result<Vec<Value>, Box<dyn std::error::Error>> {
|
||||
let path = if let Some(cat) = category {
|
||||
format!("/api/products?category={}", cat)
|
||||
} else {
|
||||
"/api/products".to_string()
|
||||
};
|
||||
|
||||
let response = self.get(&path).await?;
|
||||
self.assert_response_envelope(&response.body)?;
|
||||
|
||||
Ok(response.body["data"]["products"].as_array().unwrap_or(&vec![]).clone())
|
||||
}
|
||||
|
||||
/// Assert ResponseBuilder envelope format
|
||||
fn assert_response_envelope(&self, response: &Value) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if !response.get("success").is_some() {
|
||||
return Err("Missing 'success' field in response envelope".into());
|
||||
}
|
||||
|
||||
let success = response["success"].as_bool().unwrap_or(false);
|
||||
|
||||
if success {
|
||||
if !response.get("data").is_some() {
|
||||
return Err("Missing 'data' field in successful response".into());
|
||||
}
|
||||
} else {
|
||||
if !response.get("error").is_some() {
|
||||
return Err("Missing 'error' field in failed response".into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set session cookies for authenticated requests
|
||||
pub fn set_session_cookies(&mut self, cookies: String) {
|
||||
self.session_cookies = Some(cookies);
|
||||
}
|
||||
}
|
||||
|
||||
/// API response structure
|
||||
#[derive(Debug)]
|
||||
pub struct ApiResponse {
|
||||
pub status: u16,
|
||||
pub headers: HashMap<String, String>,
|
||||
pub body: Value,
|
||||
}
|
||||
|
||||
/// Authentication status
|
||||
#[derive(Debug)]
|
||||
pub struct AuthStatus {
|
||||
pub authenticated: bool,
|
||||
pub user_email: Option<String>,
|
||||
}
|
||||
|
||||
/// Cart state
|
||||
#[derive(Debug)]
|
||||
pub struct CartState {
|
||||
pub item_count: usize,
|
||||
pub total_amount: f64,
|
||||
}
|
||||
|
||||
/// Wallet balance
|
||||
#[derive(Debug)]
|
||||
pub struct WalletBalance {
|
||||
pub balance: f64,
|
||||
pub currency: String,
|
||||
}
|
Reference in New Issue
Block a user