"""Integration tests for Story 2.3: View Exchange Details.""" from datetime import datetime, timedelta from src.models import Exchange class TestViewExchangeDetails: """Test cases for viewing exchange details (Story 2.3).""" def test_view_exchange_details_page(self, client, db, admin): # noqa: ARG002 """Test that exchange detail page loads. Acceptance Criteria: - Clicking an exchange opens detail view """ # Login first client.post( "/admin/login", data={ "email": "admin@example.com", "password": "testpassword123", }, follow_redirects=True, ) # Create an exchange future_close_date = datetime.utcnow() + timedelta(days=7) future_exchange_date = datetime.utcnow() + timedelta(days=14) exchange = Exchange( slug=Exchange.generate_slug(), name="Test Exchange", description="Test description", budget="$20-30", max_participants=10, registration_close_date=future_close_date, exchange_date=future_exchange_date, timezone="America/New_York", state=Exchange.STATE_DRAFT, ) db.session.add(exchange) db.session.commit() # View exchange details response = client.get(f"/admin/exchange/{exchange.id}") assert response.status_code == 200 def test_exchange_details_shows_all_information(self, client, db, admin): # noqa: ARG002 """Test that all exchange information is displayed. Acceptance Criteria: - Shows all exchange information """ # Login first client.post( "/admin/login", data={ "email": "admin@example.com", "password": "testpassword123", }, follow_redirects=True, ) # Create an exchange with all fields future_close_date = datetime.utcnow() + timedelta(days=7) future_exchange_date = datetime.utcnow() + timedelta(days=14) exchange = Exchange( slug=Exchange.generate_slug(), name="Family Christmas 2025", description="Annual family gift exchange", budget="$20-30", max_participants=20, registration_close_date=future_close_date, exchange_date=future_exchange_date, timezone="America/New_York", state=Exchange.STATE_REGISTRATION_OPEN, ) db.session.add(exchange) db.session.commit() # View exchange details response = client.get(f"/admin/exchange/{exchange.id}") assert response.status_code == 200 # Verify all exchange information is displayed assert b"Family Christmas 2025" in response.data assert b"Annual family gift exchange" in response.data assert b"$20-30" in response.data assert b"20" in response.data # max_participants assert b"America/New_York" in response.data assert b"registration_open" in response.data def test_exchange_details_shows_current_state(self, client, db, admin): # noqa: ARG002 """Test that current state is displayed. Acceptance Criteria: - Shows current state """ # Login first client.post( "/admin/login", data={ "email": "admin@example.com", "password": "testpassword123", }, follow_redirects=True, ) # Create exchanges in different states future_close_date = datetime.utcnow() + timedelta(days=7) future_exchange_date = datetime.utcnow() + timedelta(days=14) draft_exchange = Exchange( slug=Exchange.generate_slug(), name="Draft Exchange", budget="$20-30", max_participants=10, registration_close_date=future_close_date, exchange_date=future_exchange_date, timezone="America/New_York", state=Exchange.STATE_DRAFT, ) db.session.add(draft_exchange) db.session.commit() # View details response = client.get(f"/admin/exchange/{draft_exchange.id}") assert response.status_code == 200 assert b"draft" in response.data def test_exchange_details_shows_registration_link(self, client, db, admin): # noqa: ARG002 """Test that registration link is shown. Acceptance Criteria: - Shows registration link (when applicable) """ # Login first client.post( "/admin/login", data={ "email": "admin@example.com", "password": "testpassword123", }, follow_redirects=True, ) # Create an exchange future_close_date = datetime.utcnow() + timedelta(days=7) future_exchange_date = datetime.utcnow() + timedelta(days=14) exchange = Exchange( slug=Exchange.generate_slug(), name="Test Exchange", budget="$20-30", max_participants=10, registration_close_date=future_close_date, exchange_date=future_exchange_date, timezone="America/New_York", state=Exchange.STATE_DRAFT, ) db.session.add(exchange) db.session.commit() # View exchange details response = client.get(f"/admin/exchange/{exchange.id}") assert response.status_code == 200 # Verify registration link is displayed with the exchange slug assert exchange.slug.encode() in response.data assert b"/exchange/" in response.data assert b"/register" in response.data def test_exchange_details_shows_participant_list(self, client, db, admin): # noqa: ARG002 """Test that participant list is shown (empty initially). Acceptance Criteria: - Shows list of registered participants """ # Login first client.post( "/admin/login", data={ "email": "admin@example.com", "password": "testpassword123", }, follow_redirects=True, ) # Create an exchange future_close_date = datetime.utcnow() + timedelta(days=7) future_exchange_date = datetime.utcnow() + timedelta(days=14) exchange = Exchange( slug=Exchange.generate_slug(), name="Test Exchange", budget="$20-30", max_participants=10, registration_close_date=future_close_date, exchange_date=future_exchange_date, timezone="America/New_York", state=Exchange.STATE_DRAFT, ) db.session.add(exchange) db.session.commit() # View exchange details response = client.get(f"/admin/exchange/{exchange.id}") assert response.status_code == 200 # Verify participant section exists assert b"Participants" in response.data or b"participants" in response.data # Since no participants yet, should show empty message assert ( b"No participants yet" in response.data or b"no participants" in response.data.lower() ) def test_exchange_details_not_found(self, client, db, admin): # noqa: ARG002 """Test that 404 is returned for non-existent exchange. Acceptance Criteria: - Handle non-existent exchange gracefully """ # Login first client.post( "/admin/login", data={ "email": "admin@example.com", "password": "testpassword123", }, follow_redirects=True, ) # Try to view non-existent exchange response = client.get("/admin/exchange/99999") assert response.status_code == 404 def test_exchange_details_handles_missing_description(self, client, db, admin): # noqa: ARG002 """Test that missing optional fields are handled gracefully. Acceptance Criteria: - Shows all exchange information - Handle optional fields (description) """ # Login first client.post( "/admin/login", data={ "email": "admin@example.com", "password": "testpassword123", }, follow_redirects=True, ) # Create exchange without description future_close_date = datetime.utcnow() + timedelta(days=7) future_exchange_date = datetime.utcnow() + timedelta(days=14) exchange = Exchange( slug=Exchange.generate_slug(), name="Test Exchange", description=None, # No description budget="$20-30", max_participants=10, registration_close_date=future_close_date, exchange_date=future_exchange_date, timezone="America/New_York", state=Exchange.STATE_DRAFT, ) db.session.add(exchange) db.session.commit() # View exchange details response = client.get(f"/admin/exchange/{exchange.id}") assert response.status_code == 200 # Should handle missing description gracefully assert ( b"No description" in response.data or b"no description" in response.data.lower() ) def test_exchange_details_navigation(self, client, db, admin): # noqa: ARG002 """Test that navigation back to dashboard exists. Acceptance Criteria: - Provide navigation back to dashboard """ # Login first client.post( "/admin/login", data={ "email": "admin@example.com", "password": "testpassword123", }, follow_redirects=True, ) # Create an exchange future_close_date = datetime.utcnow() + timedelta(days=7) future_exchange_date = datetime.utcnow() + timedelta(days=14) exchange = Exchange( slug=Exchange.generate_slug(), name="Test Exchange", budget="$20-30", max_participants=10, registration_close_date=future_close_date, exchange_date=future_exchange_date, timezone="America/New_York", state=Exchange.STATE_DRAFT, ) db.session.add(exchange) db.session.commit() # View exchange details response = client.get(f"/admin/exchange/{exchange.id}") assert response.status_code == 200 # Verify back link to dashboard exists assert b"dashboard" in response.data.lower() or b"back" in response.data.lower()