test: add feedback endpoint tests including DB persistence
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
128
backend/tests/test_feedback.py
Normal file
128
backend/tests/test_feedback.py
Normal file
@@ -0,0 +1,128 @@
|
||||
import pytest
|
||||
from unittest.mock import patch, AsyncMock
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_submit_feedback(client, auth_headers):
|
||||
"""Test successful feedback submission — saves to DB and sends emails."""
|
||||
with patch("app.api.endpoints.feedback.settings") as mock_settings, \
|
||||
patch("app.api.endpoints.feedback.EmailService") as mock_email:
|
||||
mock_settings.FEEDBACK_EMAIL = "support@test.com"
|
||||
mock_email.send_feedback_email = AsyncMock(return_value=True)
|
||||
mock_email.send_feedback_confirmation_email = AsyncMock(return_value=True)
|
||||
|
||||
response = await client.post(
|
||||
"/api/v1/feedback",
|
||||
json={
|
||||
"email": "test@example.com",
|
||||
"feedback_type": "Bug Report",
|
||||
"message": "Something is broken in the tree editor when I try to save.",
|
||||
},
|
||||
headers=auth_headers,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["success"] is True
|
||||
assert "submitted" in data["message"].lower()
|
||||
|
||||
# Verify both emails were called
|
||||
mock_email.send_feedback_email.assert_called_once()
|
||||
mock_email.send_feedback_confirmation_email.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_submit_feedback_saves_to_db_even_if_email_fails(client, auth_headers, test_db):
|
||||
"""Test that feedback is persisted even when email sending fails."""
|
||||
from sqlalchemy import select, func
|
||||
from app.models.feedback import Feedback
|
||||
|
||||
with patch("app.api.endpoints.feedback.settings") as mock_settings, \
|
||||
patch("app.api.endpoints.feedback.EmailService") as mock_email:
|
||||
mock_settings.FEEDBACK_EMAIL = "support@test.com"
|
||||
mock_email.send_feedback_email = AsyncMock(return_value=False)
|
||||
mock_email.send_feedback_confirmation_email = AsyncMock(return_value=False)
|
||||
|
||||
response = await client.post(
|
||||
"/api/v1/feedback",
|
||||
json={
|
||||
"email": "test@example.com",
|
||||
"feedback_type": "Feature Request",
|
||||
"message": "Please add dark mode to the export preview screen.",
|
||||
},
|
||||
headers=auth_headers,
|
||||
)
|
||||
|
||||
# Should still succeed — DB write happened
|
||||
assert response.status_code == 200
|
||||
assert response.json()["success"] is True
|
||||
|
||||
# Verify it was saved to the database
|
||||
result = await test_db.execute(select(func.count()).select_from(Feedback))
|
||||
count = result.scalar()
|
||||
assert count >= 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_submit_feedback_not_configured(client, auth_headers):
|
||||
"""Test 503 when FEEDBACK_EMAIL is not set."""
|
||||
with patch("app.api.endpoints.feedback.settings") as mock_settings:
|
||||
mock_settings.FEEDBACK_EMAIL = None
|
||||
|
||||
response = await client.post(
|
||||
"/api/v1/feedback",
|
||||
json={
|
||||
"email": "test@example.com",
|
||||
"feedback_type": "General Feedback",
|
||||
"message": "This is a general feedback message for testing.",
|
||||
},
|
||||
headers=auth_headers,
|
||||
)
|
||||
|
||||
assert response.status_code == 503
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_submit_feedback_validation_message_too_short(client, auth_headers):
|
||||
"""Test validation — message too short."""
|
||||
response = await client.post(
|
||||
"/api/v1/feedback",
|
||||
json={
|
||||
"email": "test@example.com",
|
||||
"feedback_type": "Bug Report",
|
||||
"message": "short",
|
||||
},
|
||||
headers=auth_headers,
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_submit_feedback_invalid_type(client, auth_headers):
|
||||
"""Test validation — invalid feedback type."""
|
||||
response = await client.post(
|
||||
"/api/v1/feedback",
|
||||
json={
|
||||
"email": "test@example.com",
|
||||
"feedback_type": "Invalid Type",
|
||||
"message": "This should fail because the type is invalid.",
|
||||
},
|
||||
headers=auth_headers,
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_submit_feedback_requires_auth(client):
|
||||
"""Test that unauthenticated requests are rejected."""
|
||||
response = await client.post(
|
||||
"/api/v1/feedback",
|
||||
json={
|
||||
"email": "anon@example.com",
|
||||
"feedback_type": "General Feedback",
|
||||
"message": "This should fail because I'm not logged in.",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 401
|
||||
Reference in New Issue
Block a user