简体   繁体   中英

RSpec Rails mailer expectation - last delivery is of specific action/method/template

I have the following task:

My mailer has multiple actions/templates, each with the same static hardcoded subject.

In my RSpec expectation I would like to verify that certain block triggers email(changes ActionMailer::Base.deliveries.last&.something ) of specific mailer action/template.

Limitations:

  • can not rely on a delivery subject/title(not unique)
  • preferably avoid checking delivery content(they are mostly the same except for a few minor wording changes)
  • can not change a delivery subject/title generation just to make this spec pass
  • can not mock/stub mailer(I don't want to skip the rendering part, this is also a part of the test)

Methods that I tried that didn't work:

ActionMailer::Base.deliveries.last.template_model
# => nil
ActionMailer::Base.deliveries.last.template_alias
# => nil
ActionMailer::Base.deliveries.last.filename
# => nil
ActionMailer::Base.deliveries.last.metadata
# => {}
ActionMailer::Base.deliveries.last.action
# => nil

What might be an idiomatic Rails way of approaching this task? Custom header with action/template name?

Mail::Message methods(for the reference):

ActionMailer::Base.deliveries.last.public_methods(false)
=> [:perform_deliveries=,
 :mime_version=,
 :sender,
 :metadata=,
 :boundary,
 :multipart?,
 :errors,
 :to_yaml,
 :delivery_handler,
 :tag,
 :raise_delivery_errors,
 :register_for_delivery_notification,
 :inform_observers,
 :inform_interceptors,
 :in_reply_to=,
 :comments=,
 :in_reply_to,
 :reply_to,
 :references=,
 :message_id=,
 :raw_source,
 :set_envelope,
 :filename,
 :raw_envelope,
 :envelope_from,
 :envelope_date,
 :content_description,
 :content_description=,
 :content_disposition=,
 :content_id=,
 :content_location,
 :content_location=,
 :content_transfer_encoding,
 :content_transfer_encoding=,
 :transport_encoding,
 :transport_encoding=,
 :received,
 :received=,
 :header=,
 :reply_to=,
 :resent_bcc,
 :resent_bcc=,
 :resent_cc,
 :resent_cc=,
 :resent_date,
 :resent_date=,
 :resent_from,
 :resent_from=,
 :bcc,
 :resent_message_id=,
 :resent_message_id,
 :resent_sender=,
 :resent_sender,
 :resent_to=,
 :resent_to,
 :references,
 :from,
 :return_path=,
 :sender=,
 :return_path,
 :smtp_envelope_from=,
 :smtp_envelope_to=,
 :smtp_envelope_from,
 :body_encoding,
 :body_encoding=,
 :smtp_envelope_to,
 :cc_addrs,
 :bcc_addrs,
 :from_addrs,
 :has_message_id?,
 :has_date?,
 :header_fields,
 :has_charset?,
 :has_content_transfer_encoding?,
 :has_mime_version?,
 :has_transfer_encoding?,
 :destinations,
 :add_date,
 :add_message_id,
 :add_mime_version,
 :sub_type,
 :to,
 :subject,
 :subject=,
 :cc=,
 :bcc=,
 :add_content_transfer_encoding,
 :perform_deliveries,
 :<=>,
 :message_content_type,
 :delivery_status_part,
 :add_content_type,
 :add_charset,
 :==,
 :main_type,
 :transfer_encoding,
 :diagnostic_code,
 :mime_parameters,
 :[],
 :[]=,
 :remote_mta,
 :retryable?,
 :html_part=,
 :bounced?,
 :final_recipient,
 :add_transfer_encoding,
 :text_part=,
 :convert_to_multipart,
 :attachment,
 :keywords,
 :charset=,
 :delivery_handler=,
 :without_attachments!,
 :error_status,
 :delivery_status_report?,
 :decode_body,
 :all_parts,
 :skip_deletion,
 :mark_for_delete=,
 :is_marked_for_delete?,
 :inspect,
 :multipart_report?,
 :method_missing,
 :attachment?,
 :mime_version,
 :add_file,
 :action,
 :raise_delivery_errors=,
 :parts,
 :to_s,
 :body=,
 :content_type_parameters,
 :has_attachments?,
 :add_part,
 :find_first_mime_type,
 :encoded,
 :date,
 :decoded,
 :attachments,
 :track_links,
 :part,
 :templated?,
 :metadata,
 :export_headers,
 :track_opens,
 :template_alias,
 :template_model,
 :message_stream,
 :export_attachments,
 :body_html,
 :body_text,
 :message_id,
 :comments,
 :to_addrs,
 :from=,
 :postmark_response,
 :default,
 :to_postmark_hash,
 :content_disposition,
 :content_id,
 :has_content_type?,
 :keywords=,
 :delivery_method,
 :date=,
 :text?,
 :cc,
 :delivered=,
 :postmark_response=,
 :encode!,
 :mime_type,
 :html?,
 :tag=,
 :delivered,
 :delivered?,
 :track_links=,
 :track_opens=,
 :postmark_attachments=,
 :postmark_attachments,
 :read,
 :message_stream=,
 :prerender,
 :text_part,
 :html_part,
 :reply,
 :ready_to_send!,
 :template_model=,
 :deliver!,
 :headers,
 :header,
 :content_type,
 :to=,
 :charset,
 :deliver,
 :body,
 :content_type=]

Related question:

Rails, RSpec: How to test, that a specific mailer action gets triggered (uses mocks)

That's what I currently ended up with(until I find a better way):

added the following line to the each of related mailer actions:

headers['X-Rails-Template'] = __method__

add my specs looks a bit like this:

subject { -> { described_class.call } }

let(:last_template_name) do
  -> do
    m = ActionMailer::Base.deliveries.last
    next if m.blank?

    m.header['X-Rails-Template']&.value
  end
end

it do
  is_expected.to change { ActionMailer::Base.deliveries.count }.to(1)
                   .and change(&last_template_name).to('mailer_action_name1')
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM