test(time-entries): cover grouped filters and serializer formatting

This commit is contained in:
2026-04-24 22:19:36 +03:30
parent 83bc3568d0
commit 7cae494892
4 changed files with 216 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
from datetime import datetime
from apps.clients.models import Client
from apps.projects.models import Project
from apps.tags.models import Tag
from apps.time_entries.api.filters import TimeEntryFilter
from apps.time_entries.models import TimeEntry
from apps.users.models import User
from apps.workspaces.models import Workspace
def make_aware(year, month, day, hour=9, minute=0, second=0):
from django.utils import timezone
return timezone.make_aware(datetime(year, month, day, hour, minute, second), timezone.get_current_timezone())
def test_time_entry_filter_supports_project_client_tags_and_custom_dates(db):
user = User.objects.create_user(mobile="09124444444", password="secret123")
workspace = Workspace.objects.create(name="Core", owner=user)
client_a = Client.objects.create(workspace=workspace, name="Client A")
client_b = Client.objects.create(workspace=workspace, name="Client B")
project_a = Project.objects.create(workspace=workspace, client=client_a, name="Project A")
project_b = Project.objects.create(workspace=workspace, client=client_b, name="Project B")
tag_backend = Tag.objects.create(workspace=workspace, name="Backend", color="#0EA5E9")
tag_ops = Tag.objects.create(workspace=workspace, name="Ops", color="#10B981")
entry_a = TimeEntry.objects.create(
workspace=workspace,
user=user,
project=project_a,
description="Backend work",
start_time=make_aware(2026, 4, 10, 10, 0, 0),
end_time=make_aware(2026, 4, 10, 12, 0, 0),
)
entry_a.tags.set([tag_backend])
entry_b = TimeEntry.objects.create(
workspace=workspace,
user=user,
project=project_b,
description="Ops work",
start_time=make_aware(2026, 4, 18, 14, 0, 0),
end_time=make_aware(2026, 4, 18, 15, 30, 0),
)
entry_b.tags.set([tag_ops])
queryset = TimeEntry.objects.filter(workspace=workspace, is_deleted=False)
filtered = TimeEntryFilter(
data={
"workspace": str(workspace.id),
"project": str(project_a.id),
"client": str(client_a.id),
"tags": str(tag_backend.id),
"started_after": "2026-04-01",
"started_before": "2026-04-15",
},
queryset=queryset,
).qs
assert list(filtered) == [entry_a]
def test_time_entry_filter_supports_status_values(db):
user = User.objects.create_user(mobile="09125555555", password="secret123")
workspace = Workspace.objects.create(name="Core", owner=user)
ended_entry = TimeEntry.objects.create(
workspace=workspace,
user=user,
description="Ended entry",
start_time=make_aware(2026, 4, 24, 9, 0, 0),
end_time=make_aware(2026, 4, 24, 10, 0, 0),
)
running_entry = TimeEntry.objects.create(
workspace=workspace,
user=user,
description="Running entry",
start_time=make_aware(2026, 4, 15, 9, 0, 0),
)
queryset = TimeEntry.objects.filter(workspace=workspace, is_deleted=False)
ended = TimeEntryFilter(data={"status": "ended"}, queryset=queryset).qs
running = TimeEntryFilter(data={"status": "running"}, queryset=queryset).qs
assert list(ended) == [ended_entry]
assert list(running) == [running_entry]

View File

@@ -0,0 +1,29 @@
from datetime import datetime
from django.utils import timezone
from apps.time_entries.api.serializers import TimeEntrySerializer
from apps.time_entries.models import TimeEntry
from apps.users.models import User
from apps.workspaces.models import Workspace
def test_time_entry_serializer_keeps_seconds(db):
user = User.objects.create_user(mobile="09123333333", password="secret123")
workspace = Workspace.objects.create(name="Core", owner=user)
current_timezone = timezone.get_current_timezone()
start_time = timezone.make_aware(datetime(2026, 4, 23, 10, 15, 42), current_timezone)
end_time = timezone.make_aware(datetime(2026, 4, 23, 11, 0, 5), current_timezone)
entry = TimeEntry.objects.create(
workspace=workspace,
user=user,
start_time=start_time,
end_time=end_time,
)
data = TimeEntrySerializer(entry).data
assert data["start_time"] == start_time.strftime("%Y-%m-%d %H:%M:%S")
assert data["end_time"] == end_time.strftime("%Y-%m-%d %H:%M:%S")

View File

@@ -0,0 +1,47 @@
from datetime import timedelta
import pytest
from django.utils import timezone
from rest_framework.exceptions import ValidationError
from apps.time_entries.services.time_entries import create_time_entry, stop_time_entry
from apps.users.models import User
from apps.workspaces.models import Workspace
@pytest.fixture
def workspace_owner(db):
user = User.objects.create_user(mobile="09121111111", password="secret123")
workspace = Workspace.objects.create(name="Core", owner=user)
return user, workspace
def test_create_time_entry_allows_only_one_running_timer_per_workspace(workspace_owner):
user, workspace = workspace_owner
create_time_entry(
user=user,
workspace_id=workspace.id,
start_time=timezone.now(),
)
with pytest.raises(ValidationError):
create_time_entry(
user=user,
workspace_id=workspace.id,
start_time=timezone.now() + timedelta(minutes=5),
)
def test_stop_time_entry_sets_end_time_and_duration(workspace_owner):
user, workspace = workspace_owner
entry = create_time_entry(
user=user,
workspace_id=workspace.id,
start_time=timezone.now() - timedelta(hours=1),
)
stopped_entry = stop_time_entry(entry, end_time=timezone.now())
assert stopped_entry.end_time is not None
assert stopped_entry.duration is not None

View File

@@ -0,0 +1,51 @@
from datetime import datetime
from django.utils import timezone
from rest_framework.test import APIClient
from apps.time_entries.models import TimeEntry
from apps.users.models import User
from apps.workspaces.models import Workspace
def make_aware(year, month, day, hour=9, minute=0, second=0):
return timezone.make_aware(datetime(year, month, day, hour, minute, second), timezone.get_current_timezone())
def test_time_entry_list_returns_grouped_payload_for_ended_entries(db):
user = User.objects.create_user(mobile="09126666666", password="secret123")
workspace = Workspace.objects.create(name="Core", owner=user)
first_entry = TimeEntry.objects.create(
workspace=workspace,
user=user,
description="Morning work",
start_time=make_aware(2026, 4, 24, 9, 0, 0),
end_time=make_aware(2026, 4, 24, 10, 30, 0),
)
TimeEntry.objects.create(
workspace=workspace,
user=user,
description="Running work",
start_time=make_aware(2026, 4, 24, 11, 0, 0),
)
client = APIClient()
client.force_authenticate(user=user)
response = client.get(
"/api/time-entries/",
{
"workspace": str(workspace.id),
"status": "ended",
"limit": 10,
"offset": 0,
},
)
assert response.status_code == 200
assert response.data["current_page_items_count"] == 1
assert response.data["has_more"] is False
assert len(response.data["groups"]) == 1
assert len(response.data["groups"][0]["days"]) == 1
assert response.data["groups"][0]["days"][0]["entries"][0]["id"] == str(first_entry.id)