No routes matches '/users/sign_in' on feature test with RSpec - ruby-on-rails

I'm trying to write a feature test with RSpec to test my sign in form, but I always get the following:
1) the signin process signs me in
Failure/Error: visit '/users/sign_in'
ActionController::RoutingError:
No route matches [GET] "/users/sign_in"
But the route exists:
Prefix Verb URI Pattern Controller#Action
GET /(*any)(.:format) redirect(301)
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
That's my spec_helper:
# Include devise methdos
require 'devise'
# Include Capybara
require 'capybara/rspec'
# Use SimpleCov for code coverage
require 'simplecov'
require 'simplecov-shield'
SimpleCov.start 'rails'
SimpleCov.formatters = [
SimpleCov::Formatter::HTMLFormatter,
SimpleCov::Formatter::ShieldFormatter
]
# 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 'shoulda-matchers'
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
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)
module ControllerMacros
def attributes_with_foreign_keys(*args)
FactoryGirl.build(*args).attributes.delete_if do |k, v|
['id', 'type', 'foreign_id', 'foreign_type', 'created_at', 'updated_at'].member?(k)
end
end
end
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.use_instantiated_fixtures = false
config.mock_with :rspec
# Use FactoryGirl for fixtures
config.include FactoryGirl::Syntax::Methods
# Auto-detect spec types
config.infer_spec_type_from_file_location!
# Insert devise helpers in controller specs
config.include Devise::TestHelpers, type: :controller
config.extend ControllerMacros, :type => :controller
config.include ControllerMacros
# 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.before(:suite) do
# Clean all tables to start
DatabaseCleaner.clean_with :truncation
# Use transactions for tests
DatabaseCleaner.strategy = :transaction
# Truncating doesn't drop schemas, ensure we're clean here, app *may not* exist
Apartment::Tenant.drop('test') rescue nil
# Create the default tenant for our tests
Account.create!(name: 'Test', domain: 'test', email: 'info#example.com')
end
config.before(:each) do
# Start transaction for this test
DatabaseCleaner.start
# Switch into the default tenant
Apartment::Tenant.switch! 'test'
# Use Timecop to freeze times on time-critical tests
Timecop.return
end
config.after(:each) do
# Reset tentant back to `public`
Apartment::Tenant.reset
# Rollback transaction
DatabaseCleaner.clean
end
end
And this is my test (/spec/features/login_spec.rb):
require 'spec_helper'
describe 'the signin process', type: :feature do
before :each do
FactoryGirl.build(:user, email: 'user#example.com', password: 'password')
end
it 'signs me in' do
visit '/users/sign_in'
within('#session') do
fill_in 'Email', :with => 'user#example.com'
fill_in 'Password', :with => 'password'
end
click_button 'Sign in'
expect(page).to have_content 'Success'
end
end

If you are using subdomains, you probably need to set something up like this:
spec/support/subdomains.rb
def switch_to_subdomain(subdomain)
# lvh.me always resolves to 127.0.0.1
Capybara.app_host = "http://#{subdomain}.lvh.me"
end
def switch_to_main_domain
Capybara.app_host = "http://lvh.me"
end
The above is taken from this handy blog post. There are some other ideas in there, re: not relying on lvh.me.
Once this is set up you can specify the subdomain using a url helper for this test:
it 'signs me in' do
switch_to_subdomain('test')
visit new_user_session_path
...

Related

DatabaseCleaner doesn't seem to clean between suits

saviors.
I'm having a trouble with cleaning database after each RSpec example.
The thing is, that when I run rspec command, users_controller_spec.rb complains that there are more records than the example expects. Indeed the records are being created as it says if I check with rails c.
when I run the this suite alone, it will be successful, so I assume it is because DatabaseCleaner doesn't clean the user records which other specs create(the number of user records matches the extra records users_controller_spec example claims to be). They are created in before :all block(if that matters).
Here is my rails_helper.rb
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
require 'devise'
require 'admin/v1/dashboard_controller'
# Requires supporting ruby files with custom matchers and macros, etc, in
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.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.include Devise::Test::ControllerHelpers, type: :controller
config.include ControllerMacros, type: :controller
# 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
config.include FactoryGirl::Syntax::Methods
config.infer_spec_type_from_file_location!
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
end
users_controller.rb
describe 'GET #index' do
it 'populates an array of users' do
user1 = create(:user)
user2 = create(:user)
get :index
expect(assigns(:users)).to match_array([user1, user2])
end
it 'renders :index template' do
get :index, {}
expect(response).to render_template :index
end
end
UPDATE1: this is where the extra user records are created
require 'rails_helper'
describe Admin::V1::MessagesController do
let(:admin_user) do
admin_user = double('admin_user')
allow(request.env['warden']).to receive(:authenticate!).and_return(admin_user)
allow(controller).to receive(:current_admin_v1_admin_user).and_return(admin_user)
p '==='
end
before { login_admin_user admin_user }
describe 'GET #index' do
it 'renders :index template' do
get :index, {}
expect(response).to render_template :index
end
end
describe 'GET #get_users' do
before :all do
#user1 = create(:user, nickname: 'hiro')
#user2 = create(:user, nickname: 'elise')
end
context 'with params' do
it 'populates an array of users matching on nickname' do
get :get_users, format: :json, query: 'h'
expect(assigns(:users)).to match_array([#user1])
end
end
context 'without params' do
it 'populates an array of all users' do
get :get_users, format: :json
expect(assigns(:users)).to match_array([#user1, #user2])
end
end
end
describe 'GET #get_messages' do
before :all do
#user1 = create(:user)
#user2 = create(:user)
#message1 = create(:message, user_id: #user1.id)
#message2 = create(:message, user_id: #user1.id)
#message3 = create(:message, user_id: #user2.id)
end
context 'with user_id' do
it 'populates an array of messages with the user_id' do
get :get_messages, format: :json, user_id: #user1.id
expect(assigns(:messages)).to match_array([#message1, #message2])
end
end
end
end
Unfortunately RSpec's before(:all) does not play nicely with transactional tests. The code in before(:all) gets run before the transaction is opened, meaning any records created there will not be rolled back when the transaction is aborted. You are responsible for manually cleaning these items up in an after(:all).
See rspec-rails#496 and Using before(:all) in RSpec will cause you lots of trouble unless you know what you are doing
after(:all) do
# before/after(:all) is not transactional; see https://www.relishapp.com/rspec/rspec-rails/docs/transactions
DatabaseCleaner.clean_with(:truncation)
end

RSpec InfiniteRedirectError when visiting root_path

It's with a capybara feature test. I have no before_action filters set in my controller for the root page, so I'm completely stumped by this. Anyone else had the same problem?
The line that causes the error is simply
visit(root_path)
Very weird.
Also, when running just this test on its own, it passes, but when running the whole test suite, it fails with the InfiniteRedirectError.
user_and_role_spec.rb:
require 'rails_helper'
def manually_create_user
visit new_user_registration_path
fill_in('user_first_name', :with => 'Test')
fill_in('user_last_name', :with => 'User')
fill_in('user_email', :with => 'testuser#email.com')
fill_in('user_password', :with => 'testuser')
fill_in('user_password_confirmation', :with => 'testuser')
click_button('Sign up')
end
def create_user_and_login_as(type)
user = FactoryGirl.create(type)
visit(new_user_session_path)
fill_in('user_email', :with => user.email)
fill_in('user_password', :with => user.password)
click_button('Log in')
end
describe 'with users and roles' do
context "if user is not an admin" do
it "makes sure Login/Logout works" do
visit(root_path)
click_link("Sign up")
fill_in('user_email', :with => "testuser#email.com")
fill_in('user_first_name', :with => "Test")
fill_in('user_last_name', :with => "User")
fill_in('user_password', :with => "password")
fill_in('user_password_confirmation', :with => "password")
click_button "Sign up"
expect(current_path).to eq(root_path)
expect(page).to have_content('Welcome! You have signed up successfully.')
end
end
end
static_pages_controller.rb:
class StaticPagesController < ApplicationController
before_action :an_admin?, only: [:admin]
def home
#testimonials = Testimonial.all
end
def admin
#groups = Group.all
#users = User.all
#students = Student.all
#teachers = Teacher.all
end
private
def an_admin?
unless signed_in? && (current_user.admin == true)
redirect_to root_path, notice: "You have to be a signed-in admin to view the admin page"
end
end
end
routes.rb:
Rails.application.routes.draw do
resources :materials
root 'static_pages#home'
devise_for :users, :controllers => { registrations: 'registrations' }
get 'admin' => 'static_pages#admin'
resources :groups
resources :users
resources :students
resources :teachers
resources :testimonials
post 'assign_to_group' => 'students#assign_to_group' # Could have been 'patch', but default in the controller method is 'post', so I left the method as default and changed this route to 'post'. Doesn't NEED to be patch.
post 'remove_from_group' => 'students#remove_from_group'
post 'unassign_teacher' => 'groups#unassign_teacher'
post 'assign_as_student' => 'teachers#assign_as_student'
post 'assign_as_teacher' => 'students#assign_as_teacher'
post 'add_student' => 'groups#add_student'
post 'remove_student_from_group' => 'groups#remove_student_from_group'
end
rails_helper.rb:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
require 'database_cleaner'
require 'devise'
# Add additional requires below this line. Rails is not loaded until this point!
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# 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.maintain_test_schema!
RSpec.configure do |config|
# 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
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
config.include Devise::TestHelpers, :type => :controller
Capybara.register_driver :rack_test do |app|
Capybara::RackTest::Driver.new(app, :respect_data_method => true, :redirect_limit => 20)
end
end
spec_helper.rb:
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
end
test.log:
Started GET "/" for 127.0.0.1 at 2015-05-19 13:37:49 +0200
Processing by StaticPagesController#home as HTML
Redirected to http://www.example.com/
Filter chain halted as :an_admin? rendered or redirected
Completed 302 Found in 6ms (ActiveRecord: 0.0ms)
Started GET "/" for 127.0.0.1 at 2015-05-19 13:37:49 +0200
Processing by StaticPagesController#home as HTML
Redirected to http://www.example.com/
Filter chain halted as :an_admin? rendered or redirected
Completed 302 Found in 7ms (ActiveRecord: 0.0ms)
Started GET "/" for 127.0.0.1 at 2015-05-19 13:37:49 +0200
Processing by StaticPagesController#home as HTML
Redirected to http://www.example.com/
Filter chain halted as :an_admin? rendered or redirected
...etc etc
To me, this says my before_action in my static_pages_controller kicked in, but I don't understand why it would, given the an_admin? method's code?
UPDATE:
I may be getting close to solving this: static_controller_spec is run before user_and_role_spec when running the full test suite. When I disable static_controller_spec, the user_and_role_spec test runs with no errors when running the whole test suite. The culprit seems to be this line:
controller.class.skip_before_action :an_admin?
This line is in the static_controller_spec:
require "rails_helper.rb"
describe StaticPagesController do
describe "GET #home" do
it "renders the :home view" do
get :home
expect(response).to render_template :home
end
end
describe "GET #admin" do
it "renders the :admin view" do
# This is line 14. The next line is intended to disable the :an_admin? before_action in the controller
controller.class.skip_before_action :an_admin?
get :admin
expect(response).to render_template :admin
# The next line is intended to reverse line 15
controller.class.before_action :an_admin?
end
it "requires user to be signed_in"
it "requires user to be an admin"
end
end
I wanted to disable the before_action for this test. To be honest, I don't really understand that line - it was a straight copy/paste from somewhere. It seems to be messing up my user_and_role_spec test, though, but I don't understand why. Any ideas?
In your user_and_role_spec.rb you have an extra end after the end closing def create_user_and_login_as(type).
You need two end at the bottom of spec to close describe 'with users and roles' do and context "if user is not an admin" do.
In your routes.rb you need an end at the bottom to close Rails.application.routes.draw do
I am not sure if you just did not paste them, but it does matter in your application and it does matter when you post code.
SOLVED:
With reference to the update in my original post, I simply completely removed those two controller.class lines in the static_pages_controller_spec and the whole test suite passes (thank god!). Of course, it does make me wonder why I had those lines in there in the first place - I simply can't remember.
It's all still a bit of a mystery, though, which is why I started this other thread to try to shed some light on it. I know I'm asking for a fair bit of hand-holding here, but any help would be much appreciated. I do study a lot myself, but it's also great to get other people's input too.

undefined local variable or method page (RSpec)

some_spec.rb
require 'spec_helper'
describe "Authentication." do
subject { page }
let(:user) { FactoryGirl.create(:user) }
before {visit new_user_session_path}
describe "Login with username" do
before do
fill_in "Login", with: user.username
fill_in "Password", with: user.password
click_button "Sign in"
end
expect(page).to have_content('Signed in successfully.')
end
describe "Login with email" do
before do
fill_in "Login", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
expect(page).to have_content('Signed in successfully.')
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'
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 }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
# ## 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
What's the problem? After run command terminal returned error: undefined local variable or method 'page'.
The following question did not help me:
rspec+capybara undefined local variable or method
I think you should remove subject { page } from your spec.
page is defined in Capybara.
Important: wrap your expectations by it blocks!

Undefined method "contain" for controller spec

It's definitely best to divide specs up so you have specs pertaining to each aspect of the MVC architecture, but I think there is a slight crossover with controller specs and view specs.
With view specs, you should only be concerned with the view, but with controller specs I still think it would be a good idea to test that the correct view is rendered, and maybe even test the content of the view, although more in-depth testing of the content should take place in the view spec.
Despite this clear article, https://www.relishapp.com/rspec/rspec-rails/v/2-1/docs/controller-specs/render-views, describing how to do this, I just cannot integrate my view and controller specs.
I keep getting the error undefined method 'contain'!
Here's my spec_helper:
# 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 'capybara/rspec'
require 'capybara/rails'
require 'factory_girl_rails'
require 'ap'
def set(factory)
#user = FactoryGirl.create(factory)
end
def sign_up(first_name, last_name, profile_name, email, password)
visit "/"
click_link "Register"
fill_in('First name', with: first_name)
fill_in('Last name', with: last_name)
fill_in('Profile name', with: profile_name)
fill_in('Email', with: email)
fill_in('Password', with: password)
fill_in('Password confirmation', with: password)
click_button 'Sign up'
end
def sign_in(email, password)
visit "/"
click_link "Sign In"
fill_in('Email', with: email)
fill_in('Password', with: password)
click_button 'Sign in'
end
def sign_out
visit "/"
click_link "Sign Out"
end
#Webrat.configure do |config|
# config.mode = :rails
#end
#webrat
require 'capybara/poltergeist'
# Capybara.javascript_driver = :poltergeist
Capybara.javascript_driver = :selenium
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|
# true means 'yes, filter these specs'
config.filter_run_excluding stress: true
# config.current_driver = :webkit
# config.use_transactional_fixtures = false
# config.include Capybara::DSL
DatabaseCleaner.strategy = :truncation
config.after(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
# config.before(:suite) do
# DatabaseCleaner.strategy = :transaction
# DatabaseCleaner.clean_with(:truncation)
# DatabaseCleaner.start
# end
# config.after(:each) do
# DatabaseCleaner.clean
# end
#config.after(:suite) do
# DatabaseCleaner.strategy = :transaction
# DatabaseCleaner.clean_with(:truncation)
# DatabaseCleaner.clean
# end
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# config.include RSpec::Rails::RequestExampleGroup, type: :feature
# 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
I18n.enforce_available_locales = 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"
end
Here's my controller spec:
require "spec_helper"
describe UserFriendshipsController, type: :controller do
render_views
let (:user_1) { FactoryGirl.create(:user_1)}
before {
sign_in user_1
get :index
}
it "renders the :index view" do
response.should render_template(:index)
end
it "view contains expected html" do
# a sanity test more than anything
response.should contain("Welcome to the home page")
end
end
Upon running this spec I get this:
.F
Failures:
1) UserFriendshipsController view contains expected html
Failure/Error: response.should contain("Listing widgets")
NoMethodError:
undefined method `contain' for #<RSpec::Core::ExampleGroup::Nested_1:0x00000008632268>
# ./spec/controllers/user_friendships_spec.rb:18:in `block (2 levels) in <top (required)>'
Finished in 0.1835 seconds
2 examples, 1 failure
Why is this happening? How can I get this to work?
If you look at the relish documentation for the current 2.14 version of Rspec you'll see that they're using match now instead:
expect(response.body).to match /Listing widgets/m
Using the should syntax, this should work:
response.body.should match(/Welcome to the home page/)
Right, it was a very unclear article from Rspec that caused this error. It was using webrat in its example and didn't think to tell you. If anyone else gets here, you can add webrat to your gemfile to use the contain method:
Gemfile
group :test do
gem 'webrat'
end
However, it makes a lot more sense to use rspec's native match method:
expect(response.body).to match /Listing widgets/m

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

Resources