Rails - How do you test ActionMailer sent a specific email in tests

后端 未结 7 2021
面向向阳花
面向向阳花 2020-12-23 12:58

Currently in my tests I do something like this to test if an email is queued to be sent

assert_difference(\'ActionMailer::Base.deliveries.size\', 1) do              


        
相关标签:
7条回答
  • 2020-12-23 13:13

    As of 2020 (Rails 6 era, probably introduced earlier) you can do the following: (using a SystemTest example) TL;DR: use assert_emails from ActionMailer::TestHelper and ActionMailer::Base.deliveries.last to access the mail itself.

    require "application_system_test_case"
    require 'test_helper'
    require 'action_mailer/test_helper'
    
    class ContactTest < ApplicationSystemTestCase
      include ActionMailer::TestHelper
    
      test "Send mail via contact form on landing page" do
        visit root_url
    
        fill_in "Message", with: 'message text'
    
        # Asserting a mail is sent
        assert_emails 1 do
          click_on "Send"
        end
    
        # Asserting stuff within that mail
        last_email  = ActionMailer::Base.deliveries.last
    
        assert_equal ['whatever'], last_email.reply_to
        assert_equal "contact", last_email.subject
        assert_match /Mail from someone/, last_email.body.to_s
      end
    end
    

    Official doc:

    • ActionMailer Guide/Testing
    • Testing Guide/ActionMailer

    Note Instead of manually checking the content of the mail as in the system test above, you can also test whether a specific mailer action was used, like this:

    assert_enqueued_email_with ContactMailer, :welcome, args: ["Hello", "Goodbye"]
    

    And some other handy assertion, see https://api.rubyonrails.org/v6.0.3.2/classes/ActionMailer/TestHelper.html#method-i-assert_emails .

    0 讨论(0)
  • 2020-12-23 13:18

    Using current Rspec syntax, I ended up using the following:

    last_email = ActionMailer::Base.deliveries.last
    expect(last_email.to).to eq ['test@example.com']
    expect(last_email.subject).to have_content 'Welcome'
    

    The context of my test was a feature spec where I wanted to make sure a welcome email was sent to a user after signing up.

    0 讨论(0)
  • 2020-12-23 13:19

    As of rails 3 ActionMailer::Base.deliveries is an array of Mail::Message's. From the mail documentation:

    #  mail['from'] = 'mikel@test.lindsaar.net'
    #  mail[:to]    = 'you@test.lindsaar.net'
    #  mail.subject 'This is a test email'
    #  mail.body    = 'This is a body'
    # 
    #  mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
    

    From that it should be easy to test your mail's in an integration

    mail = ActionMailer::Base.deliveries.last
    
    assert_equal 'mikel@test.lindsaar.net', mail['from'].to_s
    
    assert_equal 'you@test.lindsaar.net', mail['to'].to_s
    
    0 讨论(0)
  • 2020-12-23 13:23

    A little late, but it may help others:

    You could use Email-spec, a collection of Rspec/Minitest matchers and Cucumber steps.

    0 讨论(0)
  • 2020-12-23 13:27

    The test framework shoulda has an excellent helper which lets you assert certain conditions about an email that was sent. Yes, you could do it yourself with ActionMailer.deliveries, but shoulda makes it all one neat little block

    0 讨论(0)
  • 2020-12-23 13:29

    When using the ActionMailer during tests, all mails are put in a big array called deliveries. What you basically are doing (and is sufficient mostly) is checking if emails are present in the array. But if you want to specifically check for a certain email, you have to know what is actually stored in the array. Luckily the emails themselves are stored, thus you are able to iterate through the array and check each email.

    See ActionMailer::Base to see what configuration methods are available, which you can use to determine what emails are present in the array. Some of the most suitable methods for your case probably are

    • recipients: Takes one or more email addresses. These addresses are where your email will be delivered to. Sets the To: header.
    • subject: The subject of your email. Sets the Subject: header.
    0 讨论(0)
提交回复
热议问题