feat: add comprehensive tests for Story 2.3 View Exchange Details
Add integration tests covering all acceptance criteria: - Clicking an exchange opens detail view - Shows all exchange information - Shows list of registered participants - Shows current state - Shows registration link (when applicable) - Handle missing optional fields gracefully - Navigation back to dashboard Story: 2.3 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
330
tests/integration/test_view_exchange_details.py
Normal file
330
tests/integration/test_view_exchange_details.py
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
"""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()
|
||||||
Reference in New Issue
Block a user