Hi,
Let's say I send an email through Sidekiq like below.
MyMailer.delay.welcome(param1, param2)
Now I want to test (with Rspec) that I am actually queuing an email with specific params. How should I do that with Rspec?
I try to stub_chain'' but it did not work.
Thanks
Did you look in the wiki? :cake:
Thanks but it solves half of the problem.
The Wiki shows how to test if something is queued but for example I cannot test if the first param is eql to '[email protected]' for example.
The job's in the array. Pull it out and introspect it.
Cool! Thanks a lot :)
Related to this:
require 'sidekiq/testing'
Sidekiq::Testing.fake!
class ExampleMailer < ActionMailer::Base
def example_mail(destination, content)
puts "Sending an email to #{destination}:\n#{content}"
end
end
class RegularWorker
include Sidekiq::Worker
def perform(destination, content)
puts "Doing something else with email #{destination}\n#{content}"
end
end
RegularWorker.perform_async("[email protected]", "Hello world!")
ExampleMailer.delay.example_mail("[email protected]", "Hello world!")
regular_job = RegularWorker.jobs.first
mailer_job = ExampleMailer.jobs.first
puts "args on the first RegularWorker job: #{regular_job["args"]}"
puts "args on the first DelayedMailer job: #{mailer_job["args"]}"
This prints for me:
$ rails runner ./sidekiq_testcase.rb
ran MailTrigger#do_thing
args on the first RegularWorker job: ["[email protected]", "Hello world!"]
args on the first DelayedMailer job: ["---\n- !ruby/class 'ExampleMailer'\n- :example_mail\n- - [email protected]\n - Hello world!\n"]
I think I understand why this happens: DelayedMailer jobs still have to be dispatched to the right ActionMailer class and method so there's another layer of indirection in the job arguments. So to get the args out I actually had to do another step:
(target, method_name, args) = YAML.load(mailer_job["args"].first)
I think it would be more convenient (but maybe unnecessary or even intrusive) if Sidekiq's fake testing mode dispatched mailer jobs onto arrays specific to the class/method_name, something like ExampleMailer.sidekiq_jobs.example_mail or somewhere on Sidekiq::Extensions::DelayedMailer, so that we could check jobs for a specific mailer and method directly. It feels wrong to have to rely on an implementation detail of DelayedMailer to test the args passed to delayed mailer jobs.
If you use rspec-sidekiq this pull-request might be handy. It lets you write:
expect(SomeMailer.instance_method :some_mail).to be_delayed(args)
Hey @mperham , it seems like none of these solutions work on Rails 5.2 for mailers based on ActiveJob and without Delayed extensions. Do you recommend using Delayed extensions for delayed emails, or is it better to stick deliver_later?
@FunkyloverOne assuming deliver_later:
```ruby
class SomeControllerTest < ActionDispatch::IntegrationTest
include ActiveJob::TestHelper
test "enque an email" do
assert_enqueued_with queue: "mailers" do
post some_path
end
end
end
Most helpful comment
If you use
rspec-sidekiqthis pull-request might be handy. It lets you write: