From 80fda6a4a4452531b4d0d9f1d69b72fa3005c6d9 Mon Sep 17 00:00:00 2001 From: Bernard Siebens Date: Fri, 21 Aug 2026 17:43:30 +0200 Subject: [PATCH] Verify the news-publish notification chain end-to-end New test: publishing a news item with the "notify linked members" toggle checked creates a Notification, sends a push (mocked webpush call asserted), and the row actually shows up -- unread -- in the member's own mobile inbox. Confirms mobile.signals' post_save hook on Notification (built generically, not news-specific) correctly catches notifications created from the management app's own publish flow, not just the ones mobile's own views create. No bugs found; this closes the loop the request asked to verify. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9 --- management/tests.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/management/tests.py b/management/tests.py index e4c1bcc..0db5e68 100644 --- a/management/tests.py +++ b/management/tests.py @@ -1,4 +1,5 @@ import datetime +import json import os import sys from decimal import Decimal @@ -4173,6 +4174,37 @@ class NewsManagementTests(ManagementTestBase): self.assertEqual(len(mail.outbox), 0) + def test_notify_members_checkbox_creates_an_in_app_notification_and_pushes_it(self): + # End-to-end: the publish-time toggle all the way through to the mobile + # app's own inbox and its push channel -- not just the email side + # test_notify_members_checkbox_emails_the_audience above already covers. + from mobile.models import PushSubscription + + member_user = User.objects.create_user(email="jamie@example.com", password="pw-secret-123") + member = Member.objects.create(first_name="Jamie", last_name="Doe", email="jamie@example.com", user=member_user) + ClubMembership.objects.create(club=self.club, member=member, season=self.season, status=ClubMembership.StatusChoices.ACTIVE) + PushSubscription.objects.create(club=self.club, member=member, endpoint="https://push.example.com/jamie", p256dh="key1", auth="key2") + item = News.objects.create(club=self.club, title="Signed: New Player", body="Body.") + self.client.force_login(self.editor) + + with ( + override_settings(VAPID_PRIVATE_KEY="test-private-key", VAPID_ADMIN_EMAIL="admin@example.com"), + mock.patch("mobile.services.push.webpush") as webpush_mock, + ): + self.club_post("news_publish", {"published_at": timezone.now().strftime("%Y-%m-%dT%H:%M"), "notify_members": "on"}, item.pk) + + notification = Notification.objects.get(member=member, title="Signed: New Player") + self.assertIsNotNone(notification.sent_at) + webpush_mock.assert_called_once() + self.assertEqual(json.loads(webpush_mock.call_args.kwargs["data"])["title"], "Signed: New Player") + + # And it actually shows up in the member's own mobile inbox, not just the DB row. + self.client.logout() + self.client.force_login(member_user) + response = self.client.get(reverse("mobile:notifications"), HTTP_HOST="ajax-united.rosterchief.app") + self.assertContains(response, "Signed: New Player") + self.assertEqual(response.context["unread_notification_count"], 1) + def test_a_coach_manager_can_submit_a_draft_for_review(self): item = News.objects.create(club=self.club, title="Draft item", body="Body.") self.client.force_login(self.coach_manager)