Align frontend API contracts
This commit is contained in:
@@ -80,23 +80,23 @@ class ProfileModelTest(TestCase):
|
||||
"""Test OneToOne relationship with User"""
|
||||
self.assertIsNotNone(self.profile.user)
|
||||
|
||||
def test_profile_first_name_optional(self):
|
||||
"""Test first_name field is optional"""
|
||||
def test_profile_first_name_required(self):
|
||||
"""Test first_name field is required and stored without NULL."""
|
||||
field = self.profile._meta.get_field("first_name")
|
||||
self.assertTrue(field.blank)
|
||||
self.assertTrue(field.null)
|
||||
self.assertFalse(field.blank)
|
||||
self.assertFalse(field.null)
|
||||
|
||||
def test_profile_last_name_optional(self):
|
||||
"""Test last_name field is optional"""
|
||||
def test_profile_last_name_required(self):
|
||||
"""Test last_name field is required and stored without NULL."""
|
||||
field = self.profile._meta.get_field("last_name")
|
||||
self.assertTrue(field.blank)
|
||||
self.assertTrue(field.null)
|
||||
self.assertFalse(field.blank)
|
||||
self.assertFalse(field.null)
|
||||
|
||||
def test_profile_middle_name_optional(self):
|
||||
"""Test middle_name field is optional"""
|
||||
def test_profile_middle_name_optional_but_not_null(self):
|
||||
"""Test middle_name remains optional but stored without NULL."""
|
||||
field = self.profile._meta.get_field("middle_name")
|
||||
self.assertTrue(field.blank)
|
||||
self.assertTrue(field.null)
|
||||
self.assertFalse(field.null)
|
||||
|
||||
def test_profile_bio_optional(self):
|
||||
"""Test bio field is optional"""
|
||||
@@ -126,7 +126,7 @@ class ProfileModelTest(TestCase):
|
||||
self.profile.middle_name = middle_name
|
||||
self.profile.last_name = last_name
|
||||
self.assertEqual(
|
||||
self.profile.full_name, f"{first_name} {middle_name} {last_name}"
|
||||
self.profile.full_name, f"{last_name} {first_name} {middle_name}"
|
||||
)
|
||||
|
||||
# Test with only first name
|
||||
|
||||
@@ -33,6 +33,9 @@ class UserRegistrationSerializerTest(TestCase):
|
||||
"password": self.password,
|
||||
"password_confirm": self.password,
|
||||
"phone": f"+7{fake.numerify('##########')}",
|
||||
"first_name": fake.first_name(),
|
||||
"middle_name": fake.first_name(),
|
||||
"last_name": fake.last_name(),
|
||||
}
|
||||
|
||||
def test_valid_registration_data(self):
|
||||
@@ -95,6 +98,20 @@ class UserRegistrationSerializerTest(TestCase):
|
||||
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"]))
|
||||
self.assertEqual(user.profile.first_name, self.user_data["first_name"])
|
||||
self.assertEqual(user.profile.middle_name, self.user_data["middle_name"])
|
||||
self.assertEqual(user.profile.last_name, self.user_data["last_name"])
|
||||
|
||||
def test_registration_requires_first_and_last_name(self):
|
||||
data = self.user_data.copy()
|
||||
data.pop("first_name")
|
||||
data.pop("last_name")
|
||||
|
||||
serializer = UserRegistrationSerializer(data=data)
|
||||
|
||||
self.assertFalse(serializer.is_valid())
|
||||
self.assertIn("first_name", serializer.errors)
|
||||
self.assertIn("last_name", serializer.errors)
|
||||
|
||||
|
||||
class UserSerializerTest(TestCase):
|
||||
@@ -217,6 +234,7 @@ class AdminUserUpdateSerializerTest(TestCase):
|
||||
"is_active": False,
|
||||
"first_name": fake.first_name(),
|
||||
"middle_name": fake.first_name(),
|
||||
"last_name": fake.last_name(),
|
||||
},
|
||||
partial=True,
|
||||
)
|
||||
|
||||
@@ -57,6 +57,18 @@ class UserServiceTest(TestCase):
|
||||
self.assertEqual(UserService.get_user_role(user), UserService.ROLE_ADMIN)
|
||||
self.assertTrue(user.groups.filter(name=UserService.ROLE_ADMIN).exists())
|
||||
|
||||
def test_create_user_with_profile_names(self):
|
||||
user = UserService.create_user(
|
||||
**self.user_data,
|
||||
first_name="Иван",
|
||||
middle_name="Иванович",
|
||||
last_name="Иванов",
|
||||
)
|
||||
|
||||
self.assertEqual(user.profile.first_name, "Иван")
|
||||
self.assertEqual(user.profile.middle_name, "Иванович")
|
||||
self.assertEqual(user.profile.last_name, "Иванов")
|
||||
|
||||
def test_get_user_by_email_found(self):
|
||||
"""Test getting user by existing email"""
|
||||
found_user = UserService.get_user_by_email(self.user.email)
|
||||
@@ -191,8 +203,8 @@ class UserServiceTest(TestCase):
|
||||
|
||||
queryset = UserService.get_filtered_users_queryset(ordering="first_name")
|
||||
|
||||
ids = list(queryset.values_list("id", flat=True)[:2])
|
||||
self.assertEqual(ids, [second.id, first.id])
|
||||
ids = list(queryset.values_list("id", flat=True))
|
||||
self.assertLess(ids.index(second.id), ids.index(first.id))
|
||||
|
||||
def test_get_user_capabilities_for_admin(self):
|
||||
"""Test admin capabilities set."""
|
||||
|
||||
@@ -7,6 +7,7 @@ from django.urls import reverse
|
||||
from faker import Faker
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient, APITestCase
|
||||
from rest_framework_simplejwt.token_blacklist.models import BlacklistedToken
|
||||
|
||||
from .factories import ProfileFactory, UserFactory
|
||||
|
||||
@@ -26,6 +27,9 @@ class RegisterViewTest(APITestCase):
|
||||
"password": self.password,
|
||||
"password_confirm": self.password,
|
||||
"phone": f"+7{fake.numerify('##########')}",
|
||||
"first_name": fake.first_name(),
|
||||
"middle_name": fake.first_name(),
|
||||
"last_name": fake.last_name(),
|
||||
}
|
||||
|
||||
def test_register_success(self):
|
||||
@@ -39,7 +43,9 @@ class RegisterViewTest(APITestCase):
|
||||
self.assertIn("access", response.data["tokens"])
|
||||
|
||||
# Verify user was created
|
||||
self.assertTrue(User.objects.filter(email=self.user_data["email"]).exists())
|
||||
created_user = User.objects.get(email=self.user_data["email"])
|
||||
self.assertEqual(created_user.profile.first_name, self.user_data["first_name"])
|
||||
self.assertEqual(created_user.profile.last_name, self.user_data["last_name"])
|
||||
|
||||
def test_register_passwords_do_not_match(self):
|
||||
"""Test registration fails when passwords don't match"""
|
||||
@@ -77,6 +83,17 @@ class RegisterViewTest(APITestCase):
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
self.assertIn("password", response.data)
|
||||
|
||||
def test_register_requires_first_and_last_name(self):
|
||||
data = self.user_data.copy()
|
||||
data.pop("first_name")
|
||||
data.pop("last_name")
|
||||
|
||||
response = self.client.post(self.register_url, data, format="json")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
self.assertIn("first_name", response.data)
|
||||
self.assertIn("last_name", response.data)
|
||||
|
||||
|
||||
class LoginViewTest(APITestCase):
|
||||
"""Tests for LoginView"""
|
||||
@@ -125,7 +142,7 @@ class LoginViewTest(APITestCase):
|
||||
|
||||
|
||||
class LogoutViewTest(APITestCase):
|
||||
def test_logout_returns_success_message(self):
|
||||
def test_logout_blacklists_refresh_tokens_and_returns_empty_payload(self):
|
||||
user = UserFactory.create_user()
|
||||
tokens = UserService.get_tokens_for_user(user)
|
||||
self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {tokens['access']}")
|
||||
@@ -133,7 +150,8 @@ class LogoutViewTest(APITestCase):
|
||||
response = self.client.post(reverse("api_v1:user:logout"), {}, format="json")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["message"], "Успешный выход")
|
||||
self.assertEqual(response.data, {})
|
||||
self.assertEqual(BlacklistedToken.objects.filter(token__user=user).count(), 1)
|
||||
|
||||
|
||||
class CurrentUserViewTest(APITestCase):
|
||||
@@ -151,11 +169,26 @@ class CurrentUserViewTest(APITestCase):
|
||||
response = self.client.get(self.current_user_url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
set(response.data.keys()),
|
||||
{
|
||||
"id",
|
||||
"username",
|
||||
"email",
|
||||
"phone",
|
||||
"is_active",
|
||||
"role",
|
||||
"role_label",
|
||||
"profile",
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.data["id"], self.user.id)
|
||||
self.assertEqual(response.data["email"], self.user.email)
|
||||
self.assertEqual(response.data["role"], "user")
|
||||
self.assertFalse(response.data["capabilities"]["can_refresh_dashboard"])
|
||||
self.assertIn("profile", response.data)
|
||||
self.assertEqual(
|
||||
set(response.data["profile"].keys()),
|
||||
{"first_name", "middle_name", "last_name", "full_name"},
|
||||
)
|
||||
|
||||
def test_get_current_user_unauthenticated(self):
|
||||
"""Test getting current user when unauthenticated"""
|
||||
@@ -220,7 +253,24 @@ class AdminUserManagementViewTest(APITestCase):
|
||||
response = self.client.get(self.list_url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
usernames = {item["username"] for item in response.data}
|
||||
self.assertEqual(
|
||||
set(response.data["results"][0].keys()),
|
||||
{
|
||||
"id",
|
||||
"username",
|
||||
"email",
|
||||
"phone",
|
||||
"is_active",
|
||||
"role",
|
||||
"role_label",
|
||||
"profile",
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
set(response.data["results"][0]["profile"].keys()),
|
||||
{"first_name", "middle_name", "last_name", "full_name"},
|
||||
)
|
||||
usernames = {item["username"] for item in response.data["results"]}
|
||||
self.assertIn(self.admin.username, usernames)
|
||||
self.assertIn(self.user.username, usernames)
|
||||
|
||||
@@ -237,7 +287,7 @@ class AdminUserManagementViewTest(APITestCase):
|
||||
response = self.client.get(self.list_url, {"search": "Петрович"})
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
usernames = [item["username"] for item in response.data]
|
||||
usernames = [item["username"] for item in response.data["results"]]
|
||||
self.assertEqual(usernames, [self.user.username])
|
||||
|
||||
def test_admin_can_order_users(self):
|
||||
@@ -249,7 +299,7 @@ class AdminUserManagementViewTest(APITestCase):
|
||||
response = self.client.get(self.list_url, {"ordering": "first_name"})
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
ordered_ids = [item["id"] for item in response.data]
|
||||
ordered_ids = [item["id"] for item in response.data["results"]]
|
||||
self.assertLess(ordered_ids.index(second.id), ordered_ids.index(first.id))
|
||||
|
||||
def test_admin_can_create_user_with_role(self):
|
||||
@@ -270,6 +320,18 @@ class AdminUserManagementViewTest(APITestCase):
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
created = User.objects.get(username=payload["username"])
|
||||
self.assertTrue(created.is_staff)
|
||||
self.assertEqual(
|
||||
set(response.data.keys()),
|
||||
{
|
||||
"id",
|
||||
"username",
|
||||
"email",
|
||||
"phone",
|
||||
"role",
|
||||
"role_label",
|
||||
"is_active",
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.data["role"], "admin")
|
||||
self.assertEqual(created.profile.first_name, "Петр")
|
||||
self.assertEqual(created.profile.middle_name, "Петрович")
|
||||
@@ -283,6 +345,7 @@ class AdminUserManagementViewTest(APITestCase):
|
||||
"role": "admin",
|
||||
"first_name": "Иван",
|
||||
"middle_name": "Иванович",
|
||||
"last_name": "Иванов",
|
||||
"is_verified": True,
|
||||
},
|
||||
format="json",
|
||||
@@ -292,6 +355,18 @@ class AdminUserManagementViewTest(APITestCase):
|
||||
self.user.refresh_from_db()
|
||||
self.assertTrue(self.user.is_staff)
|
||||
self.assertTrue(self.user.is_verified)
|
||||
self.assertEqual(
|
||||
set(response.data.keys()),
|
||||
{
|
||||
"id",
|
||||
"username",
|
||||
"email",
|
||||
"phone",
|
||||
"role",
|
||||
"role_label",
|
||||
"is_active",
|
||||
},
|
||||
)
|
||||
self.assertEqual(self.user.profile.first_name, "Иван")
|
||||
self.assertEqual(self.user.profile.middle_name, "Иванович")
|
||||
|
||||
@@ -302,6 +377,10 @@ class AdminUserManagementViewTest(APITestCase):
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["id"], self.user.id)
|
||||
self.assertEqual(
|
||||
set(response.data["profile"].keys()),
|
||||
{"first_name", "middle_name", "last_name", "full_name"},
|
||||
)
|
||||
|
||||
def test_admin_cannot_patch_self_to_inactive(self):
|
||||
url = reverse("api_v1:user:admin-user-detail", args=[self.admin.id])
|
||||
@@ -324,10 +403,15 @@ class AdminUserManagementViewTest(APITestCase):
|
||||
def test_admin_can_patch_self_with_safe_fields(self):
|
||||
url = reverse("api_v1:user:admin-user-detail", args=[self.admin.id])
|
||||
|
||||
response = self.client.patch(url, {"first_name": "Админ"}, format="json")
|
||||
response = self.client.patch(
|
||||
url,
|
||||
{"first_name": "Админ", "last_name": "Админов"},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["profile"]["first_name"], "Админ")
|
||||
self.assertEqual(response.data["role"], "admin")
|
||||
self.assertNotIn("profile", response.data)
|
||||
|
||||
def test_admin_can_deactivate_user(self):
|
||||
url = reverse("api_v1:user:admin-user-deactivate", args=[self.user.id])
|
||||
@@ -348,6 +432,18 @@ class AdminUserManagementViewTest(APITestCase):
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.user.refresh_from_db()
|
||||
self.assertTrue(self.user.is_active)
|
||||
self.assertEqual(
|
||||
set(response.data.keys()),
|
||||
{
|
||||
"id",
|
||||
"username",
|
||||
"email",
|
||||
"phone",
|
||||
"role",
|
||||
"role_label",
|
||||
"is_active",
|
||||
},
|
||||
)
|
||||
|
||||
def test_admin_cannot_deactivate_self(self):
|
||||
url = reverse("api_v1:user:admin-user-deactivate", args=[self.admin.id])
|
||||
|
||||
Reference in New Issue
Block a user