Rspec and named routes - ruby-on-rails

I'm quite new to rails, and trying to follow the railstutorial. Everything goes fine, except for my tests which can't get past the named routes (5.3.3)
My routes.rb :
SampleApp::Application.routes.draw do
resources :users
match '/signup', to: 'users#new'
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'pages#contact'
root to: 'static_pages#home'
#Commented stuff
My firsts tests (spec/controllers/static_pages_controller_spec.rb) :
describe "Static pages" do
subject { page }
shared_examples_for "all static pages" do
it { should have_selector('h1', text: heading) }
it { should have_selector('title', text: full_title(page_title)) }
end
describe "Home page" do
before { visit root_path }
let(:heading) { 'Sample App' }
let(:page_title) { 'Home' }
it_should_behave_like "all static pages"
end
#Other tests
The spec_helper.rb looks like (without all the commented stuff)
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
end
The errors I get from rspec are all like this one :
Static pages Home page it should behave like all static pages
Failure/Error: before { visit root_path }
NameError:
undefined local variable or method `root_path' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_1::Nested_1:0x00000004a12210>
Shared Example Group: "all static pages" called from ./spec/controllers/static_pages_controller_spec.rb:17
# ./spec/controllers/static_pages_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
I already tried using
include Rails.application.routes.url_helpers
in the spec_helper, but it changed my errors to
Static pages Home page it should behave like all static pages
Failure/Error: Unable to find matching line from backtrace
SystemStackError:
stack level too deep
# /usr/lib/ruby/1.9.1/forwardable.rb:185
I also tried different way of renaming my routes, but none of them worked. I'm back to the tutorial version.
If it can be of any help in finding what exactly is a problem, I'm on Ubuntu 11.10, with rails 3.2.1 and ruby 1.9.2p290. Hope you can help, I spend quite a while googling for a solution and didn't find any ^^'

Named routes should work if you put the following in rspec_helper.rb:
RSpec.configure do |config|
config.include Rails.application.routes.url_helpers
...
end
Is that how you set it up?

I don't think you have access to named routes inside of your rspec controller specs. You could however just do visit('/'), which is the equivalent of root_path.

Google brought me here, even my error message doesn't fit 100%.
In my case Capybara command visitis unknown...
Error:
NoMethodError:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0xa49a73c>
Since Capybara 2.0 one has to use folder spec/features capybara commands don't work in folder spec/requests anymore.
That helped me:
http://alindeman.github.com/2012/11/11/rspec-rails-and-capybara-2.0-what-you-need-to-know.html
Hope you find this usefull.

I had the same problem, with the same Tutorial. It turns out that I needed to just restart the Spork service, and all worked fine.
The solution posted by Tom L worked for me, but when I removed that line and restarted Spork, that also fixed the problem.
Hope that helps out any other people who are wary about deviating from the tutorial's code!

You should have used
rails generate rspec:install
instead of
rspec --init
and you wouldn't have had to modify the config file.
Don't do it now though or your application will break and you'll have to waste some more time figuring out why it broke.

Named routes should work if you put the following in rails_helper.rb not the spec_helper.rb:
checkout at my rails_helper.rb code
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
# Prevent database truncation if the environment is production
if Rails.env.production?
abort('The Rails environment is running in production mode!')
end
require 'rspec/rails'
require 'capybara/rails'
RSpec.configure do |config|
config.include Rails.application.routes.url_helpers
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
config.include Warden::Test::Helpers
end
begin
ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
puts e.to_s.strip
exit 1
end
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
end

Related

Rspec not loading ControllerMacros module in Linux (but fine on OS X)

I have written some controller tests in a Rails app that uses Devise and Rspec. Following this guide, I've created a controller_macros.rb in the /spec/support/ directory. There is also a devise.rb file in the same directory, with:
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.extend ControllerMacros, :type => :controller
end
Both files are being required in the spec_helper.rb file, with this line:
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Now here is what is weird: this approach works fine on an OS X laptop, but fails in my Linux desktop. They both use the same RVM settings, same gemsets, same everything.
The error I get when running the tests in Linux is:
uninitialized constant ControllerMacros (NameError)
Obviously the controller_macros.rb module is failing to load in Linux. I've seen SO answers suggesting that config.extend could be changed to config.include, but that doesn't fix the problem.
Any ideas where I can look or what I can test to help isolate the issue?
I'm using Rails 4.1.8 and Rspec 3.1.7.
I struggled with this as well. Answers just weren't working for me. This is what I did (Ubuntu, Rails 4, Rspec 3):
spec/rails_helper.rb
# <snip> env stuff
require 'spec_helper'
require 'rspec/rails'
require 'devise'
require 'support/controller_macros'
# <snip> some non-devise stuff
RSpec.configure do |config|
# <snip> some more non-devise stuff
config.include Devise::TestHelpers, type: :controller
config.include ControllerMacros, type: :controller
end
spec/support/controller_macros.rb
module ControllerMacros
def login_user
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
sign_in user
end
end
students_controller.rb
require "rails_helper"
describe StudentsController, type: :controller do
before do
login_user
end
describe "GET index" do
it "has a 200 status code" do
get :index
response.code.should eq("200")
end
end
end
I solved this by adding
require Rails.root.join("spec/support/macros/controller_macros.rb")
to the top of my spec/support/devise.rb file

Rspec undefined local variable or method root_path

I'm starting to use Rspec, but when I run bundle exec rspec I get an error
/spec/requests/pages_spec.rb:20:in `block (2 levels) in <top (required)>': undefined local
variable or method `root_path' for #<Class:0x00000102e46850> (NameError)
I do not have Spork or Guard running so the question below shouldn't apply
undefined local variable or method `root_path' (Rspec Spork Guard)
I have added config.include Rails.application.routes.url_helpers in my spec_helper.rb file, but that did not help.
undefined local variable or method `root_path' Hartl's Tutorial Chapter 5.3.2
Here's pages_spec.rb
require 'spec_helper'
describe "Pages" do
describe "navigation" do
def self.it_should_be_on(path_name, value=nil)
before { visit path_name }
it "should be on #{path_name}" do
page.should have_link('Home')
page.should have_link('Inventory')
page.should have_link('FAQ')
page.should have_link('About Us')
page.should have_link('Location')
page.should have_link('Contact Us')
# page.should have_link('Login')
end
end
it_should_be_on root_path
it_should_be_on faq_path
it_should_be_on about_path
it_should_be_on location_path
it_should_be_on contact_path
# it_should_be_on login_path
end
end
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 'rspec/autorun'
# 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 }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
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
# 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 = true
# 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
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
config.include Capybara::DSL
config.include Rails.application.routes.url_helpers
end
Update
After reading about shared_examples, I tried this out successfully. Is there a better way to write this test? I ended up separating out the pages into individual pages like Home page etc.
require 'spec_helper'
describe "Pages" do
subject { page }
shared_examples "navigation" do |path_name|
before { visit send( path_name) }
describe "navigation links should be on #{path_name}" do
it { should have_link('Home') }
it { should have_link('Inventory') }
it { should have_link('FAQ') }
it { should have_link('About Us') }
it { should have_link('Location') }
it { should have_link('Contact Us') }
# it { should have_link('Login') }
end
end
describe "Home Page" do
include_examples "navigation", :root_path
end
end
None of the Rails helpers are available at the top level of RSpec's describe block. They are only available within the lower level blocks (e.g. let, before, it, etc.).
If you want to share code such as this across examples, you can use a shared_context or a shared_example, as described in the RSpec documentation, or switch to using symbols as parameters while at the describe level and defer interpretation of them as methods until you're within the lower level blocks, as shown in the answer from #IharDrozdov.
To save your structure - you can change the code like this:
require 'spec_helper'
describe "Pages" do
describe "navigation" do
shared_examples_for 'main page' do |path_name|
before { visit send(path_name) }
it "should be on #{path_name}" do
page.should have_link('Home')
page.should have_link('Inventory')
page.should have_link('FAQ')
page.should have_link('About Us')
page.should have_link('Location')
page.should have_link('Contact Us')
# page.should have_link('Login')
end
end
it_should_behave_like 'main_page', :root_path
it_should_behave_like 'main_page', :faq_path
it_should_behave_like 'main_page', :about_path
it_should_behave_like 'main_page', :location_path
it_should_behave_like 'main_page', :contact_path
# it_should_behave_like 'main_page', :login_path
end
end
because "paths are not defined at the class level in specs"(c)
You cannot call path methods in spec class. It should be in it block.
And your structure is not perfect. It will be better to put code in modules and then include it, if you want to avoid the duplication.

RSpec not finding my named routes

I'm having an inexplicably hard time getting my named routes to work within my rspec tests.
Here's what I'm seeing:
1) Home GET / works!
Failure/Error: get root_path
NameError:
undefined local variable or method `root_path' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x007fe13b0c1538>
# ./spec/requests/home_spec.rb:6:in `block (3 levels) in <top (required)>'
2) Home GET / shows products!
Failure/Error: get products_path
NameError:
undefined local variable or method `products_path' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x007fe13b0cdea0>
# ./spec/requests/home_spec.rb:10:in `block (3 levels) in <top (required)>'
spec/requests/home_spec.rb
require 'spec_helper'
describe "Home" do
describe "GET /" do
it "works!" do
get root_path
response.status.should be(200)
end
it "shows products!" do
get products_path
response.status.should be(200)
end
end
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 'rspec/autorun'
# 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}
require 'spree/core/testing_support/factories'
RSpec.configure do |config|
config.mock_with :rspec
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.before(:suite) do
# DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
# DatabaseCleaner.start
end
config.after(:each) do
# DatabaseCleaner.clean
end
config.include Rails.application.routes.url_helpers
end
You can see that the test is including spec_helper, and spec_helper is including the routing methods. Here's my rake routes:
bundle exec rake routes
...
root / spree/home#index
products GET /products(.:format) spree/products#index
...
Any idea what could be going on here to prevent the routes from working? Thanks!
If you're wanting to reference the route of an engine from tests within an dummy application, or just an application itself, then you'll need to prefix the routing helpers with the engine name. For Spree, you would reference the routes like:
spree.products_path
Similarly, if you want to reference routes of the main application from an engine, you'll need to use main_app:
main_app.root_path

undefined method `visit' when using RSpec and Capybara in rails

I can't get capybara working with rspec. It gives me this error:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1:0x16529f8 #example=nil>
I know there are lots of posts about this but non of the solutions are working for me. Most of them involve the specs not being in /spec/features - which mine is in.
First the error:
$bundle exec rspec spec
F
Failures:
1) security signs users in
Failure/Error: visit "/sessions/new"
NoMethodError:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1:0x16529f8 #example=nil>
# ./spec/features/security_spec.rb:4:in `(root)'
Finished in 0.006 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/features/security_spec.rb:3 # security signs users in
I think its important to note that at first I was using the URL Helper 'new_sessions_path' and it kept giving me an error undefined local variable or method 'new_sessions_path'. I know it is valid because:
$ rake routes
logout_sessions GET /sessions/logout(.:format) sessions#logout
sessions POST /sessions(.:format) sessions#create
new_sessions GET /sessions/new(.:format) sessions#new
contracts POST /contracts(.:format) contracts#create
new_contracts GET /contracts/new(.:format) contracts#new
edit_contracts GET /contracts/edit(.:format) contracts#edit
GET /contracts(.:format) contracts#show
PUT /contracts(.:format) contracts#update
DELETE /contracts(.:format) contracts#destroy
root / contracts#index
My Gemfile:
source 'https://rubygems.org'
gem 'rails', '3.2.11'
gem 'execjs'
group :assets do
gem 'sass-rails', '~> 3.2.3'
gem 'coffee-rails', '~> 3.2.1'
gem 'uglifier', '>= 1.0.3'
end
gem 'jquery-rails'
gem 'activerecord-oracle_enhanced-adapter', '~> 1.4.1'
gem 'jruby-openssl'
gem 'therubyrhino'
gem 'kaminari'
gem 'nokogiri'
group :development do
gem 'warbler'
end
group :test do
gem 'rspec-rails'
gem 'capybara'
gem 'activerecord-jdbcsqlite3-adapter'
end
spec_helper.rb inside of my_app/spec:
# 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 'rspec/autorun'
# Capybara integration
require 'capybara/rspec'
require 'capybara/rails'
# 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|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
# Include path helpers
config.include Rails.application.routes.url_helpers
end
my_app/spec/features/security_spec.rb:
describe "security", :type => :feature do
it "signs users in" do
visit "/sessions/new"
fill_in "username", :with => "user"
fill_in "password", :with => "pass"
click_button "Sign In"
page.should have_content('Login Successful')
end
end
I've tried defining the test above both with and without :type => :feature. It makes no difference either way. Any ideas what I should try next?
Try to add:
config.include Capybara::DSL
to your config block.
# 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 'rspec/autorun'
# 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|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
# Include path helpers
config.include Rails.application.routes.url_helpers
config.include Capybara::DSL
end
Adding require 'rails_helper' at the top of my feature ended up fixing my problem:
require 'rails_helper'
describe "security", :type => :feature do
it "signs users in" do
visit new_sessions_path
fill_in "username", :with => "user"
fill_in "password", :with => "pass"
click_button "Sign In"
page.should have_content('Login Successful')
end
end
This seems odd to me since every example I've seen for rspec and capybara didn't have that require, but oh well. Problem solved.
Original Answer (older versions of rspec)
require 'spec_helper' is used by older versions of RSpec. The better answer would be require 'rails_helper'.
Since Capybara 2.0 one has to use folder spec/features Capybara commands don't work in folder spec/requests anymore.
Try performing all your setup in a before block:
spec/features/security_spec.rb
describe "security" do
before do
visit "/sessions/new"
fill_in "username", :with => "user"
fill_in "password", :with => "pass"
click_button "Sign In"
end
it "signs users in" do
page.should have_content('Login Successful')
end
end
I also had this problem,
Adding require 'rails_helper' at the top of my feature ended up fixing my problem:
require 'rails_helper'
RSpec.describe "Products", type: :request do
describe "GET /products" do
it "display tasks" do
Product.create!(:name => "samsung")
visit products_path
page.should have_content("samsung")
#expect(response).to have_http_status(200)
end
end
end
And add the 'config.include Capybara::DSL' in rails_helper.rb
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
config.include Capybara::DSL
end
Other than the upgrading issue which you would run into when ugprading from an older Rails app with require 'spec_helper.rb' instead of require 'rails_helper.rb', this happens for 3 known reasons:
1. Your spec isn't of type "feature"
which means Capybara doesn't know how to run it using Javascript or a browser. You want to do one of two things: 1) Typically, you want config.infer_spec_type_from_file_location! set in your RSpec.configure and that will mean that what's in the features folder will be a feature.
if you have something non-standard, you can add type: :feature to the spec describe block to turn that spec in a feature, but typically it's easier just to put them into the /features folder and let the infer setting do its job.
2. You accidentally put the visit outside of the it block
The visit must be within the it, which is within the describe. Be sure not to put the visit directly within the describe.
3. Some other kernal panic you can't see has caused Capy to shut down the spec.
This is a nasty one to diagnose but I have seen it. It means that Capy didn't actually parse this file correctly, and so somehow isn't in the right scope when it gets to the visit block. Carefully pick apart your Capy spec to figure out where you introduced it.
I induced the kernal panic today but have a let block be called page (whoops). page appears to be a reserved word for Rspec or Capy here, and it causes the kernal panic, thus leading to the spec not to parse thus leading to the visit method not being found.
in my case, it was simply changing this:
let(:page) {Page.new()}
to
let(:content_page) {Page.new()}
Notice that the word page is not reserved by Rails, and works fine as a database name and also a model name, but the specific construction of using page here as the let variable name seemed to cause Capy to get kind of crappy.

Capybara methods are undefined

I cannot get capybara to work. I am using capybara 2.0.0
I get this error
Failure/Error: visit "/users/sign_in"
NoMethodError:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_21:0x007fdda4c6eba0>
on this spec
spec/requests/forgot_password_spec.rb
describe "forgot password" do
it "redirects user to users firms subdomain" do
visit "/users/sign_in"
end
end
I do not get any errors that it cannot find capybara and it's included in the spec_helper.rb
spec_helper.rb
require 'rubygems'
require 'spork'
require 'database_cleaner'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
require 'rspec/autorun'
require 'factory_girl'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
config.include RequestMacros, :type => :request
config.mock_with :rspec
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.infer_base_class_for_anonymous_controllers = false
end
Spork.each_run do
FactoryGirl.reload
end
end
Has anybody else encountered this?
If you've got version >= 2.0, any tests that use Capybara methods like visit should go under a spec/features directory, and not under spec/requests, where they'd normally reside in Capybara 1.1.2.
Have a look at the following links for more information:
rspec-rails and capybara 2.0: what you need to know
rspec-rails gem Capybara page
If you don't want to use a spec/features directory, you should be able to mark a test as a feature in the following way and have Capybara methods work:
describe "Some action", type: :feature do
before do
visit "/users/sign_in"
# ...
end
# ...
end
In my case, I got this error because I forgot to putrequire "spec_helper"
at the top of my new spec file.
I've done it enough times that I'm adding an answer to an already answered question in hopes that it helps some other knucklehead (or most likely me searching this again in the future).

Resources