ChatGPT解决这个技术问题 Extra ChatGPT

Clearing out ActionMailer::Base.deliveries after RSpec test

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?

why should not use ActionMailer::Base.deliveries = [] in your setup block?
Is this spec located in spec/mailers/?

N
Nikita Fedyashev
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

To avoid repeating this, you can put it in the config block of spec_helper.rb: config.before(:each) { ActionMailer::Base.deliveries.clear }
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.
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.
c
coorasse

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.


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
d
d_rail

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

Thanks for the tip! This feels like a much cleaner approach to me. Works with Rails 4.1 and Rspec 3.1.
Yup. this was the issue I had. I forgot to add type: :mailer. Thanks d_rail!
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.
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.