mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 15:11:09 -05:00
Add state machine diagrams and code examples for ThrillWiki
- Created a comprehensive documentation file for state machine diagrams, detailing various states and transitions for models such as EditSubmission, ModerationReport, and Park Status. - Included transition matrices for each state machine to clarify role requirements and guards. - Developed a new document providing code examples for implementing state machines, including adding new state machines to models, defining custom guards, implementing callbacks, and testing state machines. - Added examples for document approval workflows, custom guards, email notifications, and cache invalidation callbacks. - Implemented a test suite for document workflows, covering various scenarios including approval, rejection, and transition logging.
This commit is contained in:
@@ -1,117 +1,541 @@
|
||||
from django.test import TestCase, Client
|
||||
"""
|
||||
Comprehensive tests for the parks app state machine.
|
||||
|
||||
This module contains tests for:
|
||||
- Park status FSM transitions
|
||||
- Park transition wrapper methods
|
||||
- Transition history logging
|
||||
- Related model updates during transitions
|
||||
"""
|
||||
|
||||
from django.test import TestCase
|
||||
from django.contrib.auth import get_user_model
|
||||
from apps.parks.models import Park, ParkArea, ParkLocation, Company as Operator
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils import timezone
|
||||
from django_fsm import TransitionNotAllowed
|
||||
from .models import Park, Company
|
||||
from datetime import date
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
def create_test_location(park: Park) -> ParkLocation:
|
||||
"""Helper function to create a test location"""
|
||||
park_location = ParkLocation.objects.create(
|
||||
park=park,
|
||||
street_address="123 Test St",
|
||||
city="Test City",
|
||||
state="TS",
|
||||
country="Test Country",
|
||||
postal_code="12345",
|
||||
)
|
||||
# Set coordinates using the helper method
|
||||
park_location.set_coordinates(34.0522, -118.2437) # latitude, longitude
|
||||
park_location.save()
|
||||
return park_location
|
||||
# ============================================================================
|
||||
# Park FSM Transition Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ParkModelTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls) -> None:
|
||||
# Create test user
|
||||
cls.user = User.objects.create_user(
|
||||
username="testuser",
|
||||
email="test@example.com",
|
||||
password="testpass123",
|
||||
)
|
||||
class ParkTransitionTests(TestCase):
|
||||
"""Comprehensive tests for Park FSM transitions."""
|
||||
|
||||
# Create test company
|
||||
cls.operator = Operator.objects.create(
|
||||
name="Test Company", website="http://example.com"
|
||||
)
|
||||
|
||||
# Create test park
|
||||
cls.park = Park.objects.create(
|
||||
name="Test Park",
|
||||
operator=cls.operator,
|
||||
status="OPERATING",
|
||||
website="http://testpark.com",
|
||||
)
|
||||
|
||||
# Create test location
|
||||
cls.location = create_test_location(cls.park)
|
||||
|
||||
def test_park_creation(self) -> None:
|
||||
"""Test park instance creation and field values"""
|
||||
self.assertEqual(self.park.name, "Test Park")
|
||||
self.assertEqual(self.park.operator, self.operator)
|
||||
self.assertEqual(self.park.status, "OPERATING")
|
||||
self.assertEqual(self.park.website, "http://testpark.com")
|
||||
self.assertTrue(self.park.slug)
|
||||
|
||||
def test_park_str_representation(self) -> None:
|
||||
"""Test string representation of park"""
|
||||
self.assertEqual(str(self.park), "Test Park")
|
||||
|
||||
def test_park_coordinates(self) -> None:
|
||||
"""Test park coordinates property"""
|
||||
coords = self.park.coordinates
|
||||
self.assertIsNotNone(coords)
|
||||
if coords:
|
||||
self.assertAlmostEqual(coords[0], 34.0522, places=4) # latitude
|
||||
self.assertAlmostEqual(coords[1], -118.2437, places=4) # longitude
|
||||
|
||||
def test_park_formatted_location(self) -> None:
|
||||
"""Test park formatted_location property"""
|
||||
expected = "123 Test St, Test City, TS, 12345, Test Country"
|
||||
self.assertEqual(self.park.formatted_location, expected)
|
||||
|
||||
|
||||
class ParkAreaTests(TestCase):
|
||||
def setUp(self) -> None:
|
||||
# Create test company
|
||||
self.operator = Operator.objects.create(
|
||||
name="Test Company", website="http://example.com"
|
||||
)
|
||||
|
||||
# Create test park
|
||||
self.park = Park.objects.create(
|
||||
name="Test Park", operator=self.operator, status="OPERATING"
|
||||
)
|
||||
|
||||
# Create test location
|
||||
self.location = create_test_location(self.park)
|
||||
|
||||
# Create test area
|
||||
self.area = ParkArea.objects.create(
|
||||
park=self.park, name="Test Area", description="Test Description"
|
||||
)
|
||||
|
||||
def test_area_creation(self) -> None:
|
||||
"""Test park area creation"""
|
||||
self.assertEqual(self.area.name, "Test Area")
|
||||
self.assertEqual(self.area.park, self.park)
|
||||
self.assertTrue(self.area.slug)
|
||||
|
||||
|
||||
class ParkViewTests(TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.client = Client()
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.user = User.objects.create_user(
|
||||
username="testuser",
|
||||
email="test@example.com",
|
||||
password="testpass123",
|
||||
username='testuser',
|
||||
email='test@example.com',
|
||||
password='testpass123',
|
||||
role='USER'
|
||||
)
|
||||
self.operator = Operator.objects.create(
|
||||
name="Test Company", website="http://example.com"
|
||||
self.moderator = User.objects.create_user(
|
||||
username='moderator',
|
||||
email='moderator@example.com',
|
||||
password='testpass123',
|
||||
role='MODERATOR'
|
||||
)
|
||||
self.park = Park.objects.create(
|
||||
name="Test Park", operator=self.operator, status="OPERATING"
|
||||
self.admin = User.objects.create_user(
|
||||
username='admin',
|
||||
email='admin@example.com',
|
||||
password='testpass123',
|
||||
role='ADMIN'
|
||||
)
|
||||
self.location = create_test_location(self.park)
|
||||
|
||||
# Create operator company
|
||||
self.operator = Company.objects.create(
|
||||
name='Test Operator',
|
||||
description='Test operator company',
|
||||
roles=['OPERATOR']
|
||||
)
|
||||
|
||||
def _create_park(self, status='OPERATING', **kwargs):
|
||||
"""Helper to create a Park with specified status."""
|
||||
defaults = {
|
||||
'name': 'Test Park',
|
||||
'slug': 'test-park',
|
||||
'description': 'A test park',
|
||||
'operator': self.operator,
|
||||
'timezone': 'America/New_York'
|
||||
}
|
||||
defaults.update(kwargs)
|
||||
return Park.objects.create(status=status, **defaults)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Operating status transitions
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def test_operating_to_closed_temp_transition(self):
|
||||
"""Test transition from OPERATING to CLOSED_TEMP."""
|
||||
park = self._create_park(status='OPERATING')
|
||||
self.assertEqual(park.status, 'OPERATING')
|
||||
|
||||
park.transition_to_closed_temp(user=self.user)
|
||||
park.save()
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'CLOSED_TEMP')
|
||||
|
||||
def test_operating_to_closed_perm_transition(self):
|
||||
"""Test transition from OPERATING to CLOSED_PERM."""
|
||||
park = self._create_park(status='OPERATING')
|
||||
|
||||
park.transition_to_closed_perm(user=self.moderator)
|
||||
park.closing_date = date.today()
|
||||
park.save()
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'CLOSED_PERM')
|
||||
self.assertIsNotNone(park.closing_date)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Under construction transitions
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def test_under_construction_to_operating_transition(self):
|
||||
"""Test transition from UNDER_CONSTRUCTION to OPERATING."""
|
||||
park = self._create_park(status='UNDER_CONSTRUCTION')
|
||||
self.assertEqual(park.status, 'UNDER_CONSTRUCTION')
|
||||
|
||||
park.transition_to_operating(user=self.user)
|
||||
park.save()
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'OPERATING')
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Closed temp transitions
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def test_closed_temp_to_operating_transition(self):
|
||||
"""Test transition from CLOSED_TEMP to OPERATING (reopen)."""
|
||||
park = self._create_park(status='CLOSED_TEMP')
|
||||
|
||||
park.transition_to_operating(user=self.user)
|
||||
park.save()
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'OPERATING')
|
||||
|
||||
def test_closed_temp_to_closed_perm_transition(self):
|
||||
"""Test transition from CLOSED_TEMP to CLOSED_PERM."""
|
||||
park = self._create_park(status='CLOSED_TEMP')
|
||||
|
||||
park.transition_to_closed_perm(user=self.moderator)
|
||||
park.closing_date = date.today()
|
||||
park.save()
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'CLOSED_PERM')
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Closed perm transitions (to final states)
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def test_closed_perm_to_demolished_transition(self):
|
||||
"""Test transition from CLOSED_PERM to DEMOLISHED."""
|
||||
park = self._create_park(status='CLOSED_PERM')
|
||||
|
||||
park.transition_to_demolished(user=self.moderator)
|
||||
park.save()
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'DEMOLISHED')
|
||||
|
||||
def test_closed_perm_to_relocated_transition(self):
|
||||
"""Test transition from CLOSED_PERM to RELOCATED."""
|
||||
park = self._create_park(status='CLOSED_PERM')
|
||||
|
||||
park.transition_to_relocated(user=self.moderator)
|
||||
park.save()
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'RELOCATED')
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Invalid transitions (final states)
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def test_demolished_cannot_transition(self):
|
||||
"""Test that DEMOLISHED state cannot transition further."""
|
||||
park = self._create_park(status='DEMOLISHED')
|
||||
|
||||
with self.assertRaises(TransitionNotAllowed):
|
||||
park.transition_to_operating(user=self.moderator)
|
||||
|
||||
def test_relocated_cannot_transition(self):
|
||||
"""Test that RELOCATED state cannot transition further."""
|
||||
park = self._create_park(status='RELOCATED')
|
||||
|
||||
with self.assertRaises(TransitionNotAllowed):
|
||||
park.transition_to_operating(user=self.moderator)
|
||||
|
||||
def test_operating_cannot_directly_demolish(self):
|
||||
"""Test that OPERATING cannot directly transition to DEMOLISHED."""
|
||||
park = self._create_park(status='OPERATING')
|
||||
|
||||
with self.assertRaises(TransitionNotAllowed):
|
||||
park.transition_to_demolished(user=self.moderator)
|
||||
|
||||
def test_operating_cannot_directly_relocate(self):
|
||||
"""Test that OPERATING cannot directly transition to RELOCATED."""
|
||||
park = self._create_park(status='OPERATING')
|
||||
|
||||
with self.assertRaises(TransitionNotAllowed):
|
||||
park.transition_to_relocated(user=self.moderator)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Wrapper method tests
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def test_reopen_wrapper_method(self):
|
||||
"""Test the reopen() wrapper method."""
|
||||
park = self._create_park(status='CLOSED_TEMP')
|
||||
|
||||
park.reopen(user=self.user)
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'OPERATING')
|
||||
|
||||
def test_close_temporarily_wrapper_method(self):
|
||||
"""Test the close_temporarily() wrapper method."""
|
||||
park = self._create_park(status='OPERATING')
|
||||
|
||||
park.close_temporarily(user=self.user)
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'CLOSED_TEMP')
|
||||
|
||||
def test_close_permanently_wrapper_method(self):
|
||||
"""Test the close_permanently() wrapper method."""
|
||||
park = self._create_park(status='OPERATING')
|
||||
closing = date(2025, 12, 31)
|
||||
|
||||
park.close_permanently(closing_date=closing, user=self.moderator)
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'CLOSED_PERM')
|
||||
self.assertEqual(park.closing_date, closing)
|
||||
|
||||
def test_close_permanently_without_date(self):
|
||||
"""Test close_permanently() without closing_date."""
|
||||
park = self._create_park(status='OPERATING')
|
||||
|
||||
park.close_permanently(user=self.moderator)
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'CLOSED_PERM')
|
||||
self.assertIsNone(park.closing_date)
|
||||
|
||||
def test_demolish_wrapper_method(self):
|
||||
"""Test the demolish() wrapper method."""
|
||||
park = self._create_park(status='CLOSED_PERM')
|
||||
|
||||
park.demolish(user=self.moderator)
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'DEMOLISHED')
|
||||
|
||||
def test_relocate_wrapper_method(self):
|
||||
"""Test the relocate() wrapper method."""
|
||||
park = self._create_park(status='CLOSED_PERM')
|
||||
|
||||
park.relocate(user=self.moderator)
|
||||
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'RELOCATED')
|
||||
|
||||
def test_start_construction_wrapper_method(self):
|
||||
"""Test the start_construction() wrapper method if applicable."""
|
||||
# This depends on allowed transitions - skip if not allowed
|
||||
try:
|
||||
park = self._create_park(status='OPERATING')
|
||||
park.start_construction(user=self.moderator)
|
||||
park.refresh_from_db()
|
||||
self.assertEqual(park.status, 'UNDER_CONSTRUCTION')
|
||||
except TransitionNotAllowed:
|
||||
# If transition from OPERATING to UNDER_CONSTRUCTION is not allowed
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Park Transition History Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ParkTransitionHistoryTests(TestCase):
|
||||
"""Tests for Park transition history logging."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.moderator = User.objects.create_user(
|
||||
username='moderator',
|
||||
email='moderator@example.com',
|
||||
password='testpass123',
|
||||
role='MODERATOR'
|
||||
)
|
||||
self.operator = Company.objects.create(
|
||||
name='Test Operator',
|
||||
description='Test operator company',
|
||||
roles=['OPERATOR']
|
||||
)
|
||||
|
||||
def _create_park(self, status='OPERATING'):
|
||||
"""Helper to create a Park."""
|
||||
return Park.objects.create(
|
||||
name='Test Park',
|
||||
slug='test-park',
|
||||
description='A test park',
|
||||
operator=self.operator,
|
||||
status=status,
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
def test_transition_creates_state_log(self):
|
||||
"""Test that transitions create StateLog entries."""
|
||||
from django_fsm_log.models import StateLog
|
||||
|
||||
park = self._create_park(status='OPERATING')
|
||||
|
||||
park.transition_to_closed_temp(user=self.moderator)
|
||||
park.save()
|
||||
|
||||
park_ct = ContentType.objects.get_for_model(park)
|
||||
log = StateLog.objects.filter(
|
||||
content_type=park_ct,
|
||||
object_id=park.id
|
||||
).first()
|
||||
|
||||
self.assertIsNotNone(log)
|
||||
self.assertEqual(log.state, 'CLOSED_TEMP')
|
||||
self.assertEqual(log.by, self.moderator)
|
||||
|
||||
def test_multiple_transitions_create_multiple_logs(self):
|
||||
"""Test that multiple transitions create multiple log entries."""
|
||||
from django_fsm_log.models import StateLog
|
||||
|
||||
park = self._create_park(status='OPERATING')
|
||||
park_ct = ContentType.objects.get_for_model(park)
|
||||
|
||||
# First transition
|
||||
park.transition_to_closed_temp(user=self.moderator)
|
||||
park.save()
|
||||
|
||||
# Second transition
|
||||
park.transition_to_operating(user=self.moderator)
|
||||
park.save()
|
||||
|
||||
logs = StateLog.objects.filter(
|
||||
content_type=park_ct,
|
||||
object_id=park.id
|
||||
).order_by('timestamp')
|
||||
|
||||
self.assertEqual(logs.count(), 2)
|
||||
self.assertEqual(logs[0].state, 'CLOSED_TEMP')
|
||||
self.assertEqual(logs[1].state, 'OPERATING')
|
||||
|
||||
def test_transition_log_includes_user(self):
|
||||
"""Test that transition logs include the user who made the change."""
|
||||
from django_fsm_log.models import StateLog
|
||||
|
||||
park = self._create_park(status='OPERATING')
|
||||
|
||||
park.transition_to_closed_perm(user=self.moderator)
|
||||
park.save()
|
||||
|
||||
park_ct = ContentType.objects.get_for_model(park)
|
||||
log = StateLog.objects.filter(
|
||||
content_type=park_ct,
|
||||
object_id=park.id
|
||||
).first()
|
||||
|
||||
self.assertEqual(log.by, self.moderator)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Park Model Business Logic Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ParkBusinessLogicTests(TestCase):
|
||||
"""Tests for Park model business logic."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.operator = Company.objects.create(
|
||||
name='Test Operator',
|
||||
description='Test operator company',
|
||||
roles=['OPERATOR']
|
||||
)
|
||||
self.property_owner = Company.objects.create(
|
||||
name='Property Owner',
|
||||
description='Property owner company',
|
||||
roles=['PROPERTY_OWNER']
|
||||
)
|
||||
|
||||
def test_park_creates_with_valid_operator(self):
|
||||
"""Test park can be created with valid operator."""
|
||||
park = Park.objects.create(
|
||||
name='Test Park',
|
||||
slug='test-park',
|
||||
description='A test park',
|
||||
operator=self.operator,
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
self.assertEqual(park.operator, self.operator)
|
||||
|
||||
def test_park_slug_auto_generated(self):
|
||||
"""Test that park slug is auto-generated from name."""
|
||||
park = Park.objects.create(
|
||||
name='My Amazing Theme Park',
|
||||
description='A test park',
|
||||
operator=self.operator,
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
self.assertEqual(park.slug, 'my-amazing-theme-park')
|
||||
|
||||
def test_park_url_generated(self):
|
||||
"""Test that frontend URL is generated on save."""
|
||||
park = Park.objects.create(
|
||||
name='Test Park',
|
||||
slug='test-park',
|
||||
description='A test park',
|
||||
operator=self.operator,
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
self.assertIn('test-park', park.url)
|
||||
|
||||
def test_opening_year_computed_from_opening_date(self):
|
||||
"""Test that opening_year is computed from opening_date."""
|
||||
park = Park.objects.create(
|
||||
name='Test Park',
|
||||
slug='test-park',
|
||||
description='A test park',
|
||||
operator=self.operator,
|
||||
opening_date=date(2020, 6, 15),
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
self.assertEqual(park.opening_year, 2020)
|
||||
|
||||
def test_search_text_populated(self):
|
||||
"""Test that search_text is populated on save."""
|
||||
park = Park.objects.create(
|
||||
name='Test Park',
|
||||
slug='test-park',
|
||||
description='A wonderful theme park',
|
||||
operator=self.operator,
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
self.assertIn('test park', park.search_text)
|
||||
self.assertIn('wonderful theme park', park.search_text)
|
||||
self.assertIn('test operator', park.search_text)
|
||||
|
||||
def test_park_with_property_owner(self):
|
||||
"""Test park with separate property owner."""
|
||||
park = Park.objects.create(
|
||||
name='Test Park',
|
||||
slug='test-park',
|
||||
description='A test park',
|
||||
operator=self.operator,
|
||||
property_owner=self.property_owner,
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
self.assertEqual(park.operator, self.operator)
|
||||
self.assertEqual(park.property_owner, self.property_owner)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Park Historical Slug Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ParkSlugHistoryTests(TestCase):
|
||||
"""Tests for Park historical slug tracking."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.operator = Company.objects.create(
|
||||
name='Test Operator',
|
||||
description='Test operator company',
|
||||
roles=['OPERATOR']
|
||||
)
|
||||
|
||||
def test_historical_slug_created_on_name_change(self):
|
||||
"""Test that historical slug is created when name changes."""
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from apps.core.history import HistoricalSlug
|
||||
|
||||
park = Park.objects.create(
|
||||
name='Original Name',
|
||||
description='A test park',
|
||||
operator=self.operator,
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
original_slug = park.slug
|
||||
|
||||
# Change name
|
||||
park.name = 'New Name'
|
||||
park.save()
|
||||
|
||||
# Check historical slug was created
|
||||
park_ct = ContentType.objects.get_for_model(park)
|
||||
historical = HistoricalSlug.objects.filter(
|
||||
content_type=park_ct,
|
||||
object_id=park.id,
|
||||
slug=original_slug
|
||||
).first()
|
||||
|
||||
self.assertIsNotNone(historical)
|
||||
self.assertEqual(historical.slug, original_slug)
|
||||
|
||||
def test_get_by_slug_finds_current_slug(self):
|
||||
"""Test get_by_slug finds park by current slug."""
|
||||
park = Park.objects.create(
|
||||
name='Test Park',
|
||||
slug='test-park',
|
||||
description='A test park',
|
||||
operator=self.operator,
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
found_park, is_historical = Park.get_by_slug('test-park')
|
||||
|
||||
self.assertEqual(found_park, park)
|
||||
self.assertFalse(is_historical)
|
||||
|
||||
def test_get_by_slug_finds_historical_slug(self):
|
||||
"""Test get_by_slug finds park by historical slug."""
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from apps.core.history import HistoricalSlug
|
||||
|
||||
park = Park.objects.create(
|
||||
name='Original Name',
|
||||
description='A test park',
|
||||
operator=self.operator,
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
original_slug = park.slug
|
||||
|
||||
# Change name to create historical slug
|
||||
park.name = 'New Name'
|
||||
park.save()
|
||||
|
||||
# Find by historical slug
|
||||
found_park, is_historical = Park.get_by_slug(original_slug)
|
||||
|
||||
self.assertEqual(found_park, park)
|
||||
self.assertTrue(is_historical)
|
||||
|
||||
Reference in New Issue
Block a user