Rspec controller action not found - ruby-on-rails

test is failing becasue it says the action does not exist, when it clearly does. Is it becasue it is a nested route? Any thoughts?
Update:
I moved resources :orders outside of the nested route and tests passed. So it has something to do with it being nested.
OrderController
def index
if current_printer
#orders = Order.all
#printer = Printer.find(params[:printer_id])
end
if current_user
#orders = Order.where(user_id: params[:user_id])
end
end
OrdersController Spec
require 'rails_helper'
RSpec.describe OrdersController, :type => :controller do
describe "unauthorized user" do
before :each do
# This simulates an anonymous user
login_with_user nil
binding.pry
end
it "should be redirected back to new user session" do
get :index
expect( response ).to redirect_to( new_user_session_path )
end
end
end
Routes
resources :users, only: [:index, :show] do
resources :orders
end
Error
Failures:
1) OrdersController unauthorized user should be redirected back to new user session
Failure/Error: get :index
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"orders"}

When testing controllers that have nested routes you must pass in a hash of the url params.
for example my routes looked like this
user_orders GET /users/:user_id/orders(.:format) orders#index
so in my test I passed in a hash with user_id
get :index, { user_id: 1 }
Tests passing :)

Related

Testing singular resource controller with RSpec

I have defined a singular resource in my routes.rb which looks like this
Rails.application.routes.draw do
resource :dog, only: [:create], to: "dog#create", controller: "dog"
end
After that I've defined a controller with a create action like this
class DogController < ApplicationController
def create
render json: {}, status: :ok
end
end
And now I'm trying to test it out with RSpec like this
require "rails_helper"
describe DogController do
it "works" do
post :create, params: { foo: :bar }
end
end
This is throwing this error instead of passing:
ActionController::UrlGenerationError:
No route matches {:action=>"create", :controller=>"dog", :foo=>:bar}
What am I doing wrong?
Change your route to
resource :dog, only: [:create], :controller => "dog"
It is better to use plural controllers even if its a singular resource
http://edgeguides.rubyonrails.org/routing.html#singular-resources
Your create action is not taking in any parameter. It's just rendering json and returning a status code

ActionController::UrlGenerationError: No route matches when trying to test the controller

I'm getting an ActionController::UrlGenerationError: No route matches (:action => "edit", :controller => "goals") error, when I'm trying to test the goals controller
Here is my goals_controller_test.rb
require 'test_helper'
class GoalsControllerTest < ActionController::TestCase
test "should be redirected when not logged in" do
get :new
assert_response :redirect
assert_redirected_to new_user_session_path
end
test "should render the new page when logged in" do
sign_in users(:guillermo)
get :new
assert_response :success
end
test "should get edit" do
get :edit
assert_response :success
end
test "should get show" do
get :show
assert_response :success
end
end
This is my routes.rb
Rails.application.routes.draw do
devise_for :users
authenticated :user do
root 'du#dashboard', as: "authenticated_root"
end
resources :goals
root 'du#Home'
end
My goals_controller.rb
class GoalsController < ApplicationController
before_filter :authenticate_user!, only: [:new]
def new
end
def edit
end
def show
end
private
def find_user
#user = User.find(params[:user_id])
end
def find_goal
#goal = Goal.find(params[:id])
end
end
I find it weird that if I use get 'goals/edit' instead of resources :goals the test passes.
Thank you very much for any guideline.
When you use resources :goals Rails generates for you the following routes (RESTful):
goals GET /goals(.:format) goals#index
POST /goals(.:format) goals#create
new_goal GET /goals/new(.:format) goals#new
edit_goal GET /goals/:id/edit(.:format) goals#edit
goal GET /goals/:id(.:format) goals#show
PATCH /goals/:id(.:format) goals#update
PUT /goals/:id(.:format) goals#update
DELETE /goals/:id(.:format) goals#destroy
As you can see, to hit the edit action /goals/:id/edit you need to pass an :id. That way, in your controller you'll be able to find the record by the given :id => Goal.find(params[:id]). So, in your tests you need to pass this :id, something like:
get :edit, id: 1 # mapping to /goals/1/edit
If you manually add this route get 'goals/edit', it works because it maps directly to /goals/edit (NOTE there is no :id).
Btw, I recommend you to review the official Routing guides: http://guides.rubyonrails.org/routing.html
#goal = Goal.create(your params here) or use factory girl gem or fixtures
you should pass id get :edit ,id: #goal
useful article

Rspec fails with ActionController::UrlGenerationError

Rspec fails with ActionController::UrlGenerationError with a URL I would think is valid. I've tried messing with the params of Rspec request, as well as fiddled with the routes.rb, but I'm still missing something.
The weird thing is, it works 100% as expected when testing locally with curl.
Error:
Failure/Error: get :index, {username: #user.username}
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"api/v1/users/devices", :username=>"isac_mayer"}
Relevant code:
spec/api/v1/users/devices_controller_spec.rb
require 'rails_helper'
RSpec.describe Api::V1::Users::DevicesController, type: :controller do
before do
#user = FactoryGirl::create :user
#device = FactoryGirl::create :device
#user.devices << #device
#user.save!
end
describe "GET" do
it "should GET a list of devices of a specific user" do
get :index, {username: #user.username} # <= Fails here, regardless of params. (Using FriendlyId by the way)
# expect..
end
end
end
app/controllers/api/v1/users/devices_controller.rb
class Api::V1::Users::DevicesController < Api::ApiController
respond_to :json
before_action :authenticate, :check_user_approved_developer
def index
respond_with #user.devices.select(:id, :name)
end
end
config/routes.rb
namespace :api, path: '', constraints: {subdomain: 'api'}, defaults: {format: 'json'} do
namespace :v1 do
resources :checkins, only: [:create]
resources :users do
resources :approvals, only: [:create], module: :users
resources :devices, only: [:index, :show], module: :users
end
end
end
Relevant line from rake routes
api_v1_user_devices GET /v1/users/:user_id/devices(.:format) api/v1/users/devices#index {:format=>"json", :subdomain=>"api"}
The index action requires a :user_id parameter, but you haven't supplied one in the params hash. Try:
get :index, user_id: #user.id
The error message is a bit confusing, because you aren't actually supplying a URL; instead you are calling the #get method on the test controller, and passing it a list of arguments, the first one is the action (:index), and the second is the params hash.
Controller specs are unit tests for controller actions, and they expect that the request parameters are correctly specified. Routing is not the responsibility of the controller; if you want to verify that a particular URL is routed to the right controller action (since as you mention, you are using friendly-id), you may want to consider a routing spec.

ActionController::UrlGenerationError - with route defined and action in controller, still getting error for no route

I'm getting the following error in RSpec when running my schools_controller_spec.rb test:
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"schools"}
What's puzzling me is that I have the routes configured, and the action defined in the appropriate controller. I'm not getting this error for other tests in the spec, such as 'GET #index', etc. Running Rails 4.2 with RSpec/Capybara.
Here's the routes.rb:
Rails.application.routes.draw do
root to: 'pages#home', id: 'home'
resources :users
resources :schools
resource :session, only: [:new, :create, :destroy]
match '/home', to: 'pages#home', via: 'get', as: 'home_page'
end
rake routes returns:
schools GET /schools(.:format) schools#index
POST /schools(.:format) schools#create
new_school GET /schools/new(.:format) schools#new
edit_school GET /schools/:id/edit(.:format) schools#edit
school GET /schools/:id(.:format) schools#show
PATCH /schools/:id(.:format) schools#update
PUT /schools/:id(.:format) schools#update
DELETE /schools/:id(.:format) schools#destroy
There's the route defined on the fifth line, as schools#show.
The schools_controller.rb:
class SchoolsController < ApplicationController
before_action :require_signin
before_filter :admin_only, except: :index, :show
def index
#schools = School.all
end
def show
# code pending
end
private
def admin_only
unless current_user.admin?
redirect_to :back, alert: "Access denied."
end
end
end
The link to the individual school seems to be properly defined in the view helper (_school.html.haml):
%li#schools
= link_to school.name, school
= school.short_name
= school.city
= school.state
and looking at the front-end HTML confirms it's working correctly. I can see, for example: Community College of the Air Force. When I click that link the page shows the following in the debug dump:
--- !ruby/hash:ActionController::Parameters
controller: schools
action: show
id: '1'
Finally, for good measure, here's the spec file (schools_controller_spec.rb):
require 'rails_helper'
describe SchoolsController, type: :controller do
# specs omitted for other actions
describe 'GET #show' do
context "when not signed in" do
it "returns a 302 redirect code" do
get :show
expect(response.status).to eq 302
end
it "redirects to the signin page" do
get :show
expect(response).to redirect_to new_session_path
end
end
context "when signed in as user" do
before :each do
#user = double(:user)
allow(controller).to receive(:current_user).and_return #user
#school = create(:school)
end
it "assigns the school to the #school variable" do
get :show
expect(assigns(:school)).to eq #school
end
end
end
end
The route appears in rake routes. The method is defined in the appropriate controller. There don't appear to be any silly naming errors (e.g. plural/singular). The spec doesn't appear to have any issues routing GET #index or other routes for example. Everything works exactly as expected in the browser.
So why do I keep getting the "no route matches" error when I run my controller spec?
This is because the show action is expecting an id which you currently aren't passing. Replace:
get :show
With this:
get :show, id: school.id
The above assumes you have a school variable, perhaps a let in a before block?
let(:school) { create(:school) }

Rspec testing devise failing because assigns always nil

I'm having controller test with devise, but it always fail because assigns always return nil, please help to find where the problem is, thanks a million!
posts_controller_spec.rb:
RSpec.describe PostsController, :type => :controller do
describe "with valid session" do
describe "GET index" do
it "assigns all posts as #posts" do
sign_in :admin, #user
post = create(:post)
get :index, {}
expect(assigns(:posts)).to eq([post])
end
end
end
...
end
posts_controller.rb
class PostsController < ApplicationController
before_action :authenticate_user!
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
...
end
I've included devise test helpers in spec/rails_helper.rb
config.include Devise::TestHelpers, type: :controller
In my case, post is scoped under admin, not sure if that makes difference (functional test doesn't get through routes?), so I just include my routes.rb here
routes.rb:
Rails.application.routes.draw do
root to: 'home#index'
get 'admin', to: 'admin#index'
devise_for :users
scope '/admin' do
resources :posts
end
end
And finally, the output from rspec:
1) PostsController with valid session GET index assigns all posts as #posts
Failure/Error: expect(assigns(:posts)).to eq([post])
expected: [#<Post id: 57, title: "MyText", body: "MyText", image_url: "MyString", created_at: "2014-09-02 14:36:01", updated_at: "2014-09-02 14:36:01", user_id: 1>]
got: nil
(compared using ==)
# ./spec/controllers/posts_controller_spec.rb:53:in `block (4 levels) in <top (required)>'
I've read this thread rspec test of my controller returns nil (+factory girl) , and followed the suggestion to change get :index to controller.index . The suggestion is that if that passes the test then it's a routing problem. It does pass the test, but I still have no idea where the routing problem is, and why the get :index is not working...
It's just a small mistake: create an user before using devise sign_in
RSpec.describe PostsController, :type => :controller do
describe "with valid session" do
let (:user) { create(:user) }
describe "GET index" do
it "assigns all posts as #posts" do
sign_in user
post = create(:post)
get :index, {}
expect(assigns(:posts)).to eq([post])
end
...
end
end
end

Resources