diff --git a/shiftregister/fallback/tests.py b/shiftregister/fallback/tests.py index 7ce503c..c242819 100644 --- a/shiftregister/fallback/tests.py +++ b/shiftregister/fallback/tests.py @@ -1,3 +1,171 @@ -from django.test import TestCase +import uuid +from datetime import timedelta -# Create your tests here. +from django.test import Client, TestCase +from django.urls import reverse +from django.utils import timezone + +from shiftregister.fallback.models import FallbackAssignment, TeamMember +from shiftregister.importer.models import Calendar, Event, Room + + +class ShiftTradeTests(TestCase): + def setUp(self): + # Create test data + self.room = Room.objects.create(name="Test Room", required_helpers=2) + + self.event = Event.objects.create( + uuid=uuid.uuid4(), + calendar=Calendar.objects.create(url="https://example.com/calendar"), + start_at=timezone.now(), + duration=timedelta(hours=2), + room=self.room, + deleted=False, + ) + + self.team_member1 = TeamMember.objects.create(name="Team Member 1", pin=1111) + + self.team_member2 = TeamMember.objects.create(name="Team Member 2", pin=2222) + + self.team_member3 = TeamMember.objects.create(name="Team Member 3", pin=3333) + + self.assignment = FallbackAssignment.objects.create( + shift=self.event, team_member=self.team_member1, traded_to=self.team_member3 + ) + + self.client = Client() + + def test_invalid_pin_keeps_assignment_unchanged(self): + """Test that wrong PIN prevents any changes to the assignment""" + response = self.client.post( + reverse( + "my_fallback_shifts", + kwargs={"team_member_id": self.team_member2.url_id()}, + ), + {"take_shift": "true", "assignment_id": self.assignment.id, "pin": "9999"}, + ) + + self.assignment.refresh_from_db() + self.assertEqual(self.assignment.team_member, self.team_member1) + self.assertEqual(self.assignment.traded_to, self.team_member3) + + def test_take_shift_updates_traded_to(self): + """Test that taking a shift properly updates the traded_to field""" + response = self.client.post( + reverse( + "my_fallback_shifts", + kwargs={"team_member_id": self.team_member2.url_id()}, + ), + { + "take_shift": "true", + "assignment_id": self.assignment.id, + "pin": self.team_member2.pin, + }, + follow=True, + ) + + # Assignment should now be traded to team_member2 + self.assignment.refresh_from_db() + self.assertEqual(self.assignment.traded_to, self.team_member2) + self.assertEqual( + self.assignment.team_member, self.team_member1 + ) # Original owner unchanged + + def test_return_shift_clears_traded_to(self): + """Test that returning a shift clears the traded_to field""" + + # Then return it + response = self.client.post( + reverse( + "my_fallback_shifts", + kwargs={"team_member_id": self.team_member3.url_id()}, + ), + { + "take_shift": "true", + "assignment_id": self.assignment.id, + "pin": self.team_member3.pin, + }, + follow=True, + ) + + # Assignment should be returned (traded_to cleared) + self.assignment.refresh_from_db() + self.assertIsNone(self.assignment.traded_to) + self.assertEqual( + self.assignment.team_member, self.team_member1 + ) # Original owner unchanged + + def test_reclaim_shift_clears_traded_to(self): + """Test that original owner can reclaim their shift""" + + # Original owner reclaims it + response = self.client.post( + reverse( + "my_fallback_shifts", + kwargs={"team_member_id": self.team_member1.url_id()}, + ), + { + "take_shift": "true", + "assignment_id": self.assignment.id, + "pin": self.team_member1.pin, + }, + follow=True, + ) + + # Assignment should be reclaimed (traded_to cleared) + self.assignment.refresh_from_db() + self.assertIsNone(self.assignment.traded_to) + self.assertEqual(self.assignment.team_member, self.team_member1) + + def test_take_shift_from_other_trader(self): + """Test that a member can take over a shift that was already traded to someone else""" + # Verify initial state + self.assertEqual(self.assignment.team_member, self.team_member1) + self.assertEqual(self.assignment.traded_to, self.team_member3) + + # team_member2 takes the shift from team_member3 + response = self.client.post( + reverse( + "my_fallback_shifts", + kwargs={"team_member_id": self.team_member2.url_id()}, + ), + { + "take_shift": "true", + "assignment_id": self.assignment.id, + "pin": self.team_member2.pin, + }, + follow=True, + ) + + # Assignment should now be traded to team_member2 + self.assignment.refresh_from_db() + self.assertEqual( + self.assignment.team_member, self.team_member1 + ) # Original owner unchanged + self.assertEqual(self.assignment.traded_to, self.team_member2) # New trader + + def test_form_validation_prevents_changes(self): + """Test that invalid form data doesn't modify any assignments""" + initial_count = FallbackAssignment.objects.count() + initial_state = FallbackAssignment.objects.values_list( + "id", "team_member_id", "traded_to_id" + ) + + response = self.client.post( + reverse( + "my_fallback_shifts", + kwargs={"team_member_id": self.team_member1.url_id()}, + ), + { + "take_shift": "true", + "assignment_id": "not_a_number", + "pin": "also_not_a_number", + }, + ) + + # No assignments should be created or modified + self.assertEqual(FallbackAssignment.objects.count(), initial_count) + current_state = FallbackAssignment.objects.values_list( + "id", "team_member_id", "traded_to_id" + ) + self.assertEqual(list(initial_state), list(current_state)) diff --git a/shiftregister/settings.py b/shiftregister/settings.py index 51841a0..34e8083 100644 --- a/shiftregister/settings.py +++ b/shiftregister/settings.py @@ -10,6 +10,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.0/ref/settings/ """ +import sys from pathlib import Path import environ @@ -31,6 +32,9 @@ environ.Env.read_env(BASE_DIR / ".env") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = env("ENVIRONMENT") == "development" +# Check if we're running tests +TESTING = "test" in sys.argv + # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = env( "SECRET_KEY", @@ -61,7 +65,7 @@ THIRDPARTY_APPS = [ "phonenumber_field", ] -if DEBUG: +if DEBUG and not TESTING: THIRDPARTY_APPS += ["debug_toolbar"] LOCAL_APPS = [ @@ -90,7 +94,7 @@ MIDDLEWARE = [ "shiftregister.app.middleware.check_helper", ] -if DEBUG: +if DEBUG and not TESTING: MIDDLEWARE.insert(0, "debug_toolbar.middleware.DebugToolbarMiddleware") ROOT_URLCONF = "shiftregister.urls"