Skip to content

Commit 71d1fdd

Browse files
Improve email template tests
- Add sent_emails fixture to capture SentEmail objects during tests - Remove EmailTemplate class mocking in favor of real template usage - Add assertions to verify correct template identifiers are used - Verify email templates belong to correct conferences - Verify emails are sent to correct recipients with correct placeholders - Updated key test files: submissions, grants, and API tests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Marco Acierno <[email protected]>
1 parent 601884e commit 71d1fdd

File tree

4 files changed

+86
-49
lines changed

4 files changed

+86
-49
lines changed

backend/api/grants/tests/test_send_grant.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ def _send_grant(client, conference, conference_code=None, **kwargs):
9191
return response
9292

9393

94-
def test_send_grant(graphql_client, user, mocker, django_capture_on_commit_callbacks):
95-
mock_email_template = mocker.patch("api.grants.mutations.EmailTemplate")
94+
def test_send_grant(graphql_client, user, mocker, django_capture_on_commit_callbacks, sent_emails):
9695
graphql_client.force_login(user)
9796
conference = ConferenceFactory(active_grants=True)
9897
EmailTemplateFactory(
@@ -118,13 +117,18 @@ def test_send_grant(graphql_client, user, mocker, django_capture_on_commit_callb
118117
user=user, conference=conference, privacy_policy="grant"
119118
).exists()
120119

121-
# An email is sent to the user
122-
mock_email_template.objects.for_conference().get_by_identifier().send_email.assert_called_once_with(
123-
recipient=user,
124-
placeholders={
125-
"user_name": user.full_name,
126-
},
127-
)
120+
# Verify that the correct email template was used and email was sent
121+
emails_sent = sent_emails()
122+
assert emails_sent.count() == 1
123+
124+
sent_email = emails_sent.first()
125+
assert sent_email.email_template.identifier == EmailTemplateIdentifier.grant_application_confirmation
126+
assert sent_email.email_template.conference == conference
127+
assert sent_email.recipient == user
128+
assert sent_email.recipient_email == user.email
129+
130+
# Verify placeholders were processed correctly
131+
assert sent_email.placeholders["user_name"] == user.full_name
128132

129133

130134
def test_cannot_send_a_grant_if_grants_are_closed(graphql_client, user, mocker):

backend/api/submissions/tests/test_send_submission.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,9 @@ def _submit_proposal(client, conference, submission, **kwargs):
141141

142142

143143
def test_submit_talk(
144-
graphql_client, user, django_capture_on_commit_callbacks, mocker, settings
144+
graphql_client, user, django_capture_on_commit_callbacks, mocker, settings, sent_emails
145145
):
146146
settings.FRONTEND_URL = "http://testserver"
147-
mock_email_template = mocker.patch("api.submissions.mutations.EmailTemplate")
148147
mock_notify = mocker.patch("api.submissions.mutations.notify_new_cfp_submission")
149148
graphql_client.force_login(user)
150149

@@ -219,14 +218,20 @@ def test_submit_talk(
219218

220219
mock_notify.delay.assert_called_once()
221220

222-
mock_email_template.objects.for_conference().get_by_identifier().send_email.assert_called_once_with(
223-
recipient=user,
224-
placeholders={
225-
"user_name": user.full_name,
226-
"proposal_title": "English",
227-
"proposal_url": f"http://testserver/submission/{talk.hashid}",
228-
},
229-
)
221+
# Verify that the correct email template was used and email was sent
222+
emails_sent = sent_emails()
223+
assert emails_sent.count() == 1
224+
225+
sent_email = emails_sent.first()
226+
assert sent_email.email_template.identifier == EmailTemplateIdentifier.proposal_received_confirmation
227+
assert sent_email.email_template.conference == conference
228+
assert sent_email.recipient == user
229+
assert sent_email.recipient_email == user.email
230+
231+
# Verify placeholders were processed correctly
232+
assert sent_email.placeholders["user_name"] == user.full_name
233+
assert sent_email.placeholders["proposal_title"] == "English"
234+
assert sent_email.placeholders["proposal_url"] == f"http://testserver/submission/{talk.hashid}"
230235

231236

232237
def test_submit_talk_with_photo_to_upload(graphql_client, user, mocker):

backend/conftest.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,21 @@ def matcher(req):
116116
requests_mock.add_matcher(matcher)
117117

118118
return wrapper
119+
120+
121+
@pytest.fixture
122+
def sent_emails(db):
123+
"""
124+
Fixture to capture and provide access to SentEmail objects created during tests.
125+
This fixture allows tests to verify email template usage and email creation
126+
without mocking the EmailTemplate class.
127+
128+
Returns:
129+
A callable that returns a QuerySet of SentEmail objects created during the test.
130+
"""
131+
from notifications.models import SentEmail
132+
133+
def get_sent_emails():
134+
return SentEmail.objects.all()
135+
136+
return get_sent_emails

backend/submissions/tests/test_tasks.py

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def test_handle_new_cfp_submission():
4545
assert "Marco Acierno" in str(slack_mock.send_message.mock_calls[0])
4646

4747

48-
def test_send_proposal_rejected_email():
48+
def test_send_proposal_rejected_email(sent_emails):
4949
submission = SubmissionFactory(
5050
conference__name=LazyI18nString({"en": "Conf"}),
5151
title=LazyI18nString({"en": "Title"}),
@@ -55,26 +55,31 @@ def test_send_proposal_rejected_email():
5555

5656
EmailTemplateFactory(
5757
conference=submission.conference,
58-
identifier=EmailTemplateIdentifier.proposal_scheduled,
58+
identifier=EmailTemplateIdentifier.proposal_rejected,
5959
)
6060

61-
with patch("submissions.tasks.EmailTemplate") as mock_email_template:
62-
send_proposal_rejected_email(
63-
proposal_id=submission.id,
64-
)
65-
66-
mock_email_template.objects.for_conference().get_by_identifier().send_email.assert_called_once_with(
67-
recipient=submission.speaker,
68-
placeholders={
69-
"proposal_title": "Title",
70-
"proposal_type": submission.type.name,
71-
"conference_name": "Conf",
72-
"speaker_name": "Marco",
73-
},
61+
send_proposal_rejected_email(
62+
proposal_id=submission.id,
7463
)
7564

76-
77-
def test_send_proposal_in_waiting_list_email():
65+
# Verify that the correct email template was used and email was sent
66+
emails_sent = sent_emails()
67+
assert emails_sent.count() == 1
68+
69+
sent_email = emails_sent.first()
70+
assert sent_email.email_template.identifier == EmailTemplateIdentifier.proposal_rejected
71+
assert sent_email.email_template.conference == submission.conference
72+
assert sent_email.recipient == submission.speaker
73+
assert sent_email.recipient_email == submission.speaker.email
74+
75+
# Verify placeholders were processed correctly
76+
assert sent_email.placeholders["proposal_title"] == "Title"
77+
assert sent_email.placeholders["proposal_type"] == submission.type.name
78+
assert sent_email.placeholders["conference_name"] == "Conf"
79+
assert sent_email.placeholders["speaker_name"] == "Marco"
80+
81+
82+
def test_send_proposal_in_waiting_list_email(sent_emails):
7883
submission = SubmissionFactory(
7984
conference__name=LazyI18nString({"en": "Conf"}),
8085
title=LazyI18nString({"en": "Title"}),
@@ -87,17 +92,22 @@ def test_send_proposal_in_waiting_list_email():
8792
identifier=EmailTemplateIdentifier.proposal_in_waiting_list,
8893
)
8994

90-
with patch("submissions.tasks.EmailTemplate") as mock_email_template:
91-
send_proposal_in_waiting_list_email(
92-
proposal_id=submission.id,
93-
)
94-
95-
mock_email_template.objects.for_conference().get_by_identifier().send_email.assert_called_once_with(
96-
recipient=submission.speaker,
97-
placeholders={
98-
"proposal_title": "Title",
99-
"proposal_type": submission.type.name,
100-
"conference_name": "Conf",
101-
"speaker_name": "Marco",
102-
},
95+
send_proposal_in_waiting_list_email(
96+
proposal_id=submission.id,
10397
)
98+
99+
# Verify that the correct email template was used and email was sent
100+
emails_sent = sent_emails()
101+
assert emails_sent.count() == 1
102+
103+
sent_email = emails_sent.first()
104+
assert sent_email.email_template.identifier == EmailTemplateIdentifier.proposal_in_waiting_list
105+
assert sent_email.email_template.conference == submission.conference
106+
assert sent_email.recipient == submission.speaker
107+
assert sent_email.recipient_email == submission.speaker.email
108+
109+
# Verify placeholders were processed correctly
110+
assert sent_email.placeholders["proposal_title"] == "Title"
111+
assert sent_email.placeholders["proposal_type"] == submission.type.name
112+
assert sent_email.placeholders["conference_name"] == "Conf"
113+
assert sent_email.placeholders["speaker_name"] == "Marco"

0 commit comments

Comments
 (0)