Skip to content
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

Add support for Rails engines routes in request specs #2368

Closed
drwl opened this issue Aug 2, 2020 · 15 comments · Fixed by #2372
Closed

Add support for Rails engines routes in request specs #2368

drwl opened this issue Aug 2, 2020 · 15 comments · Fixed by #2372

Comments

@drwl
Copy link
Contributor

drwl commented Aug 2, 2020

Is your feature request related to a problem? Please describe.
When using the scaffold generator in Rails 6, rspec-rails will generate a request spec that uses url helpers. These generated specs work in a regular Rails application, but don't automatically work in Rails engines.

Rails engines tend to have routes that don't live inside Rails.application.routes. Instead, they are usually namespaced:

# Taken from https://guides.rubyonrails.org/engines.html#routes
Blorgh::Engine.routes.draw do
  resources :articles
end

Request specs are being pushed for, in favor of Controller specs [1]. Controller specs allow for route sets to be set [2] in specs, while Requests specs do not. (To me, it also looks like one is unable to set the route set for Feature and System specs as well.)

One is able to do:

module AppComponent
  RSpec.describe TeamsController, type: :controller do
    routes { AppComponent::Engine.routes }
    ...
# This works

But not able to do:

module AppComponent
  RSpec.describe "/teams", type: :request do
    routes { AppComponent::Engine.routes }
    ....
# => NoMethodError:
# =>  undefined method `routes' for RSpec::ExampleGroups::Teams:Class

[1] http://rspec.info/blog/2016/07/rspec-3-5-has-been-released/
[2] https://github.com/rspec/rspec-rails/blob/main/lib/rspec/rails/example/controller_example_group.rb#L110

Describe the solution you'd like
Add the ability for the route set to be set in request specs, and possibly in feature and system specs as well.

Describe alternatives you've considered
One could not use url_helpers in request specs for Rails engines and instead hardcode the route urls (i.e. '/teams'), however, since url_helpers are used by the generators it seems like it would make sense to add support.

@drwl
Copy link
Contributor Author

drwl commented Aug 2, 2020

An alternative name to the issue could be Allow for route set to be set in request specs.

@pirj
Copy link
Member

pirj commented Aug 2, 2020

What happens if you

get "/teams"

in your request spec without specifying routes in the spec itself?

@drwl
Copy link
Contributor Author

drwl commented Aug 2, 2020

@pirj I get this:

Failures:

  1) /teams GET /index renders a successful response
     Failure/Error: get '/teams'

     ActionController::RoutingError:
       No route matches [GET] "/teams"
     # ./spec/requests/app_component/teams_spec.rb:34:in `block (3 levels) in <module:AppComponent>'
     # ./spec/rails_helper.rb:77:in `block (3 levels) in <top (required)>'
     # ./spec/rails_helper.rb:76:in `block (2 levels) in <top (required)>'

Finished in 1 minute 19.49 seconds (files took 2.2 seconds to load)

Which seems to make sense, if it's looking at Rails.application for routes. This is the output from within a Request spec inside an engine.

[27] pry(#<RSpec::ExampleGroups::Teams::GETIndex>)> @routes
=> #<ActionDispatch::Routing::RouteSet:0x00007fa0dad65830>
[28] pry(#<RSpec::ExampleGroups::Teams::GETIndex>)> @routes.url_helpers
=> #<Module:0x00007fa0da64ceb8>
[29] pry(#<RSpec::ExampleGroups::Teams::GETIndex>)> ls @routes.url_helpers
ActiveSupport::Concern#methods: append_features  class_methods  included
#<Module:0x00007fa0dad65678>#methods:
  app_component_url                       rails_conductor_inbound_email_reroute_url  rails_mailgun_inbound_emails_url         rails_representation_url
  edit_rails_conductor_inbound_email_url  rails_conductor_inbound_email_url          rails_mandrill_inbound_emails_url        rails_sendgrid_inbound_emails_url
  new_rails_conductor_inbound_email_url   rails_conductor_inbound_emails_url         rails_mandrill_inbound_health_check_url  rails_service_blob_url
  rails_blob_representation_url           rails_direct_uploads_url                   rails_postmark_inbound_emails_url        update_rails_disk_service_url
  rails_blob_url                          rails_disk_service_url                     rails_relay_inbound_emails_url
#<Module:0x00007fa0dad655b0>#methods:
  app_component_path                       rails_conductor_inbound_email_path          rails_mailgun_inbound_emails_path         rails_representation_path
  edit_rails_conductor_inbound_email_path  rails_conductor_inbound_email_reroute_path  rails_mandrill_inbound_emails_path        rails_sendgrid_inbound_emails_path
  new_rails_conductor_inbound_email_path   rails_conductor_inbound_emails_path         rails_mandrill_inbound_health_check_path  rails_service_blob_path
  rails_blob_path                          rails_direct_uploads_path                   rails_postmark_inbound_emails_path        update_rails_disk_service_path
  rails_blob_representation_path           rails_disk_service_path                     rails_relay_inbound_emails_path
#<Module:0x00007fa0da67c500>.methods: _routes  full_url_for  optimize_routes_generation?  polymorphic_path  polymorphic_url  route_for  url_for  url_options
#<Module:0x00007fa0da67c500>#methods: _routes
instance variables: @_dependencies  @_included_block  @_proxy
[30] pry(#<RSpec::ExampleGroups::Teams::GETIndex>)> ls AppComponent::Engine.routes.url_helpers
ActiveSupport::Concern#methods: append_features  class_methods  included
#<Module:0x00007fa0df8180f8>#methods:
  edit_game_url  edit_team_url  game_url  games_url  new_game_url  new_prediction_url  new_team_url  prediction_url  root_url  team_url  teams_url  welcome_url
#<Module:0x00007fa0df8180d0>#methods:
  edit_game_path  edit_team_path  game_path  games_path  new_game_path  new_prediction_path  new_team_path  prediction_path  root_path  team_path  teams_path  welcome_path
#<Module:0x00007fa0ddd375b8>.methods: _routes  full_url_for  optimize_routes_generation?  polymorphic_path  polymorphic_url  route_for  url_for  url_options
#<Module:0x00007fa0ddd375b8>#methods: _routes
instance variables: @_dependencies  @_included_block  @_proxy

This is the output from a controller spec inside the engine, with routes being set.

[6] pry(#<RSpec::ExampleGroups::AppComponentTeamsController::GETIndex>)> ls Rails.application.routes.url_helpers
ActiveSupport::Concern#methods: append_features  class_methods  included
#<Module:0x00007fdc2ac53d30>#methods:
  app_component_url                       rails_conductor_inbound_email_reroute_url  rails_mailgun_inbound_emails_url         rails_representation_url
  edit_rails_conductor_inbound_email_url  rails_conductor_inbound_email_url          rails_mandrill_inbound_emails_url        rails_sendgrid_inbound_emails_url
  new_rails_conductor_inbound_email_url   rails_conductor_inbound_emails_url         rails_mandrill_inbound_health_check_url  rails_service_blob_url
  rails_blob_representation_url           rails_direct_uploads_url                   rails_postmark_inbound_emails_url        update_rails_disk_service_url
  rails_blob_url                          rails_disk_service_url                     rails_relay_inbound_emails_url
#<Module:0x00007fdc2ac53d08>#methods:
  app_component_path                       rails_conductor_inbound_email_path          rails_mailgun_inbound_emails_path         rails_representation_path
  edit_rails_conductor_inbound_email_path  rails_conductor_inbound_email_reroute_path  rails_mandrill_inbound_emails_path        rails_sendgrid_inbound_emails_path
  new_rails_conductor_inbound_email_path   rails_conductor_inbound_emails_path         rails_mandrill_inbound_health_check_path  rails_service_blob_path
  rails_blob_path                          rails_direct_uploads_path                   rails_postmark_inbound_emails_path        update_rails_disk_service_path
  rails_blob_representation_path           rails_disk_service_path                     rails_relay_inbound_emails_path
#<Module:0x00007fdc2ec2e360>.methods: _routes  full_url_for  optimize_routes_generation?  polymorphic_path  polymorphic_url  route_for  url_for  url_options
#<Module:0x00007fdc2ec2e360>#methods: _routes
instance variables: @_dependencies  @_included_block  @_proxy
[7] pry(#<RSpec::ExampleGroups::AppComponentTeamsController::GETIndex>)> ls @routes.url_helpers
ActiveSupport::Concern#methods: append_features  class_methods  included
#<Module:0x00007fdc2f280ba0>#methods:
  edit_game_url  edit_team_url  game_url  games_url  new_game_url  new_prediction_url  new_team_url  prediction_url  root_url  team_url  teams_url  welcome_url
#<Module:0x00007fdc2f280b78>#methods:
  edit_game_path  edit_team_path  game_path  games_path  new_game_path  new_prediction_path  new_team_path  prediction_path  root_path  team_path  teams_path  welcome_path
#<Module:0x00007fdc35329448>.methods: _routes  full_url_for  optimize_routes_generation?  polymorphic_path  polymorphic_url  route_for  url_for  url_options
#<Module:0x00007fdc35329448>#methods: _routes
instance variables: @_dependencies  @_included_block  @_proxy

@drwl
Copy link
Contributor Author

drwl commented Aug 2, 2020

If you want to play around, I've setup a plain rails app with rspec rails - https://github.com/drwl/rspec-rails-issue-2368

You can get similar errors of url helpers not being found by running bundle exec rspec from within ./blorgh/.

@JonRowe
Copy link
Member

JonRowe commented Aug 3, 2020

What happens if you do: @routes = AppComponent::Engine.routes in a before block?

@drwl
Copy link
Contributor Author

drwl commented Aug 10, 2020

@JonRowe still leads to issues with url helpers not being found -- https://github.com/drwl/rspec-rails-issue-2368/commit/00a961bc57acd5b578ace6f718e3e61e10f941f0

@JonRowe
Copy link
Member

JonRowe commented Aug 11, 2020

@drwl but does the route resolve? e.g. if you do get "/teams"

@JonRowe
Copy link
Member

JonRowe commented Aug 11, 2020

To solve this we need to figure out how rails own testing does this now, engines are supposed to be isolated so they are not supposed to work from the outside, which makes it tricky. Normally I'd suggest mounting them in an app and testing it through the app.

In fact I'd expect you to have to mount the engine to make a request test / spec work, as they are full stack.

@drwl
Copy link
Contributor Author

drwl commented Aug 13, 2020

@JonRowe If I'm running the spec from within the engine, the route /teams does not resolve.

If there's a request spec that covers only things in the engine, I'd expect that it should work. Right now it's not. Is there any investigation I can help do to help with this?

@drwl
Copy link
Contributor Author

drwl commented Aug 13, 2020

I'm not sure why I didn't think about this before, but I tried generating a scaffold inside a rails engine in a rails app that uses minitest. The result had controller tests with this include statement:

include Engine.routes.url_helpers

And that seems to work. Perhaps this is something that could be included in the generator?

https://github.com/drwl/rspec-rails-issue-2368/commit/766bdbe1814002e4c1543d79c8c276277b3de488

@JonRowe
Copy link
Member

JonRowe commented Aug 13, 2020

If that works... would you consider a PR? I feel like a engine Engine that is:

def self.engine(module)
  include module.routes.url_helpers
end

Would be a useful addition

@drwl
Copy link
Contributor Author

drwl commented Aug 15, 2020

@JonRowe I'm confused about what you mean? Can you elaborate?

I found the corresponding line in the controller test generator for adding the line in Rails generator

@JonRowe
Copy link
Member

JonRowe commented Aug 17, 2020

I was suggesting creating a PR to support engines officially that did that include under the hood but if you don't have the time I can close this

@drwl
Copy link
Contributor Author

drwl commented Aug 18, 2020

@JonRowe I understood that part, I'd be happy to submit a PR. I was confused about:

If that works... would you consider a PR? I feel like a engine Engine that is:

@drwl
Copy link
Contributor Author

drwl commented Aug 20, 2020

I'm working on a PR #2372

I'm using Travis to run tests since it's taking a while for me to run the test suite locally.

@JonRowe JonRowe linked a pull request Aug 24, 2020 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants