Ruby on Rails - Rspec test with Devise is failing - ruby-on-rails

I have a Problem with an rspec-request-test in my rails app. The tests, that need a user-login are failing. I have implemented the devise-tests according to this tutorial. Also I found many links, that are using a similar approach. e.g. here
Here is an extract of my gemfile:
gem 'devise', '~> 3.5'
gem 'devise-i18n'
gem 'devise-i18n-views'
gem 'cancancan', '~> 1.10'
gem 'rolify'
gem 'alchemy_cms', '~> 3.2.0'
gem 'rspec-core'
gem 'rspec-rails'
gem 'i18n-tasks', '~> 0.8.7'
gem 'factory_girl_rails'
Here is the rspec-test, that is failing: (spec/requests/campaigns_spec.rb)
require 'rails_helper'
RSpec.describe "Campaigns", type: :request do
describe "GET /campaigns" do
it "responds with 200" do
sign_in_as_a_valid_user_request
get campaigns_path
expect(response).to have_http_status(200)
end
end
end
You should only see this page, when you are logged in. So in the test I want to log in as a User (created with FactoryGirl), than go to the site, and get a 200-response. In the application itself this is working good.
spec/rails_helper.rb (extract)
...
require 'spec_helper'
require 'rspec/rails'
require 'devise'
require 'support/devise_support'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.include Devise::TestHelpers, type: :controller
config.include Devise::TestHelpers, type: :view
config.include ValidUserRequestHelper
...
end
spec/support/devise_support.rb
module ValidUserRequestHelper
def sign_in_as_a_valid_user_request
#user ||= FactoryGirl.create :user
post_via_redirect user_session_path, 'user[email]' => #user.email, 'user[password]' => #user.password
end
end
here is the error, that the test is throwing:
1) Campaigns GET /campaigns responds with 200
Failure/Error: sign_in_as_a_valid_user_request
ActionController::RoutingError:
Alchemy::Page not found "/"
# ./spec/support/devise_support.rb:13:in `sign_in_as_a_valid_user_request'
# ./spec/requests/campaigns_spec.rb:6:in `block (3 levels) in <top (required)>'
According to the links that I found, this should work! but it doesn't... Can anyone tell me why? Why is there a routing error? The app itself is working fine.

The routing error occurs, because your host app does not know of the engines routes. That's why you have to use the routing proxy objects of rails engines in views outside the current controller scope. Please read more about rails engines and the characteristics of their routes in the official rails guides
Luckily, Alchemy comes with a handy test helper that solves your problems. Just add this to your spec_helper:
# spec/spec_helper.rb
require 'alchemy/test_support/controller_requests'
...
RSpec.configure do |config|
config.include Alchemy::TestSupport::ControllerRequests
...
end
Know you can use alchemy_get instead of get in your request specs.

Related

Tell rspec (core) that test is testing controller

Trying to run this test but keep getting the following error:
Failure/Error: get :index
NoMethodError:
undefined method `get' for #<RSpec::ExampleGroups::TestModuleTestController::Controller:0x007fa4bc120d00>
Note: I'm not using rspec-rails.
require "spec_helper"
module TestModule
describe TestController, :type => :controller do
describe "controller" do
it "sets X-Frame-Options to ALLOWALL" do
get :index
expect(response.headers['X-Frame-Options']).to eq('ALLOWALL')
end
end
end
end
Note: I'm not using rspec-rails.
That's your problem right there. All the rails type specs (controller, request, features, views) are part of rspec-rails not rspec-core.
Without rspec-rails the type metadata does absolutely nothing - its just a plain example group describing a class.
The solution is to add rspec-rails to your gemfile.
group :development, :test do
gem 'rspec-rails', '~> 3.6'
end
And run rails g rspec install.
https://github.com/rspec/rspec-rails

Cant sign_in/login_as in feature test devise capybara rspec

I have been bashing my skull for the past 4 hours.
So basicly i cant login/sign in as a user in my feature test, i am using devise_auth_token gem.
Feature test:
1 require 'rails_helper'
2
3 # TODO: rename unit to features
4 feature 'Access' do
5 before :each do
6 #user = Fabricate :user
7 #user.confirm
8
9 #post = Fabricate :post, user: #user
10 Fabricate :note, post: #post
11 end
12
13 it 'should show error if not loged in' do
14 visit api_posts_path
15 expect(page).to have_content '{"errors":["Authorized users only."]}'
16 end
17
18 it 'should let all user roles view list of posts', format: :js do
19 login_as #user, scope: :user
20 visit api_posts_path
21 binding.pry
My spec helper:
require 'database_cleaner'
require 'devise'
require 'auth'
include Devise::TestHelpers
include Warden::Test::Helpers
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.include Devise::TestHelpers, :type => :controller
config.include Warden::Test::Helpers
config.before :suite do
Warden.test_mode!
end
config.include AuthHelper
# 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
# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
# These two settings work together to allow you to limit a spec run
# to individual examples or groups you care about by tagging them with
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
# get run.
config.filter_run :focus
config.run_all_when_everything_filtered = true
# Allows RSpec to persist some state between runs in order to support
# the `--only-failures` and `--next-failure` CLI options. We recommend
# you configure your source control system to ignore this file.
config.example_status_persistence_file_path = "spec/examples.txt"
# Limits the available syntax to the non-monkey patched syntax that is
# recommended. For more details, see:
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
config.disable_monkey_patching!
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = 'doc'
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
# 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
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
=end
end
It gives me that the user is not authorized.
My gemfile:
source 'https://rubygems.org'
gem 'rails', '4.2.6'
gem 'sqlite3'
gem 'uglifier', '>= 1.3.0'
gem 'jbuilder', '~> 2.0'
group :development, :test do
gem 'better_errors'
gem 'binding_of_caller'
gem 'bullet'
gem 'meta_request'
gem 'pry-awesome_print'
gem 'pry-rails'
gem 'quiet_assets'
gem 'rspec-rails', '~> 3.0'
gem 'rubocop', require: false
gem 'fabrication'
gem 'database_cleaner'
gem 'capybara'
end
gem 'devise_token_auth'
gem 'puma'
gem 'rack-cors'
For the specific error you're having I think the most likely cause here is that you don't have config.use_transactional_fixtures = false in your spec_helper, which would mean you're still running with transactional database access in your tests and any objects you create in your tests won't actually be visible to the app in js: true tests. A second issue (not causing this problem) is that you aren't calling Warden.test_reset! in an after block.
The bigger issue here is you appear to be using Capybara to test an API, which Capybara isn't designed for. You probably want to using request specs to test an API.

Guard not loading Capybara DSL

I'm running Rails 4, trying to set up some integration test with Rspec and Capybara. I want to set up guard to run 'zeus test .' whenever I make changes. Problem is, whenever anything form the Capybara DSL is called, or whenever I try to use route helpers, I'm given errors like this:
undefined local variable or method `root_path' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_1:0x007f55682c6d60>
If I replace root_path with '/' it get:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_1:0x007f556833bbb0>
If I just run 'rspec spec .' or 'zeus test .' it works fine.
I've tried removing the 'cmd: 'zeus test .' option from my Guardfile, but I'm having the same issues. It seems clear that the problem is with Guard and unrelated to zeus.
In my Gemfile:
group :development, :test do
gem 'capybara'
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'guard-rspec', require: false
gem 'better_errors'
gem 'binding_of_caller'
end
Spec helper:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'factory_girl_rails'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
end
Spec I'm trying to run:
require 'spec_helper'
describe "HomePage" do
describe "Root page" do
before { visit root_path }
it "works!" do
page.status_code.should be(200)
end
it 'contains bottom nav buttons' do
page.should have_link 'How it works'
page.should have_link 'Customer Service'
page.should have_link 'Terms of Service'
page.should have_link 'Contact Us'
end
end
end
try add
config.include Capybara::DSL
to your spec_helper.rb
Try to add url_helpers to spec_helper.rb
RSpec.configure do |config|
...
config.include Rails.application.routes.url_helpers
end
and check my other answer about visit method missing
I fixed this problem by commenting out this line in my spec_helper.rb:
require 'rspec/autorun'
Again, the problem was only with Guard and I suppose that autorun somehow skips over the config block in the spec_helper, so everything works fine now. Hope this helps someone else having the same problem.

Rspec - obvious test is failing, how to troubleshoot?

I have a very simple app I'm trying to test with rspec. I'm having a hard time figuring out if my configuration is the problem, or if it's the code. The first line of /people/index.html.erb is <h1>Totally Awesome Page</h1>.
The error:
expected to find text "Totally Awesome Page" in "Index"
./spec/features/people_spec.rb:19:in `block (3 levels) in <class:PeopleSpec>'
test gems:
group :development, :test do
gem 'rspec'
gem 'rspec-rails'
gem 'capybara'
gem 'factory_girl_rails'
end
spec/features/people_spec.rb:
require 'spec_helper'
class PeopleSpec < ActionDispatch::IntegrationTest
describe "People" do
describe "Index" do
before { visit '/people'}
it { should have_content('Totally Awesome Page')}
end
end
end
spec/spec_helper:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'minitest/autorun'
require 'capybara/rails'
require 'capybara/rspec'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
config.include Capybara::DSL
end
routes:
people_path GET /people(.:format) people#index
POST /people(.:format) people#create
new_person_path GET /people/new(.:format) people#new
edit_person_pathGET /people/:id/edit(.:format) people#edit
person_path GET /people/:id(.:format) people#show
PATCH /people/:id(.:format) people#update
PUT /people/:id(.:format) people#update
DELETE /people/:id(.:format) people#destroy
Add gem 'launchy' and then you can use save_and_open_page after visit to see how rendered page looks like.
Add subject { page } to the spec to fix it.
If you say it than it have to point to something. In your test it doesn't.
You can use should on page to do that (page is not the only one you can test. There are more, like response or even lambdas) that way:
it "some description" do
page.should have_content('foo')
end
or if you have many tests for page than you can write them in a short way:
it { should have_content('foo') }
but you need to specify subject for it first:
subject { page }

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.

Resources