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:
pacnpal
2025-12-22 08:55:39 -05:00
parent b508434574
commit 45d97b6e68
71 changed files with 8608 additions and 633 deletions

View File

@@ -1,6 +1,7 @@
from django.urls import path, include
from . import views, views_search
from apps.rides.views import ParkSingleCategoryListView
from apps.core.views.views import FSMTransitionView
from .views_roadtrip import (
RoadTripPlannerView,
CreateTripView,
@@ -99,6 +100,8 @@ urlpatterns = [
path("<slug:slug>/", views.ParkDetailView.as_view(), name="park_detail"),
path("<slug:slug>/edit/", views.ParkUpdateView.as_view(), name="park_update"),
path("<slug:slug>/actions/", views.park_actions, name="park_actions"),
path("<slug:slug>/status-actions/", views.park_status_actions, name="park_status_actions"),
path("<slug:slug>/header-badge/", views.park_header_badge, name="park_header_badge"),
# Area views
path(
"<slug:park_slug>/areas/<slug:area_slug>/",
@@ -147,4 +150,12 @@ urlpatterns = [
"<slug:park_slug>/rides/",
include("apps.rides.park_urls", namespace="rides"),
),
# FSM transition endpoint for parks
# URL: /parks/<slug>/transition/<transition_name>/
path(
"<slug:slug>/transition/<str:transition_name>/",
FSMTransitionView.as_view(),
{"app_label": "parks", "model_name": "park"},
name="park_transition",
),
]

View File

@@ -132,6 +132,29 @@ def park_actions(request: HttpRequest, slug: str) -> HttpResponse:
return render(request, "parks/partials/park_actions.html", {"park": park})
def park_status_actions(request: HttpRequest, slug: str) -> HttpResponse:
"""Return FSM status actions for park moderators"""
park = get_object_or_404(Park, slug=slug)
# Only show to moderators
if not request.user.has_perm('parks.change_park'):
return HttpResponse("")
return render(request, "parks/partials/park_status_actions.html", {
"park": park,
"user": request.user
})
def park_header_badge(request: HttpRequest, slug: str) -> HttpResponse:
"""Return the header status badge partial for a park"""
park = get_object_or_404(Park, slug=slug)
return render(request, "parks/partials/park_header_badge.html", {
"park": park,
"user": request.user
})
def get_park_areas(request: HttpRequest) -> HttpResponse:
"""Return park areas as options for a select element"""
park_id = request.GET.get("park")