""" Pytest configuration and fixtures for the recruitment application tests. """ import os import sys import django from pathlib import Path # Setup Django BASE_DIR = Path(__file__).resolve().parent # Add the project root to sys.path sys.path.append(str(BASE_DIR)) # Set the Django settings module os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings') # Configure Django django.setup() import pytest from django.test import TestCase from django.contrib.auth.models import User from django.core.files.uploadedfile import SimpleUploadedFile from django.utils import timezone from datetime import datetime, time, timedelta, date from recruitment.models import ( JobPosting, Candidate, ZoomMeeting, FormTemplate, FormStage, FormField, FormSubmission, FieldResponse, BulkInterviewTemplate, ScheduledInterview, TrainingMaterial, Source, HiringAgency, Profile, MeetingComment, JobPostingImage, BreakTime ) from recruitment.forms import ( JobPostingForm, CandidateForm, ZoomMeetingForm, MeetingCommentForm, CandidateStageForm, BulkInterviewTemplateForm, BreakTimeFormSet ) # Removed: django_db_setup fixture conflicts with Django TestCase # Django TestCase handles its own database setup @pytest.fixture def user(): """Create a regular user for testing""" return User.objects.create_user( username='testuser', email='test@example.com', password='testpass123', is_staff=False ) @pytest.fixture def staff_user(): """Create a staff user for testing""" return User.objects.create_user( username='staffuser', email='staff@example.com', password='testpass123', is_staff=True ) @pytest.fixture def profile(user): """Create a user profile""" return Profile.objects.create(user=user) @pytest.fixture def job(staff_user): """Create a job posting for testing""" return JobPosting.objects.create( title='Software Engineer', department='IT', job_type='FULL_TIME', workplace_type='REMOTE', location_country='Saudi Arabia', description='Job description', qualifications='Job qualifications', created_by=staff_user, status='ACTIVE', max_applications=100, open_positions=1 ) @pytest.fixture def candidate(job): """Create a candidate for testing""" return Candidate.objects.create( first_name='John', last_name='Doe', email='john@example.com', phone='1234567890', job=job, stage='Applied' ) @pytest.fixture def zoom_meeting(): """Create a Zoom meeting for testing""" return ZoomMeeting.objects.create( topic='Interview with John Doe', start_time=timezone.now() + timedelta(hours=1), duration=60, timezone='UTC', join_url='https://zoom.us/j/123456789', meeting_id='123456789', status='waiting' ) @pytest.fixture def form_template(staff_user, job): """Create a form template for testing""" return FormTemplate.objects.create( job=job, name='Test Application Form', description='Test form template', created_by=staff_user, is_active=True ) @pytest.fixture def form_stage(form_template): """Create a form stage for testing""" return FormStage.objects.create( template=form_template, name='Personal Information', order=0 ) @pytest.fixture def form_field(form_stage): """Create a form field for testing""" return FormField.objects.create( stage=form_stage, label='First Name', field_type='text', order=0, required=True ) @pytest.fixture def form_submission(form_template): """Create a form submission for testing""" return FormSubmission.objects.create( template=form_template, applicant_name='John Doe', applicant_email='john@example.com' ) @pytest.fixture def field_response(form_submission, form_field): """Create a field response for testing""" return FieldResponse.objects.create( submission=form_submission, field=form_field, value='John' ) @pytest.fixture def interview_schedule(staff_user, job): """Create an interview schedule for testing""" # Create candidates first candidates = [] for i in range(3): candidate = Candidate.objects.create( first_name=f'Candidate{i}', last_name=f'Test{i}', email=f'candidate{i}@example.com', phone=f'12345678{i}', job=job, stage='Interview' ) candidates.append(candidate) return BulkInterviewTemplate.objects.create( job=job, created_by=staff_user, start_date=date.today() + timedelta(days=1), end_date=date.today() + timedelta(days=7), working_days=[0, 1, 2, 3, 4], # Mon-Fri start_time=time(9, 0), end_time=time(17, 0), interview_duration=60, buffer_time=15, break_start_time=time(12, 0), break_end_time=time(13, 0) ) @pytest.fixture def scheduled_interview(candidate, job, zoom_meeting): """Create a scheduled interview for testing""" return ScheduledInterview.objects.create( candidate=candidate, job=job, zoom_meeting=zoom_meeting, interview_date=timezone.now().date(), interview_time=time(10, 0), status='scheduled' ) @pytest.fixture def meeting_comment(user, zoom_meeting): """Create a meeting comment for testing""" return MeetingComment.objects.create( meeting=zoom_meeting, author=user, content='This is a test comment' ) @pytest.fixture def file_content(): """Create test file content""" return b'%PDF-1.4\n% ... test content ...' @pytest.fixture def uploaded_file(file_content): """Create an uploaded file for testing""" return SimpleUploadedFile( 'test_file.pdf', file_content, content_type='application/pdf' ) @pytest.fixture def job_form_data(): """Basic job posting form data for testing""" return { 'title': 'Test Job Title', 'department': 'IT', 'job_type': 'FULL_TIME', 'workplace_type': 'REMOTE', 'location_city': 'Riyadh', 'location_state': 'Riyadh', 'location_country': 'Saudi Arabia', 'description': 'Job description', 'qualifications': 'Job qualifications', 'salary_range': '5000-7000', 'application_deadline': '2025-12-31', 'max_applications': '100', 'open_positions': '1', 'hash_tags': '#hiring, #jobopening' } @pytest.fixture def candidate_form_data(job): """Basic candidate form data for testing""" return { 'job': job.id, 'first_name': 'John', 'last_name': 'Doe', 'phone': '1234567890', 'email': 'john@example.com' } @pytest.fixture def zoom_meeting_form_data(): """Basic Zoom meeting form data for testing""" start_time = timezone.now() + timedelta(hours=1) return { 'topic': 'Test Meeting', 'start_time': start_time.strftime('%Y-%m-%dT%H:%M'), 'duration': 60 } @pytest.fixture def interview_schedule_form_data(job): """Basic interview schedule form data for testing""" # Create candidates first candidates = [] for i in range(2): candidate = Candidate.objects.create( first_name=f'Interview{i}', last_name=f'Candidate{i}', email=f'interview{i}@example.com', phone=f'12345678{i}', job=job, stage='Interview' ) candidates.append(candidate) return { 'candidates': [c.pk for c in candidates], 'start_date': (date.today() + timedelta(days=1)).isoformat(), 'end_date': (date.today() + timedelta(days=7)).isoformat(), 'working_days': [0, 1, 2, 3, 4], 'start_time': '09:00', 'end_time': '17:00', 'interview_duration': '60', 'buffer_time': '15' } @pytest.fixture def client(): """Django test client""" from django.test import Client return Client() @pytest.fixture def authenticated_client(client, user): """Authenticated Django test client""" client.force_login(user) return client @pytest.fixture def authenticated_staff_client(client, staff_user): """Authenticated staff Django test client""" client.force_login(staff_user) return client @pytest.fixture def mock_zoom_api(): """Mock Zoom API responses""" with pytest.MonkeyPatch().context() as m: m.setattr('recruitment.utils.create_zoom_meeting', lambda *args, **kwargs: { 'status': 'success', 'meeting_details': { 'meeting_id': '123456789', 'join_url': 'https://zoom.us/j/123456789', 'password': 'meeting123' }, 'zoom_gateway_response': {'status': 'waiting'} }) yield @pytest.fixture def mock_time_slots(): """Mock available time slots for interview scheduling""" return [ {'date': date.today() + timedelta(days=1), 'time': '10:00'}, {'date': date.today() + timedelta(days=1), 'time': '11:00'}, {'date': date.today() + timedelta(days=1), 'time': '14:00'}, {'date': date.today() + timedelta(days=2), 'time': '09:00'}, {'date': date.today() + timedelta(days=2), 'time': '15:00'} ] # Test markers def pytest_configure(config): """Configure custom markers""" config.addinivalue_line( "markers", "slow: marks tests as slow (deselect with '-m \"not slow\"')" ) config.addinivalue_line( "markers", "integration: marks tests as integration tests" ) config.addinivalue_line( "markers", "unit: marks tests as unit tests" ) config.addinivalue_line( "markers", "security: marks tests as security tests" ) config.addinivalue_line( "markers", "api: marks tests as API tests" ) # Pytest hooks for better test output # Note: HTML reporting hooks are commented out to avoid plugin validation issues # def pytest_html_report_title(report): # """Set the HTML report title""" # report.title = "Recruitment Application Test Report" # def pytest_runtest_logreport(report): # """Customize test output""" # if report.when == 'call' and report.failed: # # Add custom information for failed tests # pass