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("[email protected]") }
# 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("[email protected]") }
instead I get the same error.
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