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,128 +1,184 @@
from decimal import Decimal
import pytest
from rest_framework.test import APIClient
from django.test import TestCase
from rest_framework.test import APITestCase
from apps.projects.models import Project
from apps.time_entries.services.rates import resolve_rate
from apps.users.models import User
from apps.workspaces.models import PriceUnit, Workspace, WorkspaceMembership, WorkspaceUserRate
from apps.workspaces.models import (
PriceUnit,
Workspace,
WorkspaceMembership,
WorkspaceUserRate,
)
from apps.workspaces.services.rates import (
update_workspace_user_rate,
upsert_workspace_user_rate,
)
@pytest.fixture()
def api_client():
return APIClient()
class WorkspaceRateTests(APITestCase):
@classmethod
def setUpTestData(cls):
cls.owner = User.objects.create_user(mobile="09127770001", password="secret123")
cls.admin = User.objects.create_user(mobile="09127770002", password="secret123")
cls.member = User.objects.create_user(mobile="09127770003", password="secret123")
cls.workspace = Workspace.objects.create(name="Rates", owner=cls.owner)
WorkspaceMembership.objects.create(
workspace=cls.workspace,
user=cls.admin,
role=WorkspaceMembership.Role.ADMIN,
is_active=True,
)
WorkspaceMembership.objects.create(
workspace=cls.workspace,
user=cls.member,
role=WorkspaceMembership.Role.MEMBER,
is_active=True,
)
cls.project = Project.objects.create(workspace=cls.workspace, name="Billing")
PriceUnit.objects.create(
code="USD",
name="US Dollar",
local_name="Dollar",
symbol="$",
)
PriceUnit.objects.create(
code="EUR",
name="Euro",
local_name="Euro",
symbol="EUR",
)
def test_resolve_rate_uses_workspace_user_rate(self):
WorkspaceUserRate.objects.create(
workspace=self.workspace,
user=self.member,
hourly_rate=Decimal("40.00"),
currency="EUR",
effective_from=self.project.created_at,
is_active=True,
)
hourly_rate, currency = resolve_rate(self.member, self.project)
self.assertEqual(hourly_rate, Decimal("40.00"))
self.assertEqual(currency, "EUR")
def test_resolve_rate_returns_none_when_workspace_rate_is_missing(self):
hourly_rate, currency = resolve_rate(self.member, self.project)
self.assertIsNone(hourly_rate)
self.assertEqual(currency, "")
def test_admin_can_manage_workspace_user_rates(self):
self.client.force_authenticate(user=self.admin)
create_response = self.client.post(
"/api/workspace-user-rates/",
{
"workspace_id": str(self.workspace.id),
"user_id": str(self.member.id),
"hourly_rate": "35.50",
"currency": "USD",
},
format="json",
)
self.assertEqual(create_response.status_code, 201)
rate_id = create_response.data["id"]
self.assertTrue(
WorkspaceUserRate.objects.filter(id=rate_id, is_deleted=False).exists()
)
update_response = self.client.patch(
f"/api/workspace-user-rates/{rate_id}/",
{"hourly_rate": "42.00"},
format="json",
)
self.assertEqual(update_response.status_code, 200)
self.assertEqual(update_response.data["hourly_rate"], "42.00")
delete_response = self.client.delete(f"/api/workspace-user-rates/{rate_id}/")
self.assertEqual(delete_response.status_code, 204)
self.assertTrue(WorkspaceUserRate.all_objects.get(id=rate_id).is_deleted)
def test_member_cannot_manage_rates(self):
self.client.force_authenticate(user=self.member)
response = self.client.post(
"/api/workspace-user-rates/",
{
"workspace_id": str(self.workspace.id),
"user_id": str(self.member.id),
"hourly_rate": "25.00",
"currency": "USD",
},
format="json",
)
self.assertEqual(response.status_code, 403)
@pytest.fixture()
def owner(db):
return User.objects.create_user(mobile="09127770001", password="secret123")
class WorkspaceRateServiceTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.owner = User.objects.create_user(mobile="09127770011", password="secret123")
cls.member = User.objects.create_user(mobile="09127770012", password="secret123")
cls.workspace = Workspace.objects.create(name="Rate Services", owner=cls.owner)
def test_upsert_workspace_user_rate_creates_uppercase_currency_rate(self):
rate = upsert_workspace_user_rate(
self.workspace,
self.member.id,
Decimal("12.50"),
"usd",
)
@pytest.fixture()
def admin(db):
return User.objects.create_user(mobile="09127770002", password="secret123")
self.assertEqual(rate.hourly_rate, Decimal("12.50"))
self.assertEqual(rate.currency, "USD")
self.assertTrue(rate.is_active)
def test_upsert_workspace_user_rate_updates_existing_inactive_rate(self):
rate = WorkspaceUserRate.objects.create(
workspace=self.workspace,
user=self.member,
hourly_rate=Decimal("10.00"),
currency="USD",
effective_from=self.workspace.created_at,
is_active=False,
)
@pytest.fixture()
def member(db):
return User.objects.create_user(mobile="09127770003", password="secret123")
updated = upsert_workspace_user_rate(
self.workspace,
self.member.id,
Decimal("20.00"),
"eur",
)
self.assertEqual(updated.id, rate.id)
self.assertEqual(updated.hourly_rate, Decimal("20.00"))
self.assertEqual(updated.currency, "EUR")
self.assertTrue(updated.is_active)
@pytest.fixture()
def workspace(owner, admin, member):
workspace = Workspace.objects.create(name="Rates", owner=owner)
WorkspaceMembership.objects.create(workspace=workspace, user=admin, role=WorkspaceMembership.Role.ADMIN, is_active=True)
WorkspaceMembership.objects.create(workspace=workspace, user=member, role=WorkspaceMembership.Role.MEMBER, is_active=True)
return workspace
def test_update_workspace_user_rate_updates_only_changed_fields(self):
rate = WorkspaceUserRate.objects.create(
workspace=self.workspace,
user=self.member,
hourly_rate=Decimal("10.00"),
currency="USD",
effective_from=self.workspace.created_at,
is_active=True,
)
updated = update_workspace_user_rate(
rate,
hourly_rate=Decimal("15.00"),
currency="gbp",
)
@pytest.fixture()
def project(workspace, owner, admin, member):
return Project.objects.create(workspace=workspace, name="Billing")
@pytest.fixture()
def price_units(db):
PriceUnit.objects.create(code="USD", name="US Dollar", local_name="دلار آمریکا", symbol="$")
PriceUnit.objects.create(code="EUR", name="Euro", local_name="یورو", symbol="")
def test_resolve_rate_uses_workspace_user_rate(workspace, project, member):
WorkspaceUserRate.objects.create(
workspace=workspace,
user=member,
hourly_rate=Decimal("40.00"),
currency="EUR",
effective_from=project.created_at,
is_active=True,
)
hourly_rate, currency = resolve_rate(member, project)
assert hourly_rate == Decimal("40.00")
assert currency == "EUR"
def test_resolve_rate_falls_back_to_workspace_user_rate(workspace, project, member):
WorkspaceUserRate.objects.create(
workspace=workspace,
user=member,
hourly_rate=Decimal("40.00"),
currency="EUR",
effective_from=project.created_at,
is_active=True,
)
hourly_rate, currency = resolve_rate(member, project)
assert hourly_rate == Decimal("40.00")
assert currency == "EUR"
def test_admin_can_manage_workspace_user_rates(api_client, admin, member, workspace, price_units):
api_client.force_authenticate(user=admin)
create_response = api_client.post(
"/api/workspace-user-rates/",
{
"workspace_id": str(workspace.id),
"user_id": str(member.id),
"hourly_rate": "35.50",
"currency": "USD",
},
format="json",
)
assert create_response.status_code == 201
rate_id = create_response.data["id"]
assert WorkspaceUserRate.objects.filter(id=rate_id, is_deleted=False).exists()
update_response = api_client.patch(
f"/api/workspace-user-rates/{rate_id}/",
{"hourly_rate": "42.00"},
format="json",
)
assert update_response.status_code == 200
assert update_response.data["hourly_rate"] == "42.00"
delete_response = api_client.delete(f"/api/workspace-user-rates/{rate_id}/")
assert delete_response.status_code == 204
assert WorkspaceUserRate.all_objects.get(id=rate_id).is_deleted is True
def test_member_cannot_manage_rates(api_client, member, workspace, price_units):
api_client.force_authenticate(user=member)
workspace_response = api_client.post(
"/api/workspace-user-rates/",
{
"workspace_id": str(workspace.id),
"user_id": str(member.id),
"hourly_rate": "25.00",
"currency": "USD",
},
format="json",
)
assert workspace_response.status_code == 403
self.assertEqual(updated.hourly_rate, Decimal("15.00"))
self.assertEqual(updated.currency, "GBP")