rspec / rspec-rails

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

Invoking `with_routing` does not work with the `get :index` style of invoking controller actions in controller specs #1652

Open fables-tales opened 8 years ago

fables-tales commented 8 years ago

Original context: https://github.com/rspec/rspec-rails/issues/817

App that demonstrates issue: https://github.com/samphippen/test_issue_817

In order for this issue to be fixed, all specs in the app linked above should pass.

ghost commented 8 years ago

I would like to tackle this issue for hacktoberfest.

fables-tales commented 8 years ago

@johndavidmartinez please do go ahead! Let me know if you need any help.

ghost commented 8 years ago

Sorry. I feel like I overcommitted in the moment. I haven’t had time to work on this issue. I wanted to let you all know. Thanks.

csexton commented 8 years ago

I spent some time looking into this. It is odd. I wanted to write up my findings in case someone had an ideas. Sorry if this is overly detailed, but I found it useful to type it up:

To recap the test app that @samphippen made. It has two test cases:

  1. Pass Calling with_routing directly from the spec
  2. Faill Defining a method that calls with_routing and then calling it from the spec

with_routing overrides the route map by making a new instance and temporarily setting it to @routes.

The fun fact:

The @routes ivar is just not getting set in case #2. Works just fine in case #1. I spent some time trying different things to set it.

The work around:

This can be worked around by setting @params in the spec file:

   def skip_routing
     with_routing do |map|
+      @routes = map
       map.draw do
         get 'subclass/index' => "subclass#index"
       end
     end
   end

Suggestions?

I tried setting @params harder in RoutingAssertions#with_routing :grin: Or moving it to right before the yield, but no luck.

Any ideas on why the ivar is not in scope when with_routing is called from within a method? Is there something special about how defining a method in a describe is scoped?

Maroo-b commented 7 years ago

I tried also to debug the issue and I wanted to share the results:

1- the passing test is using route_to matcher which delegates to assert_recognizes from Action Pack I noted that the temporary @routes is available which make test test pass 2- for the second test: the call to get invokes process method, in this context the temporary @routes isn't available

why not use @cupakromer suggestion to use routes.draw?

  specify do
    routes.draw { get ':controller/:action' }
    expect(get: '/subclass/test').to route_to("subclass#test")
  end

  specify do
    routes.draw { get ':controller/:action' }
    get :test
    expect(response.body).to eq 'ok'
  end
csexton commented 7 years ago

Spent more time on this with the help of @h-m-m, and found the same thing. Tried to dig into why @routes wasn't set to the temporary instance (because it looks like it should be), but never got to the bottom of it.

bquorning commented 7 years ago

Is this issue related to/fixed by rails/rails#27371 ?

GBH commented 6 years ago

Hi Rspec people.

This might be helpful: https://stackoverflow.com/questions/27068995/with-routing-test-helper-doesnt-work-for-integration-tests/27083128

I had to waste time googling this again recently. This: http://api.rubyonrails.org/v5.1/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-with_routing is only useful for checking route generation, not executing calls like it was in Rails4 controller tests.

So that little helper draws routes, allows to call new routes and then restored them to default state.