Files
saldo/tests/test_routes.py
T

242 lines
8.7 KiB
Python

from __future__ import annotations
from decimal import Decimal
from app.extensions import db
from app.models import AllocationSuggestion, Category, CommunityAccount, Month, MonthlyEntryValue
def test_health_route(client):
response = client.get("/health")
assert response.status_code == 200
assert response.json["status"] == "ok"
def test_first_run_redirects_to_setup(empty_client):
response = empty_client.get("/", follow_redirects=False)
assert response.status_code == 302
assert "/auth/setup" in response.headers["Location"]
def test_current_month_is_available_after_login(logged_in_client):
response = logged_in_client.get("/")
assert response.status_code == 200
assert b"2026-04" in response.data or b"2026-05" in response.data
assert b"Dauerauftr\xc3\xa4ge pr\xc3\xbcfen" in response.data
assert b"Extern mitzuteilen" in response.data
def test_analytics_route_uses_new_cost_focused_sections(logged_in_client):
response = logged_in_client.get("/analytics")
content = response.get_data(as_text=True)
assert response.status_code == 200
assert "Kategorien im Monat" in content
assert "Kosten nach Zuordnung" in content
assert "Budgets im Monatsverlauf" in content
assert "Größte Einträge im Monat" in content
assert "Sparkonten" in content
assert "category-chart-back" in content
assert "entry-drilldown-chart" not in content
assert '"Pers\\u00f6nliche Auszahlung"' in content
assert "Person A" in content
assert "Person B" in content
def test_planning_detail_refreshes_stale_suggestions_after_distribution_sync(logged_in_client):
month = Month.query.filter_by(label="2026-04").first()
sparen_value = next(
item for item in month.entry_values if item.entry.name == "Sparziel"
)
sparen_allocation = next(
item for item in month.allocations if item.target_account.slug == "sparen"
)
sparen_value.planned_amount = Decimal("0.00")
sparen_allocation.amount = Decimal("1539.20")
for suggestion in month.suggestions:
suggestion.suggested_amount = Decimal("0.00")
db.session.commit()
response = logged_in_client.get("/planning/2026-04")
db.session.refresh(sparen_value)
refreshed_suggestions = AllocationSuggestion.query.filter_by(month_id=month.id).all()
assert response.status_code == 200
assert sparen_value.planned_amount == Decimal("1539.20")
assert sum((item.suggested_amount for item in refreshed_suggestions), Decimal("0.00")) > Decimal("0.00")
def test_community_entry_can_be_updated_via_annual_amount(app, logged_in_client):
month = Month.query.filter_by(label="2026-04").first()
value = next(
item for item in month.entry_values if item.entry.name == "Miete"
)
response = logged_in_client.post(
f"/planning/{month.label}/entry",
data={
"value_id": value.id,
"return_dialog": f"category-dialog-{value.entry.category_id}",
"entry_name": value.entry.name,
"category_id": value.entry.category_id,
"planned_amount": "",
"annual_amount": "1800.00",
"benefit_scope": value.entry.benefit_scope,
"note": value.note or "",
},
)
updated_value = db.session.get(MonthlyEntryValue, value.id)
assert response.status_code == 302
assert updated_value.planned_amount == Decimal("150.00")
def test_distribution_dialog_shows_direct_budget_form(logged_in_client):
response = logged_in_client.get("/planning/2026-04")
assert response.status_code == 200
assert b"Budget direkt anpassen" in response.data
assert b"Sparkonto" in response.data
def test_planning_shows_budgets_and_community_accounts(logged_in_client):
response = logged_in_client.get("/planning/2026-04")
assert response.status_code == 200
assert b"Budgets" in response.data
assert b"Gemeinschaftskonten" in response.data
assert b"Auszahlung Person A" in response.data
assert b"Auszahlung Person B" in response.data
def test_planning_delete_actions_render_confirmation_hooks(logged_in_client):
response = logged_in_client.get("/planning/2026-04")
assert response.status_code == 200
assert b'data-confirm-submit="Einkommenszeile wirklich l\xc3\xb6schen?' in response.data
assert b'data-confirm-submit="Kategorie wirklich l\xc3\xb6schen?' in response.data
assert b'data-confirm-submit="Konto wirklich l\xc3\xb6schen?' in response.data
assert b'data-confirm-submit="Eintrag wirklich l\xc3\xb6schen?' in response.data
def test_community_account_can_assign_budget_categories(logged_in_client):
community_account = CommunityAccount.query.filter_by(slug="hauptkonto").first()
category = Category.query.filter_by(slug="wohnen").first()
response = logged_in_client.post(
f"/planning/2026-04/community-accounts/{community_account.id}",
data={
"name": community_account.name,
"description": community_account.description or "",
"category_ids": [str(category.id)],
},
)
db.session.refresh(category)
assert response.status_code == 302
assert category.community_account_id == community_account.id
def test_deleted_category_can_be_created_again(logged_in_client):
create_response = logged_in_client.post(
"/planning/2026-04/categories",
data={"name": "Testbudget", "area": "budget"},
)
assert create_response.status_code == 302
category = Category.query.filter_by(slug="testbudget").first()
original_id = category.id
delete_response = logged_in_client.post(f"/planning/2026-04/categories/{category.id}/delete")
assert delete_response.status_code == 302
recreate_response = logged_in_client.post(
"/planning/2026-04/categories",
data={"name": "Testbudget", "area": "budget"},
)
restored = Category.query.filter_by(slug="testbudget").first()
assert recreate_response.status_code == 302
assert restored.id == original_id
assert restored.is_active is True
def test_deleted_community_account_can_be_created_again(logged_in_client):
create_response = logged_in_client.post(
"/planning/2026-04/community-accounts",
data={"name": "Testkonto", "description": ""},
)
assert create_response.status_code == 302
community_account = CommunityAccount.query.filter_by(slug="testkonto").first()
original_id = community_account.id
delete_response = logged_in_client.post(
f"/planning/2026-04/community-accounts/{community_account.id}/delete"
)
assert delete_response.status_code == 302
recreate_response = logged_in_client.post(
"/planning/2026-04/community-accounts",
data={"name": "Testkonto", "description": "Wieder da"},
)
restored = CommunityAccount.query.filter_by(slug="testkonto").first()
assert recreate_response.status_code == 302
assert restored.id == original_id
assert restored.is_active is True
assert restored.description == "Wieder da"
def test_community_account_rejects_budget_assigned_to_other_account(logged_in_client):
primary_account = CommunityAccount.query.filter_by(slug="hauptkonto").first()
secondary_response = logged_in_client.post(
"/planning/2026-04/community-accounts",
data={"name": "Fixkostenkonto", "description": ""},
follow_redirects=True,
)
assert secondary_response.status_code == 200
secondary_account = CommunityAccount.query.filter_by(slug="fixkostenkonto").first()
category = Category.query.filter_by(slug="wohnen").first()
category.community_account_id = primary_account.id
db.session.commit()
response = logged_in_client.post(
f"/planning/2026-04/community-accounts/{secondary_account.id}",
data={
"name": secondary_account.name,
"description": secondary_account.description or "",
"category_ids": [str(category.id)],
},
follow_redirects=True,
)
db.session.refresh(category)
assert response.status_code == 200
assert category.community_account_id == primary_account.id
assert b"bereits anderen Konten zugewiesen" in response.data
def test_community_account_can_be_deleted_and_unassigns_budgets(logged_in_client):
community_account = CommunityAccount.query.filter_by(slug="hauptkonto").first()
category = Category.query.filter_by(slug="wohnen").first()
category.community_account_id = community_account.id
db.session.commit()
response = logged_in_client.post(
f"/planning/2026-04/community-accounts/{community_account.id}/delete"
)
db.session.refresh(category)
db.session.refresh(community_account)
assert response.status_code == 302
assert community_account.is_active is False
assert category.community_account_id is None