Testing email: last email is nil when sent through a background worker
email, rspec, ruby-on-rails, sidekiq, testing
Solution
When requiring `sidekiq/testing` and not `sidekiq/testing/inline`, the jobs are put on the queue but not executed until a command like this is given:
Sidekiq::Extensions::DelayedMailer.drain
I use a helper method like this in my specs:
def process_async
EventWorker.drain
Sidekiq::Extensions::DelayedMailer.drain
end
Where EventWorker might be a custom worker in my app, and `Sidekiq::Extensions::DelayedMailer` is where delayed mails go by default with Sidekiq.
I can then have a spec like this:
#do stuff that should send an email and trigger other sidekiq events
...
process_async
...
#assert the email was sent correctly
There is a great explanation of all this on the SideKiq wiki: https://github.com/mperham/sidekiq/wiki/Testing
Problem
I'm trying to add some tests for email using this railscast, however I'm getting `undefined method 'to' for nil:NilClass`. The emails are actually processed through a background worker using Sidekiq and I know that they send properly since they work in production and also they would send before I added `require 'sidekiq/testing'` to `spec_helper.rb` So basically my problem is how do I access the email in Sidekiq? I've tried to let the workers process the email but still got the same error. spec/support/mailer_macros.rb ``` module MailerMacros def last_email ActionMailer::Base.deliveries.last end def reset_email ActionMailer::Base.deliveries = [] end end ``` spec/spec_helper.rb ``` require 'sidekiq/testing' ... config.include MailerMacros config.before(:each) { reset_email } ``` config/environments/test.rb ``` config.action_mailer.delivery_method = :test config.action_mailer.default_url_options = { host: 'localhost:8080' } ``` controllers/tickets_controller.rb ``` def create @ticket = current_user.tickets.build(params[:ticket]) if @ticket.save Sidekiq::Client.enqueue(TicketNotifier, @ticket.id) flash[:success] = "Your ticket has been submitted successfully." redirect_to ticket_path(@ticket) else render 'new' end end ``` part of the spec: ``` require 'spec_helper' describe "Tickets" do subject { page } describe "when creating a new ticket successfully" do before do login_as_user visit new_ticket_path fill_in "Subject", with: "Test ticket" fill_in "Description", with: "This is a test ticket" select 'Billing', from: "ticket[category]" click_button "Submit Ticket" end specify { last_email.to.should include("admin@email.com") } # the rest tests the tickets#show view it { should have_selector('title', text: "Ticket #1") } it { should have_content("ticket has been submitted successfully") } ... end end ``` When I use `specify { ActionMailer::Base.deliveries.last.to.should include("admin@email.com") }` instead I get the same error.