I need to test that a flash message comes up when a specific exception is raised. I am getting a no route matches error and have looked through the other topics with "Rspec Controller test, No Routes matches" and am still not sure what is wrong. This is my first time writing an rspec test. Commented out lines are various other attempts to get test to pass.
audit/businesses_controller.rb:
class Audit::BusinessesController < ApplicationController
# PUT /audit/businesses/:id
def update
remove_deleted_account_numbers_in(params)
#business = #jurisdiction.businesses.find(params[:id])
#business.changed_by = current_user
if #business.update_attributes(audit_business_params)
success_message('update')
else
#business.initialize_accounts
#business = #business
render :edit, alert: t('flash.save_failed')
end
rescue ActiveRecord::StatementInvalid => e
if e.message.include? "foreign key constraint"
#business = #jurisdiction.businesses.find(params[:id])
#business.initialize_accounts
#business = #business
render :edit, alert: "This account number is in use and cannot be deleted"
else
raise e
end
end
business_controller_spec.rb:
require "spec_helper"
describe Audit::BusinessesController do
describe "handling ActiveRecord::StatementInvalid" do
before {delete, url = 'audit/jurisdictions/:jurisdiction_id/businesses/:id(.:format)'}
it "should rescue with a flash message" do
# /audit/jurisdictions/:jurisdiction_id/businesses/:id(.:format)
# delete, businesses_id: '80776', jurisdiction_id: '795', format: 'html', id: "234769"
expect(page).to have_content("This account number is in use and cannot be deleted")
end
end
end
rake routes:
audit_businesses GET
/audit/jurisdictions/:jurisdiction_id/businesses(.:format)
audit/businesses#
POST /audit/jurisdictions/:jurisdiction_id/businesses(.:format)
audit/businesses#create
new_audit_business GET
/audit/jurisdictions/:jurisdiction_id/businesses/new(.:format)
audit/businesses#new
edit_audit_business GET
/audit/jurisdictions/:jurisdiction_id/businesses/:id/edit(.:format)
audit/businesses#edit
audit_business
GET /audit/jurisdictions/:jurisdiction_id/businesses/:id(.:format)
audit/businesses#show
PUT /audit/jurisdictions/:jurisdiction_id/businesses/:id(.:format) audit/businesses#update
DELETE /audit/jurisdictions/:jurisdiction_id/businesses/:id(.:format) audit/businesses#destroy
Error Message:
Failure/Error: before { delete audit_business_path(:jurisdiction_id, :id, :format) }
ActionController::RoutingError:
No route matches {:controller=>"audit/businesses", :action=>"/audit/jurisdictions/jurisdiction_id/businesses/id.format"}
# ./spec/controllers/businesses_controller_spec.rb:6:in `block (3 levels) in <top (required)>'
When I change the spec to:
describe Audit::BusinessesController do
describe "handling ActiveRecord::StatementInvalid" do
it "should rescue with a flash message" do
put :update, :jurisdiction_id => 1, :id => 1, :format => html
expect(controller).to set_flash[:alert].to(/This account number is in use and cannot be deleted/).now
The error is:
Failure/Error: put :update, :jurisdiction_id => 1, :id => 1, :format => html
NoMethodError:
undefined method `can_update?' for nil:NilClass
routes.rb:
namespace :audit do
root to: 'site#home'
resources :labels, only: ['index', 'destroy'] do
post 'delete_queue', on: :collection
get 'print', on: :collection
get 'print_view', on: :collection
get 'mark_printed', on: :collection
get 'users', on: :collection
end
resources :auditor_goals
resources :contracts
resource :contract_work, only: %w[show update], controller: 'contract_work'
resources :manpower
resource :county_budgets, only: :update do
get 'search'
end
get 'intro_letter_search' => 'files#intro_letter_search'
put 'intro_letter_update' => 'files#intro_letter_update'
get 'search' => 'files#search'
get 'calendar' => 'files#calendar'
get 'autocomplete' => 'files#autocomplete'
get 'direct' => 'files#direct'
get 'size_code_select' => 'businesses#size_code_select'
scope '/jurisdictions/:jurisdiction_id' do
resources :businesses, controller: 'businesses'
resources :files, controller: 'files' do
get 'print', on: :member
end
# get 'page/:page', action: :index, on: :collection
end
end
for rspec test instead write
expect(page).to have_content("flash message")
where "flash message" is the actual message of the error or exception you're trying to make pass. Eg for, flash[:notice] = "An error occurred", you would put have_content("An error occurred")
Hope that helps?!
Justin
#TzokinB - I believe "Capybara::ElementNotFound: Unable to find xpath "/html" typically means the test set is now looking for a view. Have you associated a view for to action in your controller?
Related
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) }
So I keep getting the error:
No route matches {:action=>"create", :controller=>"xaaron/api_keys"}
Which is thrown in the test:
it "should not create an api key for those not logged in" do
post :create
expect(response).to redirect_to xaaron.login_path
end
when I go to spec/dummy and run the rake routes command I see:
api_keys GET /api_keys(.:format) xaaron/api_keys#index
POST /api_keys(.:format) xaaron/api_keys#create
new_api_key GET /api_keys/new(.:format) xaaron/api_keys#new
edit_api_key GET /api_keys/:id/edit(.:format) xaaron/api_keys#edit
api_key GET /api_keys/:id(.:format) xaaron/api_keys#show
PATCH /api_keys/:id(.:format) xaaron/api_keys#update
PUT /api_keys/:id(.:format) xaaron/api_keys#update
DELETE /api_keys/:id(.:format) xaaron/api_keys#destroy
Which shows that yes this route does exist. My routes file for this engine looks like:
Xaaron::Engine.routes.draw do
get 'login' => 'sessions#new', :as => 'login'
get 'logout' => 'sessions#destroy', :as => 'logout'
get 'signup' => 'users#new', :as => 'signup'
get 'permission_denied' => 'error#denied', :as => 'permission_denied'
get 'record_not_found' => 'error#error', :as => 'record_not_found'
get 'password_reset' => 'password_resets#edit', :as => 'rest_user_password'
resource :error, controller: 'error'
resources :users
resources :api_keys
resources :sessions
resources :roles
resources :password_resets
end
What am I missing?
update
For those of you curious how I am getting these routes, its because the dummy app's routes file is set up (by default) as such:
Rails.application.routes.draw do
mount Xaaron::Engine => "/xaaron"
end
Update II
I have been reading this api docs on how routing is done in engines and I believe the way I have done this is correct, how ever the controller is defined as such:
module Xaaron
class ApiKeysController < ActionController::Base
before_action :authenticate_user!
def index
#api_key = Xaaron::ApiKey.where(:user_id => current_user.id)
end
def create
#api_key = Xaaron::ApiKey.new(:user_id => current_user.id, :api_key => SecureRandom.hex(16))
create_api_key(#api_key)
end
def destroy
Xaaron::ApiKey.find(params[:id]).destroy
flash[:notice] = 'Api Key has been deleted.'
redirect_to xarron.api_keys_path
end
end
end
You need to tell your spec you are using the engine routes:
describe ApiKeysController do
routes { Xaaron::Engine.routes }
it "should not create an api key for those not logged in" do
post :create
expect(response).to redirect_to xaaron.login_path
end
end
I am building a Rails 3 application, and I am a little confused with a controller spec. here what I have in the application:
routes.rb
get "/:user_name/library", :to => 'users#library', :as => :user_library
users_controller.rb
class UsersController < ApplicationController
def library
end
end
users_controller_spec.rb
describe "UsersController" do
describe "#library" do
let(:user){FactoryGirl.create(:user)}
it "renders the users/library.html.erb view" do
get :library, :parameters => {:user_name => user.user_name}
end
end
end
this example dose not run and it shows the following error
Failure/Error: get :library,:parameters => {:user_name => user.user_name}
ActionController::RoutingError:
No route matches {:parameters=>{:user_name=>"UserName"}, :controller=>"users", :action=>"library"}
Get rid of the :parameters key in your get:
get :library, :user_name => user.user_name
I am trying to make a test for a controller for a nested resource.
The nesting is like this in the routes.rb
resources :cars, :only => [:index, :destroy, :show] do
resources :car_subscriptions, :only => [:new, :create], :as => :follow_subscriptions
end
I'm trying to test the create action most specifically:
describe CarSubscriptionsController do
def valid_attributes
{:car_id => '1', :user_id => '2'}
end
describe "POST create" do
describe "with valid params" do
it "creates a new CarSubscription" do
expect {
post :create, :car_id => 1, :car_subscription => valid_attributes
}.to change(CarSubscription, :count).by(1)
end
it "assigns a newly created car_subscription as #car_subscription" do
post :create, :car_subscription => valid_attributes
assigns(:car_subscription).should be_a(CarSubscription)
assigns(:car_subscription).should be_persisted
end
it "redirects to the created car_subscription" do
post :create, :car_subscription => valid_attributes
response.should redirect_to(CarSubscription.last)
end
end
end
end
It's actually a part of the scaffold generated by rails script. And I only modified the valid_attributes and the post in the first 'it'
And the output is this:
1) CarSubscriptionsController POST create with valid params creates a new CarSubscription
Failure/Error: post :create, :car_id => 1, :car_subscription => valid_attributes
ActionController::RoutingError:
No route matches {:car_id=>"1", :car_subscription=>{:car_id=>"1", :user_id=>"2"}, :controller=>"car_subscriptions", :action=>"create"}
# ./spec/controllers/car_subscriptions_controller_spec.rb:34:in `block (5 levels) in <top (required)>'
# ./spec/controllers/car_subscriptions_controller_spec.rb:33:in `block (4 levels) in <top (required)>'
It's the same error for all 'it's.
I've tried removing the :as => :following_subscriptions from the routes.rb file but the same problem.
I have actually split up the resources of car_subscriptions so index and destroy are in not nested, and create and new are nested in :cars
I don't want to use hard coded paths like in this answer but if it is the only way, I can give it a try:
{ :post => "/forum_topics/1/forum_sub_topics" }.should route_to(:controller => "forum_sub_topics", :action => "create", :forum_topic_id => 1)
EDIT
Oh, and my rake routes looks like this:
car_follow_subscriptions_da POST /biler/:car_id/car_subscriptions(.:format) {:action=>"create", :controller=>"car_subscriptions", :locale=>"da"}
From what rake routes provides, I guess you should replace:
post :create, :car_id => 1, :car_subscription => valid_attributes
with:
post :create, :car_id => 1, :car_subscription => valid_attributes, :locale => "da"
I get the following error when running rspec spec/controllers/users_controller_spec.rb in section 7.3.1 of Michael Hartl's Rails Tutorial:
Failure/Error: get :show, :id => #user
ActionController::RoutingError:
No route matches {:id=>#<User id: 1, #rest is data from the factories.rb file....
Here's my code for the users_controller_spec.rb file:
require 'spec_helper'
require 'factories'
describe UsersController do
render_views
describe "GET 'show'" do
before(:each) do
#user = Factory(:user)
end
it "should be successful" do
get :show, :id => #user
response.should be_success
end
it "should find the right user" do
get :show, :id => #user
assigns(:user).should == #user
end
end
describe "GET 'new'" do
it "should be successful" do
get 'new'
response.should be_success
end
it "should have the right title" do
get 'new'
response.should have_selector("title", :content => "Sign up")
end
end
end
Here is my factories.rb code:
Factory.define :user do |user|
user.name "Michael Hartl"
user.email "mhartl#example.com"
user.password "foobar"
user.password_confirmation "foobar"
end
I inserted these lines in Spec_Helper in regards to 'factory_girl':
require 'factory_girl'
Factory.find_definitions
Any idea what's causing the routing error?
Here is my routes.rb code:
SampleApp::Application.routes.draw do
get "users/new"
match '/signup', :to => 'users#new'
match '/contact', :to => 'pages#contact'
match '/about', :to => 'pages#about'
match '/help', :to => 'pages#help'
root :to => 'pages#home'
The author's note regarding using - get :show, :id => #user instead of using - get :show, :id => #user.id:
" Second, note that the value of the hash key :id, instead of being the user’s id attribute #user.id, is the user object itself:
get :show, :id => #user
We could use the code:
get :show, :id => #user.id
to accomplish the same thing, but in this context Rails automatically converts the user object to the corresponding id. It does this by calling the to_param method on the #user variable.
You are missing a route to the show action for users. You can add something like this to the routes.rb file.
match "/users/:id" => "users#show"
If you want the normal CRUD actions, you can get rid of your users/new route and instead of the match line above, just declare them all with a single line:
resources :users
I believe your code is telling Rails that the id is the user, which of course doesn't make sense. That's creating a path like /users/#user, for which no route exists. As you probably know, you want a path like /users/1.
So I think you code should look like
get :show, :id => #user.id
or possibly
get :show, #user