Files
saldo/tests/test_shares_notifications_auth.py
2026-04-21 21:17:36 +02:00

120 lines
4.2 KiB
Python

from __future__ import annotations
import io
from datetime import date
from decimal import Decimal
from app.extensions import db
from app.models import CostParticipant, Entry, InAppNotification, Month, User
def test_share_logic_with_external_guest(app):
month = Month.query.filter_by(label="2026-04").first()
service = app.extensions["saldo.share_service"]
shared_value = next(item for item in month.entry_values if item.entry.name == "Streaming 1")
result = service.calculate_entry_shares(shared_value)
guest_share = next(item for item in result["shares"] if item["participant_name"] == "Gast")
assert guest_share["amount"] == Decimal("5.99")
assert result["external_total"] == guest_share["amount"]
def test_external_guest_shares_do_not_reduce_distribution_pool(app):
month = Month.query.filter_by(label="2026-04").first()
service = app.extensions["saldo.month_service"]
shared_value = next(item for item in month.entry_values if item.entry.name == "Streaming 1")
summary = service.compute_summary(month)
assert shared_value.entry.share_rules
assert summary.fixed_costs < summary.total_costs
def test_push_reminder_logic_creates_in_app_notifications(app):
notification_service = app.extensions["saldo.notification_service"]
count = notification_service.run_monthly_checks(date(2026, 4, 27))
assert count >= 1
assert InAppNotification.query.count() >= 1
def test_setup_route_can_create_first_admin(empty_client, empty_app):
response = empty_client.post(
"/auth/setup",
data={
"username": "setup-admin",
"display_name": "Setup Admin",
"email": "setup-admin@example.invalid",
"password": "supersecret",
"password_confirm": "supersecret",
},
follow_redirects=True,
)
with empty_app.app_context():
user = User.query.filter_by(username="setup-admin").first()
assert user is not None
assert user.role == "admin"
assert response.status_code == 200
assert "2026-04" in response.get_data(as_text=True) or "2026-05" in response.get_data(as_text=True)
def test_admin_route_requires_admin(client, app, editor_user):
client.post(
"/auth/login",
data={"username": editor_user.username, "password": "testpass"},
follow_redirects=True,
)
response = client.get("/admin/")
assert response.status_code == 403
def test_admin_can_access_admin_route(logged_in_client):
response = logged_in_client.get("/admin/")
assert response.status_code == 200
def test_admin_can_create_entry_and_backfill_existing_month(logged_in_client, app):
from app.models import Category, Entry, Month, MonthlyEntryValue
category = Category.query.filter_by(slug="haushalt").first()
month = Month.query.filter_by(label="2026-04").first()
before = MonthlyEntryValue.query.filter_by(month_id=month.id).count()
response = logged_in_client.post(
"/admin/entries",
data={
"category_id": category.id,
"name": "Tierfutter",
"slug": "tierfutter",
"default_amount": "45.00",
"amount_type": "fixed",
"sort_order": "99",
"description": "",
"is_active": "on",
},
follow_redirects=True,
)
assert response.status_code == 200
entry = Entry.query.filter_by(slug="tierfutter").first()
assert entry is not None
assert MonthlyEntryValue.query.filter_by(month_id=month.id).count() == before + 1
def test_participant_avatar_can_be_uploaded(logged_in_client, app):
response = logged_in_client.post(
"/planning/2026-04/participants",
data={
"name": "Mika",
"is_external": "on",
"return_dialog": "split-people-dialog",
"avatar_file": (io.BytesIO(b"fake-image-bytes"), "mika.png"),
},
content_type="multipart/form-data",
follow_redirects=True,
)
participant = CostParticipant.query.filter_by(name="Mika").first()
assert response.status_code == 200
assert participant is not None
assert participant.avatar_url is not None
assert participant.avatar_url.startswith("/media/avatars/")