"""Tests for contact router (T05).""" import pytest from unittest.mock import AsyncMock, patch, MagicMock from sqlalchemy import select from app.models.contact import Contact @pytest.mark.asyncio async def test_contact_valid_returns_200(client): """POST /api/contact with valid data returns 200 and saves to contacts table.""" with patch( "app.services.email_service.EmailService.send_contact_email", new_callable=AsyncMock, return_value=True, ): resp = await client.post("/api/contact", json={ "name": "Max Mustermann", "email": "max@example.com", "phone": "+49 123 456789", "message": "Ich brauche eine PA-Anlage fuer ein Festival.", "privacy_consent": True, }) assert resp.status_code == 200 data = resp.json() assert data["success"] is True @pytest.mark.asyncio async def test_contact_invalid_email_returns_422(client): """POST /api/contact with invalid email returns 422.""" resp = await client.post("/api/contact", json={ "name": "Max Mustermann", "email": "not-an-email", "phone": "+49 123 456789", "message": "Test message", "privacy_consent": True, }) assert resp.status_code == 422 @pytest.mark.asyncio async def test_contact_privacy_consent_false_returns_422(client): """POST /api/contact with privacy_consent=false returns 422.""" resp = await client.post("/api/contact", json={ "name": "Max Mustermann", "email": "max@example.com", "phone": "+49 123 456789", "message": "Test message", "privacy_consent": False, }) assert resp.status_code == 422 @pytest.mark.asyncio async def test_contact_triggers_email(client): """POST /api/contact triggers send_contact_email on EmailService.""" with patch( "app.services.email_service.EmailService.send_contact_email", new_callable=AsyncMock, return_value=True, ) as mock_send: resp = await client.post("/api/contact", json={ "name": "Erika Musterfrau", "email": "erika@example.com", "phone": "+49 987 654321", "message": "Ich benoetige Beleuchtung fuer eine Gala.", "privacy_consent": True, }) assert resp.status_code == 200 mock_send.assert_awaited_once() call_args = mock_send.call_args[0][0] assert call_args["name"] == "Erika Musterfrau" assert call_args["email"] == "erika@example.com" assert call_args["message"] == "Ich benoetige Beleuchtung fuer eine Gala." @pytest.mark.asyncio async def test_contact_saved_to_db(client, test_db): """POST /api/contact saves a record to the contacts table.""" with patch( "app.services.email_service.EmailService.send_contact_email", new_callable=AsyncMock, return_value=True, ): resp = await client.post("/api/contact", json={ "name": "DB Testuser", "email": "db@example.com", "phone": "+49 111 222333", "message": "Datenbank-Verifikation", "privacy_consent": True, }) assert resp.status_code == 200 result = await test_db.execute(select(Contact).where(Contact.email == "db@example.com")) contact = result.scalar_one_or_none() assert contact is not None assert contact.name == "DB Testuser" assert contact.message == "Datenbank-Verifikation" assert contact.privacy_consent is True assert contact.email_sent is True @pytest.mark.asyncio async def test_contact_email_failure_does_not_break_response(client): """POST /api/contact still returns 200 when email sending fails.""" with patch( "app.services.email_service.EmailService.send_contact_email", new_callable=AsyncMock, return_value=False, ): resp = await client.post("/api/contact", json={ "name": "Fail Test", "email": "fail@example.com", "phone": "+49 000 000000", "message": "Email soll fehlschlagen", "privacy_consent": True, }) assert resp.status_code == 200 assert resp.json()["success"] is True