Running ActiveJob inline in feature specs in Rails 5.2
This is how you run Ruby on Rails ActiveJob jobs when testing. Works with DelayedJob, Sidekiq, and any other queue adapter.
I recently wanted to add some feature specs to an existing Rails 5.2 application and ran into a little snag when using Capybara to click around on the page.
My application uses ActiveJob with Sidekiq for background jobs. By default these use the test adapter in the test environment. This means that the jobs will not execute when running tests but rather be collected in a way that you can then run assertions on, much like how ActionMailer works in test mode.
This is great for test performance and whatnot but no so great when you run feature tests and you want the test to run the application “for real”.
Here is the scenario written using Capybara and RSpec:
require "spec_helper"
feature "Movie Search", :js, :feature do
scenario "User searches for a movie" do
visit movie_searches_path
within('.main') do
first("input").set('alien').native.send_keys(:return)
expect(page).to have_text('1979')
expect(page).to have_text('During')
first('button').click
expect(page).to have_current_path(movie_waitlists_path)
expect(page).to have_text('alien')
end
end
end
The scenario above will visit the movie search page, search for the movie alien, queue it for downloading and then assert that the user is redirected to the movie page that will display the details of the download.
The problem was the highlighted line. When the download is initiated the application enqueues a job for fetching the details of the movie in the background and then it will automatically update the page once the job is finished. Because the jobs were not executing in test mode this never happened and the scenario failed.
Turns out that there is a very simple solution to this issue using the ActiveJob Test Helper from Rails itself. Here is the working scenario with the changes highlighted:
require "spec_helper"
feature "Movie Search", :js, :feature do
include ActiveJob::TestHelper
scenario "User searches for a movie" do
visit movie_searches_path
within('.main') do
first("input").set('alien').native.send_keys(:return)
expect(page).to have_text('1979')
expect(page).to have_text('During')
perform_enqueued_jobs do
first('button').click
end
expect(page).to have_current_path(movie_waitlists_path)
expect(page).to have_text('alien')
end
end
end
Now it works properly. Neat!