rspec / rspec-rails

RSpec for Rails 6+
https://rspec.info
MIT License
5.14k stars 1.03k forks source link

Controllers specs don't currently work on the Rails main branch (8.0.0.alpha) #2761

Closed jeromedalbert closed 1 month ago

jeromedalbert commented 1 month ago

What Ruby, Rails and RSpec versions are you using?

Ruby version: 3.3.1 Rails version: main branch (8.0.0.alpha) RSpec version: 6.1.2

Observed behaviour

When running a controller spec, I get the following error (see reproduction steps in the reproduction section of this issue):

Failures:

  1) HelloController#index
     Failure/Error: before { get :index }

     ActionController::UrlGenerationError:
       No route matches {:action=>"index", :controller=>"hello"}

Expected behaviour

Spec should pass:

.

Finished in 0.0127 seconds (files took 0.39717 seconds to load)
1 example, 0 failures

Can you provide an example reproduction?

Here is a minimal reproduction of the issue:

# my_app.rb
require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'rails', github: 'rails/rails', branch: 'main'
  gem 'rspec-rails', '6.1.2'
end

require 'rails'
require 'action_controller/railtie'
require 'rspec/rails'

class MyApp < Rails::Application
  config.eager_load = false

  routes.append { root to: 'hello#index' }
end

MyApp.initialize!

class HelloController < ActionController::Base
  def index
    render plain: 'Hello'
  end
end

describe HelloController, type: :controller do
  describe '#index' do
    before { get :index }

    it { expect(response).to be_successful }
  end
end

RSpec::Core::Runner.run([$__FILE__])

Run this file with ruby my_app.rb, and the spec should fail. It passes if you change to gem 'rails', github: 'rails/rails', ref: 'a27a1751cfd499f69499e943f12e3400b55a323e', and fails for the commit with gem 'rails', github: 'rails/rails', ref: 'e97db3b3957781c781a61fb01265feb2b57688bb'. Here is a link to the commit: https://github.com/rails/rails/commit/e97db3b3957781c781a61fb01265feb2b57688bb.

Additional information

jrafanie commented 1 month ago

@jeromedalbert I see your example failing. I'm not sure if you noticed but changing to eager_load makes your example pass:

class MyApp < Rails::Application
  config.eager_load = true

  routes.append { root to: 'hello#index' }
end

Note, rails defaults to eager load in test for CI in new apps.

jeromedalbert commented 1 month ago

Yeah, the main issue is when running tests on one's local, since it's not a CI environment and eager load is disabled by default.

jrafanie commented 1 month ago

A current workaround to make the spec pass is to add before { Rails.application.reload_routes! } in the spec, or config.before(:suite) { Rails.application.reload_routes! } in your rails helper.

I wonder if makes sense to eager load routes before it tries to fetch the routes in the specific types of example groups: controller, request, routing, system by adding something like:

        routes_reloader = ::Rails.application.routes_reloader
        routes_reloader.execute_unless_loaded if routes_reloader&.respond_to?(:execute_unless_loaded)
jeromedalbert commented 1 month ago

Looks like the commit that introduced deferred routes was reverted, and Rails main is working at the moment.

pirj commented 1 month ago

Thanks for the heads-up. Can this be closed, or is there anythibg actionable left?