Files
kakeibo/backend/tests/catalog.rs
T
suphicakir 6eb5440d4d feat(katalog): kategori ve ödeme türü uç noktaları, hane izolasyonu entegrasyon testleri
- /api/categories ve /api/payment-methods: listele, ekle, düzenle, sırala, pasife al
- Sürüm kontrolü ile eşzamanlı düzenleme çakışması (409)
- Backend lib + bin yapısına ayrıldı (entegrasyon testleri için)
- tests/: hane izolasyonu (3) ve katalog (4) entegrasyon testleri
- db:reset artık artık test veritabanlarını da siler
- api.http tamamlandı; Faz 1 tamamlandı

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 23:54:16 +03:00

217 lines
6.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 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<String> = 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;
}