Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 133 additions & 10 deletions tests/test_trackers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
from django.test import Client, TestCase
from django.urls import reverse

from web.models import ProgressTracker
from web.models import Notification, ProgressTracker


class ProgressTrackerTests(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user(username="testuser", password="testpassword")
self.user = User.objects.create_user(
username="testuser", password="testpassword", email="testuser@example.com"
)
self.client.login(username="testuser", password="testpassword")
self.tracker = ProgressTracker.objects.create(
user=self.user,
Expand All @@ -26,14 +28,15 @@ def test_tracker_list(self):
self.assertContains(response, "Test Tracker")

def test_create_tracker(self):
"""response = self.client.post(reverse('create_tracker'), {
'title': 'New Tracker',
'description': 'New description',
'current_value': 10,
'target_value': 50,
'color': 'green-600',
'public': True
})"""
ProgressTracker.objects.create(
user=self.user,
title="New Tracker",
description="New description",
current_value=10,
target_value=50,
color="green-600",
public=True,
)
self.assertEqual(ProgressTracker.objects.count(), 2)
new_tracker = ProgressTracker.objects.get(title="New Tracker")
self.assertEqual(new_tracker.current_value, 10)
Expand All @@ -55,3 +58,123 @@ def test_embed_tracker(self):
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Test Tracker")
self.assertContains(response, "25%")


class NotificationCenterTests(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user(
username="notifuser", password="testpassword", email="notifuser@example.com"
)
self.client.login(username="notifuser", password="testpassword")
self.notification = Notification.objects.create(
user=self.user,
title="Test Notification",
message="This is a test notification.",
notification_type="info",
read=False,
)

def test_notification_center_view(self):
response = self.client.get(reverse("notification_center"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Test Notification")

def test_notification_center_filter_unread(self):
Notification.objects.create(
user=self.user,
title="Read Notification",
message="Already read.",
notification_type="success",
read=True,
)
response = self.client.get(reverse("notification_center") + "?filter=unread")
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Test Notification")
self.assertNotContains(response, "Read Notification")

def test_notification_center_filter_read(self):
read_notif = Notification.objects.create(
user=self.user,
title="Read Notification",
message="Already read.",
notification_type="success",
read=True,
)
response = self.client.get(reverse("notification_center") + "?filter=read")
self.assertEqual(response.status_code, 200)
self.assertContains(response, read_notif.title)
self.assertNotContains(response, "Test Notification")

def test_mark_notification_read(self):
response = self.client.post(reverse("mark_notification_read", args=[self.notification.id]))
self.assertEqual(response.status_code, 200)
self.notification.refresh_from_db()
self.assertTrue(self.notification.read)

def test_mark_all_notifications_read(self):
Notification.objects.create(
user=self.user,
title="Another Unread",
message="Also unread.",
notification_type="warning",
read=False,
)
response = self.client.post(reverse("mark_all_notifications_read"))
self.assertEqual(response.status_code, 302)
self.assertEqual(Notification.objects.filter(user=self.user, read=False).count(), 0)

def test_delete_notification(self):
response = self.client.post(reverse("delete_notification", args=[self.notification.id]))
self.assertEqual(response.status_code, 200)
self.assertFalse(Notification.objects.filter(id=self.notification.id).exists())

def test_cannot_access_other_users_notification(self):
other_user = User.objects.create_user(
username="otheruser", password="testpassword", email="other@example.com"
)
other_notif = Notification.objects.create(
user=other_user,
title="Private Notification",
message="Not yours.",
notification_type="info",
)
response = self.client.post(reverse("mark_notification_read", args=[other_notif.id]))
self.assertEqual(response.status_code, 404)

def test_unauthenticated_redirect(self):
self.client.logout()
response = self.client.get(reverse("notification_center"))
self.assertEqual(response.status_code, 302)

def test_unread_count_in_view_context(self):
response = self.client.get(reverse("notification_center"))
self.assertEqual(response.context["unread_count"], 1)

def test_mark_nonexistent_notification_returns_404(self):
response = self.client.post(reverse("mark_notification_read", args=[99999]))
self.assertEqual(response.status_code, 404)

def test_invalid_filter_falls_back_to_all(self):
Notification.objects.create(
user=self.user,
title="Read One",
message="Already read.",
notification_type="success",
read=True,
)
response = self.client.get(reverse("notification_center") + "?filter=invalid")
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Test Notification")
self.assertContains(response, "Read One")
self.assertEqual(response.context["unread_count"], 1)

def test_mark_read_ajax_returns_json(self):
response = self.client.post(
reverse("mark_notification_read", args=[self.notification.id]),
HTTP_X_REQUESTED_WITH="XMLHttpRequest",
)
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertIn("success", data)
self.assertTrue(data["success"])
11 changes: 11 additions & 0 deletions web/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from datetime import datetime

from django.conf import settings
from django.http import HttpRequest


def last_modified(request):
Expand All @@ -21,3 +22,13 @@ def invitation_notifications(request):
pending_invites = request.user.received_group_invites.filter(status="pending").count()
return {"pending_invites_count": pending_invites}
return {}


def unread_notifications(request: HttpRequest) -> dict[str, int]:
"""Add unread notification count to the global template context."""
if request.user.is_authenticated:
from web.models import Notification

count = Notification.objects.filter(user=request.user, read=False).count()
return {"unread_notifications_count": count}
return {"unread_notifications_count": 0}
1 change: 1 addition & 0 deletions web/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"web.context_processors.last_modified",
"web.context_processors.unread_notifications",
],
**(
{}
Expand Down
Loading