My controller specs are passing when I run them one by one but are all failing when I run them together as controllers.
$rspec spec/controllers
22) SubjectsController GET index assigns all subjects as @subjects
Failure/Error: get :index, {}
ActionController::RoutingError:
No route matches {:controller=>"subjects"}
# ./spec/controllers/subjects_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
My guess is it must be something to do with database cleaner but I'm not sure best way to troubleshoot routing errors in controller specs.
Gemfile
gem 'rails', '3.2.13'
gem 'mysql2', '0.3.13'
gem 'devise', '2.2.3'
...
...
group :development, :test do
gem 'rspec-rails', '~> 2.99'
gem 'webrick', '~> 1.3'
gem 'rails-erd', '~> 1.1'
gem 'bullet', '~> 4.6'
gem 'pry-rails', '~> 0.3'
gem 'factory_girl_rails', '~> 4.4'
gem 'faker', '~> 1.2'
end
group :test do
gem 'cucumber-rails', :require => false
gem 'capybara', '~> 2.2.1'
gem 'database_cleaner', '~> 1.3.0'
gem 'launchy', '~> 2.4.2'
gem 'shoulda-matchers', '~> 2.6.1'
gem 'vcr', '~> 2.9.2'
gem 'webmock', '~> 1.13.0'
gem 'zeus', '~> 0.13.3'
end
spec/spec_helper.rb
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] = 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rake'
require 'sidekiq/testing'
Sidekiq::Logging.logger = nil
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
config.mock_with :rspec
# Only run tests that have this filter, if it exists
# config.filter_run :debug => true
# Run all the tests when all the tests are filtered
# config.run_all_when_everything_filtered = true
config.treat_symbols_as_metadata_keys_with_true_values = true
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
config.include FactoryGirl::Syntax::Methods
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new( {
provider: 'facebook',
uid: '123545',
info: {
first_name: 'John',
last_name: 'Doe',
email: '[email protected]'
},
credentials: {
token: "123456",
expires_at: Time.now + 1.week
},
extra: {
raw_info: {
gender: 'male'
}
}
})
# silence rspec 3 deprecation warnings
config.expose_current_running_example_as :example
config.infer_spec_type_from_file_location!
def login(user)
@request.env["devise.mapping"] = Devise.mappings[:user]
@user = user
@user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module
allow(controller).to receive(:current_user).and_return(@user)
sign_in @user
end
def logged_user
@user
end
end
spec/support/database_cleaner.rb
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
load "#{Rails.root}/db/seeds.rb"
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
spec/controllers/subjects_controller_spec.rb
require 'spec_helper'
describe SubjectsController, :type => :controller do
before(:each) do
login create(:admin)
end
describe "GET index" do
it "assigns all subjects as @subjects" do
subject = create(:subject)
get :index, {}
expect(assigns(:subjects)).to include(subject)
end
end
describe "GET show" do
it "assigns the requested subject as @subject" do
subject = create(:subject)
get :show, {:id => subject.to_param}
expect(assigns(:subject)).to eq(subject)
end
end
describe "GET new" do
it "assigns a new subject as @subject" do
get :new, {}
expect(assigns(:subject)).to be_a_new(Subject)
end
end
describe "GET edit" do
it "assigns the requested subject as @subject" do
subject = create(:subject)
get :edit, {:id => subject.to_param}
expect(assigns(:subject)).to eq(subject)
end
end
describe "POST create" do
describe "with valid params" do
it "creates a new Subject" do
expect {
post :create, {:subject => attributes_for(:subject) }
}.to change(Subject, :count).by(1)
end
it "assigns a newly created subject as @subject" do
post :create, { :subject => attributes_for(:subject) }
expect(assigns(:subject)).to be_a(Subject)
expect(assigns(:subject)).to be_persisted
end
it "redirects to the created subject" do
post :create, {:subject => attributes_for(:subject) }
expect(response).to redirect_to(subjects_path)
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved subject as @subject" do
allow_any_instance_of(Subject).to receive(:save).and_return(false)
post :create, {:subject => {}}
expect(assigns(:subject)).to be_a_new(Subject)
end
it "re-renders the 'new' template" do
allow_any_instance_of(Subject).to receive(:save).and_return(false)
post :create, { :subject => {} }
expect(response).to render_template("new")
end
end
end
describe "PUT update" do
describe "with valid params" do
it "updates the requested subject" do
@subject = create(:subject, name: "Alice")
put :update, id: @subject, subject: attributes_for(:subject, name: "Bob")
@subject.reload
@subject.name.should eq("Bob")
end
it "assigns the requested subject as @subject" do
@subject = create(:subject)
put :update, {:id => @subject, :subject => attributes_for(:subject) }
expect(assigns(:subject)).to eq(@subject)
end
it "redirects to the subject" do
@subject = create(:subject)
put :update, {:id => @subject, :subject => attributes_for(:subject) }
expect(response).to redirect_to(edit_subject_path)
end
end
describe "with invalid params" do
it "assigns the subject as @subject" do
@subject = create(:subject)
allow_any_instance_of(Subject).to receive(:save).and_return(false)
put :update, {:id => @subject, :subject => {}}
expect(assigns(:subject)).to eq(@subject)
end
it "re-renders the 'edit' template" do
@subject = create(:subject)
allow_any_instance_of(Subject).to receive(:save).and_return(false)
put :update, {:id => @subject, :subject => {}}
expect(response).to render_template("edit")
end
end
end
describe "DELETE destroy" do
it "destroys the requested subject" do
subject = create(:subject)
expect {
delete :destroy, {:id => subject.id}
}.to change(Subject, :count).by(-1)
end
it "redirects to the subjects list" do
subject = create(:subject)
delete :destroy, {:id => subject.id }
expect(response).to redirect_to(subjects_url)
end
end
end
rake routes
suggested_subjects GET /suggested_subjects(.:format) suggested_subjects#index
make_preferred_subject PUT /subjects/:id/make_preferred(.:format) subjects#make_preferred
subjects GET /subjects(.:format) subjects#index
POST /subjects(.:format) subjects#create
new_subject GET /subjects/new(.:format) subjects#new
edit_subject GET /subjects/:id/edit(.:format) subjects#edit
subject GET /subjects/:id(.:format) subjects#show
PUT /subjects/:id(.:format) subjects#update
app/controllers/subjects_controller.rb
class SubjectsController < ApplicationController
load_and_authorize_resource
def index
@subjects = Subject.filter(params)
respond_to do |format|
format.html
format.json { render json: {total: @subjects.count, subjects: @subjects}.to_json }
end
end
....
....
end
Figured it out.
The ActionController::RoutingError was a result of another controller spec which was calling:
routes.draw
This call wiped out the routes for subsequent specs. The solution for now (thanks to:
http://pivotallabs.com/adding-routes-for-tests-specs-with-rails-3/ ) was to add:
after do
# be sure to reload routes after the tests run, otherwise all your
# other controller specs will fail
Rails.application.reload_routes!
end
Also helpful were:
https://github.com/rspec/rspec-rails/issues/817
https://github.com/rspec/rspec-rails/issues/636
Hope this helps and good luck!