Capybara test user sign_in - ruby-on-rails

i'm run into the problem with testing user sign in procces
here my test
require 'spec_helper'
include Warden::Test::Helpers
include Devise::TestHelpers
describe "UserSignin" do
it "should allow a registered user to sign in" do
user = FactoryGirl.create(:employer, :email => "email#email.com")
user.confirm!
visit "/users/sign_in"
fill_in "Email", :with => user.email
fill_in "Password", :with => "12345678"
click_button "Sign in"
current_path.should == '/employer'
expect(page).to have_content('My Account')
end
end
if it's improtant i'm using device for authentication
in factory i also have :employer factory
problem with authenticate
after clicking sign_in i'v got an error invalid email or password
UPDATE
there was problem with configs for test environment in spec helper
the solution is to set:
DatabaseCleaner.strategy = :truncation

Related

Testing Devise Using capybara rspec and factory girl

i'm new at rails and i'm testing my devise gem User with capybara rspec and factory girl.
Here's spec code:
require 'rails_helper'
RSpec.describe User, type: :request do
it "displays the user's email after successful login" do
user = FactoryGirl.create(:user, email: 'test#test.com', password: 'password')
visit root_url
fill_in 'Email', with: 'test#test.com'
fill_in 'Password', with: 'password'
click_button 'Log in'
expect page.has_content?('jdoe')
end
end
The problem is in
expect page.has_content?('jdoe')
No matter what i put instead 'jdoe' test works perfectly without any errors.
Here's factory:
FactoryGirl.define do
factory :user do
email 'test#test.com'
password 'password'
password_confirmation 'password'
end
end
Maybe I missed something or going with a wrong way. How should I test here?
# spec/features/sessions_spec.rb
require 'rails_helper'
RSpec.feature "Sessions" do
scenario "displays the user's email after successful login" do
user = FactoryGirl.create(:user)
visit root_url
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
click_button 'Log in'
expect(page).to have_content("Signed in successfully")
# will give a false postitive if form is rerended?
expect(page).to have_content(user.email)
end
end
A few things here:
Use a feature and not a request spec for end to end testing.
Don't hardcode object attributes. The whole point of factories is that the factory takes care of generating unique data so that the tests don't give false positives due to residual state.
Use expect(page).to instead of expect page.should. expect(page).to sets a subject and uses a RSpec matcher which will show you the text of the page in an error message if it does not match.

How to factor Capybara rspec testing code?

I need to test a system in which everything is available only after a user is signed in using Devise. Every time I use "it" I have to include the signup code.
Is there a way to factor the code below so that the "let's me make a new post" test and similar tests won't have to include the sign up?
describe "new post process" do
before :all do
#user = FactoryGirl.create(:user)
#post = FactoryGirl.create(:post)
end
it "signs me in" do
visit '/users/sign_in'
within(".new_user") do
fill_in 'Email', :with => 'user#example.com'
fill_in 'Password', :with => 'password'
end
click_button 'Log in'
expect(page).to have_content 'Signed in successfully'
end
it "let's me make a new post" do
visit '/users/sign_in'
within(".new_user") do
fill_in 'Email', :with => 'user#example.com'
fill_in 'Password', :with => 'password'
end
click_button 'Log in'
visit '/posts/new'
expect( find(:css, 'select#post_id').value ).to eq('1')
end
end
Your first option is to use the Warden methods provided, as per the documentation on this page:
https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara
Your second option is just to login for real in your tests as you have done in your examples. You can streamline this though by creating some helper methods to do the login work rather than duplicating the code in all of your tests.
To do this, I would create a support directory within your spec directory, and then a macros directory within that. Then create a file spec/support/macros/authentication_macros.rb:
module AuthenticationMacros
def login_as(user)
visit '/users/sign_in'
within('.new_user') do
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
end
click_button 'Log in'
end
end
Next, update your RSpec config to load your macros. In either spec_helper.rb or rails_helper.rb if you're using a newer setup:
# Load your support files
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Include the functions defined in your modules so RSpec can access them
RSpec.configure do |config|
config.include(AuthenticationMacros)
end
Finally, update your tests to use your login_as function:
describe "new post process" do
before :each do
#user = FactoryGirl.create(:user)
#post = FactoryGirl.create(:post)
login_as #user
end
it "signs me in" do
expect(page).to have_content 'Signed in successfully'
end
it "let's me make a new post" do
expect( find(:css, 'select#post_id').value ).to eq('1')
end
end
Obviously, make sure you have password defined in your user factory.

rspec and capybara testing devise registration, user already exists failure

I am trying to test my signup and sign in through devise using rspec, capybara and factoryGirl
the problem is that the tests keep failing in the signin test with this message from activeRecord:
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
these are my tests:
describe "GET /users/sign_up" do
it "register user and send email" do
user = FactoryGirl.build(:user)
visit new_user_registration_path
fill_in "Email", :with => user.email
fill_in "Password", :with => user.password
fill_in "Password confirmation", :with => user.password
fill_in "Name", :with => user.name
click_button "Sign up"
ActionMailer::Base.deliveries.last.to.should include(user.email)
page.should_not have_content("Password confirmation")
end
end
and the signin test:
describe "GET /users/sign_in" do
it "try to login email password" do
user = FactoryGirl.create(:user)
visit new_user_session_path
fill_in "Email", :with => user.email
fill_in "Password", :with => user.password
click_button "Sign in"
page.should have_content("Signed in successfully.")
end
end
while searching for a solution I saw some people added database_cleaner and said that suppose to help. so i added the database_cleaner gem
and added these lines to my spec_helper.rb file:
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
but it still not working.
would love some guidance or idea. thanks!
adding factory girl code:
require 'factory_girl'
FactoryGirl.define do
factory :user do |f|
f.sequence(:email) {|n| "dodo#{n}#gmail.com"}
f.password "secret123"
f.name "dodo"
end
factory :partner do |f|
f.company "spectoos"
end
end
I found my problem.
the test was failing because the user that I created with factoryGirl is not confirmed. and I have the confirmable on for devise.
any after this line:
user = FactoryGirl.create(:user)
I added this line:
user.confirm!
and now its fine.
thanks

Capybara not working with factory girl

I'm using minitest with factory girl and capybara for integration tests. Capybara works fine when I don't user factory girl to create a user object, like this:
it "logs in a user successfully" do
visit signup_path
fill_in "Email", :with => "joey#ramones.com"
fill_in "Password", :with => "rockawaybeach"
fill_in "Password confirmation", :with => "rockawaybeach"
click_button "Create User"
current_path == "/"
page.text.must_include "Signed up!"
visit login_path
fill_in "Email", :with => "joey#ramones.com"
fill_in "Password", :with => "rockawaybeach"
check "Remember me"
click_button "Log in"
current_path == "/dashboard"
page.text.must_include "Logged in!"
page.text.must_include "Your Dashboard"
end
But as soon as I try to create a user with factory girl weird things start happening, such as the visit method and click_button methods stop working. For instance, there doesn't seem to be anything wrong with this test:
require "test_helper"
describe "Password resets" do
before(:each) do
#user = FactoryGirl.create(:user)
end
it "emails user when requesting password reset" do
visit login_path
click_link "password"
fill_in "Email", :with => user.email
click_button "Reset my password"
end
end
And here's my factories.rb:
FactoryGirl.define do
factory :user do |f|
f.sequence(:email) { |n| "foo#{n}#example.com" }
f.password "secret"
f.password_confirmation "secret"
end
end
Here's the actual error that I'm getting:
est_0001_emails user when requesting password reset 0:00:01.624 ERROR
undefined local variable or method `login_path' for #<#<Class:0x007fc2db48d820>:0x007fc2df337e40>
But, visit login_path works fine if I remove #user = FactoryGirl.create(:user)
Is this a bug with Capybara? Or am I doing something wrong here?
I finally got this to work using the DatabaseCleaner gem using DatabaseCleaner.strategy = truncation. Here's what I ended up with:
test_helper.rb
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "minitest/autorun"
require "capybara/rails"
require "active_support/testing/setup_and_teardown"
class IntegrationTest < MiniTest::Spec
include Rails.application.routes.url_helpers
include Capybara::DSL
register_spec_type(/integration$/, self)
def last_email
ActionMailer::Base.deliveries.last
end
def reset_email
ActionMailer::Base.deliveries = []
end
end
class HelperTest < MiniTest::Spec
include ActiveSupport::Testing::SetupAndTeardown
include ActionView::TestCase::Behavior
register_spec_type(/Helper$/, self)
end
Turn.config.format = :outline
# Database cleaner.
DatabaseCleaner.strategy = :truncation
factories.rb
FactoryGirl.define do
sequence :email do |n|
"email#{n}#example.com"
end
factory :user do
email
password "secret"
password_confirmation "secret"
end
end
integration/login_integration_test.rb
require "test_helper"
describe "Login integration" do
it "shouldn't allow an invalid login" do
visit login_path
click_button "Log In"
page.text.must_include "invalid"
end
it "should login a valid user" do
DatabaseCleaner.clean
user = FactoryGirl.create(:user)
visit login_path
within ".session" do
fill_in "session_email", :with => user.email
fill_in "session_password", :with => "secret"
end
click_button "Log In"
page.text.must_include "Logged in!"
save_and_open_page
end
end
Remove login_path and try to use url
for example
visit "/users/login" #login_path

error using rspec for devise

I am using rspec for testing devise authentication. Following is my code
require 'spec_helper'
describe User do
describe "user registration" do
it "allows new users to register with an email address and password" do
get "/users/sign_up"
fill_in "Email", :with => "abc#example.com"
fill_in "Password", :with => "abc123"
fill_in "Password confirmation", :with => "abc123"
click_button "Sign up"
response.should have_content("Welcome! You have signed up successfully.")
end
end
end
I am getting the following error.
"NoMethodError:undefined method `get' for #"
You are using controller methods and integration test methods (Capybara) in a Model spec. It will not work.
A model spec (UNIT test) will contain things like:
Test your validators/relationships
Test scopes
Methods of your model
Check out this series of Blog articles on testing with RSpec, it should help:
http://everydayrails.com/2012/03/12/testing-series-intro.html
This seems to be an model spec (describe User) which does not allow to run requests, but you probably want to write a controller spec (describe UsersController) or even an integration test.
If you are using the default rspec layout, just move your code to the appropriate directory (spec/controllers or spec/integration). I would do an integration test:
# In spec/integration/user_registration_spec.rb
require 'spec_helper'
describe "User registration" do
it "allows new users to register with an email address and password" do
get "/users/sign_up"
fill_in "Email", :with => "abc#example.com"
fill_in "Password", :with => "abc123"
fill_in "Password confirmation", :with => "abc123"
click_button "Sign up"
response.body.should have_content("Welcome! You have signed up successfully.")
end
end
Is this file in the spec/models directory? I'm guessing that's the case since you're describeing a User. The way you wrote your test is a mix between a controller-style test and an integration (acceptance) test. This is probably what you want:
require 'spec_helper'
describe User do
describe "user registration" do
it "allows new users to register with an email address and password" do
visit "/users/sign_up"
fill_in "Email", :with => "abc#example.com"
fill_in "Password", :with => "abc123"
fill_in "Password confirmation", :with => "abc123"
click_button "Sign up"
page.should have_content("Welcome! You have signed up successfully.")
end
end
end
Put this file in the spec/integration or spec/requests directory.
I would probably try something like this
require 'spec_helper'
describe User do
describe "user registration" do
it "allows new users to register with an email address and password" do
visit new_user_registration_path
current_path.should be(new_user_registration_path)
fill_in "user[email]", :with => "abc#example.com"
fill_in "user[password]", :with => "abc123"
fill_in "user[password_confirmation]", :with => "abc123"
click_button "Sign up"
expect { click_button submit }.to change(User, :count).by(1)
response.should be_redirect
response.should have_content("Welcome! You have signed up successfully.")
end
end
end
But I can highly recommend to using FactoryGirl for generating new values. Also check, which Devise modules do you use. For example if you are using a Confirmable modul, is obvious that this approach is wrong. Some useful article.

Resources