Daniel Doubrovkine bio photo

Daniel Doubrovkine

aka dB., @awscloud, former CTO @artsy, +@vestris, NYC

Email Twitter LinkedIn Github Strava

There’re two ways to test delayed jobs under RSpec.

The first is to use the library “as is”, invoking Delayed::Worker.new.work_off and examining the job results.

# create a new spline
spline = Spline.new(reticulated: false)

expect do
  # reticulate a spline in a delayed job
  spline.delay.reticulate!
end.to change(Delayed::Job, :count).by(1)

# execute all delayed jobs, successful jobs are deleted
expect do
  Delayed::Worker.new.work_off
end.to change(Delayed::Job, :count).by(-1)

expect(spline.reload.reticulated?).to be true

Unfortunately, this requires a lot of extra work to reach exceptions generated inside the delayed job worker.

A second solution that immediately executes delayed jobs has the advantage of failing loudly, predictably, and inline within your tests.

Create and require a spec/support/delayed_job.rb in your spec_helper.rb.

RSpec.configure do |config|
  config.before do
    Delayed::Worker.delay_jobs = false
  end
end

This causes immediate execution of the job in the following code.

Delayed::Worker.delay_job?(job) ? job.save : job.invoke_job

Since 4.1.0, Delayed::Worker.delay_jobs can also be a Proc. You may want to delay jobs that are scheduled in the future and immediately execute all other jobs. This is our default setup in Ruby projects at Artsy.

RSpec.configure do |config|
  config.before do
    Delayed::Worker.delay_jobs = ->(job) {
      job.run_at && job.run_at > Time.now.utc
    }
  end
end

If you must turn off this behavior in a specific test, set Delayed::Worker.delay_jobs to true.