I've written an RSpec integration test. According to test.log, I can see that it has sent an email, but when I try to access the email using ActionMailer::Base.deliveries, it always shows it is empty.
I have read the other similar questions and tried everything. I'm stumped.
Here is the code using Capybara/RSpec:
it "should notify owner" do
puts "Delivery method: #{ActionMailer::Base.delivery_method.inspect}"
# This returns: ":test", which is correct
# Get other guests to do the review
@review = Review.last
share_link = "http://#{@account.subdomain}.cozimo.local:#{Capybara.server_port}/review/#{@review.slug}"
visit(share_link)
fill_in "email", :with => @user1.email
fill_in "password", :with => "foobar"
click_button "Start Review"
# Add a comment
click_on "ice-global-note-button"
find(:css, "#ice-global-note-panel > textarea.ui-corner-all").set "Foo"
click_on "ice-global-note-submit-button"
# Test is failing here. WTF? The array should not be empty
ActionMailer::Base.deliveries.empty?.should be_false
# Check that a notification email was sent to the owner
open_email(@owner.email)
current_email.should have_content "Hi #{@owner.first_name}"
end
As you can see above, config.action_mailer.delivery_method = :test
In test.log, it shows that the email really is sent!
Sent mail to [email protected] (62ms)
Date: Tue, 29 Jan 2013 13:53:48 -0500
From: Review Studio <[email protected]>
To: [email protected]
Message-ID: <51081abcd9fbf_5bd23fef87b264a08066@Leonards-MacBook-Pro.local.mail>
Subject: Notes added for Test
Mime-Version: 1.0
Content-Type: text/plain;
charset=UTF-8
Content-Transfer-Encoding: 7bit
Hi Bruce,
Just letting you know that you have new notes added to the review:
Project: Test
Description: Test description
URL: http://ballistiq.cozimo.local:3000/review/625682740
Thanks,
Review Studio
Completed 200 OK in 170ms (Views: 0.2ms | ActiveRecord: 4.3ms)
This is an integration test using Capybara and Selenium. Therefore, you have to wait for the application to actually send the mail before checking that it has sent it.
Add a sleep 1
to tell rspec to wait after triggering the send mail event. It then resumes by checking the ActionMailer::Base.deliveries array and passed.
As mentioned, this is generally bad practice because it slows down tests.
Integration test shouldn't test the mail is sent at all. Tests should be divided up into clear responsibilities for the class being tested. Therefore, we'd structure the tests differently so that we only test for the mail being sent in another class (a controller or resource test). We could also use expectations to check that the call to the mail method was actually made though it's possible that we'd still get timing issues.
You should never use sleep or those time consuming methods on the specs, i't will only slow down your specs!
Try using an expectation on your mailer, at the beginning of your test add something like
mail = mock(mail)
mail.should_receive(:deliver)
YourMailer.should_receive(:your_method).once.and_return(mail)
that way you don't have to wait and you are actually testing what you have to test (that the code creates and delivers the mail) and not the mailer code (you only call deliver on a mail object, the actual delivery is a job of the ActionMailer tests and you have nothing to do with it on your application, you should just trust that calling those method works)
In my case config.action_mailer.perform_deliveries
was false
for test environments.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With