Files
Vorrania/backend/tests/test_navigation.py
T
ScarriffleandClaude Opus 5 be267e70a5 Seitenleiste: Eintraege ausblendbar (Backend)
Zwei Ebenen in einer Tabelle, nach dem Vorbild von DashboardLayout:
user_id NULL ist die Vorgabe des Administrators, eine Zeile mit user_id
die zusaetzliche Auswahl eines Kontos. Beide Listen gelten zusammen - wer
etwas versteckt, versteckt es zusaetzlich; einblenden, was der
Administrator ausgeblendet hat, kann niemand. Das erspart einen dritten
Zustand je Eintrag.

Als Schluessel dient der Routenpfad; der ist ohnehin eindeutig, eine
zweite Benennung waere nur eine weitere Stelle zum Auseinanderlaufen.

Drei Routen: lesen (Vorgabe, eigene Auswahl und die fertige Vereinigung
in einem Zug), eigene Auswahl setzen, Vorgabe setzen (nur Admin).

Die Eindeutigkeit laeuft ueber einen Index auf coalesce(user_id, -1).
Ein schlichtes UNIQUE(user_id) haette zwei Vorgabezeilen zugelassen, weil
NULL in SQL nie gleich NULL ist - das war im Entwurf noch falsch.

Versteckt wird nur der Eintrag, nicht die Seite: Lesezeichen,
Dashboard-Karten und Lagerort-QR sollen weiter funktionieren.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-28 20:27:14 +01:00

138 lines
4.4 KiB
Python
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.
"""Seitenleiste ausblenden: Vorgabe des Admins, eigene Auswahl, Vereinigung."""
import json
import pytest
from fastapi import HTTPException
from sqlalchemy.exc import IntegrityError
from app.models import NavigationSichtbarkeit, Role, User
from app.routers.navigation import (
eigene_auswahl_setzen,
navigation_lesen,
vorgabe_setzen,
)
from app.schemas import NavigationSetzen
@pytest.fixture()
def admin(db):
person = User(username="admin", password_hash="x", role=Role.admin)
db.add(person)
db.commit()
db.refresh(person)
return person
@pytest.fixture()
def mitbewohner(db):
person = User(username="mitbewohner", password_hash="x", role=Role.user)
db.add(person)
db.commit()
db.refresh(person)
return person
def _setze_vorgabe(db, admin, werte):
return vorgabe_setzen(NavigationSetzen(versteckt=werte), db=db, user=admin)
def _setze_eigen(db, user, werte):
return eigene_auswahl_setzen(NavigationSetzen(versteckt=werte), db=db, user=user)
# ---- Vorgabe ----
def test_ohne_eintrag_ist_nichts_versteckt(db, admin):
out = navigation_lesen(db=db, user=admin)
assert out.vorgabe == [] and out.eigen == [] and out.versteckt == []
def test_vorgabe_gilt_fuer_alle(db, admin, mitbewohner):
_setze_vorgabe(db, admin, ["/rezepte"])
assert navigation_lesen(db=db, user=mitbewohner).versteckt == ["/rezepte"]
assert navigation_lesen(db=db, user=admin).versteckt == ["/rezepte"]
def test_normaler_nutzer_darf_die_vorgabe_nicht_setzen(db, mitbewohner):
"""require_admin greift – geprueft ueber die Rolle, wie in deps.py."""
from app.deps import require_admin
with pytest.raises(HTTPException) as fehler:
require_admin(mitbewohner)
assert fehler.value.status_code == 403
# ---- Eigene Auswahl ----
def test_eigene_auswahl_betrifft_nur_einen(db, admin, mitbewohner):
_setze_eigen(db, mitbewohner, ["/history"])
assert navigation_lesen(db=db, user=mitbewohner).versteckt == ["/history"]
assert navigation_lesen(db=db, user=admin).versteckt == []
def test_eigene_auswahl_kommt_zur_vorgabe_dazu(db, admin, mitbewohner):
_setze_vorgabe(db, admin, ["/rezepte"])
_setze_eigen(db, mitbewohner, ["/history"])
out = navigation_lesen(db=db, user=mitbewohner)
assert out.vorgabe == ["/rezepte"]
assert out.eigen == ["/history"]
assert out.versteckt == ["/history", "/rezepte"]
def test_nutzer_kann_die_vorgabe_nicht_aufheben(db, admin, mitbewohner):
"""Die eigene Auswahl addiert nur – sie nimmt nichts weg."""
_setze_vorgabe(db, admin, ["/shopping"])
_setze_eigen(db, mitbewohner, [])
assert navigation_lesen(db=db, user=mitbewohner).versteckt == ["/shopping"]
# ---- Speicherung ----
def test_zweimal_setzen_legt_keine_zweite_zeile_an(db, mitbewohner):
_setze_eigen(db, mitbewohner, ["/history"])
_setze_eigen(db, mitbewohner, ["/verliehen"])
zeilen = db.query(NavigationSichtbarkeit).all()
assert len(zeilen) == 1
assert json.loads(zeilen[0].versteckt) == ["/verliehen"]
def test_nur_eine_vorgabezeile(db, admin):
"""Der Teilindex muss eine zweite Vorgabe verhindern."""
_setze_vorgabe(db, admin, ["/rezepte"])
db.add(NavigationSichtbarkeit(user_id=None, versteckt='["/shopping"]'))
with pytest.raises(IntegrityError):
db.commit()
db.rollback()
def test_nur_eine_zeile_je_konto(db, mitbewohner):
_setze_eigen(db, mitbewohner, ["/history"])
db.add(NavigationSichtbarkeit(user_id=mitbewohner.id, versteckt="[]"))
with pytest.raises(IntegrityError):
db.commit()
db.rollback()
def test_doppelte_und_leere_eintraege_fallen_weg(db, mitbewohner):
out = _setze_eigen(db, mitbewohner, ["/history", "/history", "", " ", "/verliehen"])
assert out.eigen == ["/history", "/verliehen"]
def test_kaputter_inhalt_sperrt_niemanden_aus(db, mitbewohner):
"""Lieber die volle Leiste als eine Fehlermeldung."""
db.add(NavigationSichtbarkeit(user_id=mitbewohner.id, versteckt="kein JSON"))
db.commit()
assert navigation_lesen(db=db, user=mitbewohner).versteckt == []
def test_unbekannter_schluessel_wird_mitgefuehrt_aber_stoert_nicht(db, mitbewohner):
"""Ein umbenannter Eintrag darf die Leiste nicht zerreissen – der Server
kennt die Pfade gar nicht, die Oberflaeche ignoriert Unbekanntes."""
out = _setze_eigen(db, mitbewohner, ["/gibtsnichtmehr"])
assert out.versteckt == ["/gibtsnichtmehr"]