from django.test import TestCase, Client from django.urls import reverse from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.test import override_settings from history_tracking.models import VersionBranch, ChangeSet from parks.models import Park User = get_user_model() @override_settings(HTMX_ENABLED=True) class VersionControlViewsTests(TestCase): def setUp(self): self.client = Client() self.user = User.objects.create_superuser( username='admin', email='admin@example.com', password='testpass123' ) self.client.login(username='admin', password='testpass123') self.park = Park.objects.create( name='Test Park', slug='test-park', status='OPERATING' ) self.content_type = ContentType.objects.get_for_model(Park) self.main_branch = VersionBranch.objects.create( name='main', metadata={'type': 'default_branch'} ) self.feature_branch = VersionBranch.objects.create( name='feature/test', metadata={'type': 'feature'} ) def test_version_control_panel(self): """Test rendering of version control panel""" response = self.client.get( reverse('version_control_panel'), HTTP_HX_REQUEST='true', HTTP_HX_TARGET='version-control-panel' ) self.assertEqual(response.status_code, 200) self.assertTemplateUsed('history_tracking/includes/version_control_ui.html') self.assertContains(response, 'main') # Should show main branch self.assertContains(response, 'feature/test') # Should show feature branch def test_create_branch(self): """Test branch creation through view""" response = self.client.post( reverse('create_branch'), { 'name': 'feature/new', 'metadata': '{"type": "feature", "description": "New feature"}' }, HTTP_HX_REQUEST='true' ) self.assertEqual(response.status_code, 200) self.assertTrue( VersionBranch.objects.filter(name='feature/new').exists() ) self.assertContains(response, 'Branch created successfully') def test_switch_branch(self): """Test switching between branches""" response = self.client.post( reverse('switch_branch'), {'branch_id': self.feature_branch.id}, HTTP_HX_REQUEST='true' ) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Switched to branch') self.assertContains(response, 'feature/test') def test_merge_branch(self): """Test branch merging through view""" # Create a change in feature branch ChangeSet.objects.create( branch=self.feature_branch, content_type=self.content_type, object_id=self.park.id, data={'name': 'Updated Name'}, status='applied' ) response = self.client.post( reverse('merge_branch'), { 'source_branch_id': self.feature_branch.id, 'target_branch_id': self.main_branch.id }, HTTP_HX_REQUEST='true' ) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Branch merged successfully') # Verify changes were merged main_changes = ChangeSet.objects.filter(branch=self.main_branch) self.assertEqual(main_changes.count(), 1) def test_merge_conflict_handling(self): """Test handling of merge conflicts""" # Create conflicting changes ChangeSet.objects.create( branch=self.main_branch, content_type=self.content_type, object_id=self.park.id, data={'name': 'Main Name'}, status='applied' ) ChangeSet.objects.create( branch=self.feature_branch, content_type=self.content_type, object_id=self.park.id, data={'name': 'Feature Name'}, status='applied' ) response = self.client.post( reverse('merge_branch'), { 'source_branch_id': self.feature_branch.id, 'target_branch_id': self.main_branch.id }, HTTP_HX_REQUEST='true' ) self.assertEqual(response.status_code, 409) # Conflict status self.assertContains(response, 'Merge conflicts detected') def test_view_history(self): """Test viewing version history""" # Create some changes change = ChangeSet.objects.create( branch=self.main_branch, content_type=self.content_type, object_id=self.park.id, data={'name': 'Updated Name'}, status='applied' ) response = self.client.get( reverse('version_history', kwargs={'pk': self.park.pk}), HTTP_HX_REQUEST='true' ) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Updated Name') self.assertContains(response, str(change.created_at)) def test_branch_deletion(self): """Test branch deletion through view""" response = self.client.post( reverse('delete_branch'), {'branch_id': self.feature_branch.id}, HTTP_HX_REQUEST='true' ) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Branch deleted successfully') self.assertFalse( VersionBranch.objects.filter(id=self.feature_branch.id).exists() ) def test_unauthorized_access(self): """Test that unauthorized users cannot access version control""" self.client.logout() response = self.client.get( reverse('version_control_panel'), HTTP_HX_REQUEST='true' ) self.assertEqual(response.status_code, 302) # Redirect to login def test_htmx_requirements(self): """Test that views require HTMX headers""" # Try without HTMX headers response = self.client.get(reverse('version_control_panel')) self.assertEqual(response.status_code, 400) self.assertContains( response, 'This endpoint requires HTMX', status_code=400 ) def test_branch_validation(self): """Test branch name validation in views""" response = self.client.post( reverse('create_branch'), { 'name': '[AWS-SECRET-REMOVED]ts', 'metadata': '{}' }, HTTP_HX_REQUEST='true' ) self.assertEqual(response.status_code, 400) self.assertContains( response, 'Invalid branch name', status_code=400 ) def test_branch_list_update(self): """Test that branch list updates after operations""" response = self.client.get( reverse('branch_list'), HTTP_HX_REQUEST='true' ) self.assertEqual(response.status_code, 200) self.assertContains(response, 'main') self.assertContains(response, 'feature/test') # Create new branch new_branch = VersionBranch.objects.create( name='feature/new', metadata={'type': 'feature'} ) # List should update response = self.client.get( reverse('branch_list'), HTTP_HX_REQUEST='true' ) self.assertContains(response, 'feature/new')