34

In my ActionMailer::TestCase test, I'm expecting:

@expected.to      = BuyadsproMailer.group_to(campaign.agency.users)
@expected.subject = "You submitted #{offer_log.total} worth of offers for #{offer_log.campaign.name} "
@expected.from    = "BuyAds Pro <feedback@buyads.com>"
@expected.body    = read_fixture('deliver_to_agency')

@expected.content_type = "multipart/mixed;\r\n boundary=\"something\""
@expected.attachments["#{offer_log.aws_key}.pdf"] = {
  :mime_type => 'application/pdf',
  :content => fake_pdf.body
}

and stub my mailer to get fake_pdf instead of a real PDF normally fetched from S3 so that I'm sure the bodies of the PDFs match.

However, I get this long error telling me that one email was expected but got a slightly different email:

<...Mime-Version: 1.0\r\nContent-Type: multipart/mixed\r\nContent-Transfer-Encoding: 7bit...> expected but was
<...Mime-Version: 1.0\r\nContent-Type: multipart/mixed;\r\n boundary=\"--==_mimepart_50f06fa9c06e1_118dd3fd552035ae03352b\";\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit...>

I'm not matching the charset or part-boundary of the generated email.

How do I define or stub this aspect of my expected emails?

Jordan Warbelow-Feldstein
  • 10,510
  • 12
  • 48
  • 79

2 Answers2

58

Here's an example that I copied from my rspec test of a specific attachment, hope that it helps (mail can be creating by calling your mailer method or peeking at the deliveries array after calling .deliver):

  mail.attachments.should have(1).attachment
  attachment = mail.attachments[0]
  attachment.should be_a_kind_of(Mail::Part)
  attachment.content_type.should be_start_with('application/ics;')
  attachment.filename.should == 'event.ics'
Roman
  • 13,100
  • 2
  • 47
  • 63
  • Is there a way to compare the md5 hashes? – mehulkar Mar 18 '15 at 01:53
  • 2
    Nice answer. Checking that the result is a kind of `Mail::Part` seems unnecessary though, and might make the test unnecessarily fragile if the class name is different in a future version of Rails. If the object is not of the correct type, then the likelihood of it responding to `content_type` and `filename` methods is extremely low. – Steve Jorgensen Mar 03 '16 at 01:28
  • 2
    You can also test the content of the attachment: `expect(attachment.body).to eq fake_pdf.body` – jwadsack Nov 10 '17 at 20:06
  • Newer `expects` syntax looks like this: `it { is_expected.to have(1).attachments }` – danielricecodes Apr 05 '23 at 20:21
5

I had something similar where I wanted to check an attached csv's content. I needed something like this because it looks like \r got inserted for newlines:

expect(mail.attachments.first.body.encoded.gsub(/\r/, '')).to(
  eq(
    <<~CSV
      "Foo","Bar"
      "1","2"
    CSV
  )
) 
Adverbly
  • 1,726
  • 2
  • 16
  • 23