rspec/rspec-rails

Request specs fail after upgrading to Rack 3

cjamison opened this issue · 6 comments

We have a number of request specs for our API and after upgrading Rack from 2.x to 3.x, they all started failing with:

     Failure/Error: get "/api/v1/products/1", headers: @headers
     
     NoMethodError:
       undefined method `read' for nil:NilClass

The way to resolve these errors is to convert the get request to

get "/api/v1/products/1", headers: @headers, env: { 'rack.input' => StringIO.new }

However, it seems very verbose to add this to each request. Am I missing an easier / better way to avoid this error?

This is on rspec-rails 7.1.0 and rspec-core 3.13.2.

👋 We don't include any behaviour for this ourselves and rely on the upstream Rails / rack-test helpers, is Rack 3 supported by Rails 8? I think 7 is still pinned to 2.x isn't it?

No, Rails 7 is not pinned to 2.x. At least 7.1 is not which is what we are using.

I see what happened on our end. We have another gem using/requiring Sinatra and at least Sinatra 4.1.1 is requiring rack >= 3.0.0. So, that is what caused our jump. I will see if we want to continue as things are or downgrade Sinatra to something not requiring rack 3.

My mistake 7.0 is, but not anything later, what version of Rack are you on? It seems like 3.1 made "rack.input" fully optional?

Bundle installed rack 3.1.8. In spite of "rack.input" being optional in this version, it still gave me the error message without me adding it into the test.

I'm running into similar issues; the request object isn't put into play.

terminalwire/server [main] → be rspec spec/requests/bash/installations_spec.rb
FF

Failures:

  1) Bash::Installations GET /index returns a successful response for terminalwire.sh root
     Failure/Error: request.format = :bash if request.user_agent.start_with? "curl" and not request.format.html?

     NoMethodError:
       undefined method `start_with?' for nil
     # ./app/controllers/application_controller.rb:13:in `assign_bash_format'
     # ./spec/requests/bash/installations_spec.rb:6:in `block (3 levels) in <top (required)>'

  2) Bash::Installations GET /index returns bash file contents
     Failure/Error: request.format = :bash if request.user_agent.start_with? "curl" and not request.format.html?

     NoMethodError:
       undefined method `start_with?' for nil
     # ./app/controllers/application_controller.rb:13:in `assign_bash_format'
     # ./spec/requests/bash/installations_spec.rb:6:in `block (3 levels) in <top (required)>'

Finished in 0.1009 seconds (files took 1.78 seconds to load)
2 examples, 2 failures

The specs:

require 'rails_helper'

RSpec.describe "Bash::Installations", type: :request do
  describe "GET /index" do
    before do
      get "/", headers: { "Host" => "terminalwire.sh" }
    end
    it "returns a successful response for terminalwire.sh root" do
      expect(response).to be_successful
      expect(response.body).to include("Detect operating system")
    end
    it "returns bash file contents" do
      expect(response.body).to include("Detect operating system")
    end
  end
end

Is it possible to get a minimal reproduction code ?