Files
state-corp-backend/tests/apps/user/test_serializers.py
Aleksandr Meshchriakov 8ead5ebadc
Some checks failed
CI/CD Pipeline / Code Quality Checks (push) Failing after 1m42s
CI/CD Pipeline / Run Tests (push) Successful in 1m45s
CI/CD Pipeline / Build Docker Images (push) Has been skipped
CI/CD Pipeline / Push to Gitea Registry (push) Has been skipped
CI/CD Pipeline / Deploy to Server (push) Has been skipped
Extend organization analytics contract and fix test warnings
2026-04-19 12:23:38 +02:00

395 lines
14 KiB
Python

"""Tests for user serializers"""
from datetime import datetime, timedelta
from apps.core.models import BackgroundJob, JobStatus
from apps.user.serializers import (
CurrentUserProfileSerializer,
CurrentUserSerializer,
LoginSerializer,
PasswordChangeSerializer,
ProfileUpdateSerializer,
TokenSerializer,
UserManagementSerializer,
UserRegistrationSerializer,
UserSerializer,
UserUpdateSerializer,
)
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.utils import timezone
from faker import Faker
from .factories import ProfileFactory, UserFactory
User = get_user_model()
fake = Faker("ru_RU")
class UserRegistrationSerializerTest(TestCase):
"""Tests for UserRegistrationSerializer"""
def setUp(self):
self.password = fake.password(length=12, special_chars=False)
self.user_data = {
"email": fake.unique.email(),
"username": fake.unique.user_name(),
"password": self.password,
"password_confirm": self.password,
"phone": f"+7{fake.numerify('##########')}",
}
def test_valid_registration_data(self):
"""Test valid registration data"""
serializer = UserRegistrationSerializer(data=self.user_data)
self.assertTrue(serializer.is_valid())
def test_passwords_do_not_match(self):
"""Test validation fails when passwords don't match"""
data = self.user_data.copy()
data["password_confirm"] = fake.password(length=12, special_chars=False)
serializer = UserRegistrationSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("non_field_errors", serializer.errors)
def test_short_password(self):
"""Test validation fails with short password"""
short_password = fake.pystr(min_chars=3, max_chars=5)
data = self.user_data.copy()
data["password"] = short_password
data["password_confirm"] = short_password
serializer = UserRegistrationSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("password", serializer.errors)
def test_duplicate_email(self):
"""Test validation fails with duplicate email"""
existing_user = UserFactory.create_user()
data = self.user_data.copy()
data["email"] = existing_user.email
serializer = UserRegistrationSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("email", serializer.errors)
def test_duplicate_username(self):
"""Test validation fails with duplicate username"""
existing_user = UserFactory.create_user()
data = self.user_data.copy()
data["username"] = existing_user.username
serializer = UserRegistrationSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("username", serializer.errors)
def test_create_user(self):
"""Test user creation through serializer"""
serializer = UserRegistrationSerializer(data=self.user_data)
self.assertTrue(serializer.is_valid())
user = serializer.save()
self.assertIsInstance(user, User)
self.assertEqual(user.email, self.user_data["email"])
self.assertEqual(user.username, self.user_data["username"])
self.assertTrue(user.check_password(self.user_data["password"]))
class UserSerializerTest(TestCase):
"""Tests for UserSerializer"""
def setUp(self):
self.user = UserFactory.create_user()
ProfileFactory.create_profile(user=self.user)
def test_user_serialization(self):
"""Test user serialization"""
serializer = UserSerializer(self.user)
data = serializer.data
self.assertEqual(data["id"], self.user.id)
self.assertEqual(data["email"], self.user.email)
self.assertEqual(data["username"], self.user.username)
self.assertEqual(data["phone"], self.user.phone)
self.assertEqual(data["is_verified"], self.user.is_verified)
self.assertIn("profile", data)
self.assertIn("created_at", data)
self.assertIn("updated_at", data)
def test_read_only_fields(self):
"""Test that read-only fields are not writable"""
read_only_fields = ["id", "is_verified", "created_at", "updated_at"]
serializer = UserSerializer()
for field_name in read_only_fields:
self.assertIn(field_name, serializer.Meta.read_only_fields)
class CurrentUserProfileSerializerTest(TestCase):
"""Tests for current user profile serializer"""
def setUp(self):
self.user = UserFactory.create_user()
self.profile = ProfileFactory.create_profile(
user=self.user,
first_name="Ivan",
mid_name=None,
last_name="Petrov",
)
def test_middle_name_falls_back_to_empty_string(self):
serializer = CurrentUserProfileSerializer(self.profile)
self.assertEqual(serializer.data["middle_name"], "")
class CurrentUserSerializerTest(TestCase):
"""Tests for current user serializer fields."""
def setUp(self):
self.user = UserFactory.create_user()
def test_current_user_contains_is_active(self):
serializer = CurrentUserSerializer(self.user)
self.assertIn("is_active", serializer.data)
self.assertEqual(serializer.data["is_active"], self.user.is_active)
class UserManagementSerializerTest(TestCase):
"""Tests for user management serializer."""
def setUp(self):
self.user = UserFactory.create_user()
self.user.profile.first_name = None
self.user.profile.mid_name = None
self.user.profile.last_name = None
self.user.profile.save()
def test_profile_fields_fallback_to_empty_string(self):
serializer = UserManagementSerializer(self.user)
self.assertEqual(serializer.data["first_name"], "")
self.assertEqual(serializer.data["middle_name"], "")
self.assertEqual(serializer.data["last_name"], "")
def test_metric_fields_are_derived_from_latest_job(self):
now = timezone.make_aware(datetime(2026, 4, 14, 10, 0, 0))
latest_job = BackgroundJob.objects.create(
task_id="admin-management-latest",
task_name="apps.forms.process",
user_id=self.user.id,
status=JobStatus.SUCCESS,
progress=100,
progress_message="Готово",
result={"processed": 10},
started_at=now,
completed_at=now + timedelta(minutes=3),
created_at=now,
updated_at=now + timedelta(minutes=3),
)
BackgroundJob.objects.create(
task_id="admin-management-old",
task_name="apps.forms.process",
user_id=self.user.id,
status=JobStatus.FAILURE,
progress=100,
progress_message="Ошибка",
error="old-error",
started_at=now - timedelta(minutes=15),
completed_at=now - timedelta(minutes=10),
created_at=now - timedelta(minutes=15),
updated_at=now - timedelta(minutes=10),
)
self.user.latest_job = latest_job
serializer = UserManagementSerializer(self.user)
self.assertEqual(serializer.data["progress_message"], "Готово")
self.assertEqual(serializer.data["result"], {"processed": 10})
self.assertIsNone(serializer.data["error"])
self.assertEqual(serializer.data["is_successful"], True)
self.assertEqual(serializer.data["duration"], 180.0)
class UserUpdateSerializerTest(TestCase):
"""Tests for UserUpdateSerializer"""
def setUp(self):
self.user = UserFactory.create_user()
def test_valid_update_data(self):
"""Test valid update data"""
update_data = {
"username": fake.unique.user_name(),
"phone": f"+7{fake.numerify('##########')}",
}
serializer = UserUpdateSerializer(self.user, data=update_data, partial=True)
self.assertTrue(serializer.is_valid())
updated_user = serializer.save()
self.assertEqual(updated_user.username, update_data["username"])
self.assertEqual(updated_user.phone, update_data["phone"])
def test_fields_allowed(self):
"""Test only allowed fields can be updated"""
serializer = UserUpdateSerializer()
allowed_fields = ["username", "phone"]
self.assertEqual(set(serializer.Meta.fields), set(allowed_fields))
class ProfileUpdateSerializerTest(TestCase):
"""Tests for ProfileUpdateSerializer"""
def setUp(self):
self.user = UserFactory.create_user()
self.profile = ProfileFactory.create_profile(user=self.user)
def test_valid_profile_update_data(self):
"""Test valid profile update data"""
update_data = {
"first_name": fake.first_name(),
"mid_name": fake.first_name(),
"last_name": fake.last_name(),
"bio": fake.text(max_nb_chars=200),
"date_of_birth": str(fake.date_of_birth(minimum_age=18, maximum_age=80)),
}
serializer = ProfileUpdateSerializer(
self.profile, data=update_data, partial=True
)
self.assertTrue(serializer.is_valid())
updated_profile = serializer.save()
self.assertEqual(updated_profile.first_name, update_data["first_name"])
self.assertEqual(updated_profile.mid_name, update_data["mid_name"])
self.assertEqual(updated_profile.last_name, update_data["last_name"])
self.assertEqual(updated_profile.bio, update_data["bio"])
def test_fields_allowed(self):
"""Test only allowed fields can be updated"""
serializer = ProfileUpdateSerializer()
allowed_fields = [
"first_name",
"mid_name",
"last_name",
"bio",
"avatar",
"date_of_birth",
]
self.assertEqual(set(serializer.Meta.fields), set(allowed_fields))
class LoginSerializerTest(TestCase):
"""Tests for LoginSerializer"""
def setUp(self):
self.login_data = {
"username": fake.user_name(),
"password": fake.password(length=12, special_chars=False),
}
def test_valid_login_data(self):
"""Test valid login data"""
serializer = LoginSerializer(data=self.login_data)
self.assertTrue(serializer.is_valid())
def test_missing_username(self):
"""Test validation fails without username"""
data = {"password": fake.password(length=12, special_chars=False)}
serializer = LoginSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("username", serializer.errors)
def test_missing_password(self):
"""Test validation fails without password"""
data = {"username": fake.user_name()}
serializer = LoginSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("password", serializer.errors)
class TokenSerializerTest(TestCase):
"""Tests for TokenSerializer"""
def test_valid_token_data(self):
"""Test valid token data"""
token_data = {
"access": fake.pystr(min_chars=50, max_chars=100),
"refresh": fake.pystr(min_chars=50, max_chars=100),
}
serializer = TokenSerializer(data=token_data)
self.assertTrue(serializer.is_valid())
def test_missing_access_token(self):
"""Test validation fails without access token"""
data = {"refresh": fake.pystr(min_chars=50, max_chars=100)}
serializer = TokenSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("access", serializer.errors)
def test_missing_refresh_token(self):
"""Test validation fails without refresh token"""
data = {"access": fake.pystr(min_chars=50, max_chars=100)}
serializer = TokenSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("refresh", serializer.errors)
class PasswordChangeSerializerTest(TestCase):
"""Tests for PasswordChangeSerializer"""
def setUp(self):
self.old_password = fake.password(length=12, special_chars=False)
self.new_password = fake.password(length=12, special_chars=False)
self.password_data = {
"old_password": self.old_password,
"new_password": self.new_password,
"new_password_confirm": self.new_password,
}
def test_valid_password_change_data(self):
"""Test valid password change data"""
serializer = PasswordChangeSerializer(data=self.password_data)
self.assertTrue(serializer.is_valid())
def test_passwords_do_not_match(self):
"""Test validation fails when new passwords don't match"""
data = self.password_data.copy()
data["new_password_confirm"] = fake.password(length=12, special_chars=False)
serializer = PasswordChangeSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("non_field_errors", serializer.errors)
def test_short_new_password(self):
"""Test validation fails with short new password"""
short_password = fake.pystr(min_chars=3, max_chars=5)
data = self.password_data.copy()
data["new_password"] = short_password
data["new_password_confirm"] = short_password
serializer = PasswordChangeSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("new_password", serializer.errors)
def test_missing_old_password(self):
"""Test validation fails without old password"""
new_password = fake.password(length=12, special_chars=False)
data = {"new_password": new_password, "new_password_confirm": new_password}
serializer = PasswordChangeSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertIn("old_password", serializer.errors)