7

I've been heads down in this and feel like I'm probably making a simple mistake, but I haven't been able to find any information on this problem.

I have some request specs for Rails 5 and, when I test for a redirect--but not for a rendered template--I get an error, undefined method 'response_code' for nil:NilClass. The reason for this seems to be that @response is nil when the matcher is called (inside ActionDispatch::Assertions::ResponseAssertions code, not in my code). I am able to use cURL to make a request to the API and it returns a response as expected. The point where the error is returned is here (this is the ActionDispatch code):

def generate_response_message(expected, actual = @response.response_code)
  "Expected response to be a <#{code_with_name(expected)}>,"\
  " but was a <#{code_with_name(actual)}>"
  .dup.concat(location_if_redirected).concat(response_body_if_short)
end

Notice the first line, where the default value of the actual param is set to @response.response_code.

Here's my test code:

RSpec.describe "Admin registrations", type: :request do
  describe "new sign-up" do
    subject { get new_admin_registration_path }

    it "redirects to home" do
       expect(subject).to redirect_to(new_admin_session_path)
    end
  end
end

The relevant lines in the test log are:

Started GET "/admins/sign_up" for 127.0.0.1 at 2018-07-05 10:44:05 -0700
Processing by Admins::RegistrationsController#new as HTML
Redirected to http://example.org/admins/sign_in
Completed 301 Moved Permanently in 18ms (ActiveRecord: 0.0ms)

Interestingly, when I use byebug to check the value of subject, it does return a Rack::MockResponse object, so this is somehow not getting passed through.

halfer
  • 19,824
  • 17
  • 99
  • 186
Dana Scheider
  • 389
  • 3
  • 15

2 Answers2

4

I'm sure you've probably already solved this, but for anyone else who might stumble upon this, we ran into the same thing (response not being assigned after a request way made - either get or post, didn't try other methods, but assume they would all be the same). Existing request specs that had been working all started failing.

The culprit in our case was tracked down to a module that was required in rails_helper.rb, and added to rspec's config.include list:

config.include ApiHelper, type: request

Inside AppHelper was the root cause:

include Rack::Test::Methods

Commenting that line out (and ultimately for us, removing the entire helper as it wasn't really needed) restored the request specs to their previous, and working, state.

tl;dr:

Make sure you're not including Rack::Test::Methods in config.include for your rspec config inadvertently.

Michael Shimmins
  • 19,961
  • 7
  • 57
  • 90
  • Thank you for sharing this! I did solve this, in a manner of speaking, but it was by monkey patching something, so this is a much more satisfactory solution. – Dana Scheider Dec 07 '18 at 04:12
  • This was exactly my problem too. I added `Rack::Test::Methods` to a spec in order to test uploading a CSV, but then I spent the next half hour scratching my head as to way everything worked, but the `response` object was nil. – clockworkpc Aug 18 '20 at 22:03
2

This is pretty dumb on my part but I bet someone else or myself is going to do this by accident.

If type: :request is already set in your top block, also make sure you're not accidentally overriding the response variable in your block.

Take my dumb self's example as a warning:

let(:response) { }

it 'overrides rspec\'s own dediciated response variable' do
   get your_route_here_path
   expect(response).to have_http_status(:ok)
end

results in something like:

Error: nil doesn't have property 'status'

That's because the let(:response) is actually overriding rspec's own internal response.

Just something to keep in mind, you'll probably never screw up like this but just in case.

Dylan Pierce
  • 4,313
  • 3
  • 35
  • 45