mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 21:11:11 -05:00
Add test utilities and state machine diagrams for FSM models
- Introduced reusable test utilities in `backend/tests/utils` for FSM transitions, HTMX interactions, and common scenarios. - Added factory functions for creating test submissions, parks, rides, and photo submissions. - Implemented assertion helpers for verifying state changes, toast notifications, and transition logs. - Created comprehensive state machine diagrams for all FSM-enabled models in `docs/STATE_DIAGRAMS.md`, detailing states, transitions, and guard conditions.
This commit is contained in:
@@ -34,10 +34,10 @@ def setup_page(page: Page):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def auth_page(page: Page):
|
||||
def auth_page(page: Page, live_server):
|
||||
"""Fixture for authenticated page"""
|
||||
# Login
|
||||
page.goto("http://localhost:8000/accounts/login/")
|
||||
# Login using live_server URL
|
||||
page.goto(f"{live_server.url}/accounts/login/")
|
||||
page.get_by_label("Username").fill("testuser")
|
||||
page.get_by_label("Password").fill("testpass123")
|
||||
page.get_by_role("button", name="Sign In").click()
|
||||
@@ -46,10 +46,10 @@ def auth_page(page: Page):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mod_page(page: Page):
|
||||
def mod_page(page: Page, live_server):
|
||||
"""Fixture for moderator page"""
|
||||
# Login as moderator
|
||||
page.goto("http://localhost:8000/accounts/login/")
|
||||
# Login as moderator using live_server URL
|
||||
page.goto(f"{live_server.url}/accounts/login/")
|
||||
page.get_by_label("Username").fill("moderator")
|
||||
page.get_by_label("Password").fill("modpass123")
|
||||
page.get_by_role("button", name="Sign In").click()
|
||||
@@ -58,10 +58,10 @@ def mod_page(page: Page):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_park(auth_page: Page):
|
||||
def test_park(auth_page: Page, live_server):
|
||||
"""Fixture for test park"""
|
||||
# Create test park
|
||||
auth_page.goto("http://localhost:8000/parks/create/")
|
||||
# Create test park using live_server URL
|
||||
auth_page.goto(f"{live_server.url}/parks/create/")
|
||||
auth_page.get_by_label("Name").fill("Test Park")
|
||||
auth_page.get_by_label("Location").fill("Orlando, FL")
|
||||
auth_page.get_by_label("Description").fill("A test theme park")
|
||||
@@ -72,10 +72,10 @@ def test_park(auth_page: Page):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_ride(test_park: Page):
|
||||
def test_ride(test_park: Page, live_server):
|
||||
"""Fixture for test ride"""
|
||||
# Create test ride
|
||||
test_park.goto("http://localhost:8000/rides/create/")
|
||||
# Create test ride using live_server URL
|
||||
test_park.goto(f"{live_server.url}/rides/create/")
|
||||
test_park.get_by_label("Name").fill("Test Ride")
|
||||
test_park.get_by_label("Park").select_option("Test Park")
|
||||
test_park.get_by_label("Type").select_option("Roller Coaster")
|
||||
@@ -87,10 +87,10 @@ def test_ride(test_park: Page):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_review(test_park: Page):
|
||||
def test_review(test_park: Page, live_server):
|
||||
"""Fixture for test review"""
|
||||
# Create test review
|
||||
test_park.goto("http://localhost:8000/parks/test-park/")
|
||||
# Create test review using live_server URL
|
||||
test_park.goto(f"{live_server.url}/parks/test-park/")
|
||||
test_park.get_by_role("tab", name="Reviews").click()
|
||||
test_park.get_by_role("button", name="Write Review").click()
|
||||
test_park.get_by_label("Rating").select_option("5")
|
||||
@@ -99,3 +99,310 @@ def test_review(test_park: Page):
|
||||
test_park.get_by_role("button", name="Submit Review").click()
|
||||
|
||||
yield test_park
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# FSM Testing Fixtures
|
||||
# =============================================================================
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def admin_page(page: Page, live_server):
|
||||
"""Fixture for admin/superuser page"""
|
||||
# Login as admin using live_server URL
|
||||
page.goto(f"{live_server.url}/accounts/login/")
|
||||
page.get_by_label("Username").fill("admin")
|
||||
page.get_by_label("Password").fill("adminpass123")
|
||||
page.get_by_role("button", name="Sign In").click()
|
||||
|
||||
yield page
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def submission_pending(db):
|
||||
"""Create a pending EditSubmission for FSM testing."""
|
||||
from django.contrib.auth import get_user_model
|
||||
from apps.moderation.models import EditSubmission
|
||||
from apps.parks.models import Park
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
# Get or create test user
|
||||
user, _ = User.objects.get_or_create(
|
||||
username="fsm_test_submitter",
|
||||
defaults={"email": "fsm_test@example.com"}
|
||||
)
|
||||
user.set_password("testpass123")
|
||||
user.save()
|
||||
|
||||
# Get a park
|
||||
park = Park.objects.first()
|
||||
if not park:
|
||||
pytest.skip("No parks available for testing")
|
||||
|
||||
content_type = ContentType.objects.get_for_model(Park)
|
||||
|
||||
submission = EditSubmission.objects.create(
|
||||
user=user,
|
||||
content_type=content_type,
|
||||
object_id=park.pk,
|
||||
submission_type="EDIT",
|
||||
changes={"description": "FSM test submission"},
|
||||
reason="FSM e2e test",
|
||||
status="PENDING"
|
||||
)
|
||||
|
||||
yield submission
|
||||
|
||||
# Cleanup
|
||||
try:
|
||||
submission.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def submission_approved(db):
|
||||
"""Create an approved EditSubmission for FSM testing."""
|
||||
from django.contrib.auth import get_user_model
|
||||
from apps.moderation.models import EditSubmission
|
||||
from apps.parks.models import Park
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
user, _ = User.objects.get_or_create(
|
||||
username="fsm_test_submitter_approved",
|
||||
defaults={"email": "fsm_approved@example.com"}
|
||||
)
|
||||
|
||||
park = Park.objects.first()
|
||||
if not park:
|
||||
pytest.skip("No parks available for testing")
|
||||
|
||||
content_type = ContentType.objects.get_for_model(Park)
|
||||
|
||||
submission = EditSubmission.objects.create(
|
||||
user=user,
|
||||
content_type=content_type,
|
||||
object_id=park.pk,
|
||||
submission_type="EDIT",
|
||||
changes={"description": "Already approved"},
|
||||
reason="FSM approved test",
|
||||
status="APPROVED"
|
||||
)
|
||||
|
||||
yield submission
|
||||
|
||||
try:
|
||||
submission.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def park_operating(db):
|
||||
"""Create an operating Park for FSM testing."""
|
||||
from tests.factories import ParkFactory
|
||||
|
||||
park = ParkFactory(
|
||||
name="FSM Test Park Operating",
|
||||
slug="fsm-test-park-operating",
|
||||
status="OPERATING"
|
||||
)
|
||||
|
||||
yield park
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def park_closed_temp(db):
|
||||
"""Create a temporarily closed Park for FSM testing."""
|
||||
from tests.factories import ParkFactory
|
||||
|
||||
park = ParkFactory(
|
||||
name="FSM Test Park Closed Temp",
|
||||
slug="fsm-test-park-closed-temp",
|
||||
status="CLOSED_TEMP"
|
||||
)
|
||||
|
||||
yield park
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def park_closed_perm(db):
|
||||
"""Create a permanently closed Park for FSM testing."""
|
||||
from tests.factories import ParkFactory
|
||||
from datetime import date, timedelta
|
||||
|
||||
park = ParkFactory(
|
||||
name="FSM Test Park Closed Perm",
|
||||
slug="fsm-test-park-closed-perm",
|
||||
status="CLOSED_PERM",
|
||||
closing_date=date.today() - timedelta(days=365)
|
||||
)
|
||||
|
||||
yield park
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ride_operating(db, park_operating):
|
||||
"""Create an operating Ride for FSM testing."""
|
||||
from tests.factories import RideFactory
|
||||
|
||||
ride = RideFactory(
|
||||
name="FSM Test Ride Operating",
|
||||
slug="fsm-test-ride-operating",
|
||||
park=park_operating,
|
||||
status="OPERATING"
|
||||
)
|
||||
|
||||
yield ride
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ride_sbno(db, park_operating):
|
||||
"""Create an SBNO Ride for FSM testing."""
|
||||
from tests.factories import RideFactory
|
||||
|
||||
ride = RideFactory(
|
||||
name="FSM Test Ride SBNO",
|
||||
slug="fsm-test-ride-sbno",
|
||||
park=park_operating,
|
||||
status="SBNO"
|
||||
)
|
||||
|
||||
yield ride
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ride_closed_perm(db, park_operating):
|
||||
"""Create a permanently closed Ride for FSM testing."""
|
||||
from tests.factories import RideFactory
|
||||
from datetime import date, timedelta
|
||||
|
||||
ride = RideFactory(
|
||||
name="FSM Test Ride Closed Perm",
|
||||
slug="fsm-test-ride-closed-perm",
|
||||
park=park_operating,
|
||||
status="CLOSED_PERM",
|
||||
closing_date=date.today() - timedelta(days=365)
|
||||
)
|
||||
|
||||
yield ride
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def queue_item_pending(db):
|
||||
"""Create a pending ModerationQueue item for FSM testing."""
|
||||
from django.contrib.auth import get_user_model
|
||||
from apps.moderation.models import ModerationQueue
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
user, _ = User.objects.get_or_create(
|
||||
username="fsm_queue_flagger",
|
||||
defaults={"email": "fsm_queue@example.com"}
|
||||
)
|
||||
|
||||
queue_item = ModerationQueue.objects.create(
|
||||
item_type="CONTENT_REVIEW",
|
||||
status="PENDING",
|
||||
priority="MEDIUM",
|
||||
title="FSM Test Queue Item",
|
||||
description="Queue item for FSM e2e testing",
|
||||
flagged_by=user
|
||||
)
|
||||
|
||||
yield queue_item
|
||||
|
||||
try:
|
||||
queue_item.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def bulk_operation_pending(db):
|
||||
"""Create a pending BulkOperation for FSM testing."""
|
||||
from django.contrib.auth import get_user_model
|
||||
from apps.moderation.models import BulkOperation
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
user, _ = User.objects.get_or_create(
|
||||
username="fsm_bulk_creator",
|
||||
defaults={"email": "fsm_bulk@example.com", "is_staff": True}
|
||||
)
|
||||
|
||||
operation = BulkOperation.objects.create(
|
||||
operation_type="IMPORT",
|
||||
status="PENDING",
|
||||
priority="MEDIUM",
|
||||
description="FSM Test Bulk Operation",
|
||||
parameters={"test": True},
|
||||
created_by=user,
|
||||
total_items=10
|
||||
)
|
||||
|
||||
yield operation
|
||||
|
||||
try:
|
||||
operation.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Helper Fixtures
|
||||
# =============================================================================
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def live_server(live_server_url):
|
||||
"""Provide the live server URL for tests.
|
||||
|
||||
Note: This fixture is provided by pytest-django. The live_server_url
|
||||
fixture provides the URL as a string.
|
||||
"""
|
||||
class LiveServer:
|
||||
url = live_server_url
|
||||
|
||||
return LiveServer()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def moderator_user(db):
|
||||
"""Get or create a moderator user for testing."""
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
user, _ = User.objects.get_or_create(
|
||||
username="moderator",
|
||||
defaults={
|
||||
"email": "moderator@example.com",
|
||||
"is_staff": True
|
||||
}
|
||||
)
|
||||
user.set_password("modpass123")
|
||||
user.save()
|
||||
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def regular_user(db):
|
||||
"""Get or create a regular user for testing."""
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
user, _ = User.objects.get_or_create(
|
||||
username="testuser",
|
||||
defaults={"email": "testuser@example.com"}
|
||||
)
|
||||
user.set_password("testpass123")
|
||||
user.save()
|
||||
|
||||
return user
|
||||
|
||||
Reference in New Issue
Block a user