2

I've got a integration test that is run through capybara. It visits a webpage, creates an object, and renders the results. When the object is created, the controller enqueues several jobs that create some related objects.

When I run my integration test, I want to be able to examine the rendered page as if those jobs had finished. The 2 obvious solutions are:

  1. Set the queue adapter as :inline
  2. Manually execute/clear the enqueued jobs after creating the object.

For 1), I've attempted to set the queue adapter in a before(:each) to :inline, but this does not change the adapter, it continues to use the test adapter (which is set in my test.rb config file):

before(:each) { ActiveJob::Base.queue_adapter = :inline }
after(:each) { ActiveJob::Base.queue_adapter = :test }
it "should work" do
  puts ActiveJob::Base.queue_adapter
end

which outputs: #<ActiveJob::QueueAdapters::TestAdapter:0x007f93a1061ee0 @enqueued_jobs=[], @performed_jobs=[]>

For 2), I'm not sure if this is actually possible. ActiveJob::TestHelpers provides perform_enqueued_jobs, but this methods isn't helpful, as it seems to work only for jobs explicitly referenced in the passed in block.

cgat
  • 3,689
  • 4
  • 24
  • 38

1 Answers1

3

Assuming you're using RSpec the easiest way to use perform_enqueued_jobs is with an around block. Combining that with metatdata tags you can do something like

RSpec.configure do |config|
  config.include(RSpec::ActiveJob)

  # clean out the queue after each spec
  config.after(:each) do
    ActiveJob::Base.queue_adapter.enqueued_jobs = []
    ActiveJob::Base.queue_adapter.performed_jobs = []
  end

  config.around :each, perform_enqueued: true do |example|
    @old_perform_enqueued_jobs = ActiveJob::Base.queue_adapter.perform_enqueued_jobs
    ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
    example.run
    ActiveJob::Base.queue_adapter.perform_enqueued_jobs = @old_perform_enqueued_jobs
  end

  config.around :each, peform_enququed_at: true do |example|
    @old_perform_enqueued_at_jobs = ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs
    ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true
    example.run
    ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = @old_perform_enqueued_at_jobs
  end
end

Note: you need to specify the queue_adapter as :test in your config/environments/test.rb if it's not already set

You can then specify :perform_enqueued metadata on a test and any jobs specified will be run

it "should work", :perform_enqueued do
  # Jobs triggered in this test will be run
end
Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
  • I found this one later, https://stackoverflow.com/questions/27859731/execute-pending-job-with-activejob-in-rspec/29967430. Which is very similar. – cgat Jul 26 '18 at 16:13
  • You know, this actually didn't work in my feature test (capybara). I've confirmed that the around block is being executed. Any ideas? Also, 'rspec/active_job' is not required in the above code – cgat Jul 26 '18 at 16:27
  • @cgat You have left the queue_adapter as :test correct? Since the block is being run - check the contents of ActiveJob::Base.queue_adapter.enqueued_jobs, and ActiveJob::Base.queue_adapter.performed_jobs after the `example.run` and see if the jobs you think are being queued actually are – Thomas Walpole Jul 26 '18 at 16:57
  • @cgat Actually you might need to check them at the beginning of the `after` block since IIRC correctly it will get run before `example.run` returns. – Thomas Walpole Jul 26 '18 at 17:01
  • 1
    So I think I've zero'd in on the problem. It seems my test has a different instance of the test adapter than the one that is referenced within the around callback. So, even though I'm setting `perform_enqueued_jobs` to true in the test adapter of the around callback, I'm not seeing that within my test. If I inline behaviour in the spec example, it works. I have no idea where the other test adapter instance is coming from though. – cgat Jul 27 '18 at 16:11
  • @cgat Every time `...queue_adapter = :test` is called a new instance of the test adapter is created, so if you're calling that anywhere in a before/after block or in your test the instances could/would be different – Thomas Walpole Jul 27 '18 at 16:23
  • Exactly, which is why I'm a bit baffled. I'm only setting it in the test.rb config file. It seems presence of `config.include ActiveJob::TestHelper` in my rspec config is causing the adapter to be reset at some point. Removing that line, I get the same instance of the adapter in the rspec config as in the actual test. – cgat Jul 27 '18 at 17:12
  • @cgat If you're not using minitest you shouldn't be including ActiveJob::TestHelper – Thomas Walpole Jul 27 '18 at 17:16
  • Oh wow, thanks. We just upgraded from Rails 4.2 and I was using the TestHelper methods `clear_enqueued_jobs` to clear my queue in an after block. It's working now. Thanks for your help. – cgat Jul 27 '18 at 17:27