""" Contract test for GET /healthcare/appointments endpoint. This test MUST fail before implementation. """ import pytest from django.test import TestCase from django.urls import reverse from rest_framework.test import APIClient from rest_framework import status import json class HealthcareAppointmentsGetContractTest(TestCase): def setUp(self): self.client = APIClient() self.appointments_url = '/api/v1/healthcare/appointments/' # Tenant authentication header self.tenant_auth = {'HTTP_AUTHORIZATION': 'Bearer tenant_token'} def test_get_appointments_success(self): """Test successful retrieval of appointments list.""" response = self.client.get( self.appointments_url, **self.tenant_auth ) # This should fail before implementation assert response.status_code == status.HTTP_200_OK data = response.json() assert 'appointments' in data assert isinstance(data['appointments'], list) # Check pagination structure assert 'pagination' in data pagination = data['pagination'] assert 'page' in pagination assert 'limit' in pagination assert 'total' in pagination assert 'pages' in pagination def test_get_appointments_unauthorized(self): """Test appointments list retrieval without authentication.""" response = self.client.get(self.appointments_url) assert response.status_code == status.HTTP_401_UNAUTHORIZED def test_get_appointments_with_pagination(self): """Test appointments list retrieval with pagination parameters.""" params = { 'page': 2, 'limit': 20 } response = self.client.get( self.appointments_url, data=params, **self.tenant_auth ) assert response.status_code == status.HTTP_200_OK data = response.json() assert data['pagination']['page'] == 2 assert data['pagination']['limit'] == 20 def test_get_appointments_with_search(self): """Test appointments list retrieval with search parameter.""" params = { 'search': 'ahmad' } response = self.client.get( self.appointments_url, data=params, **self.tenant_auth ) assert response.status_code == status.HTTP_200_OK data = response.json() # All returned appointments should match search criteria for appointment in data['appointments']: search_match = ( 'ahmad' in appointment['patient_name'].lower() or 'ahmad' in appointment['doctor_name'].lower() or 'ahmad' in appointment['notes'].lower() ) assert search_match def test_get_appointments_filter_by_date_range(self): """Test appointments list retrieval filtered by date range.""" params = { 'start_date': '2024-01-01', 'end_date': '2024-01-31' } response = self.client.get( self.appointments_url, data=params, **self.tenant_auth ) assert response.status_code == status.HTTP_200_OK data = response.json() # All returned appointments should be within the date range for appointment in data['appointments']: appointment_date = appointment['appointment_datetime'].split('T')[0] assert '2024-01-01' <= appointment_date <= '2024-01-31' def test_get_appointments_filter_by_status(self): """Test appointments list retrieval filtered by status.""" params = { 'status': 'CONFIRMED' } response = self.client.get( self.appointments_url, data=params, **self.tenant_auth ) assert response.status_code == status.HTTP_200_OK data = response.json() # All returned appointments should have the specified status for appointment in data['appointments']: assert appointment['status'] == 'CONFIRMED' def test_get_appointments_filter_by_doctor(self): """Test appointments list retrieval filtered by doctor.""" params = { 'doctor_id': 'doctor-001' } response = self.client.get( self.appointments_url, data=params, **self.tenant_auth ) assert response.status_code == status.HTTP_200_OK data = response.json() # All returned appointments should be with the specified doctor for appointment in data['appointments']: assert appointment['doctor_id'] == 'doctor-001' def test_get_appointments_filter_by_patient(self): """Test appointments list retrieval filtered by patient.""" params = { 'patient_id': 'patient-001' } response = self.client.get( self.appointments_url, data=params, **self.tenant_auth ) assert response.status_code == status.HTTP_200_OK data = response.json() # All returned appointments should be for the specified patient for appointment in data['appointments']: assert appointment['patient_id'] == 'patient-001' def test_get_appointments_data_structure(self): """Test that appointment data structure matches the contract.""" response = self.client.get( self.appointments_url, **self.tenant_auth ) if response.status_code == status.HTTP_200_OK and len(response.json()['appointments']) > 0: appointment = response.json()['appointments'][0] # Required fields according to contract required_fields = [ 'id', 'patient_id', 'patient_name', 'doctor_id', 'doctor_name', 'appointment_datetime', 'duration', 'status', 'type', 'reason', 'notes', 'tenant_id', 'created_at', 'updated_at' ] for field in required_fields: assert field in appointment # Field types and enums assert isinstance(appointment['id'], str) assert isinstance(appointment['patient_id'], str) assert isinstance(appointment['patient_name'], str) assert isinstance(appointment['doctor_id'], str) assert isinstance(appointment['doctor_name'], str) assert isinstance(appointment['appointment_datetime'], str) assert isinstance(appointment['duration'], int) assert appointment['status'] in ['SCHEDULED', 'CONFIRMED', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED', 'NO_SHOW'] assert appointment['type'] in ['CONSULTATION', 'FOLLOW_UP', 'PROCEDURE', 'EMERGENCY', 'CHECKUP'] def test_get_appointments_with_patient_details(self): """Test that appointment data includes patient details.""" response = self.client.get( self.appointments_url, data={'include_patient_details': 'true'}, **self.tenant_auth ) if response.status_code == status.HTTP_200_OK and len(response.json()['appointments']) > 0: appointment = response.json()['appointments'][0] # Should include patient details assert 'patient_details' in appointment patient_details = appointment['patient_details'] # Patient details should include relevant fields expected_patient_fields = ['ic_number', 'phone', 'email', 'age', 'gender'] for field in expected_patient_fields: assert field in patient_details def test_get_appointments_with_doctor_details(self): """Test that appointment data includes doctor details.""" response = self.client.get( self.appointments_url, data={'include_doctor_details': 'true'}, **self.tenant_auth ) if response.status_code == status.HTTP_200_OK and len(response.json()['appointments']) > 0: appointment = response.json()['appointments'][0] # Should include doctor details assert 'doctor_details' in appointment doctor_details = appointment['doctor_details'] # Doctor details should include relevant fields expected_doctor_fields = ['specialization', 'license_number', 'department'] for field in expected_doctor_fields: assert field in doctor_details def test_get_appointments_sorting(self): """Test appointments list retrieval with sorting.""" params = { 'sort_by': 'appointment_datetime', 'sort_order': 'asc' } response = self.client.get( self.appointments_url, data=params, **self.tenant_auth ) assert response.status_code == status.HTTP_200_OK data = response.json() # Appointments should be sorted by datetime in ascending order appointment_datetimes = [appointment['appointment_datetime'] for appointment in data['appointments']] assert appointment_datetimes == sorted(appointment_datetimes) def test_get_appointments_tenant_isolation(self): """Test that appointments are isolated by tenant.""" response = self.client.get( self.appointments_url, **self.tenant_auth ) if response.status_code == status.HTTP_200_OK: data = response.json() # All returned appointments should belong to the authenticated tenant for appointment in data['appointments']: assert 'tenant_id' in appointment # This will be validated once implementation exists def test_get_appointments_upcoming_only(self): """Test appointments list retrieval for upcoming appointments only.""" params = { 'upcoming_only': 'true' } response = self.client.get( self.appointments_url, data=params, **self.tenant_auth ) assert response.status_code == status.HTTP_200_OK data = response.json() # All returned appointments should be in the future # This will be validated once implementation exists pass def test_get_appointments_with_reminders(self): """Test that appointment data includes reminder information.""" response = self.client.get( self.appointments_url, data={'include_reminders': 'true'}, **self.tenant_auth ) if response.status_code == status.HTTP_200_OK and len(response.json()['appointments']) > 0: appointment = response.json()['appointments'][0] # Should include reminder information assert 'reminders' in appointment reminders = appointment['reminders'] # Should be a list assert isinstance(reminders, list) if len(reminders) > 0: reminder = reminders[0] expected_reminder_fields = ['type', 'sent_at', 'status'] for field in expected_reminder_fields: assert field in reminder def test_get_appointments_with_virtual_info(self): """Test that appointment data includes virtual consultation information.""" response = self.client.get( self.appointments_url, data={'include_virtual_info': 'true'}, **self.tenant_auth ) if response.status_code == status.HTTP_200_OK and len(response.json()['appointments']) > 0: appointment = response.json()['appointments'][0] # Should include virtual consultation info if applicable if appointment.get('is_virtual', False): assert 'virtual_consultation' in appointment virtual_info = appointment['virtual_consultation'] expected_virtual_fields = ['platform', 'link', 'instructions'] for field in expected_virtual_fields: assert field in virtual_info