-
Notifications
You must be signed in to change notification settings - Fork 120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mailer_helper update #11665
mailer_helper update #11665
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,26 +15,106 @@ def strip_tags(str) | |
ActionController::Base.helpers.strip_tags(str) | ||
end | ||
|
||
# @param [String,String[],nil] to The email address(es) the message must've been sent to. | ||
# @param [String,nil] subject The subject the email must've had | ||
# @param [String[],nil] Array of substrings that must appear in body. | ||
def expect_delivered_email(to: nil, subject: nil, body: nil) | ||
email = ActionMailer::Base.deliveries.find do |sent_mail| | ||
next unless to.present? && sent_mail.to == to | ||
next unless subject.present? && sent_mail.subject == subject | ||
if body.present? | ||
delivered_body = sent_mail.text_part.decoded.squish | ||
body.to_a.each do |expected_body| | ||
next unless delivered_body.include?(expected_body) | ||
end | ||
end | ||
true | ||
end | ||
email = find_sent_email(to:, subject:, body:) | ||
|
||
error_message = <<~ERROR | ||
Unable to find email matching args: | ||
to: #{to} | ||
subject: #{subject} | ||
body: #{body} | ||
Sent mails: #{ActionMailer::Base.deliveries} | ||
Sent mails: | ||
#{summarize_all_deliveries(to:, subject:, body:).indent(2)} | ||
ERROR | ||
|
||
expect(email).to_not be(nil), error_message | ||
end | ||
|
||
# @param [String,nil] to If provided, the email address the message must've been sent to | ||
# @param [String,nil] subject If provided, the subject the email must've had | ||
# @param [String[],nil] Array of substrings that must appear in body. | ||
def expect_email_not_delivered(to: nil, subject: nil, body: nil) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TBH I would like to rework this as an Rspec matcher, something like expect { some_code }.to have_delivered_email(...) But I needed to limit scope a little here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with you on both counts—that would be nice, but this is a good step forward for now. |
||
email = find_sent_email(to:, subject:, body:) | ||
|
||
error_message = <<~ERROR | ||
Found an email matching the below (but shouldn't have): | ||
to: #{to} | ||
subject: #{subject} | ||
body: #{body} | ||
Sent mails: | ||
#{summarize_all_deliveries(to:, subject:, body:).indent(2)} | ||
ERROR | ||
|
||
expect(email).to be(nil), error_message | ||
end | ||
|
||
private | ||
|
||
def body_matches(email:, body:) | ||
return true if body.nil? | ||
|
||
delivered_body = email.text_part.decoded.squish | ||
|
||
Array.wrap(body).all? do |expected_substring| | ||
delivered_body.include?(expected_substring) | ||
end | ||
end | ||
|
||
def to_matches(email:, to:) | ||
return true if to.nil? | ||
|
||
to = Array.wrap(to).to_set | ||
|
||
(email.to.to_set - to).empty? | ||
end | ||
|
||
def find_sent_email( | ||
to:, | ||
subject:, | ||
body: | ||
) | ||
ActionMailer::Base.deliveries.find do |email| | ||
to_ok = to_matches(email:, to:) | ||
subject_ok = subject.nil? || email.subject == subject | ||
body_ok = body_matches(email:, body:) | ||
|
||
to_ok && subject_ok && body_ok | ||
end | ||
end | ||
|
||
def summarize_delivery( | ||
email:, | ||
to:, | ||
subject:, | ||
body: | ||
) | ||
body_text = email.text_part.decoded.squish | ||
|
||
body_summary = body.presence && Array.wrap(body).map do |substring| | ||
found = body_text.include?(substring) | ||
"- #{substring.inspect} (#{found ? 'found' : 'not found'})" | ||
end.join("\n") | ||
|
||
to_ok = to_matches(email:, to:) | ||
subject_ok = subject.nil? || subject == email.subject | ||
|
||
[ | ||
"To: #{email.to}#{to_ok ? '' : ' (did not match)'}", | ||
"Subject: #{email.subject}#{subject_ok ? '' : ' (did not match)'}", | ||
body.presence && "Body:\n#{body_summary.indent(2)}", | ||
].compact.join("\n") | ||
end | ||
|
||
def summarize_all_deliveries(query) | ||
ActionMailer::Base.deliveries.map do |email| | ||
summary = summarize_delivery(email:, **query) | ||
[ | ||
"- #{summary.lines.first.chomp}", | ||
*summary.lines.drop(1).map { |l| l.chomp.indent(2) }, | ||
].join("\n") | ||
end.join("\n") | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out
body:
is only comparing against the plaintext version of the email, so checking for HTML here fails.Previously, we weren't correctly processing these body checks, so this was erroneously passing prior to this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I sometimes wonder how many tests erroneously pass and conceal bugs. 😬 Glad you found this.