Description
What Ruby, Rails and RSpec versions are you using?
Ruby version: 2.6.7
Rails version: 6.0.3.7
RSpec version:
RSpec 3.10
- rspec-core 3.10.1
- rspec-expectations 3.10.1
- rspec-mocks 3.10.2
- rspec-rails 5.0.1 (and 4.0.2 before updating)
- rspec-support 3.10.2
Observed behaviour
Using redirect_to url_for(my_extra_param: 'a value')
in a Concern, and then testing that concern with a controller test using controller(ActionController::Base.include(MyConcern))
and requesting an action defined in the test controller and drawn with routes.draw
, always fails with ActionController::UrlGenerationError
as it cannot find the test routes.
Expected behaviour
Test routes added with routes.draw
are available and url_for
succeeds to build a url of the current route.
Can you provide an example app?
EDIT: here's a repo that reproduces this issue: https://github.com/henrahmagix/rails-bug-app/tree/c887222dc542572c4453a2c0f987afeefd730065
I will leave the example originally posted here intact below.
Unfortunately rubygems is down right now, so I can't bundle install
on a new app to double-check my setup shows the bug correctly. So here's the test file that I would add to rails new
that shows it:
Click to expand
require 'rspec/rails'
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec
config.mock_with :rspec
config.filter_rails_from_backtrace!
end
module MockConcern
extend ActiveSupport::Concern
included do
before_action :redirect_if_requested
end
private
def redirect_if_requested
redirect_to url_for(redirected_from_concern: true) if params[:redirect_me] == 'yes'
end
end
describe 'url_for bug in concern tests', type: :controller do
controller(ActionController::Base.include(MockConcern)) do
def test
render plain: 'testing'
end
end
before do
routes.draw do
get "test" => "anonymous#test"
end
end
it 'succeeds when url_for is not called in the concern' do
get :test, params: { redirect_me: 'no' }, session: nil
expect(response).not_to be_redirect
end
it 'fails when url_for is called in the concern' do
get :test, params: { redirect_me: 'yes' }, session: nil
expect(response).to be_redirect
end
end
class MockController < ActionController::Base
def in_real
redirect_to url_for(extra_param: 'in_real')
end
end
describe 'url_for bug in controller tests', type: :controller do
controller(MockController) do
def test
render plain: 'testing'
end
def in_mock
redirect_to url_for(extra_param: 'in_mock')
end
end
before do
routes.draw do
get "test" => "mock#test"
get "in_real" => "mock#in_real"
get "in_mock" => "mock#in_mock"
end
end
it 'succeeds when url_for is not called' do
get :test, params: nil, session: nil
expect(response).not_to be_redirect
expect(response.body).to eql('testing')
end
it 'fails when url_for is called in the real controller' do
get :in_real, params: nil, session: nil
expect(response).to be_redirect
end
it 'fails when url_for is called in the mock controller' do
get :in_mock, params: nil, session: nil
expect(response).to be_redirect
end
end
I will link to a rails new
app that I've confirmed shows the same results once rubygems is back up =)