feat(test): added test for models

This commit is contained in:
sankalp committed 2025-12-11 21:52:51 +05:45
1 parent 63d63d5e5c
commit 54df9af013
4 files changed
+259 -32

No files matched your search

@@ -0,0 +1,17 @@
# Generated by Django 6.0 on 2025-12-11 15:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("src", "0003_notification"),
]
operations = [
migrations.AlterField(
model_name="invoice",
name="due_date",
field=models.DateField(),
),
]
+1 -1
View File
@@ -23,7 +23,7 @@ class Invoice(TimeStampedModel):
invoice_number = models.CharField(max_length=20, unique=True, editable=False)
amount = models.DecimalField(max_digits=10, decimal_places=2)
date_issued = models.DateField(auto_now_add=True)
due_date = models.DateField(auto_now=True)
due_date = models.DateField()
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default="DRAFT")
def save(self, *args, **kwargs):
+134
View File
@@ -0,0 +1,134 @@
from datetime import timedelta
from decimal import Decimal
from django.core.exceptions import ValidationError
from django.test import TestCase
from django.utils import timezone
from src.models.clients import Client
from src.models.finance import Invoice
from src.models.productivity import TimeEntry
from src.models.projects import Milestone, Project, Task
from src.models.services import Service
class ClientModelTest(TestCase):
def test_short_code_generation(self):
client1 = Client.objects.create(name="Sankalp Corp", email="s@example.com")
self.assertEqual(client1.short_code, "SAN001")
client2 = Client.objects.create(name="Sankalp Inc", email="s2@example.com")
self.assertEqual(client2.short_code, "SAN002")
client3 = Client.objects.create(name="Other Corp", email="o@example.com")
self.assertEqual(client3.short_code, "OTH001")
class ProjectModelTest(TestCase):
def setUp(self):
self.client = Client.objects.create(name="Test Client", email="c@example.com")
def test_deadline_validation(self):
start_date = timezone.localdate()
deadline = start_date - timedelta(days=1) # Deadline before start
project = Project(
name="Bad Project",
client=self.client,
start_date=start_date,
deadline=deadline,
)
with self.assertRaises(ValidationError):
project.clean()
def test_milestone_str(self):
project = Project.objects.create(name="P1", client=self.client)
milestone = Milestone.objects.create(project=project, title="M1")
self.assertIn("✗", str(milestone))
milestone.is_completed = True
milestone.save()
self.assertIn("✓", str(milestone))
def test_task_due_date_validation(self):
yesterday = timezone.localdate() - timedelta(days=1)
task = Task(
project=Project.objects.create(name="P1", client=self.client),
title="Old Task",
due_date=yesterday,
)
with self.assertRaises(ValidationError):
task.clean()
class ServiceModelTest(TestCase):
def setUp(self):
self.client = Client.objects.create(name="Test Client", email="c@example.com")
def test_expiry_date_validation(self):
start_date = timezone.localdate()
expiry_date = start_date - timedelta(days=1)
service = Service(
client=self.client,
name="Bad Service",
service_type="DOMAIN",
start_date=start_date,
expiry_date=expiry_date,
)
with self.assertRaises(ValidationError):
service.clean()
class FinanceModelTest(TestCase):
def setUp(self):
self.client = Client.objects.create(name="Test Client", email="c@example.com")
self.project = Project.objects.create(name="P1", client=self.client)
def test_invoice_number_generation(self):
# Client short code is TES001
inv1 = Invoice.objects.create(
client=self.client,
project=self.project,
amount=Decimal("100.00"),
due_date=timezone.localdate(),
)
self.assertEqual(inv1.invoice_number, "TES001-0001")
inv2 = Invoice.objects.create(
client=self.client,
project=self.project,
amount=Decimal("200.00"),
due_date=timezone.localdate(),
)
self.assertEqual(inv2.invoice_number, "TES001-0002")
class ProductivityModelTest(TestCase):
def setUp(self):
self.client = Client.objects.create(name="Test Client", email="c@example.com")
self.project = Project.objects.create(name="P1", client=self.client)
def test_duration_calculation(self):
start = timezone.now()
end = start + timedelta(hours=2, minutes=30)
entry = TimeEntry.objects.create(
project=self.project, description="Coding", start_time=start, end_time=end
)
# Refresh to get DB value if needed, but save() sets it on instance
self.assertEqual(entry.duration, timedelta(hours=2, minutes=30))
def test_clean_validation(self):
start = timezone.now()
end = start - timedelta(hours=1)
entry = TimeEntry(
project=self.project,
description="Time Travel",
start_time=start,
end_time=end,
)
with self.assertRaises(ValidationError):
entry.clean()
+107 -31
View File
@@ -1,50 +1,126 @@
from datetime import timedelta
from decimal import Decimal
from django.contrib.auth import get_user_model
from django.core import mail
from django.test import TestCase
from django.utils import timezone
from src.models.clients import Client
from src.models.finance import Invoice
from src.models.notifications import Notification, check_and_send_notifications
from src.models.projects import Project
from src.models.productivity import TimeEntry
from src.models.projects import Milestone, Project, Task
from src.models.services import Service
User = get_user_model()
class NotificationTests(TestCase):
def test_send_deadline_notifications(self):
# Setup
User.objects.create_superuser("admin", "admin@example.com", "password")
client = Client.objects.create(name="Test Client", email="client@example.com")
def setUp(self):
self.admin = User.objects.create_superuser(
"admin", "admin@example.com", "password"
)
self.client = Client.objects.create(
name="Test Client", email="client@example.com"
)
self.tomorrow = timezone.localdate() + timedelta(days=1)
# Project due tomorrow
tomorrow = timezone.localdate() + timezone.timedelta(days=1)
Project.objects.create(name="Test Project", client=client, deadline=tomorrow)
def test_project_deadline_notification(self):
with self.settings(ADMINS=[("Admin", "admin@example.com")]):
Project.objects.create(
name="Test Project", client=self.client, deadline=self.tomorrow
)
check_and_send_notifications()
# Run notification check
# 1 to client, 1 to admin
self.assertEqual(len(mail.outbox), 2)
self.assertTrue(
Notification.objects.filter(
subject__contains="Project Deadline"
).exists()
)
def test_milestone_due_notification(self):
with self.settings(ADMINS=[("Admin", "admin@example.com")]):
project = Project.objects.create(name="Test Project", client=self.client)
Milestone.objects.create(
project=project, title="Test Milestone", due_date=self.tomorrow
)
check_and_send_notifications()
# 1 to client, 1 to admin
self.assertEqual(len(mail.outbox), 2)
self.assertTrue(
Notification.objects.filter(subject__contains="Milestone Due").exists()
)
def test_task_due_notification(self):
with self.settings(ADMINS=[("Admin", "admin@example.com")]):
project = Project.objects.create(name="Test Project", client=self.client)
Task.objects.create(
project=project, title="Test Task", due_date=self.tomorrow
)
check_and_send_notifications()
# 1 to admin only
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, ["admin@example.com"])
self.assertTrue(
Notification.objects.filter(subject__contains="Task Due").exists()
)
def test_service_expiry_notification(self):
Service.objects.create(
client=self.client,
name="Test Service",
service_type="DOMAIN",
expiry_date=self.tomorrow,
)
check_and_send_notifications()
# Verify emails sent
# Expecting 2 emails: 1 to client, 1 to admin
self.assertEqual(len(mail.outbox), 2)
# Verify Notification objects created
self.assertEqual(Notification.objects.count(), 2)
client_notif = Notification.objects.get(recipient="client@example.com")
self.assertIn("Project Deadline Reminder", client_notif.subject)
admin_notif = Notification.objects.get(recipient="admin@example.com")
self.assertIn("Admin Alert", admin_notif.subject)
def test_no_notifications_if_not_due(self):
# Setup
client = Client.objects.create(name="Test Client", email="client@example.com")
# Project due day after tomorrow
day_after = timezone.localdate() + timezone.timedelta(days=2)
Project.objects.create(name="Future Project", client=client, deadline=day_after)
# 1 to client only
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, ["client@example.com"])
self.assertTrue(
Notification.objects.filter(subject__contains="Service Expiry").exists()
)
def test_invoice_due_notification(self):
project = Project.objects.create(name="Test Project", client=self.client)
Invoice.objects.create(
client=self.client,
project=project,
amount=Decimal("100.00"),
due_date=self.tomorrow,
status="SENT",
)
check_and_send_notifications()
self.assertEqual(len(mail.outbox), 0)
self.assertEqual(Notification.objects.count(), 0)
# 1 to client
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, ["client@example.com"])
self.assertTrue(
Notification.objects.filter(subject__contains="Invoice Due").exists()
)
def test_time_entry_notification(self):
with self.settings(ADMINS=[("Admin", "admin@example.com")]):
project = Project.objects.create(name="Test Project", client=self.client)
now = timezone.now()
TimeEntry.objects.create(
project=project,
description="Work done",
start_time=now - timedelta(hours=2),
end_time=now - timedelta(hours=1),
)
check_and_send_notifications()
# 1 to admin
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, ["admin@example.com"])
self.assertTrue(
Notification.objects.filter(
subject__contains="Time Entry Logged"
).exists()
)