389 lines
10 KiB
Python
389 lines
10 KiB
Python
"""
|
|
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.contrib.auth.models import User
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
from django.utils import timezone
|
|
from datetime import time, timedelta, date
|
|
|
|
from recruitment.models import (
|
|
JobPosting, Candidate, ZoomMeeting, FormTemplate, FormStage, FormField,
|
|
FormSubmission, FieldResponse, BulkInterviewTemplate, ScheduledInterview,Profile, MeetingComment,
|
|
|
|
)
|
|
|
|
|
|
# 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
|