Clearing out ActionMailer::Base.deliveries after RSpec test

18,669

Solution 1

RSpec.describe UserMailer do
  before do
    # ActionMailer::Base.deliveries is a regular array
    ActionMailer::Base.deliveries = []

    # or use ActionMailer::Base.deliveries.clear
  end

  it "sends welcome email" do
    user = create(:user)
    UserMailer.welcome_email(user).deliver_now
    expect(ActionMailer::Base.deliveries).to be_present
  end
end

Solution 2

You can clear the deliveries after each test quite easily, adding this into your spec_helper.rb.

RSpec.configure do |config|
  config.before { ActionMailer::Base.deliveries.clear }      
end

I'd suggest reading my article about the correct emails configuration in Rails where I talk also about testing them correctly.

Solution 3

As Andy Lindeman points out, clearing the deliveries is done automatically for mailer tests. However, for other types, simply add , :type => :mailer to the wrapping block to force the same behavior.

describe "tests that send emails", type: :mailer do
  # some tests
end
Share:
18,669
Remy Vanherweghem
Author by

Remy Vanherweghem

Software developer at Google, Irvine Blog Google+ Twitter

Updated on June 05, 2022

Comments

  • Remy Vanherweghem
    Remy Vanherweghem almost 2 years

    I have the following RSpec test for my UserMailer class:

    require "spec_helper"
    
    describe UserMailer do
      it "should send welcome emails" do
        ActionMailer::Base.deliveries.should be_empty
        user = Factory(:user)
        UserMailer.welcome_email(user).deliver
        ActionMailer::Base.deliveries.should_not be_empty
      end
    end
    

    This test passed the first time, but failed the second time I ran it. After doing a little bit of debugging, it appears that the 1st test added an item to the ActionMailer::Base.deliveries array and that item never got cleared out. That causes the first line in the test to fail since the array is not empty.

    What's the best way to clear out the ActionMailer::Base.deliveries array after an RSpec test?

  • Luke Francl
    Luke Francl about 12 years
    To avoid repeating this, you can put it in the config block of spec_helper.rb: config.before(:each) { ActionMailer::Base.deliveries.clear }
  • Andy Lindeman
    Andy Lindeman over 11 years
    This should not be needed as RSpec mailer specs should be setup to clear the deliveries array automatically. See github.com/rspec/rspec-rails/issues/661 for details.
  • froderik
    froderik over 10 years
    It is supposed to work for mailer specs but not for request specs - then you need to clear it yourself somehow. Me? I am going for the Luke Francl method.
  • kasia
    kasia over 9 years
    Thanks for the tip! This feels like a much cleaner approach to me. Works with Rails 4.1 and Rspec 3.1.
  • karlingen
    karlingen about 9 years
    Yup. this was the issue I had. I forgot to add type: :mailer. Thanks d_rail!
  • Kevin Walsh
    Kevin Walsh about 9 years
    This seems like the clearest solution so far. For projects using email-spec, consider calling reset_mailer in the before block in place of ActionMailer::Base.deliveries.clear as reset_mailer does a little extra work that may be helpful. RSpec.configure do |config| config.before(:each) { reset_mailer } end
  • C.J.
    C.J. almost 9 years
    This seems fundamentally fragile to me. Decorating test cases with special flags to make them behave in ways that are not obvious. I prefer the other answers.
  • sevenseacat
    sevenseacat about 8 years
    adding a "mailer" tag to a test that is not specifically a mailer unit test seems broken. I'd rather go for one of the other approaches.