Capybara issue: #request must be an ActionDispatch::Request - ruby-on-rails

I'm having problems making Capybara work with Rails. Just testing that suposedly interesting test thing. OK, in the attached code there are a couple of equivalent tests. The first one is made with shoulda-context + Test::Unit that comes with Rails. The second test is made with capybara and shoulda-context too.
require 'integration_test_helper'
class UsersTest < ActionDispatch::IntegrationTest
fixtures :all
context "signup" do
context "failure" do
setup do
#attr = { :name => "", :email => "", :password => "", :password_confirmation => "" }
end
should "not make a new user" do
assert_no_difference 'User.count' do
post_via_redirect "users", :user =>#attr # enviem les dades d'un nou usuari via create (POST /users)
assert_template 'users/new' # ens retorna a users/new, que significa que no s'ha creat l'usuari
assert_select "div#error_explanation" # comprovem que conte missatges d'error
end
end
should "not make a new user (capybara)" do
assert_no_difference 'User.count' do
visit '/signup'
fill_in 'Name', :with => #attr[:name]
fill_in 'Email', :with => #attr[:email]
fill_in 'Password', :with => #attr[:password]
fill_in 'Confirmation', :with => #attr[:password_confirmation]
click_button 'Sign Up!'
assert_template 'users/new' # ens retorna a users/new, que significa que no s'ha creat l'usuari
assert_select "div#error_explanation" # comprovem que conte missatges d'error
end
end
end
end
While the first one works OK, the capybara one throws this error message:
================================================================================
Error:
test: signup failure should not make a new user (capybara). (UsersTest):
ArgumentError: #request must be an ActionDispatch::Request
test/integration/users_test.rb:30:in `block (4 levels) in <class:UsersTest>'
test/integration/users_test.rb:23:in `block (3 levels) in <class:UsersTest>'
================================================================================
the required *integration_test_helper.rb* file is an accumulator of all suposed solutions I've found googling around and that don't work for me.
require 'test_helper'
require 'capybara/rails'
require 'database_cleaner'
# Transactional fixtures do not work with Selenium tests, because Capybara
# uses a separate server thread, which the transactions would be hidden
# from. We hence use DatabaseCleaner to truncate our test database.
DatabaseCleaner.strategy = :truncation
class ActionDispatch::IntegrationTest
# Make the Capybara DSL available in all integration tests
include Capybara::DSL
# Stop ActiveRecord from wrapping tests in transactions
self.use_transactional_fixtures = false
teardown do
DatabaseCleaner.clean # Truncate the database
Capybara.reset_sessions! # Forget the (simulated) browser state
Capybara.use_default_driver # Revert Capybara.current_driver to Capybara.default_driver
end
end
Has anybody a solution? Should I try another Integration frmawork such as webrat?
My setup is:
marcel#pua:~/Desenvolupament/Rails3Examples/ror_tutorial$ rake about
About your application's environment
Ruby version 1.9.2 (x86_64-linux)
RubyGems version 1.8.15
Rack version 1.3
Rails version 3.1.3
JavaScript Runtime therubyracer (V8)
Active Record version 3.1.3
Action Pack version 3.1.3
Active Resource version 3.1.3
Action Mailer version 3.1.3
Active Support version 3.1.3
Middleware ActionDispatch::Static, Rack::Lock, #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000002b9bac0>, Rack::Runtime, Rack::MethodOverride, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::RemoteIp, Rack::Sendfile, ActionDispatch::Reloader, ActionDispatch::Callbacks, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, ActionDispatch::Head, Rack::ConditionalGet, Rack::ETag, ActionDispatch::BestStandardsSupport
Application root /mnt/dropbox/Dropbox/DESENVOLUPAMENT/Rails3Examples/ror_tutorial
Environment development
Database adapter sqlite3
Database schema version 20120127011330
Also
shoulda-context (1.0.0)
capybara (1.1.2)
Thanks

You're mixing up your test types and attempting to assert a template in the wrong type of test. You should only be asserting templates within your Functional tests, where you're just directly testing a controller and not actually simulating a user interaction.
Capybara is meant specifically for Integration testing, which is essentially running tests from the viewpoint of an end-user interacting with a browser. In these tests, you should not be asserting templates because an end-user can't see that deep into your application. What you should instead be testing is that an action lands you on the correct path.
current_path.should == new_user_path
page.should have_selector('div#error_explanation')
See "The DSL" section in Capybara's README on git: https://github.com/jnicklas/capybara
Official explanation for your issue: https://github.com/jnicklas/capybara/issues/240

For my completeness, because i'll know that I'll come back to this link over and over:
Those using test unit and capybara this is a good primer too: from techiferous.
Notice the use of assert page.has_content?("something")
This is good to use as well as assert_equal some_path, current_path for testing routes.
Is it the most complete, don't know, but you don't need much more.

Thanks for your tips #Ryan. I was trying to figure out how to translate some RSpec Integration test examples from http://ruby.railstutorial.org/chapters/sign-up#sec:rspec_integration_tests into Test::Unit + Capybara. The original RSpec Integration test was
it "should not make a new user" do
lambda do
visit signup_path
fill_in "Name", :with => ""
fill_in "Email", :with => ""
fill_in "Password", :with => ""
fill_in "Confirmation", :with => ""
click_button
response.should render_template('users/new')
response.should have_selector("div#error_explanation")
end.should_not change(User, :count)
end
end
So, after your answer, I supose that the original example should not contain response.should render_template('users/new')

Related

Devise logs out current user on redirect during rspec feature test

I am having an issue where I am writing an rspec feature test which authenticates to an application using devise and creates a record.
When hitting submit to create the record, on redirect, I am logged out of my session.
I can't seem to find anything odd in the logfile and I am able to reproduce this issue using both selenium-webdriver and chromedriver-helper.
I am wondering if anyone else has run into this issue and how you might have solved it.
My environment:
rails 4.2.6
devise 3.5.6
selenium-webdriver 2.53.0
chromedriver-helper 1.0.0
rspec-rails 3.4.2
capybara 2.7.0
spec/support/devise.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.include Devise::TestHelpers, type: :view
end
spec/features/notes/create_note_spec.rb:
require 'rails_helper'
feature 'note management' do
scenario 'user can create a new note' do
visit root_path
click_link 'Sign In'
fill_in 'user_email', with: user.email
fill_in 'user_password', with: CONFIG[:test_user_password]
click_button 'Log in'
click_link 'Notes'
click_link 'New Note'
fill_in 'note_title', with: Faker::Lorem.word
fill_in 'note_content', with: Faker::Lorem.paragraph
click_button 'Create Note'
expect(page).to have_content 'Note created'
end
end
I think you need to enable Warden Test Mode to make it all work.
Check this wiki page

How can I test integration with RSpec and Devise

I have quite some issues with testing the features of my rails application using RSpec. I have a company controller, and are using devise to make sure that you need to be logged in to access the controller.
I then have integration tests like the following:
describe "with valid information" do
before do
fill_in "company_address", with: "My special address"
fill_in "company_name", with: "My User"
fill_in "company_contact_email", with: "test#test.com"
fill_in "company_contact_name", with: "Someone Hello"
end
it "should create a company" do
expect { click_button submit }.to change(Company, :count).by(1)
end
end
It, of course, fails because I don't have a user who is logged in. I have tried creating a test helper like described here, and it works well for controllers, but not for integration tests.
What is the best way to log a user in with Devise, prior to these tests?
add file devise.rb to rspec/support
And here is content
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
Another way to solve your problem: Rails integration test with the devise gem

Response object in Rspec 1.3.4 with Capybara

I'm trying to use the following test to see if a login form correctly redirects:
it "should allow you to login" do
visit "/"
fill_in 'Email', :with => 'admin#example.com'
fill_in 'Pass', :with => 'password'
click_button 'Login'
response.should be_redirect
end
However, rspec fails with the message that response doesn't exist. I'm running a rails 2.3.4 app, so I have rspec 1.3.4 installed. How do I test for the response?
I assume this is an integration spec (what RSpec calls a 'request spec' in version 2)? If so, the response object is not available. For that, you'll need a controller spec, e.g.:
describe MyController do
it "should redirect" do
post :some_path, {:email => 'admin#example.com', :pass => 'password'}
response.should be_redirect
end
end
Or in your integration spec, test the expected path after a successful redirect. This works in RSpec 2, not sure about RSpec 1:
current_path.should == "/some_path"
I think you need to ask Capybara instead of the rails test helpers.
session.status_code.should == "301" # or 302
should do it.
Look at the examples here:
http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#status_code-instance_method

Rails by Example Tutorial Request Examples and Capybara

In the Rails on Rails Tutorial by Michael Hartl, the Request Examples make assertions on the response. I installed the cabybara and steak gem to create acceptance tests. After installing capybara, the requests examples are configured to use capybara. capybara examples have a different syntax and don't recognize the response.
How do I reset the Request Examples to run as RSpec example?
Test Error:
4) Users signup failure should not make a new user
Failure/Error: click_button
wrong number of arguments (0 for 1)
# ./spec/requests/users_spec.rb:13
# ./spec/requests/users_spec.rb:7
Request Example
describe "failure" do
it "should not make a new user" do
lambda do
visit signup_path
fill_in "Name", :with => ""
fill_in "Email", :with => ""
fill_in "Password", :with => ""
fill_in "Confirmation", :with => ""
click_button
response.should render_template('users/new')
end.should_not change(User, :count)
end
end
This might have something to do with rspec-rails request_example_group.rb.
request_example_group.rb
If the capybara lines are commented out, then the Request Examples are not defaulted to capybara.
capybara do
include Capybara
end
In the Acceptance examples, include capybara.
require File.expand_path(File.dirname(__FILE__) + '/acceptance_helper')
feature "This Is My First Feature", %q{
In order to ...
As a ...
I want to ...
} do
include Capybara
scenario "Scenario name" do
visit signup_path
fill_in "Name", :with => ""
fill_in "Email", :with => ""
fill_in "Password", :with => ""
fill_in "Confirmation", :with => ""
click_button "Sign up"
page.has_content?('welcome to the sample app')
end
end
I ended up forking rspec-rails and commenting out the capybara lines.
In the Gemfile, the gem installed from the fork.
Why bother? We want both white box and black box testing.
As you correctly point out in your answer, rspec-rails will include Capybara if it is installed. I think they're assuming that it never hurts to include Capybara, just in case you need it. Is that a problem for you? In other words, what specifically is the Capybara DSL conflicting with?
(This might be also be worth bringing up on the RSpec mailing list.)
As for the error you posted, it seems that you are simply missing an argument to the click_button method.

config.cache_classes = false messing up rspec tests?

I'm following the Ruby on Rails Tutorial by Michael Hartl (railstutorial.org).
At some point I got tired of tests failing just bescause the tests used old cached versions of classes, so I turned off config.cache_classes in the test environment. That fixed the issue and everything went good for some time.
Until I tried implementing the Integration tests in Chapter 8.4.3. At this point the data entered into the database with
it "should make a new user" do
lambda do
visit signup_path
fill_in "Name", :with => "Example User"
fill_in "Email", :with => "user#example.com"
fill_in "Password", :with => "foobar"
fill_in "Confirmation", :with => "foobar"
click_button
response.should have_selector("div.flash.success",
:content => "Welcome")
response.should render_template('users/show')
end.should change(User, :count).by(1)
end
would remain in the Database after each test, so only the first time this test ran it would work, after that it always fails until i manually empty the database.
Apart from that it worked.
But now in chapter 9, again the integration test fails:
describe "when signed in" do
before(:each) do
#user = Factory(:user)
visit signin_path
fill_in :email, :with => #user.email
fill_in :password, :with => #user.password
click_button
end
it "should have a signout link" do
visit root_path
response.should have_selector("a", :href => signout_path,
:content => "Sign out")
end
This time it just doesn't work, the user is not getting logged in and the resulting page has no sign out link, just the normal sign in link.
When testing this in a webbrowser it works fine.
It took me hours and days of searching the internet and testing different stuff and finally I found the solution: Turning config.cache_classes back on.
Now it works flawlessly.
So can anyone explain to me why config.cache_classes makes the tests fail? And how can I turn off caching without messing up my tests?
Thanks in Advance,
Best regards, Tobias
When you make a Capybara call, it uses rack-test to emulate a call to the rails app. Every time a call is completed, it reloads all rails classes. What this means is that the #user object you created before you called 'visit signin_path' gets nil'd out because all ActiveRecord objects have been reloaded.
When you set cache-classes to true, it tells Rack not to reload the ActiveRecord objects on every request, so your tests pass again.
I believe that if you want the test you wrote above to pass without turning on cache-classes, you should move the '#user = Factory(:user)' line below the 'visit signin_path' line.
I had exactly the same problem and like you setting config.cache_classes to true solved the problem. But caching classes in the test environment really isn't what you want I don't think. I certainly don't understand why caching classes makes the tests pass.
So the way I found to solve this was to install a database cleane as the reason the tests are failing is due to duplicate entries in the test database. https://github.com/bmabey/database_cleaner
Then in your gemfile, in your test group add this.
gem 'database_cleaner', '0.6.6'
then run "bundle install" to install this gem
Then... in your spec_helper.rb file, add this..
RSpec.configure do |config|
.
.
.
.
config.before(:each) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean
end
This will clear your test database before each run of your rspec tests.
Hope this helps.
Cheers,
mark.

Resources