Files
bin/finance/tests/test_transactions_sort.py
2026-09-28 19:29:25 +02:00

90 lines
3.8 KiB
Python

from datetime import date, timedelta
from decimal import Decimal
import pytest
from app.models.tables import Account, Category, Transaction
H = {"Authorization": "Bearer test-key"}
def _tx(db, acc, day, amount, purpose="Zweck", counterparty="X", category=None, n=[0]):
n[0] += 1
db.add(Transaction(account_id=acc.id, booking_date=day, amount=Decimal(amount),
purpose=purpose, counterparty=counterparty, status="confirmed",
category_id=category.id if category else None,
dedup_hash=f"sort-{n[0]}"))
@pytest.fixture
def small(db):
zeta = Account(bank="t", iban="DE-SO-1", name="Zeta", type="giro")
alpha = Account(bank="t", iban="DE-SO-2", name="alpha", type="giro")
kat = Category(name="Miete")
db.add_all([zeta, alpha, kat])
db.flush()
_tx(db, zeta, date(2026, 1, 3), "-5.00", "b-Zweck", "Bert", kat)
_tx(db, alpha, date(2026, 1, 1), "20.00", "A-Zweck", "anna", None)
_tx(db, zeta, date(2026, 1, 2), "-30.00", "c-Zweck", "Carl", kat)
db.commit()
def _amounts(client, qs):
r = client.get(f"/api/transactions?{qs}", headers=H)
assert r.status_code == 200
return [Decimal(t["amount"]) for t in r.json()]
def test_standard_bleibt_datum_aufsteigend(client, small):
assert _amounts(client, "") == [Decimal("20.00"), Decimal("-30.00"), Decimal("-5.00")]
@pytest.mark.parametrize("sort,dir,expected", [
("betrag", "asc", ["-30.00", "-5.00", "20.00"]),
("betrag", "desc", ["20.00", "-5.00", "-30.00"]),
("datum", "desc", ["-5.00", "-30.00", "20.00"]),
("konto", "asc", ["20.00", "-5.00", "-30.00"]), # alpha vor Zeta (case-insensitiv), Gleichstand -> id
("zweck", "asc", ["20.00", "-5.00", "-30.00"]), # A-, b-, c-Zweck
("empfaenger", "desc", ["-30.00", "-5.00", "20.00"]), # Carl, Bert, anna
("kategorie", "asc", ["-5.00", "-30.00", "20.00"]), # Miete (id-Reihenfolge), unkategorisiert zuletzt
("kategorie", "desc", ["-30.00", "-5.00", "20.00"]), # unkategorisiert auch absteigend zuletzt
])
def test_sortierung_je_spalte(client, small, sort, dir, expected):
assert _amounts(client, f"sort={sort}&dir={dir}") == [Decimal(e) for e in expected]
def test_ungueltige_werte_fallen_auf_standard(client, small):
assert _amounts(client, "sort=foo;drop&dir=hoch") == _amounts(client, "")
client.post("/login", data={"username": "admin", "password": "geheim"})
assert client.get("/buchungen?sort=foo&dir=bar").status_code == 200
@pytest.fixture
def many(db):
acc = Account(bank="t", iban="DE-SO-3", name="Viel", type="giro")
db.add(acc)
db.flush()
for i in range(1, 61): # Beträge i,37; Datum verwürfelt
_tx(db, acc, date(2026, 1, 1) + timedelta(days=(i * 7) % 60), f"{i}.37", f"Miete {i}")
db.commit()
def test_sortierung_gilt_ueber_alle_seiten(client, many):
client.post("/login", data={"username": "admin", "password": "geheim"})
p1 = client.get("/buchungen?sort=betrag&dir=desc").text
p2 = client.get("/buchungen?sort=betrag&dir=desc&page=2").text
assert ">60,37</td>" in p1 and ">1,37</td>" not in p1
assert ">1,37</td>" in p2 and ">60,37</td>" not in p2
def test_links_erhalten_filter_und_sortierung(client, many):
client.post("/login", data={"username": "admin", "password": "geheim"})
html = client.get("/buchungen?q=Miete&sort=betrag&dir=asc").text
# Aktiver Spaltenkopf kehrt die Richtung um, übernimmt den Filter, ohne page.
assert 'href="/buchungen?q=Miete&status=confirmed&sort=betrag&dir=desc"' in html
# Inaktive Spalte startet aufsteigend.
assert 'href="/buchungen?q=Miete&status=confirmed&sort=datum&dir=asc"' in html
# Pager behält Filter + Sortierung.
assert "q=Miete&status=confirmed&sort=betrag&dir=asc&page=2" in html
assert "▲" in html