Testing ActionMailer multipart emails(text and html version) with RSpec

后端 未结 5 905
灰色年华
灰色年华 2021-01-30 22:06

I\'m currently testing my mailers with RSpec, but I\'ve started setting up multipart emails as described in the Rails Guides here: http://guides.rubyonrails.org/action_mailer_b

相关标签:
5条回答
  • 2021-01-30 22:18

    To make things even simpler, you can use

    message.text_part    and
    message.html_part
    

    to find the respective parts. This works even for structured multipart/alternative messages with attachments. (Tested on Ruby 1.9.3 with Rails 3.0.14.)

    These methods employ some kind of heuristic to find the respective message parts, so if your message has multiple text parts (e.g. as Apple Mail creates them) it might fail to do the "right thing".

    This would change the above method to

    def body_should_match_regex(mail, regex)
     if mail.multipart?
      ["text", "html"].each do |part|
       mail.send("#{part}_part").body.raw_source.should match(regex)
      end
     else
      mail.body.raw_source.should match(regex)
     end
    end
    

    which works for both plaintext (non-multipart) messages and multipart messages and tests all message bodies against a specific regular expression.

    Now, any volunteers to make a "real" RSpec matcher out of this? :) Something like

    @mail.bodies_should_match /foobar/
    

    would be a lot nicer ...

    0 讨论(0)
  • 2021-01-30 22:24

    To supplement, nilmethod's excellent answer, you can clean up your specs by testing both text and html versions using a shared example group:

    spec_helper.rb

    def get_message_part (mail, content_type)
      mail.body.parts.find { |p| p.content_type.match content_type }.body.raw_source
    end
    
    shared_examples_for "multipart email" do
      it "generates a multipart message (plain text and html)" do
        mail.body.parts.length.should eq(2)
        mail.body.parts.collect(&:content_type).should == ["text/plain; charset=UTF-8", "text/html; charset=UTF-8"]
      end
    end
    

    your_email_spec.rb

    let(:mail) { YourMailer.action }
    
    shared_examples_for "your email content" do
      it "has some content" do
        part.should include("the content")
      end
    end
    
    it_behaves_like "multipart email"
    
    describe "text version" do
      it_behaves_like "your email content" do
        let(:part) { get_message_part(mail, /plain/) }
      end
    end
    
    describe "html version" do
      it_behaves_like "your email content" do
        let(:part) { get_message_part(mail, /html/) }
      end
    end
    
    0 讨论(0)
  • 2021-01-30 22:26

    This can be tested with regular expressions.

    Finding things in the HTML portion (use #should after this to match):

    mail.body.parts.find {|p| p.content_type.match /html/}.body.raw_source
    

    Finding things in the plain text portion (use #should after this to match):

    mail.body.parts.find {|p| p.content_type.match /plain/}.body.raw_source
    

    Checking that it is, indeed, generating a multipart message:

    it "generates a multipart message (plain text and html)" do
      mail.body.parts.length.should == 2
      mail.body.parts.collect(&:content_type).should == ["text/html; charset=UTF-8", "text/plain; charset=UTF-8"]
    end 
    
    0 讨论(0)
  • 2021-01-30 22:32

    I have done this way, I found it simpler since the content of both emails is gonna be similar except styles and markup.

    context 'When there are no devices' do
      it 'makes sure both HTML and text version emails are sent' do
        expect(mail.body.parts.count).to eq(2)
        # You can even make sure the types of the part are `html` and `text`
      end
    
      it 'does not list any lockboxes to be removed in both types emails' do
        mail.body.parts.each do |part|
          expect(part.body).to include('No devices to remove')
        end
      end
    end
    
    0 讨论(0)
  • 2021-01-30 22:38

    If your email has attachments the text and html parts will end be placed in a multipart/alternative part. This is noted on under Sending Emails with Attachments in the Rails 3 Guide.

    To handle this, I first simplified the get_message_part method above to:

    def get_message_part(mail, content_type)
      mail.body.parts.find { |p| p.content_type.match content_type }
    end
    

    Then in my test:

    multipart = get_message_part(email, /multipart/)
    
    html = get_message_part(multipart, /html/)
    html_body = html.body.raw_source
    
    assert_match 'some string', html_body
    
    0 讨论(0)
提交回复
热议问题