All checks were successful
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e394-2a69-7df0-8980-22a0ebe55216
190 lines
7 KiB
Python
190 lines
7 KiB
Python
import factory
|
|
import pytest
|
|
from django.urls import reverse
|
|
|
|
from .models import Ausschreibung
|
|
|
|
|
|
class AusschreibungFactory(factory.django.DjangoModelFactory):
|
|
class Meta:
|
|
model = Ausschreibung
|
|
|
|
titel = factory.Sequence(lambda n: f"Ausschreibung {n}")
|
|
ausschreiber = "Testausschreiber GmbH"
|
|
status = 1
|
|
|
|
|
|
# --- Model tests ---
|
|
|
|
@pytest.mark.django_db
|
|
def test_ausschreibung_str():
|
|
a = AusschreibungFactory(titel="Test Ausschreibung")
|
|
assert str(a) == "Test Ausschreibung"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@pytest.mark.parametrize("status,expected", [
|
|
(1, True), (5, True), (9, True),
|
|
(10, False), (11, False), (13, False),
|
|
])
|
|
def test_ist_aktiv(status, expected):
|
|
a = AusschreibungFactory(status=status)
|
|
assert a.ist_aktiv == expected
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_naechste_frist_returns_earlier():
|
|
from datetime import date, timedelta
|
|
heute = date.today()
|
|
a = AusschreibungFactory(
|
|
bieterfragen_bis=heute + timedelta(days=5),
|
|
abgabe_bis=heute + timedelta(days=10),
|
|
)
|
|
assert a.naechste_frist == heute + timedelta(days=5)
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_naechste_frist_none_when_past():
|
|
from datetime import date, timedelta
|
|
gestern = date.today() - timedelta(days=1)
|
|
a = AusschreibungFactory(bieterfragen_bis=gestern, abgabe_bis=None)
|
|
assert a.naechste_frist is None
|
|
|
|
|
|
# --- View tests ---
|
|
|
|
@pytest.mark.django_db
|
|
def test_liste_get(admitted_client):
|
|
response = admitted_client.get(reverse("ausschreibungen:liste"))
|
|
assert response.status_code == 200
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_neu_get(admitted_client):
|
|
response = admitted_client.get(reverse("ausschreibungen:neu"))
|
|
assert response.status_code == 200
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_neu_post_valid(admitted_client):
|
|
data = {"titel": "Neue Ausschreibung", "ausschreiber": "Stadt XY"}
|
|
response = admitted_client.post(reverse("ausschreibungen:neu"), data)
|
|
assert response.status_code == 302
|
|
a = Ausschreibung.objects.get(titel="Neue Ausschreibung")
|
|
assert response.url == reverse("ausschreibungen:detail", kwargs={"pk": a.pk})
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_detail_get(admitted_client):
|
|
a = AusschreibungFactory()
|
|
response = admitted_client.get(reverse("ausschreibungen:detail", kwargs={"pk": a.pk}))
|
|
assert response.status_code == 200
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_status_post(admitted_client):
|
|
a = AusschreibungFactory(status=1)
|
|
url = reverse("ausschreibungen:status", kwargs={"pk": a.pk})
|
|
response = admitted_client.post(url, {"status": "4"})
|
|
assert response.status_code == 200
|
|
a.refresh_from_db()
|
|
assert a.status == 4
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_status_htmx_returns_partial(admitted_client):
|
|
a = AusschreibungFactory(status=1)
|
|
url = reverse("ausschreibungen:status", kwargs={"pk": a.pk})
|
|
response = admitted_client.post(url, {"status": "3"}, HTTP_HX_REQUEST="true")
|
|
assert response.status_code == 200
|
|
assert b"status-widget" in response.content
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_dashboard_expiry_boundary(admitted_client):
|
|
from datetime import date, timedelta
|
|
|
|
from vergabe_teilnahme.apps.bibliothek.models import Nachweis
|
|
|
|
for title, days in [('Expired', -1), ('Boundary', 60), ('Later', 61)]:
|
|
Nachweis.objects.create(titel=title, gueltig_bis=date.today() + timedelta(days=days))
|
|
Nachweis.objects.create(titel='Undated')
|
|
response = admitted_client.get(reverse('ausschreibungen:dashboard'))
|
|
assert response.status_code == 200
|
|
assert [n.titel for n in response.context['ablaufende_nachweise']] == ['Expired', 'Boundary']
|
|
assert 'Boundary' in response.content.decode()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_list_search_combines_filters_and_htmx(admitted_client):
|
|
matching = AusschreibungFactory(titel='Network upgrade', ausschreiber='City', status=4)
|
|
AusschreibungFactory(titel='Other', ausschreiber='City', status=3)
|
|
AusschreibungFactory(titel='Archived', ausschreiber='City', status=4, archiviert=True)
|
|
for query in ['Network', 'City']:
|
|
response = admitted_client.get(reverse('ausschreibungen:liste'),
|
|
{'q': query, 'status': '4'}, HTTP_HX_REQUEST='true')
|
|
assert list(response.context['ausschreibungen']) == [matching]
|
|
assert 'ausschreibungen/liste_partial.html' in [t.name for t in response.templates]
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_historical_result_validation_and_save(admitted_client):
|
|
url = reverse('ausschreibungen:neu')
|
|
response = admitted_client.get(url, {'historisch': '1'})
|
|
assert 'name="ergebnis"' in response.content.decode()
|
|
data = {'titel': 'Historical award', 'ausschreiber': 'City',
|
|
'historisch_erfassen': '1', 'teilnahmeentscheidung': 'teilnahme',
|
|
'ergebnis': 'invalid'}
|
|
response = admitted_client.post(url, data)
|
|
assert response.status_code == 200
|
|
assert response.context['form'].errors['ergebnis']
|
|
assert not Ausschreibung.objects.filter(titel=data['titel']).exists()
|
|
data['ergebnis'] = 'gewonnen'
|
|
response = admitted_client.post(url, data)
|
|
assert response.status_code == 302
|
|
tender = Ausschreibung.objects.get(titel=data['titel'])
|
|
assert tender.nachbetrachtung.ergebnis == 'gewonnen'
|
|
assert tender.status == 10
|
|
assert tender.teilnahmeentscheidung == 'teilnahme'
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_global_search_tasks_partners_and_issuer(admitted_client):
|
|
from vergabe_teilnahme.apps.aufgaben.models import Aufgabe
|
|
from vergabe_teilnahme.apps.partner.models import Subunternehmer
|
|
|
|
tender = AusschreibungFactory(titel='Tender', ausschreiber='UniqueIssuer')
|
|
task = Aufgabe.objects.create(titel='UniqueTask', ausschreibung=tender)
|
|
partner = Subunternehmer.objects.create(name='UniquePartner')
|
|
cases = [
|
|
('UniqueIssuer', reverse('ausschreibungen:detail', kwargs={'pk': tender.pk})),
|
|
('UniqueTask', reverse('ausschreibungen:aufgaben:detail',
|
|
kwargs={'ausschreibung_id': tender.pk, 'pk': task.pk})),
|
|
('UniquePartner', reverse('partner:su_detail', kwargs={'pk': partner.pk})),
|
|
]
|
|
for query, target in cases:
|
|
response = admitted_client.get('/suche/', {'q': query})
|
|
assert response.status_code == 200
|
|
assert f'href="{target}"' in response.content.decode()
|
|
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_inline_status_with_rendered_csrf_header(mitarbeiter):
|
|
import json
|
|
import re
|
|
|
|
from django.test import Client
|
|
|
|
client = Client(enforce_csrf_checks=True)
|
|
client.force_login(mitarbeiter)
|
|
tender = AusschreibungFactory(status=1)
|
|
response = client.get(reverse('ausschreibungen:detail', kwargs={'pk': tender.pk}))
|
|
headers = json.loads(re.search(r"hx-headers='([^']+)'", response.content.decode())[1])
|
|
url = reverse('ausschreibungen:status', kwargs={'pk': tender.pk})
|
|
assert client.post(url, {'status': '4'}).status_code == 403
|
|
response = client.post(url, {'status': '4'}, HTTP_HX_REQUEST='true',
|
|
HTTP_X_CSRFTOKEN=headers['X-CSRFToken'])
|
|
assert response.status_code == 200
|
|
tender.refresh_from_db()
|
|
assert tender.status == 4
|