130 lines
5.4 KiB
Python
130 lines
5.4 KiB
Python
"""
|
|
Tests for the email reminder template consistency fixes:
|
|
- Part D: NotificationService.send_email auto-wraps plain-text in branded template
|
|
- Part A: dept-champion notification uses email= (not recipient=) kwarg
|
|
- Part B/C: branded reminder templates render with the expected context
|
|
"""
|
|
from unittest.mock import patch
|
|
|
|
from django.template.loader import render_to_string
|
|
from django.test import TestCase
|
|
|
|
from apps.notifications.services import NotificationService
|
|
|
|
|
|
class AutoWrapBrandedTemplateTests(TestCase):
|
|
"""Part D — plain-text messages are auto-wrapped in the branded template."""
|
|
|
|
@patch("apps.notifications.services.send_mail")
|
|
def test_plain_text_gets_branded_html(self, mock_send_mail):
|
|
NotificationService.send_email(
|
|
email="patient@example.com",
|
|
subject="Test Subject",
|
|
message="Line one.\n\nLine two.\nLine three.",
|
|
)
|
|
# send_mail was called with an html_message
|
|
_, kwargs = mock_send_mail.call_args
|
|
self.assertIsNotNone(kwargs.get("html_message"))
|
|
html = kwargs["html_message"]
|
|
# The branded template contributes these structural markers
|
|
self.assertIn("email-container", html) # the 600px card from base_email_template
|
|
self.assertIn("<!DOCTYPE", html) # full HTML document shell
|
|
# Plain-text content was converted to HTML paragraphs
|
|
self.assertIn("Line one.", html)
|
|
self.assertIn("<br>", html) # single newline -> <br>
|
|
self.assertIn("<p>", html) # double newline -> new paragraph
|
|
|
|
@patch("apps.notifications.services.send_mail")
|
|
def test_explicit_html_message_is_not_overwritten(self, mock_send_mail):
|
|
"""Callers that already provide html_message keep it as-is (no double-wrapping)."""
|
|
custom_html = "<div>My custom layout</div>"
|
|
NotificationService.send_email(
|
|
email="patient@example.com",
|
|
subject="Test",
|
|
message="Plain text fallback",
|
|
html_message=custom_html,
|
|
)
|
|
_, kwargs = mock_send_mail.call_args
|
|
self.assertEqual(kwargs["html_message"], custom_html)
|
|
|
|
|
|
class DeptChampionNotificationKwargTests(TestCase):
|
|
"""Part A — the recipient= bug is fixed (send_email uses email= kwarg).
|
|
|
|
We verify indirectly: send_email no longer receives an unexpected 'recipient'
|
|
kwarg, which used to cause a TypeError swallowed by try/except.
|
|
"""
|
|
|
|
@patch("apps.notifications.services.send_mail")
|
|
def test_send_email_signature_rejects_recipient_kwarg(self, mock_mail):
|
|
"""The send_email method must not accept 'recipient' as a kwarg (the bug).
|
|
|
|
Python validates kwargs at call time, so TypeError fires before the
|
|
body runs — we must NOT mock send_email itself.
|
|
"""
|
|
with self.assertRaises(TypeError):
|
|
NotificationService.send_email(
|
|
recipient="someone@example.com", # wrong kwarg — should TypeError
|
|
subject="Test",
|
|
message="Test",
|
|
)
|
|
|
|
|
|
class BrandedReminderTemplateTests(TestCase):
|
|
"""Parts B & C — the reminder templates extend the base and render branded HTML."""
|
|
|
|
def _assert_branded(self, html):
|
|
"""Structural markers contributed by base_email_template.html."""
|
|
self.assertIn("<!DOCTYPE", html)
|
|
self.assertIn("email-container", html)
|
|
|
|
def test_inquiry_dept_response_reminder_renders(self):
|
|
html = render_to_string("emails/inquiry_dept_response_reminder.html", {
|
|
"inquiry": type("Obj", (), {"reference_number": "INQ-001", "subject": "Test"})(),
|
|
"department_name": "Lab",
|
|
"hours_remaining": 12,
|
|
"sla_due_at": "2026-07-15T10:00:00",
|
|
"inquiry_url": "https://example.com/inquiries/1/",
|
|
})
|
|
self._assert_branded(html)
|
|
self.assertIn("INQ-001", html)
|
|
self.assertIn("Lab", html)
|
|
|
|
def test_observation_dept_response_reminder_renders(self):
|
|
html = render_to_string("emails/observation_dept_response_reminder.html", {
|
|
"observation": type("Obj", (), {"tracking_code": "OBS-001", "title": "Spill"})(),
|
|
"department_name": "Lab",
|
|
"hours_remaining": 8,
|
|
"sla_due_at": "2026-07-15T10:00:00",
|
|
"observation_url": "https://example.com/observations/1/",
|
|
})
|
|
self._assert_branded(html)
|
|
self.assertIn("OBS-001", html)
|
|
|
|
def test_inquiry_sla_reminder_renders(self):
|
|
html = render_to_string("emails/inquiry_sla_reminder.html", {
|
|
"inquiry": type("Obj", (), {
|
|
"reference_number": "INQ-002",
|
|
"subject": "Billing",
|
|
"due_at": "2026-07-15T10:00:00",
|
|
})(),
|
|
"hours_remaining": 24,
|
|
"inquiry_url": "https://example.com/inquiries/2/",
|
|
})
|
|
self._assert_branded(html)
|
|
self.assertIn("INQ-002", html)
|
|
|
|
def test_inquiry_sla_second_reminder_renders_urgent(self):
|
|
html = render_to_string("emails/inquiry_sla_second_reminder.html", {
|
|
"inquiry": type("Obj", (), {
|
|
"reference_number": "INQ-003",
|
|
"subject": "Billing",
|
|
"due_at": "2026-07-15T10:00:00",
|
|
})(),
|
|
"hours_remaining": 2,
|
|
"inquiry_url": "https://example.com/inquiries/3/",
|
|
})
|
|
self._assert_branded(html)
|
|
self.assertIn("URGENT", html)
|
|
self.assertIn("#dc2626", html) # red accent for urgency
|