gapguide-api / apps /skills /tests /test_admin_skills.py
arifRB's picture
Deploy GapGuide backend (Docker)
ffd36e0 verified
Raw
History Blame Contribute Delete
4.28 kB
"""Tests for admin-only skill CRUD at /api/admin/skills/.
Matches the existing test_roles.py style (pytest + force_authenticate).
"""
import pytest
from django.contrib.auth import get_user_model
from rest_framework import status
from rest_framework.test import APIClient
from apps.roles.models import Role, RoleSkill
from apps.skills.models import Skill, UserSkill
User = get_user_model()
pytestmark = pytest.mark.django_db
ADMIN_SKILLS_URL = '/api/admin/skills/'
@pytest.fixture
def admin_client():
user = User.objects.create_user(
username='admin@test.example', email='admin@test.example',
password='x', name='Admin', role_type='ADMIN',
is_staff=True,
)
c = APIClient()
c.force_authenticate(user=user)
return c
@pytest.fixture
def student_client():
user = User.objects.create_user(
username='student@test.example', email='student@test.example',
password='x', name='Student', role_type='STUDENT',
)
c = APIClient()
c.force_authenticate(user=user)
return c
@pytest.fixture
def skill():
return Skill.objects.create(
skill_name='Python', category='Programming', difficulty_level='BEGINNER',
)
class TestSkillAdminPermissions:
def test_student_forbidden_on_create(self, student_client):
resp = student_client.post(ADMIN_SKILLS_URL, {
'skill_name': 'Rust', 'category': 'Programming',
'difficulty_level': 'INTERMEDIATE',
}, format='json')
assert resp.status_code == status.HTTP_403_FORBIDDEN
def test_anonymous_forbidden(self, skill):
resp = APIClient().get(ADMIN_SKILLS_URL)
# Default DRF returns 401 for unauthenticated, 403 if auth succeeds
# but permission fails. Either way, access is denied.
assert resp.status_code in (status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN)
class TestSkillAdminCrud:
def test_admin_full_cycle(self, admin_client):
# Create
resp = admin_client.post(ADMIN_SKILLS_URL, {
'skill_name': 'Go',
'category': 'Programming',
'description': 'Google Go',
'difficulty_level': 'INTERMEDIATE',
}, format='json')
assert resp.status_code == status.HTTP_201_CREATED, resp.data
skill_id = resp.data['id']
# List
resp = admin_client.get(ADMIN_SKILLS_URL)
assert resp.status_code == status.HTTP_200_OK
# Paginated response wraps rows in `results`.
rows = resp.data['results'] if isinstance(resp.data, dict) else resp.data
assert any(r['id'] == skill_id for r in rows)
# Update
resp = admin_client.patch(
f'{ADMIN_SKILLS_URL}{skill_id}/',
{'description': 'Updated'}, format='json',
)
assert resp.status_code == status.HTTP_200_OK
assert resp.data['description'] == 'Updated'
# Delete (no references) succeeds
resp = admin_client.delete(f'{ADMIN_SKILLS_URL}{skill_id}/')
assert resp.status_code == status.HTTP_204_NO_CONTENT
assert not Skill.objects.filter(pk=skill_id).exists()
def test_delete_blocked_when_user_skill_references_it(self, admin_client, skill):
# Reference the skill from a UserSkill row.
user = User.objects.create_user(
username='ref@test.example', email='ref@test.example',
password='x', name='Ref',
)
UserSkill.objects.create(
user=user, skill=skill, proficiency=50, user_level='BEGINNER',
)
resp = admin_client.delete(f'{ADMIN_SKILLS_URL}{skill.id}/')
assert resp.status_code == status.HTTP_409_CONFLICT
assert 'student skill profiles' in resp.data['detail']
# Skill still exists.
assert Skill.objects.filter(pk=skill.id).exists()
def test_delete_blocked_when_role_skill_references_it(self, admin_client, skill):
role = Role.objects.create(role_name='Dev', industry='Tech')
RoleSkill.objects.create(
role=role, skill=skill, required_level='BEGINNER',
)
resp = admin_client.delete(f'{ADMIN_SKILLS_URL}{skill.id}/')
assert resp.status_code == status.HTTP_409_CONFLICT
assert 'role requirements' in resp.data['detail']