test(backend): convert existing app suites to unittest

This commit is contained in:
2026-04-30 12:41:54 +03:30
parent 204225dd16
commit 8774a4d4dc
16 changed files with 1785 additions and 1780 deletions

View File

@@ -1,159 +1,137 @@
import pytest
from django.test import TestCase
from rest_framework.test import APIClient
from apps.notifications.services import store as services
from apps.notifications.services import RedisNotificationStore
from apps.notifications.tests.test_services import FakeRedis
from apps.notifications.tests.fakes import FakeRedis
from apps.users.models import User
from apps.workspaces.models import Workspace, WorkspaceMembership
@pytest.fixture()
def fake_redis(monkeypatch):
redis = FakeRedis()
monkeypatch.setattr(services, "redis_client", redis)
return redis
class WorkspaceMembershipNotificationTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.owner = cls._create_user(1)
cls.member = cls._create_user(2)
@staticmethod
def _create_user(index):
return User.objects.create_user(
mobile=f"091200000{index:02d}",
password="secret123",
first_name=f"User{index}",
)
@pytest.fixture()
def api_client():
return APIClient()
def setUp(self):
self.client = APIClient()
self.fake_redis = FakeRedis()
self.original_redis_client = services.redis_client
services.redis_client = self.fake_redis
def tearDown(self):
services.redis_client = self.original_redis_client
def _create_user(index: int) -> User:
return User.objects.create_user(
mobile=f"091200000{index:02d}",
password="secret123",
first_name=f"User{index}",
)
@staticmethod
def _notifications_for(user):
notifications, _ = RedisNotificationStore.list(str(user.id), paginate=False)
return notifications
def test_workspace_create_notifies_initial_members_not_owner(self):
self.client.force_authenticate(user=self.owner)
def _notifications_for(user):
notifications, _ = RedisNotificationStore.list(
str(user.id),
paginate=False,
)
return notifications
response = self.client.post(
"/api/workspaces/",
{
"name": "Ops",
"description": "Workspace",
"members": [
{
"user_id": str(self.member.id),
"role": WorkspaceMembership.Role.ADMIN,
}
],
},
format="json",
)
self.assertEqual(response.status_code, 201)
self.assertEqual(self._notifications_for(self.owner), [])
member_notifications = self._notifications_for(self.member)
self.assertEqual(len(member_notifications), 1)
self.assertEqual(member_notifications[0]["type"], "workspace_membership_added")
self.assertEqual(member_notifications[0]["meta"]["workspace_name"], "Ops")
self.assertEqual(
member_notifications[0]["meta"]["new_role"],
WorkspaceMembership.Role.ADMIN,
)
@pytest.fixture()
def owner(db):
return _create_user(1)
def test_workspace_membership_crud_emits_all_expected_events(self):
workspace = Workspace.objects.create(name="Design", description="", owner=self.owner)
self.client.force_authenticate(user=self.owner)
create_response = self.client.post(
"/api/workspace-memberships/",
{
"workspace": str(workspace.id),
"user": str(self.member.id),
"role": WorkspaceMembership.Role.MEMBER,
"is_active": True,
},
format="json",
)
self.assertEqual(create_response.status_code, 201)
@pytest.fixture()
def member(db):
return _create_user(2)
membership_id = create_response.data["id"]
notifications = self._notifications_for(self.member)
self.assertEqual(
[item["type"] for item in notifications],
["workspace_membership_added"],
)
role_response = self.client.patch(
f"/api/workspace-memberships/{membership_id}/",
{"role": WorkspaceMembership.Role.ADMIN},
format="json",
)
self.assertEqual(role_response.status_code, 200)
@pytest.fixture()
def another_member(db):
return _create_user(3)
deactivate_response = self.client.patch(
f"/api/workspace-memberships/{membership_id}/",
{"is_active": False},
format="json",
)
self.assertEqual(deactivate_response.status_code, 200)
remove_response = self.client.delete(
f"/api/workspace-memberships/{membership_id}/"
)
self.assertEqual(remove_response.status_code, 204)
@pytest.fixture()
def third_member(db):
return _create_user(4)
@pytest.fixture()
def fourth_member(db):
return _create_user(5)
def test_workspace_create_notifies_initial_members_not_owner(
fake_redis, api_client, owner, member
):
api_client.force_authenticate(user=owner)
response = api_client.post(
"/api/workspaces/",
{
"name": "Ops",
"description": "Workspace",
"members": [
{"user_id": str(member.id), "role": WorkspaceMembership.Role.ADMIN}
notifications = self._notifications_for(self.member)
self.assertEqual(
[item["type"] for item in notifications],
[
"workspace_membership_removed",
"workspace_membership_deactivated",
"workspace_membership_role_changed",
"workspace_membership_added",
],
},
format="json",
)
)
assert response.status_code == 201
owner_notifications = _notifications_for(owner)
member_notifications = _notifications_for(member)
def test_workspace_membership_update_skips_self_notifications(self):
workspace = Workspace.objects.create(name="Product", description="", owner=self.owner)
owner_membership = WorkspaceMembership.objects.get(
workspace=workspace,
user=self.owner,
is_deleted=False,
)
self.client.force_authenticate(user=self.owner)
assert owner_notifications == []
assert len(member_notifications) == 1
assert member_notifications[0]["type"] == "workspace_membership_added"
assert member_notifications[0]["meta"]["workspace_name"] == "Ops"
assert member_notifications[0]["meta"]["new_role"] == WorkspaceMembership.Role.ADMIN
def test_workspace_membership_crud_emits_add_role_change_deactivate_and_remove(
fake_redis, api_client, owner, member
):
workspace = Workspace.objects.create(name="Design", description="", owner=owner)
api_client.force_authenticate(user=owner)
create_response = api_client.post(
"/api/workspace-memberships/",
{
"workspace": str(workspace.id),
"user": str(member.id),
"role": WorkspaceMembership.Role.MEMBER,
"is_active": True,
},
format="json",
)
assert create_response.status_code == 201
membership_id = create_response.data["id"]
notifications = _notifications_for(member)
assert [item["type"] for item in notifications] == ["workspace_membership_added"]
role_response = api_client.patch(
f"/api/workspace-memberships/{membership_id}/",
{"role": WorkspaceMembership.Role.ADMIN},
format="json",
)
assert role_response.status_code == 200
deactivate_response = api_client.patch(
f"/api/workspace-memberships/{membership_id}/",
{"is_active": False},
format="json",
)
assert deactivate_response.status_code == 200
remove_response = api_client.delete(f"/api/workspace-memberships/{membership_id}/")
assert remove_response.status_code == 204
notifications = _notifications_for(member)
assert [item["type"] for item in notifications] == [
"workspace_membership_removed",
"workspace_membership_deactivated",
"workspace_membership_role_changed",
"workspace_membership_added",
]
def test_workspace_membership_update_skips_self_notifications(
fake_redis, api_client, owner
):
workspace = Workspace.objects.create(name="Product", description="", owner=owner)
owner_membership = WorkspaceMembership.objects.get(
workspace=workspace,
user=owner,
is_deleted=False,
)
api_client.force_authenticate(user=owner)
response = api_client.patch(
f"/api/workspace-memberships/{owner_membership.id}/",
{"role": WorkspaceMembership.Role.OWNER},
format="json",
)
assert response.status_code == 403
assert _notifications_for(owner) == []
response = self.client.patch(
f"/api/workspace-memberships/{owner_membership.id}/",
{"role": WorkspaceMembership.Role.OWNER},
format="json",
)
self.assertEqual(response.status_code, 403)
self.assertEqual(self._notifications_for(self.owner), [])