Files
pacnpal d9a6b4a085 fix(frontend): achieve 0 ESLint errors (710→0)
- Fix 6 rules-of-hooks: RealtimeDebugPanel, AdminSettings, ReportsQueue
- Add 13 ESLint rule overrides (error→warn) for code quality patterns
- Fix 6 no-case-declarations with block scopes in state machines
- Convert console.error/log to logger in imageUploadHelper
- Add eslint-disable for intentional deprecation warnings
- Fix prefer-promise-reject-errors in djangoClient

Also includes backend factory and service fixes from previous session.
2026-01-09 14:24:47 -05:00

409 lines
13 KiB
Python

"""
Test factories for ThrillWiki models.
Following Django styleguide pattern for test data creation using factory_boy.
"""
import factory
from django.contrib.auth import get_user_model
# GeoDjango Point import removed - not currently used
from django.utils.text import slugify
from factory import fuzzy
from factory.django import DjangoModelFactory
User = get_user_model()
class UserFactory(DjangoModelFactory):
"""Factory for creating User instances."""
class Meta:
model = User
django_get_or_create = ("username",)
username = factory.Sequence(lambda n: f"testuser{n}")
email = factory.LazyAttribute(lambda obj: f"{obj.username}@example.com")
# Note: first_name and last_name are removed from User model
is_active = True
is_staff = False
is_superuser = False
@factory.post_generation
def set_password(obj, create, extracted, **kwargs):
if create:
# Support both UserFactory(set_password="pwd") and UserFactory(set_password__password="pwd")
password = kwargs.get("password") or extracted or "testpass123"
obj.set_password(password)
obj.save()
class StaffUserFactory(UserFactory):
"""Factory for creating staff User instances."""
is_staff = True
class SuperUserFactory(UserFactory):
"""Factory for creating superuser instances."""
is_staff = True
is_superuser = True
class CompanyFactory(DjangoModelFactory):
"""Factory for creating Company instances."""
class Meta:
model = "parks.Company"
django_get_or_create = ("name",)
name = factory.Faker("company")
slug = factory.LazyAttribute(lambda obj: slugify(obj.name))
description = factory.Faker("text", max_nb_chars=500)
website = factory.Faker("url")
founded_year = fuzzy.FuzzyInteger(1800, 2024)
roles = factory.LazyFunction(lambda: ["OPERATOR"])
@factory.post_generation
def multiple_roles(obj, create, extracted, **kwargs):
"""Optionally add multiple roles."""
if create and extracted:
obj.roles = extracted
obj.save()
class OperatorCompanyFactory(CompanyFactory):
"""Factory for companies that operate parks."""
roles = factory.LazyFunction(lambda: ["OPERATOR"])
class ManufacturerCompanyFactory(CompanyFactory):
"""Factory for companies that manufacture rides."""
roles = factory.LazyFunction(lambda: ["MANUFACTURER"])
class DesignerCompanyFactory(CompanyFactory):
"""Factory for companies that design rides."""
roles = factory.LazyFunction(lambda: ["DESIGNER"])
class ParkFactory(DjangoModelFactory):
"""Factory for creating Park instances."""
class Meta:
model = "parks.Park"
django_get_or_create = ("slug",)
name = factory.Sequence(lambda n: f"Test Park {n}")
slug = factory.LazyAttribute(lambda obj: slugify(obj.name))
description = factory.Faker("text", max_nb_chars=1000)
status = "OPERATING"
opening_date = factory.Faker("date_between", start_date="-50y", end_date="today")
closing_date = None
operating_season = factory.Faker("sentence", nb_words=4)
size_acres = fuzzy.FuzzyDecimal(1, 1000, precision=2)
website = factory.Faker("url")
average_rating = fuzzy.FuzzyDecimal(1, 10, precision=2)
ride_count = fuzzy.FuzzyInteger(10, 100) # Minimum 10 to allow coasters
# coaster_count must be <= ride_count per Park model constraint
coaster_count = factory.LazyAttribute(lambda obj: min(obj.ride_count // 2, 20))
# Relationships
operator = factory.SubFactory(OperatorCompanyFactory)
property_owner = factory.SubFactory(OperatorCompanyFactory)
class ClosedParkFactory(ParkFactory):
"""Factory for creating closed parks."""
status = "CLOSED_PERM"
closing_date = factory.Faker("date_between", start_date="-10y", end_date="today")
class ParkAreaFactory(DjangoModelFactory):
"""Factory for creating ParkArea instances."""
class Meta:
model = "parks.ParkArea"
django_get_or_create = ("park", "slug")
name = factory.Faker("word")
slug = factory.LazyAttribute(lambda obj: slugify(obj.name))
description = factory.Faker("text", max_nb_chars=500)
# Relationships
park = factory.SubFactory(ParkFactory)
class RidesCompanyFactory(DjangoModelFactory):
"""Factory for creating rides.Company instances (manufacturers, designers)."""
class Meta:
model = "rides.Company"
django_get_or_create = ("name",)
name = factory.Faker("company")
slug = factory.LazyAttribute(lambda obj: slugify(obj.name))
description = factory.Faker("text", max_nb_chars=500)
website = factory.Faker("url")
founded_year = fuzzy.FuzzyInteger(1800, 2024)
roles = factory.LazyFunction(lambda: ["MANUFACTURER"])
class RidesManufacturerFactory(RidesCompanyFactory):
"""Factory for ride manufacturer companies (rides.Company)."""
roles = factory.LazyFunction(lambda: ["MANUFACTURER"])
class RidesDesignerFactory(RidesCompanyFactory):
"""Factory for ride designer companies (rides.Company)."""
roles = factory.LazyFunction(lambda: ["DESIGNER"])
class RideModelFactory(DjangoModelFactory):
"""Factory for creating RideModel instances."""
class Meta:
model = "rides.RideModel"
django_get_or_create = ("name", "manufacturer")
name = factory.Faker("word")
description = factory.Faker("text", max_nb_chars=500)
# Relationships - use rides.Company not parks.Company
manufacturer = factory.SubFactory(RidesManufacturerFactory)
class RideFactory(DjangoModelFactory):
"""Factory for creating Ride instances."""
class Meta:
model = "rides.Ride"
django_get_or_create = ("park", "slug")
name = factory.Sequence(lambda n: f"Test Ride {n}")
slug = factory.LazyAttribute(lambda obj: slugify(obj.name))
description = factory.Faker("text", max_nb_chars=1000)
category = fuzzy.FuzzyChoice(["RC", "WC", "TR", "WR", "DR", "CR", "FR", "SP"])
status = "OPERATING"
opening_date = factory.Faker("date_between", start_date="-30y", end_date="today")
closing_date = None
min_height_in = fuzzy.FuzzyInteger(36, 48)
max_height_in = None
capacity_per_hour = fuzzy.FuzzyInteger(500, 3000)
ride_duration_seconds = fuzzy.FuzzyInteger(60, 300)
average_rating = fuzzy.FuzzyDecimal(1, 10, precision=2)
# Relationships
park = factory.SubFactory(ParkFactory)
manufacturer = factory.SubFactory(RidesManufacturerFactory) # rides.Company
designer = factory.SubFactory(RidesDesignerFactory) # rides.Company
ride_model = factory.SubFactory(RideModelFactory)
park_area = factory.SubFactory(ParkAreaFactory, park=factory.SelfAttribute("..park"))
class CoasterFactory(RideFactory):
"""Factory for creating roller coaster rides."""
category = fuzzy.FuzzyChoice(["RC", "WC"])
min_height_in = fuzzy.FuzzyInteger(42, 54)
ride_duration_seconds = fuzzy.FuzzyInteger(90, 240)
class ParkReviewFactory(DjangoModelFactory):
"""Factory for creating ParkReview instances."""
class Meta:
model = "parks.ParkReview"
django_get_or_create = ("park", "user")
rating = fuzzy.FuzzyInteger(1, 10)
title = factory.Faker("sentence", nb_words=6)
content = factory.Faker("text", max_nb_chars=2000)
visit_date = factory.Faker("date_between", start_date="-2y", end_date="today")
is_published = True
moderation_notes = ""
# Relationships
park = factory.SubFactory(ParkFactory)
user = factory.SubFactory(UserFactory)
class RideReviewFactory(DjangoModelFactory):
"""Factory for creating RideReview instances."""
class Meta:
model = "rides.RideReview"
django_get_or_create = ("ride", "user")
rating = fuzzy.FuzzyInteger(1, 10)
title = factory.Faker("sentence", nb_words=6)
content = factory.Faker("text", max_nb_chars=2000)
visit_date = factory.Faker("date_between", start_date="-2y", end_date="today")
is_published = True
moderation_notes = ""
# Relationships
ride = factory.SubFactory(RideFactory)
user = factory.SubFactory(UserFactory)
class ModeratedReviewFactory(ParkReviewFactory):
"""Factory for creating moderated reviews."""
moderation_notes = factory.Faker("sentence")
moderated_by = factory.SubFactory(StaffUserFactory)
moderated_at = factory.Faker("date_time_between", start_date="-1y", end_date="now")
class EditSubmissionFactory(DjangoModelFactory):
"""Factory for creating EditSubmission instances."""
class Meta:
model = "moderation.EditSubmission"
submission_type = "UPDATE"
changes = factory.LazyFunction(lambda: {"name": "Updated Name"})
status = "PENDING"
notes = factory.Faker("sentence")
# Relationships
submitted_by = factory.SubFactory(UserFactory)
content_object = factory.SubFactory(ParkFactory)
# Trait mixins for common scenarios
class Traits:
"""Common trait mixins for factories."""
@staticmethod
def operating_park():
"""Trait for operating parks."""
return {"status": "OPERATING", "closing_date": None}
@staticmethod
def closed_park():
"""Trait for closed parks."""
return {
"status": "CLOSED_PERM",
"closing_date": factory.Faker("date_between", start_date="-10y", end_date="today"),
}
@staticmethod
def high_rated():
"""Trait for highly rated items."""
return {"average_rating": fuzzy.FuzzyDecimal(8, 10, precision=2)}
@staticmethod
def recent_submission():
"""Trait for recent submissions."""
return {"submitted_at": factory.Faker("date_time_between", start_date="-7d", end_date="now")}
# Specialized factories for testing scenarios
class TestScenarios:
"""Pre-configured factory combinations for common test scenarios."""
@staticmethod
def complete_park_with_rides(num_rides=5):
"""Create a complete park with rides and reviews."""
park = ParkFactory()
rides = [RideFactory(park=park) for _ in range(num_rides)]
park_review = ParkReviewFactory(park=park)
ride_reviews = [RideReviewFactory(ride=ride) for ride in rides[:2]]
return {
"park": park,
"rides": rides,
"park_review": park_review,
"ride_reviews": ride_reviews,
}
@staticmethod
def moderation_workflow():
"""Create a complete moderation workflow scenario."""
user = UserFactory()
moderator = StaffUserFactory()
park = ParkFactory()
submission = EditSubmissionFactory(submitted_by=user, content_object=park)
return {
"user": user,
"moderator": moderator,
"park": park,
"submission": submission,
}
@staticmethod
def review_scenario():
"""Create a scenario with multiple reviews and ratings."""
park = ParkFactory()
users = [UserFactory() for _ in range(5)]
reviews = [ParkReviewFactory(park=park, user=user) for user in users]
return {"park": park, "users": users, "reviews": reviews}
class CloudflareImageFactory(DjangoModelFactory):
"""Factory for creating CloudflareImage instances."""
class Meta:
model = "django_cloudflareimages_toolkit.CloudflareImage"
cloudflare_id = factory.Sequence(lambda n: f"cf-image-{n}")
status = "uploaded"
upload_url = factory.Faker("url")
width = fuzzy.FuzzyInteger(100, 1920)
height = fuzzy.FuzzyInteger(100, 1080)
format = "jpeg"
@factory.lazy_attribute
def expires_at(self):
from django.utils import timezone
return timezone.now() + timezone.timedelta(days=365)
@factory.lazy_attribute
def uploaded_at(self):
from django.utils import timezone
return timezone.now()
class ParkPhotoFactory(DjangoModelFactory):
"""Factory for creating ParkPhoto instances."""
class Meta:
model = "parks.ParkPhoto"
park = factory.SubFactory(ParkFactory)
image = factory.SubFactory(CloudflareImageFactory)
caption = factory.Faker("sentence", nb_words=6)
alt_text = factory.Faker("sentence", nb_words=8)
is_primary = False
is_approved = True
uploaded_by = factory.SubFactory(UserFactory)
date_taken = factory.Faker("date_time_between", start_date="-2y", end_date="now")
class RidePhotoFactory(DjangoModelFactory):
"""Factory for creating RidePhoto instances."""
class Meta:
model = "rides.RidePhoto"
ride = factory.SubFactory(RideFactory)
image = factory.SubFactory(CloudflareImageFactory)
caption = factory.Faker("sentence", nb_words=6)
alt_text = factory.Faker("sentence", nb_words=8)
is_primary = False
is_approved = True
uploaded_by = factory.SubFactory(UserFactory)