Lines
99.36 %
Functions
100 %
Branches
use axum::{
Router,
body::Body,
http::{Request, StatusCode},
routing::{get, post},
};
use serde_json::json;
use tower::ServiceExt;
use crate::common::{create_mock_jwt_auth, create_mock_user, create_test_app_state};
#[tokio::test]
async fn test_transaction_create_without_auth() {
let app_state = create_test_app_state().await;
let app = Router::new()
.route(
"/transaction/create/submit",
post(web::pages::transaction::create::submit::transaction_submit),
)
.with_state(app_state);
let transaction_data = json!({
"splits": [{
"amount": "100.00",
"amount_converted": "100.00",
"from_account": "550e8400-e29b-41d4-a716-446655440000",
"to_account": "650e8400-e29b-41d4-a716-446655440001",
"from_commodity": "550e8400-e29b-41d4-a716-446655440002",
"to_commodity": "550e8400-e29b-41d4-a716-446655440002"
}],
"note": "Test transaction",
"date": "2023-01-01T12:00:00Z"
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/transaction/create/submit")
.header("content-type", "application/json")
.body(Body::from(transaction_data.to_string()))
.unwrap(),
.await
.unwrap();
// Should fail without authentication - expecting 401 or 500
assert!(response.status().is_client_error() || response.status().is_server_error());
}
async fn test_transaction_create_with_invalid_json() {
.body(Body::from("invalid json"))
async fn test_transaction_create_with_mock_auth() {
let mock_user = create_mock_user();
let jwt_auth = create_mock_jwt_auth(mock_user);
.layer(axum::middleware::from_fn_with_state(
app_state.clone(),
move |mut req: axum::http::Request<Body>, next: axum::middleware::Next| {
let jwt_auth = jwt_auth.clone();
async move {
req.extensions_mut().insert(jwt_auth);
next.run(req).await
},
))
.with_state(app_state.clone());
// This test verifies our CreateTransaction macro integration works
// Even if it fails due to DB issues, it should not be a JSON parsing error
// We expect either success (200) or a server error (500) due to missing DB
// but NOT a client error (400) which would indicate API issues
assert!(
response.status().is_success() || response.status().is_server_error(),
"Expected success or server error, got: {}",
response.status()
);
// If we get a response, verify it has proper content type
if let Some(content_type) = response.headers().get("content-type") {
let content_type_str = content_type.to_str().unwrap_or("");
// Should be text (for success message) or JSON (for error response)
content_type_str.contains("text/") || content_type_str.contains("application/json"),
"Unexpected content type: {}",
content_type_str
async fn test_transaction_create_empty_splits() {
"splits": [],
"note": "Test transaction with no splits"
// Should return 400 for empty splits array
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
// Verify it returns JSON error response
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
let body_str = String::from_utf8(body.to_vec()).unwrap();
let json_response: serde_json::Value =
serde_json::from_str(&body_str).expect("Response should be valid JSON");
// Verify error structure
assert_eq!(json_response["status"], "fail");
assert!(json_response["message"].is_string());
assert!(json_response["message"].as_str().unwrap().contains("split"));
async fn test_transaction_create_invalid_amount() {
"amount": "invalid_amount",
"note": "Test transaction with invalid amount"
// Should return 400 for invalid amount
json_response["message"]
.as_str()
.unwrap()
.contains("Invalid amount")
async fn test_transaction_create_invalid_account_id() {
"from_account": "invalid_uuid_format",
"note": "Test transaction with invalid account ID"
// Should return 400 for invalid UUID format
.contains("Invalid")
async fn test_transaction_create_negative_amount() {
"amount": "-50.00",
"amount_converted": "-50.00",
"note": "Test transaction with negative amount"
// Should return 400 for negative amount
.contains("positive")
async fn test_transaction_create_zero_amount() {
"amount": "0.00",
"amount_converted": "0.00",
"note": "Test transaction with zero amount"
// Should return 400 for zero amount
async fn test_transaction_create_with_note() {
"note": "This is a test transaction with a note",
// Should succeed with auth (even if DB fails, it shouldn't be a parsing error)
// ListTransactions web tests
async fn test_transaction_list_page_without_auth() {
"/transaction/list",
get(web::pages::transaction::list::transaction_list_page),
.method("GET")
.uri("/transaction/list")
.body(Body::empty())
// Should succeed as this is just a static page
assert_eq!(response.status(), StatusCode::OK);
async fn test_transaction_table_without_auth() {
"/transaction/table",
get(web::pages::transaction::list::transaction_table),
.uri("/transaction/table")
async fn test_transaction_table_with_mock_auth() {
// This test verifies our ListTransactions macro integration works
// Even if it fails due to DB issues, it should not be a parsing error
// Should be HTML for the table template
content_type_str.contains("text/html"),
async fn test_transaction_table_with_account_filter() {
// Test with account filter parameter
.uri("/transaction/table?account=550e8400-e29b-41d4-a716-446655440000")
async fn test_transaction_table_with_invalid_account_filter() {
// Test with invalid account UUID
.uri("/transaction/table?account=invalid-uuid")
response.status() == StatusCode::BAD_REQUEST || response.status().is_server_error(),
"Expected bad request or server error, got: {}",
async fn test_transaction_table_empty_account_filter() {
// Test with empty account parameter
.uri("/transaction/table?account=")
// Empty string is not a valid UUID, so should return 400 or server error
async fn test_transaction_table_multiple_parameters() {
// Test with multiple query parameters (only account should be used)
.uri("/transaction/table?account=550e8400-e29b-41d4-a716-446655440000&other=value")
// Should succeed - extra parameters should be ignored