Rails 6 adds ActiveJob::TestCase#perform_enqueued_jobs without a block


ActiveJob::TestCase#perform_enqueued_jobs is used for performing all enqueued jobs in tests.

Before Rails 6

We can pass a block to perform_enqueued_jobs and it performs all the jobs specified in the duration of the block.

perform_enqueued_jobs do
  TestJob.perform_later
end
assert_enqueued_jobs 0
assert_performed_jobs 1

With Rails 6

We can use perform_enqueued_jobs without a block also. It will perform all the enqueued jobs.

TestJob.perform_later
MyJob.perform_later

perform_enqueued_jobs
assert_performed_jobs 2

Now the problem arises when we call perform_enqueued_jobs multiple times

TestJob.perform_later("John")
assert_enqueued_jobs 1
assert_performed_jobs 0

perform_enqueued_jobs # It runs the job with John
assert_performed_jobs 1

TestJob.perform_later("Michael")
assert_enqueued_jobs 2

perform_enqueued_jobs # It runs the job with both John and Michael
assert_performed_jobs 3

We can see a problem that after running the job with John, it doesn’t remove the job from the queue. That is why the second perform_enqueued_jobs call runs the job with both John and Michael.

Rails 6.1

Rails 6.1 has fixed this issue and made the behavior similar to using perform_enqueued_jobs with a block.

Let’s take the example mentioned above

TestJob.perform_later("John")
assert_enqueued_jobs 1
assert_performed_jobs 0

perform_enqueued_jobs # It runs the job with John
assert_performed_jobs 1
assert_enqueued_jobs 0

TestJob.perform_later("Michael")
assert_enqueued_jobs 1

perform_enqueued_jobs # It runs the job with Michael
assert_performed_jobs 2
assert_enqueued_jobs 0

We can see that the second perform_enqueued_jobs call runs the job with Michael only.