39435-vm/core/tests.py
2026-04-25 19:45:55 +00:00

235 lines
10 KiB
Python

from datetime import datetime
import json
from django.contrib.auth.models import User
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import Client, TestCase
from django.urls import reverse
from django.utils import timezone
from .models import Event
class EventModelTests(TestCase):
def test_slug_is_created_on_save(self):
event = Event.objects.create(
name='City Market',
start=timezone.make_aware(datetime(2026, 4, 10, 10, 0)),
end=timezone.make_aware(datetime(2026, 4, 10, 14, 0)),
)
self.assertTrue(event.slug.startswith('city-market-2026-04-10'))
class CalendarViewTests(TestCase):
def setUp(self):
Event.objects.create(
name='Riverfront Market',
location='Riverfront Pavilion',
start=timezone.make_aware(datetime(2026, 4, 10, 10, 0)),
end=timezone.make_aware(datetime(2026, 4, 10, 16, 0)),
is_published=True,
)
def test_home_page_renders(self):
response = self.client.get(reverse('home'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Show visitors exactly where your business will be on any day.')
def test_staff_dashboard_requires_login(self):
response = self.client.get(reverse('event_dashboard'))
self.assertEqual(response.status_code, 302)
self.assertIn(reverse('login'), response.url)
def test_staff_dashboard_for_staff_user(self):
staff = User.objects.create_user(username='staffer', password='pass12345', is_staff=True)
client = Client()
client.login(username='staffer', password='pass12345')
response = client.get(reverse('event_dashboard'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Manage your public event calendar securely')
self.assertContains(response, 'Generate a copy-ready widget snippet')
self.assertContains(response, 'Import a previous backup')
def test_embed_page_can_hide_header(self):
response = self.client.get(reverse('calendar_embed') + '?header=0')
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, 'Open full page')
class EventDashboardMutationTests(TestCase):
def setUp(self):
self.staff = User.objects.create_user(username='staffer', password='pass12345', is_staff=True)
self.event = Event.objects.create(
name='Editable Market',
location='Town Square',
start=timezone.make_aware(datetime(2026, 4, 12, 9, 0)),
end=timezone.make_aware(datetime(2026, 4, 12, 12, 0)),
is_published=True,
)
def _backup_file(self, payload):
return SimpleUploadedFile(
'events-backup.json',
json.dumps(payload).encode('utf-8'),
content_type='application/json',
)
def test_staff_can_export_event_backup(self):
self.client.login(username='staffer', password='pass12345')
response = self.client.get(reverse('event_export'))
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
self.assertIn('attachment; filename="roadshow-calendar-events-', response['Content-Disposition'])
payload = json.loads(response.content)
self.assertEqual(payload['version'], 1)
self.assertEqual(payload['event_count'], len(payload['events']))
exported_event = next(item for item in payload['events'] if item['slug'] == self.event.slug)
self.assertEqual(exported_event['name'], self.event.name)
def test_staff_can_preview_event_backup_restore(self):
self.client.login(username='staffer', password='pass12345')
payload = {
'version': 1,
'project': 'Roadshow Calendar',
'exported_at': '2026-04-01T10:30:00+00:00',
'event_count': 1,
'events': [
{
'name': 'Recovered Market',
'slug': 'recovered-market-2026-04-20',
'location': 'Harbor Plaza',
'start': '2026-04-20T10:00:00+00:00',
'end': '2026-04-20T14:00:00+00:00',
'event_url': 'https://example.com/recovered',
'summary': 'Recovered from backup',
'is_published': False,
}
],
}
response = self.client.post(reverse('event_import_preview'), {'backup_file': self._backup_file(payload)})
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Ready to replace the current calendar')
self.assertContains(response, 'Recovered Market')
self.assertContains(response, 'Confirm restore and replace events')
self.assertIn('event_backup_import_payload', self.client.session)
def test_staff_can_restore_event_backup(self):
self.client.login(username='staffer', password='pass12345')
payload = {
'version': 1,
'project': 'Roadshow Calendar',
'exported_at': '2026-04-01T10:30:00+00:00',
'event_count': 1,
'events': [
{
'name': 'Recovered Market',
'slug': 'recovered-market-2026-04-20',
'location': 'Harbor Plaza',
'start': '2026-04-20T10:00:00+00:00',
'end': '2026-04-20T14:00:00+00:00',
'event_url': 'https://example.com/recovered',
'summary': 'Recovered from backup',
'is_published': False,
}
],
}
preview_response = self.client.post(reverse('event_import_preview'), {'backup_file': self._backup_file(payload)})
self.assertEqual(preview_response.status_code, 200)
response = self.client.post(reverse('event_import_restore'))
self.assertRedirects(response, reverse('event_dashboard'))
self.assertEqual(Event.objects.count(), 1)
restored_event = Event.objects.get()
self.assertEqual(restored_event.name, 'Recovered Market')
self.assertEqual(restored_event.slug, 'recovered-market-2026-04-20')
self.assertEqual(restored_event.location, 'Harbor Plaza')
self.assertFalse(restored_event.is_published)
self.assertFalse(Event.objects.filter(pk=self.event.pk).exists())
self.assertNotIn('event_backup_import_payload', self.client.session)
def test_staff_can_open_edit_page(self):
self.client.login(username='staffer', password='pass12345')
response = self.client.get(reverse('event_edit', args=[self.event.slug]))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Save changes')
def test_staff_can_update_event(self):
self.client.login(username='staffer', password='pass12345')
response = self.client.post(
reverse('event_edit', args=[self.event.slug]),
{
'name': 'Updated Market',
'location': 'Town Square',
'start': '2026-04-12T09:00',
'end': '2026-04-12T13:00',
'event_url': 'https://example.com/event',
'summary': 'Updated details',
'is_published': 'on',
},
)
self.assertRedirects(response, reverse('event_dashboard_detail', args=[self.event.slug]))
self.event.refresh_from_db()
self.assertEqual(self.event.name, 'Updated Market')
self.assertEqual(self.event.summary, 'Updated details')
def test_staff_can_delete_event(self):
self.client.login(username='staffer', password='pass12345')
response = self.client.post(reverse('event_delete', args=[self.event.slug]))
self.assertRedirects(response, reverse('event_dashboard'))
self.assertFalse(Event.objects.filter(pk=self.event.pk).exists())
def test_staff_can_create_recurring_events(self):
self.client.login(username='staffer', password='pass12345')
response = self.client.post(
reverse('event_create'),
{
'name': 'Weekly Demo',
'location': 'HQ Lab',
'start': '2026-05-05T09:30',
'end': '2026-05-05T11:00',
'event_url': 'https://example.com/demo',
'summary': 'Recurring demo day',
'is_published': 'on',
'recurrence_start_date': '2026-05-01',
'recurrence_end_date': '2026-05-31',
'recurrence_weekday': '2',
},
)
self.assertRedirects(response, reverse('event_dashboard'))
recurring_events = Event.objects.filter(name='Weekly Demo').order_by('start')
self.assertEqual(recurring_events.count(), 4)
self.assertEqual(
[event.start.date().isoformat() for event in recurring_events],
['2026-05-06', '2026-05-13', '2026-05-20', '2026-05-27'],
)
self.assertEqual([event.start.hour for event in recurring_events], [9, 9, 9, 9])
self.assertEqual([event.start.minute for event in recurring_events], [30, 30, 30, 30])
self.assertTrue(all(event.is_published for event in recurring_events))
self.assertTrue(all(event.end - event.start == recurring_events[0].end - recurring_events[0].start for event in recurring_events))
def test_staff_sees_validation_error_for_invalid_recurrence_range(self):
self.client.login(username='staffer', password='pass12345')
response = self.client.post(
reverse('event_create'),
{
'name': 'Broken Weekly Demo',
'location': 'HQ Lab',
'start': '2026-05-05T09:30',
'end': '2026-05-05T11:00',
'event_url': 'https://example.com/demo',
'summary': 'Should not save',
'is_published': 'on',
'recurrence_start_date': '2026-05-20',
'recurrence_end_date': '2026-05-10',
'recurrence_weekday': '2',
},
)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'The recurring series must end on or after the start date.')
self.assertFalse(Event.objects.filter(name='Broken Weekly Demo').exists())