-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UrlGenerationError when testing mocked controllers that use url_for
just to add params
#2506
Comments
What if you controller do
include MockConcern
def test
render plain: 'testing'
end
end |
@pirj unfortunately it still fails =) |
If it fails in the real controller as well as the mock controller then this is a Rails bug / a mistake in your configuration of the routes. Rails routing configuration is quite finicky. |
@JonRowe Sorry, I think I've caused confusion with my poor naming choices in the example code I pasted. I've now made a sample repo, please refer to that =) https://github.com/henrahmagix/rails-bug-app/tree/c887222dc542572c4453a2c0f987afeefd730065 The sample repo shows that
Hope that clears this up =) Test output:
|
I've just noticed something that might help pin-down the issue here: An empty I've pushed a commit that shows this to the sample repo: see henrahmagix/rails-bug-app@cbd5cf7 (All sample repo links before this are canonical btw, so they point to the code at the time of submission.) # bad
describe HomeController, type: :controller do
controller {}
before { get :show } # good
describe HomeController, type: :controller do
before { get :show }
controller {} |
Nice find. def controller(base_class = nil, &body)
before do
self.routes = ActionDispatch::Routing::RouteSet.new.tap do |r|
r.draw do Yet another interesing thing is how def draw(&block)
clear! unless @disable_clear_and_finalize
eval_block(block)
finalize! unless @disable_clear_and_finalize
nil
end You may see that it clears routes on each call. Unless There's also this
Where "described class" in the failing test is
if you don't change the test to use a quoted class name: RSpec.describe "RedirectIfRequestedConcern", type: :controller do or set |
The simplest workaround is to use the following instead of redirect_to '/test?redirected_from_concern=true' if params[:redirect_me] == 'yes' A trick with before do
routes.disable_clear_and_finalize = true
routes.draw { get 'test' => 'anonymous#test' }
routes.finalize! didn't work for me. After looking at r.draw do
resources resource_name,
as: resource_as,
module: resource_module,
path: resource_path where we draw a resourceful route, I was under the impression that switching to RSpec.describe RedirectIfRequestedConcern, type: :controller do
controller do
include RedirectIfRequestedConcern
def index
render plain: 'Test controller, test method'
end
end
it do
get :index, params: { redirect_me: 'yes' }, session: nil
expect(response).to redirect_to('http://test.host/test?redirected_from_concern=true')
end
end this test gets into
Do you have enough information to dig deeper why routes work fine in the spec, but not the controller itself? |
@pirj Thanks for your full response =)
So I've been trying to figure this out, but it doesn't seem possible to me. Maybe smarter minds than mine could confirm? All I know is that if I print the routes available, they never include the routes drawn up in the concern test: see henrahmagix/rails-bug-app@5154e64 This makes sense to me. Like, how would it be possible for the application to know what routes RSpec has drawn to itself? I can see how request methods in tests work with mocked controllers because RSpec calls the method directly on the controller, but once we're inside code that's not defined by the test (i.e. the concern being tested), then all we have is Does this mean, for RSpec to work for my needs, In the end, is this kind of unit testing of concerns just not possible with RSpec? That's ok if so, but I would greatly appreciate it if smarter minds than mine could see if this kind of route manipulation is possible for these tests =)
Unfortunately I can't use that: my real-life usage is in a concern that's shared amongst many controllers, so I need to be able to use Specifically, we're using RouteTranslator's In the very least, in our concern code I'm certain that we need to stick to using Rails url generation helpers, and not string manipulation, to ensure that we are generating correct urls for routes that exist. Apologies for not producing a sample repo more accurate to my real-life usage =) As a "silver lining", I'm very glad for my increased knowledge of how RSpec Controller tests work now, so I'm less likely in the future to get frustrated by "No route matches" errors because I understand how everything is constructed now =) |
Routing wise, your example app is the correct behaviour, anonymous controllers only have anonymous routes |
Wondering if stubbing allow(controller).to receive(:url_for).with(locale: 'fr').and_return('/test?locale=fr')
expect(controller).to receive(:url_for).with(locale: 'fr')
get :test, ...
expect(response).to redirect_to(...) Actually, when you describe the use case, it seems like such a natural thing to do to test controller concerns in such a way. And redirecting from controller concerns is not a rare thing either. Wondering how wasn't this reported earlier. Maybe there's some cool trick I lack knowledge of how to cover such concerns with tests. |
Does anyone know of a way to save existing Essentially, is it possible to insert already-compiled routes, or must every route be compiled from source? Because if it's the latter, then most uses of Like, to be able to do this would be great: # config/routes.rb
Rails.application.routes.draw do
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
get 'home' => 'home#show'
end
# spec/my_new_test_spec.rb
before do
@orig_routes = Rails.application.routes
Rails.application.routes.draw do
insert @orig_routes
get 'my_new_test' => 'my_new_test#show'
end
end
after do
Rails.application.routes.draw do
insert @orig_routes
end
end Perhaps there's a way to decompile a route back to its (It's not possible to do |
I've managed to get these example tests passing with changes to But I feel that the gist of it is what I would love this library to be able to do: add to existing routes before each test and revert the changes afterwards. That way, all routes drawn up in tests are then available in app code when it's being tested =) (or just specific routes if we want to make this an additional option instead of a fundamental change) EDIT: I just force-amended the commit with extra comment info, and have replaced the commit link here |
I haven't had any more luck with this :'< |
@henrahmagix I've tried to reproduce this with your bug repo and a linux vm and was able to run your test successfully. Here's a gist of the output: https://gist.github.com/genehsu/d484317924aa9358ab887f7967ea5505 |
I'm not using require 'rails_helper'
class MyConcernFakeController < ApplicationController
include MyAuthConcern
def show_status
render json: {status: 'ok'}
end
end
RSpec.describe MyConcernFakeController, type: :controller do
context 'without authentication header' do
before do
routes.disable_clear_and_finalize = true
routes.draw { get 'show_status' => 'my_concern_fake#show_status' }
routes.finalize!
end
it 'raises error' do
get :show_status
expect(response).to have_http_status(401)
end
end
end |
What Ruby, Rails and RSpec versions are you using?
Ruby version: 2.6.7
Rails version: 6.0.3.7
RSpec version:
Observed behaviour
Using
redirect_to url_for(my_extra_param: 'a value')
in a Concern, and then testing that concern with a controller test usingcontroller(ActionController::Base.include(MyConcern))
and requesting an action defined in the test controller and drawn withroutes.draw
, always fails withActionController::UrlGenerationError
as it cannot find the test routes.Expected behaviour
Test routes added with
routes.draw
are available andurl_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 torails new
that shows it:Click to expand
I will link to a
rails new
app that I've confirmed shows the same results once rubygems is back up =)The text was updated successfully, but these errors were encountered: