64

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?

Mate Solymosi
  • 5,699
  • 23
  • 30
Kevin Pang
  • 41,172
  • 38
  • 121
  • 173

3 Answers3

95
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
BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
Peter Brown
  • 50,956
  • 18
  • 113
  • 146
  • 65
    To avoid repeating this, you can put it in the config block of spec_helper.rb: `config.before(:each) { ActionMailer::Base.deliveries.clear }` – Luke Francl Apr 13 '12 at 21:41
  • 8
    This should not be needed as RSpec mailer specs should be setup to clear the deliveries array automatically. See https://github.com/rspec/rspec-rails/issues/661 for details. – Andy Lindeman Jan 01 '13 at 18:47
  • 2
    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. – froderik Dec 30 '13 at 14:21
55

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.

coorasse
  • 5,278
  • 1
  • 34
  • 45
  • 6
    This seems like the clearest solution so far. For projects using [email-spec](https://github.com/bmabey/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` – Eliot Sykes Mar 29 '15 at 10:48
11

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
d_rail
  • 4,109
  • 32
  • 37
  • Thanks for the tip! This feels like a much cleaner approach to me. Works with Rails 4.1 and Rspec 3.1. – kasia Dec 15 '14 at 18:38
  • Yup. this was the issue I had. I forgot to add `type: :mailer`. Thanks d_rail! – karlingen Feb 25 '15 at 13:26
  • 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. – C.J. May 26 '15 at 17:02
  • 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. – sevenseacat Feb 04 '16 at 07:01