ActionController::UrlGenerationError when trying to test namespaced controllers - ruby-on-rails

I'm trying to write a controller specs for one of my controller action defined under Front namespace (and living in Front engine mounted in root rails app). I've been following this thing to acheive that: https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs/engine-routes-for-controllers
Here is my code:
# config/routes/rb
Rails.application.routes.draw do
mount Front::Engine => '/', as: 'front'
end
# modules/front/config/routes.rb
Front::Engine.routes.draw do
resources :items
end
# modules/front/app/controllers/front/items_controller.rb
class Front::ItemsController < Front::ApplicationController
def index
# ...
end
end
# spec/controllers/front/items_controller_spec.rb
require 'rails_helper'
RSpec.describe Front::ItemsController, type: :controller do
routes { Front::Engine.routes }
describe "GET index" do
it "assings #items" do
item = FactoryGirl.create(:item)
get :index
expect(assigns(:items)).to eq([item])
end
end
end
Running above spec gives me:
Front::ItemsController
GET index
assings #items (FAILED - 1)
Failures:
1) Front::ItemsController GET index assings #items
Failure/Error: get :index
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"front/items"}
It all works fine outside of specs, i can totally access that endpoint. Any ideas what's wrong in here? Thanks in advance.
ruby 2.3.1
rspec 3.4.4
rails 4.2.1

Related

No route matches using rspec controller test

I have the following routes:
config/routes.rb:
Rails.application.routes.draw do
scope module: :api do
namespace :v1 do
resources :users
end
end
end
controllers/api/v1/users_controller.rb:
module Api
module V1
class UsersController < ApplicationController
def index
...
end
end
end
end
The controller specs are under the folder spec/controllers/api/v1/.
spec/controllers/api/v1/users_controller_spec.rb:
module Api
module V1
RSpec.describe UsersController, type: :controller do
let!(:users) { create_list(:user, 10) }
describe 'GET /v1/users' do
before { get :index }
# Already tried `get '/v1/users'`, got the same error
it 'should return 10 users' do
expect(JSON.parse(response).size).to eq(10)
end
end
end
end
end
Once I run the tests I receive the following error:
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"api/v1/users"}
Note that it "infers" the api part from somewhere, but my routes are like these:
v1/users
v1/users/:id
...
How can I make it work?
I believe this is because you are namespacing your test with Api::V1::UsersController, but your route is defined within the scope of Api. That's why your routes are not under /api
Try removing the Api module from the controller and test or changing scope module: :api to namespace :api
Alternatively, you could keep it all as-is and make the get request to your v1_users_path or whatever the corresponding path is when you run rails routes (instead of :index).

Rspec tests not finding matching routes

I'm getting unexpected errors when running some Rspec tests. They are
1) PeopleController redirects when loading root should redirect to the splash page
Failure/Error: get '/'
ActionController::UrlGenerationError:
No route matches {:action=>"/", :controller=>"people"}
...
2) PeopleController redirects when loading /people/show should redirect to the base person path
Failure/Error: get '/show' #/show
ActionController::UrlGenerationError:
No route matches {:action=>"/show", :controller=>"people"}
I don't understand why Rspec can't find the routes.
From the controller, people_controller.rb:
class PeopleController < ApplicationController
...
def show
redirect_to people_path
end
def index
#people = Person.all
end
...
From the Rspec file people_controller_spec.rb:
describe PeopleController do
describe "redirects" do
context "when loading root" do
it "should redirect to the temp page" do
get '/'
last_response.should be_redirect
follow_redirect!
last_request.url.should include('/temp')
end
end
context "when loading /people/show" do
it "should redirect to the base people path" do
get '/people/show'
last_response.should be_redirect
follow_redirect!
last_request.url.should include('/people')
end
end
end
end
And my routes:
$ rake routes
Prefix Verb URI Pattern Controller#Action
...
person GET /people/:id(.:format) people#show
...
root GET / redirect(301, /temp)
routes.rb:
Rails.application.routes.draw do
resources :temp
resources :people
# map '/' to be a redirect to '/temp'
root :to => redirect('/temp')
end
What am I missing to get the routes from test to match up? I could see the root test not working because it's not technically handled by the People controller (I tried putting it in as a sanity test and only made myself more confused) but the /show failure really makes no sense to me.
Inside a controller test the method get takes an action argument, not a path. If the resource is a member (as opposed to a collection), you must also specify the id parameter, so:
get :show, id: 1
will call the #show action on an instance of PeopleController, with a params hash including {id: '1'}.
This is described in more detail in the Guide to Testing Rails Applications.

Rspec not finding routes that exists

I'm trying to write a controller test and Rspec isn't finding routes that I know exist and work fine on a development server.
In my routes I have a catch-all route that should redeirect to a generic controller if someone goes to a route that isn't predefined.
routes.rb
namespace :tools do
match '*unmatchedpath' => "generic#show", :via => :get
end
generic_controller.rb
def show
# do stuff
end
generic_controller_spec.rb
require 'spec_helper'
describe Tools::GenericController do
describe 'GET show' do
it 'does stuff' do
get :show
end
end
Here is the error I get from rspec when I run the test above
1) Tools::GenericController GET show does stuff
Failure/Error: get :show
ActionController::RoutingError:
No route matches {:controller=>"tools/generic", :action=>"show"}
All routes work as expected on my development server so I'm not sure why Rspec isn't finding the route.
Try:
get '*unmatchedpath' => 'tools/generic#show'

Rails engine: rake routes show its routes but on rspec execution "No route matches" is thrown

I'm trying to test a controller that is inside an engine my application is using. The spec is not within the engine, but in the application itself (I tried to test within the engine but also had problems).
My engine has the following routes.rb:
Revision::Engine.routes.draw do
resources :steps, only: [] do
collection { get :first }
end
end
The engine is mounted on the application routes.rb normally:
mount Revision::Engine => "revision"
When I run rake routes, at the last lines I get:
Routes for Revision::Engine:
first_steps GET /steps/first(.:format) revision/steps#first
root / revision/steps#first
On my engine's controller (lib/revision/app/controllers/revision/steps_controller.rb), I have:
module Revision
class StepsController < ApplicationController
def first
end
end
end
On Rspec, I test this controller with:
require 'spec_helper'
describe Revision::StepsController do
it "should work" do
get :first
response.should be_success
end
end
Then when I run this spec, I get:
ActionController::RoutingError:
No route matches {:controller=>"revision/steps", :action=>"first"}
To be sure that the route doesn't really exist, I added this to the spec:
before do
puts #routes.set.to_a.map(&:defaults)
end
And the result is this:
[...]
{:action=>"show", :controller=>"devise/unlocks"}
{:action=>"revision"}
It has only the :action parameter.
What may be wrong?
When you're trying to test an engine's controllers, you need to specify what route set you want the controller test to use, otherwise it will run it against the main app's. To do that, pass use_route: :engine_name to the get method.
require 'spec_helper'
describe Revision::StepsController do
it "should work" do
get :first, use_route: :revision # <- this is how you do it
response.should be_success
end
end

Controller spec failing to find routes defined by my Rails engine

I'm building a Rails engine under Rails 3.0.12, but I'm having issues with routes when trying to write specs for my engine's controller.
The context
I've been following an Enginex layout. The engine is named Featuring and is not isolated. It does not declare routes by itself: there is no featuring/config/routes.rb file. Instead, a routes_for_feature method is provided for the main application to define engine-specific routes.
##
# featuring/lib/featuring/rails.rb
#
require 'featuring/rails/routing'
module Featuring
class Engine < ::Rails::Engine
end
end
##
# featuring/lib/featuring/rails/routing.rb
#
module ActionDispatch::Routing
class Mapper
def routes_for_feature(feature_name)
resource_name = feature_name.to_s.pluralize.to_sym
resources resource_name, :controller => "featuring/features", :only => [:index, :show], :feature => feature_name.to_s
end
end
end
Following the Enginex template, I have a Dummy app which define the routes as so:
# featuring/spec/dummy/config/routes.rb
Dummy::Application.routes.draw do
routes_for_feature :feature_model
end
The issue
Everything is working fine when I run the rails server for the Dummy app. I can browse to http://localhost:3000/feature_models and the request is successful.
I would like to spec my Featuring::FeaturesController, but I can't get it to find the routes.
Here is the spec:
# featuring/spec/controllers/features_controller_spec.rb
require 'spec_helper'
describe Featuring::FeaturesController do
context "feature_models" do
it "GET index should be successful" do
puts Rails.application.routes.routes
get :index, { :use_route => "featuring", :feature => "feature_models" }
response.should be_success
end
end
end
And here is the result of running this spec:
rspec spec/controllers/features_controller_spec.rb:7
Featuring::FeaturesController
feature_models
GET /feature_models(.:format) {:action=>"index", :controller=>"featuring/features"}
GET /feature_models/:id(.:format) {:action=>"show", :controller=>"featuring/features"}
GET index should be successful (FAILED - 1)
Failures:
1) Featuring::FeaturesController feature_models GET index should be successful
Failure/Error: get :index, { :use_route => "featuring", :feature => "feature_models" }
ActionController::RoutingError:
No route matches {:feature=>"feature_models", :controller=>"featuring/features"}
# ./spec/controllers/features_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
As you can see, even if the routes are correctly defined, the spec'ed controller seems not to find them.
Something surprises me in the RoutingError: No route matches {:feature=>"feature_models", :controller=>"featuring/features"}. The action => "index" is not displayed.
I had a similar error, and I was also confused by the lack of {:action => "index"} in the route options. However, this turned out not to be the problem. ActionDispatch treats the lack of an :action as equivalent to {:action => "index"}. See:
https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing/route_set.rb#L545
You may be missing a request parameter in your spec, as was the case with me. Check the Parameters line in your server log when you load the page in the browser.
The trick is to add routes { } to your spec, like so:
describe Featuring::FeaturesController do
routes { Featuring::Engine.routes }
# ...
end
See also No Route Matches ... Rails Engine

Resources