import pytest from rest_framework.test import APIClient from apps.skills.models import Skill pytestmark = pytest.mark.django_db REGISTER_URL = '/api/auth/register/' LOGIN_URL = '/api/auth/login/' PROFILE_URL = '/api/auth/profile/' PARSE_RESUME_URL = '/api/auth/profile/parse-resume/' SKILLS_URL = '/api/skills/' USER_SKILLS_URL = '/api/user-skills/' VALID_USER = { 'name': 'Test User', 'email': 'test2@example.com', 'password': 'TestPass123!', 'password_confirm': 'TestPass123!' } @pytest.fixture def api_client(): return APIClient() @pytest.fixture def skill(db): return Skill.objects.create( skill_name='Python', category='Programming', difficulty_level='BEGINNER' ) @pytest.fixture def auth_client(api_client): api_client.post(REGISTER_URL, data=VALID_USER, format='json') login_resp = api_client.post( LOGIN_URL, data={'email': VALID_USER['email'], 'password': VALID_USER['password']}, format='json' ) token = login_resp.data['access'] api_client.credentials(HTTP_AUTHORIZATION=f'Bearer {token}') return api_client class TestProfile: def test_get_profile(self, auth_client): """TC-05: GET /profile/ returns profile + skills.""" response = auth_client.get(PROFILE_URL) assert response.status_code == 200 assert 'user' in response.data assert 'profile' in response.data assert 'skills' in response.data def test_update_profile(self, auth_client): """TC-05: PUT /profile/ updates degree, semester, bio.""" data = { 'degree': 'BS Computer Science', 'semester': 6, 'bio': 'I love coding', 'interests': 'AI, Web Dev' } response = auth_client.put(PROFILE_URL, data=data, format='json') assert response.status_code == 200 assert response.data['profile']['degree'] == 'BS Computer Science' assert response.data['profile']['semester'] == 6 def test_update_profile_with_skills(self, auth_client, skill): """TC-06: PUT /profile/ with skills upserts UserSkills.""" data = { 'degree': 'BS CS', 'skills': [ {'skill_id': skill.id, 'proficiency': 65} ] } response = auth_client.put(PROFILE_URL, data=data, format='json') assert response.status_code == 200 skills = response.data['skills'] assert len(skills) == 1 assert skills[0]['proficiency'] == 65 assert skills[0]['user_level'] == 'ADVANCED' # 65 > 60 def test_user_level_auto_computed(self, auth_client, skill): """TC-06: user_level is auto-derived from proficiency.""" data = {'skills': [{'skill_id': skill.id, 'proficiency': 30}]} response = auth_client.put(PROFILE_URL, data=data, format='json') assert response.status_code == 200 assert response.data['skills'][0]['user_level'] == 'BEGINNER' # 30 <= 40 def test_profile_requires_auth(self, api_client): """Profile endpoints require authentication.""" response = api_client.get(PROFILE_URL) assert response.status_code == 401 class TestSkillCatalog: def test_list_skills(self, auth_client, skill): """GET /skills/ returns skill catalog (paginated).""" response = auth_client.get(SKILLS_URL) assert response.status_code == 200 assert response.data['count'] >= 1 def test_filter_by_category(self, auth_client, skill): """GET /skills/?category=Programming filters skills.""" response = auth_client.get(f'{SKILLS_URL}?category=Programming') assert response.status_code == 200 assert all(s['category'] == 'Programming' for s in response.data['results']) class TestUserSkills: def test_add_user_skill(self, auth_client, skill): """POST /user-skills/ adds a skill to user.""" data = {'skill_id': skill.id, 'proficiency': 50} response = auth_client.post(USER_SKILLS_URL, data=data, format='json') assert response.status_code == 201 assert response.data['proficiency'] == 50 assert response.data['user_level'] == 'INTERMEDIATE' def test_update_user_skill(self, auth_client, skill): """PUT /user-skills// updates proficiency.""" # First add add_resp = auth_client.post( USER_SKILLS_URL, data={'skill_id': skill.id, 'proficiency': 30}, format='json' ) skill_id = add_resp.data['id'] # Then update update_resp = auth_client.put( f'{USER_SKILLS_URL}{skill_id}/', data={'skill_id': skill.id, 'proficiency': 70}, format='json' ) assert update_resp.status_code == 200 assert update_resp.data['user_level'] == 'ADVANCED' class TestParseResumeStub: """The Module 2 "stub" endpoint is now the real Module 8 MVP endpoint. Kept under this class name for continuity — full happy-path + edge-case coverage lives in apps/accounts/tests/test_resume_parser.py. """ def test_requires_auth(self, api_client): resp = api_client.post(PARSE_RESUME_URL, data={}, format='json') assert resp.status_code == 401 def test_empty_body_returns_400(self, auth_client): resp = auth_client.post(PARSE_RESUME_URL, data={}, format='multipart') assert resp.status_code == 400 assert 'detail' in resp.data