//! Kategori ve ödeme türü davranış testleri. mod common; use axum::http::StatusCode; use common::TestApp; use serde_json::{Value, json}; fn names(list: &Value) -> Vec<&str> { list.as_array() .unwrap() .iter() .map(|i| i["name"].as_str().unwrap()) .collect() } #[tokio::test] async fn new_household_gets_default_categories_and_payment_methods() { let app = TestApp::new().await; let s = app.register("Yeni", None).await; let (_, cats) = app.get("/categories", &s).await; assert_eq!(cats.as_array().unwrap().len(), 13); // Grup sırası: needs → wants → culture → unexpected let groups: Vec<&str> = cats .as_array() .unwrap() .iter() .map(|c| c["group"].as_str().unwrap()) .collect(); assert_eq!(groups.first(), Some(&"needs")); assert_eq!(groups.last(), Some(&"unexpected")); let (_, pms) = app.get("/payment-methods", &s).await; assert_eq!( names(&pms), vec!["Nakit", "Kredi Kartı", "Banka Kartı", "Havale/EFT"] ); assert!( pms[0].get("group").is_none(), "ödeme türünde group alanı olmamalı" ); app.cleanup().await; } #[tokio::test] async fn create_validates_and_appends_to_end_of_group() { let app = TestApp::new().await; let s = app.register("Test", None).await; // Grup zorunlu let (st, _) = app .post("/categories", &s, json!({ "name": "Grupsuz" })) .await; assert_eq!(st, StatusCode::BAD_REQUEST); // Boş ad let (st, _) = app .post( "/categories", &s, json!({ "group": "needs", "name": " " }), ) .await; assert_eq!(st, StatusCode::BAD_REQUEST); // Geçersiz grup let (st, _) = app .post("/categories", &s, json!({ "group": "luks", "name": "X" })) .await; assert_eq!(st, StatusCode::BAD_REQUEST); // Aynı ad (büyük/küçük harf duyarsız) → 409 let (st, body) = app .post( "/categories", &s, json!({ "group": "needs", "name": "MARKET" }), ) .await; assert_eq!(st, StatusCode::CONFLICT, "{body}"); // Aynı ad başka grupta serbest let (st, _) = app .post( "/categories", &s, json!({ "group": "wants", "name": "Market" }), ) .await; assert_eq!(st, StatusCode::CREATED); // Yeni kayıt grubun sonuna eklenir let (st, cat) = app .post( "/categories", &s, json!({ "group": "needs", "name": " Aidat ", "emoji": "🏢" }), ) .await; assert_eq!(st, StatusCode::CREATED); assert_eq!(cat["name"], "Aidat"); let (_, cats) = app.get("/categories", &s).await; let needs: Vec<&str> = cats .as_array() .unwrap() .iter() .filter(|c| c["group"] == "needs") .map(|c| c["name"].as_str().unwrap()) .collect(); assert_eq!(needs.last(), Some(&"Aidat")); app.cleanup().await; } #[tokio::test] async fn update_deactivate_and_version_conflict() { let app = TestApp::new().await; let s = app.register("Test", None).await; let (_, pm) = app .post( "/payment-methods", &s, json!({ "name": "Yemek Kartı", "emoji": "🍽️" }), ) .await; let path = format!("/payment-methods/{}", pm["id"].as_str().unwrap()); assert_eq!(pm["version"], 1); // Ad + emoji kaldırma, doğru sürümle let (st, upd) = app .patch( &path, &s, json!({ "name": "Multinet", "emoji": "", "version": 1 }), ) .await; assert_eq!(st, StatusCode::OK); assert_eq!(upd["name"], "Multinet"); assert_eq!(upd["emoji"], Value::Null); assert_eq!(upd["version"], 2); // Eski sürümle güncelleme → 409 (başkası değiştirmiş) let (st, _) = app .patch(&path, &s, json!({ "name": "Sodexo", "version": 1 })) .await; assert_eq!(st, StatusCode::CONFLICT); // Pasife al: varsayılan listede görünmez, include_inactive ile görünür let (st, _) = app.patch(&path, &s, json!({ "is_active": false })).await; assert_eq!(st, StatusCode::OK); let (_, active) = app.get("/payment-methods", &s).await; assert!(!names(&active).contains(&"Multinet")); let (_, all) = app.get("/payment-methods?include_inactive=true", &s).await; assert!(names(&all).contains(&"Multinet")); // Pasif kayıtla aynı adda yeni kayıt açılamaz let (st, _) = app .post("/payment-methods", &s, json!({ "name": "multinet" })) .await; assert_eq!(st, StatusCode::CONFLICT); // Olmayan / bozuk kimlik → 404 let (st, _) = app .patch( "/payment-methods/01a1cc59-0000-7000-8000-000000000000", &s, json!({ "name": "X" }), ) .await; assert_eq!(st, StatusCode::NOT_FOUND); let (st, _) = app .patch("/payment-methods/bozuk", &s, json!({ "name": "X" })) .await; assert_eq!(st, StatusCode::NOT_FOUND); app.cleanup().await; } #[tokio::test] async fn reorder_requires_complete_list() { let app = TestApp::new().await; let s = app.register("Test", None).await; let (_, cats) = app.get("/categories", &s).await; let mut culture: Vec = cats .as_array() .unwrap() .iter() .filter(|c| c["group"] == "culture") .map(|c| c["id"].as_str().unwrap().to_string()) .collect(); assert_eq!(culture.len(), 3); // Eksik liste → 400 let (st, _) = app .put( "/categories/order", &s, json!({ "group": "culture", "ids": &culture[..2] }), ) .await; assert_eq!(st, StatusCode::BAD_REQUEST); // Ters çevir → yeni sıra culture.reverse(); let (st, ordered) = app .put( "/categories/order", &s, json!({ "group": "culture", "ids": culture }), ) .await; assert_eq!(st, StatusCode::OK); assert_eq!(names(&ordered), vec!["Sinema/Konser", "Eğitim", "Kitap"]); assert_eq!(ordered[0]["sort_order"], 10); app.cleanup().await; }