diff --git a/backend/tests/api/routes/test_event_themes.py b/backend/tests/api/routes/test_event_themes.py new file mode 100644 index 0000000..20c3ac1 --- /dev/null +++ b/backend/tests/api/routes/test_event_themes.py @@ -0,0 +1,274 @@ +import uuid +from typing import Dict +import pytest +from fastapi import FastAPI +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from app.api.routes.event_themes import router as event_themes_router +from app.core.database import get_db +from app.main import app as main_app + + +# Mock the get_db dependency +@pytest.fixture +def override_get_db(db_session): + """Override get_db dependency for testing.""" + return db_session + +@pytest.fixture +def app(override_get_db): + """Create a FastAPI test application with overridden dependencies.""" + app = FastAPI() + app.include_router(event_themes_router, prefix="/event_themes", tags=["event_themes"]) + + # Override the get_db dependency + app.dependency_overrides[get_db] = lambda: override_get_db + + return app + +@pytest.fixture +def client(app: FastAPI) -> TestClient: + return TestClient(app) + + +@pytest.fixture +def theme_data() -> Dict: + return { + "name": "Animal Safari", + "description": "A wild and fun theme with safari animals", + "preview_image_url": "https://example.com/safari.jpg", + "color_palette": { + "primary": "#f4a261", + "secondary": "#2a9d8f", + "background": "#ffffff", + "text": "#264653" + }, + "fonts": { + "header": "Safari Display", + "body": "Nunito Sans" + } + } + + +class TestEventThemesRoutes: + def test_create_theme_success(self, client, db_session, theme_data): + # Act + response = client.post("/event_themes", json=theme_data) + + # Assert + assert response.status_code == 200 + data = response.json() + assert data["name"] == theme_data["name"] + assert data["description"] == theme_data["description"] + assert data["preview_image_url"] == theme_data["preview_image_url"] + assert data["color_palette"] == theme_data["color_palette"] + assert data["fonts"] == theme_data["fonts"] + assert "id" in data + + def test_create_theme_invalid_data(self, client, db_session): + # Arrange + invalid_data = { + "name": "", # Empty name should not be allowed + "color_palette": {}, # Empty color palette + "fonts": {} # Empty fonts + } + + # Act + response = client.post("/event_themes", json=invalid_data) + + print(response.json()) + + # Assert + assert response.status_code == 422 + + def test_list_themes_empty(self, client, db_session): + # Act + response = client.get("/event_themes") + + # Assert + assert response.status_code == 200 + assert response.json() == [] + + def test_list_themes_with_data(self, client, db_session, theme_data): + # Arrange + create_response = client.post("/event_themes", json=theme_data) + assert create_response.status_code == 200 + + # Act + response = client.get("/event_themes") + + # Assert + assert response.status_code == 200 + themes = response.json() + assert len(themes) == 1 + assert themes[0]["name"] == theme_data["name"] + assert "id" in themes[0] + + def test_get_theme_by_id(self, client, db_session, theme_data): + # Arrange + create_response = client.post("/event_themes", json=theme_data) + assert create_response.status_code == 200 + created_theme = create_response.json() + + # Act + response = client.get(f"/event_themes/{created_theme['id']}") + + # Assert + assert response.status_code == 200 + data = response.json() + assert data["name"] == theme_data["name"] + assert data["color_palette"] == theme_data["color_palette"] + assert data["fonts"] == theme_data["fonts"] + assert data["id"] == created_theme["id"] + + def test_get_theme_not_found(self, client, db_session): + # Act + random_id = str(uuid.uuid4()) + response = client.get(f"/event_themes/{random_id}") + + # Assert + assert response.status_code == 404 + assert response.json()["detail"] == "Theme not found" + + def test_update_theme_success(self, client, db_session, theme_data): + # Arrange + create_response = client.post("/event_themes", json=theme_data) + assert create_response.status_code == 200 + created_theme = create_response.json() + + update_data = { + "name": "Updated Safari Theme", + "color_palette": { + "primary": "#ff0000", + "secondary": "#00ff00", + "background": "#ffffff", + "text": "#000000" + } + } + + # Act + response = client.patch( + f"/event_themes/{created_theme['id']}", + json=update_data + ) + + # Assert + assert response.status_code == 200 + data = response.json() + assert data["name"] == update_data["name"] + assert data["color_palette"] == update_data["color_palette"] + assert data["id"] == created_theme["id"] + # Original fonts should remain unchanged + assert data["fonts"] == theme_data["fonts"] + + def test_update_theme_not_found(self, client, db_session): + # Arrange + random_id = str(uuid.uuid4()) + update_data = { + "name": "Updated Theme" + } + + # Act + response = client.patch( + f"/event_themes/{random_id}", + json=update_data + ) + + # Assert + assert response.status_code == 404 + assert response.json()["detail"] == "Theme not found" + + def test_update_theme_invalid_data(self, client, db_session, theme_data): + # Act + response = client.post("/event_themes", json=theme_data) + + # Assert initial creation + assert response.status_code == 200 + theme = response.json() + assert "id" in theme + + # Act - update with invalid data + invalid_data = { + "color_palette": "not_a_dict" # Should be a dictionary + } + response = client.patch(f"/event_themes/{theme['id']}", json=invalid_data) + + # Assert + assert response.status_code == 422 + + + def test_list_themes_pagination(self, client, db_session, theme_data): + # Arrange + # Create multiple themes + for i in range(5): + theme_data_copy = theme_data.copy() + theme_data_copy["name"] = f"Theme {i}" + response = client.post("/event_themes", json=theme_data_copy) + assert response.status_code == 200 + + # Act + response = client.get("/event_themes?skip=2&limit=2") + + # Assert + assert response.status_code == 200 + themes = response.json() + assert len(themes) == 2 # Should only return 2 themes + assert themes[0]["name"] == "Theme 2" + assert themes[1]["name"] == "Theme 3" + assert all("id" in theme for theme in themes) + + def test_list_themes_default_pagination(self, client, db_session, theme_data): + # Arrange + # Create more than default limit themes + for i in range(15): # Reduced from 150 for faster testing + theme_data_copy = theme_data.copy() + theme_data_copy["name"] = f"Theme {i}" + response = client.post("/event_themes", json=theme_data_copy) + assert response.status_code == 200 + + # Act + response = client.get("/event_themes") + + # Assert + assert response.status_code == 200 + themes = response.json() + assert len(themes) <= 100 # Default limit is 100 + assert all("id" in theme for theme in themes) + + def test_update_theme_partial(self, client, db_session, theme_data): + # Arrange + create_response = client.post("/event_themes", json=theme_data) + assert create_response.status_code == 200 + created_theme = create_response.json() + + update_data = { + "name": "Partially Updated Theme" + } + + # Act + response = client.patch( + f"/event_themes/{created_theme['id']}", + json=update_data + ) + + # Assert + assert response.status_code == 200 + data = response.json() + assert data["name"] == update_data["name"] + assert data["id"] == created_theme["id"] + # Other fields should remain unchanged + assert data["color_palette"] == theme_data["color_palette"] + assert data["fonts"] == theme_data["fonts"] + + def test_create_theme_missing_required_fields(self, client, db_session): + # Arrange + incomplete_data = { + "description": "Missing required name field" + } + + # Act + response = client.post("/event_themes", json=incomplete_data) + + # Assert + assert response.status_code == 422 \ No newline at end of file diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index dc7ce12..2133004 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -1,6 +1,7 @@ # tests/conftest.py import uuid from datetime import datetime, timezone +from typing import Dict import pytest @@ -326,3 +327,23 @@ def gift_category_fixture(db_session, mock_user, event_fixture): db_session.add(gift_category) db_session.commit() return gift_category + + +@pytest.fixture +def theme_data() -> Dict: + return { + "name": "Animal Safari", + "description": "A wild and fun theme with safari animals", + "preview_image_url": "https://example.com/safari.jpg", + "color_palette": { + "primary": "#f4a261", + "secondary": "#2a9d8f", + "background": "#ffffff", + "text": "#264653" + }, + "fonts": { + "header": "Safari Display", + "body": "Nunito Sans" + } + } +