I'm writing an integration test for Rails v5.1 using built-in Minitest.
Here's the integration test class:
require 'test_helper'
class PuppiesEndpointsTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
test "DELETE puppy" do
marty = people(:marty)
sign_in(marty)
# delete puppies_delete_path(marty.puppies.first.id)
# delete `/api/v1/puppies/destroy/${marty.puppies.first.id}.json`
# delete puppies_path(marty.puppies.first.id)
delete '/api/v1/puppies/destroy/6666.json'
assert_response :success
end
end
All of the routes above, including the ones that are commented out, result in the same cryptic error:
Error:
PuppiesEndpointsTest#test_DELETE_puppy:
NoMethodError: undefined method `[]=' for nil:NilClass
test/integration/puppies_endpoints_test.rb:17:in `block in <class:PuppiesEndpointsTest>'
bin/rails test test/integration/puppies_endpoints_test.rb:7
It doesn't give a stack trace or any other information to diagnose what the hell it's talking about. I used byebug to debug the marty
variable right before that delete
line that's throwing the error. It shows the expected puppies array of associated (fixture) records.
I've also placed a byebug at the very top of the controller action and this error fails the test before it reaches that byebug, so I think that pretty much rules out anything in the action code.
Here's the relevant chunk of what I see when I run rake routes
:
PATCH /api/v1/puppies/edit/:id(.:format) puppies#update
DELETE /api/v1/puppies/destroy/:id(.:format) puppies#destroy
puppies_create POST /api/v1/puppies/create(.:format) puppies#create
Here's what is actually in the my routes file:
scope '/api' do
scope '/v1' do
devise_for :people
patch 'puppies/edit/:id' => 'puppies#update'
delete 'puppies/destroy/:id' => 'puppies#destroy'#, as: 'puppies_delete'
post 'puppies/create' => 'puppies#create'
...
I'm completely stumped as to what/why I'm getting this error. The actual code is working completely as expected.
My hunch is that maybe there's a missing config variable that's not getting set for the test environment (I use dotenv gem), but I have no idea how to track that down if the error won't give me any context whatsoever.
UPDATE
I have isolated this problem to using the Devise helper sign_in
method. When I remove this method call, the problem goes away.
Here's the problematic test class:
require 'test_helper'
class PuppiesEndpointsTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
test "do stuff" do
...
app/controllers/api_controller.rb:
class ApiController < ActionController::API
end
Maybe sign_in
does not work for testing controllers that do not inherit from ActionController::Base
I changed the controller to inherit from ActionController::Base
and nothing changed. I still can't use sign_in
without getting that error, but it works find if I "manually" post
a request to the sign_in endpoint.
UPDATE 2 I found this Devise issue which sounds related to my problem: https://github.com/plataformatec/devise/issues/2065
Looks like I found the issue. Apparently, in rails-api mode, the ActionDispatch::Cookies and ActionDispatch::Session::CookieStore middlewares are inserted in the end of the middleware stack, which doesn't occur in normal Rails mode.
Due to this, those middlewares are included after Warden::Manager which messes up something in request specs.
Try to set in test.rb
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Cookies
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Session::CookieStore