rspec and capybara testing devise registration, user already exists failure - ruby-on-rails

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

Related

How to use RSpec and FactoryGirl for simple sign in

I just started using factory_girl and I tried using:
user = FactoryGirl.create(:user)
but that doesn't seem to work. Here is my code:
RSpec.feature "Send a message" do
scenario "Staff can send a message" do
visit "/"
group = Group.create!(name: "Group A")
user = FactoryGirl.create(:user)
fill_in "Email", with: "staff#example.com"
fill_in "Password", with: "password"
click_button "Sign in"
person = Person.create!(groups: [group], phone_number: "+161655555555")
message = Message.create(body: "Test Message", group_ids: [group.id])
fill_in "Enter a Message:", with: "Test Message"
check "message_group_#{group.id}"
click_button "Send Message"
expect(page).to have_content("Messages on their way!")
expect(page).to_not have_content("Body can't be blank")
expect(page).to_not have_content("Group ids can't be blank")
end
Here is my factory:
FactoryGirl.define do
factory :user do
email "cam#example.com"
password "password"
end
end
Simple right? What could be going wrong?
user = FactoryGirl.create(:user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
Also, if you use devise, you can add next lines to spec/support/warden.rb and use method login_as(user) instead of submitting login form.
RSpec.configure do |config|
config.include Warden::Test::Helpers, type: :feature
config.include Warden::Test::Helpers, type: :request
config.before :suite do
Warden.test_mode!
end
config.after :each do
Warden.test_reset!
end
end

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.

Capybara test user sign_in

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

devise-async & sidekiq - RSpec integration spec fails

I have the following integration tests written for my application's Devise based authentication:
# password_resets_spec.rb
require 'spec_helper'
describe "PasswordResets" do
it "emails user when requesting password reset" do
user = FactoryGirl.create(:user)
reset_email # or else we'll have the confirmation email in the last assertion
visit new_user_session_path
click_link "password"
fill_in "Email", with: user.email
click_button "Send"
current_path.should eq(new_user_session_path)
page.should have_content "Will receive"
last_email.to.should include(user.email)
end
it "doesn't email invalid user when requesting password reset" do
user = FactoryGirl.create(:user)
reset_email # or else we'll have the confirmation email in the last assertion
visit new_user_session_path
click_link "password"
fill_in "Email", with: 'nobody#example.com'
click_button "Send"
current_path.should eq(user_password_path)
page.should have_content "correct"
last_email.should be_nil
end
end
and:
# registers_spec.rb
require 'spec_helper'
describe "Registers" do
it "should inform the user to confirm account" do
user = FactoryGirl.build(:user)
visit new_user_registration_path
fill_in "Username", with: user.username
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Confirm password", with: user.password
click_button "Send"
current_path.should eq(root_path)
page.should have_content "You have been sent"
last_email.to.should include(user.email)
end
end
I am using Sidekiq for background jobs and last_email and reset_email come from the following module:
module MailerMacros
def last_email
ActionMailer::Base.deliveries.last
end
def reset_email
ActionMailer::Base.deliveries.clear
end
end
All three of these specs work fine when deactivating devise-async on the User model. When I switch it on, the password reset specs run OK but the register one complains about last_email being nil and I don't understand why. Is the confirmation mail sent out somehow differently compared to the password reset ones?
Note that I have the require 'sidekiq/testing/inline' line in my spec_helper.rb file so that the email sending is done instantaneously and config.action_mailer.delivery_method = :test is set for my test environment so that no actual email sending is taking place.
I have solved the issue with mhfs' help. The problem was that I had config.use_transactional_fixtures set to true in spec_helper.rb and because of this users were created in a transaction and the after_commit hook which would send the email was never called. Password resets apparently didn't run inside transactions, that's why they worked.
So I had to switch use_transactional_fixtures off and use database_cleaner to keep my database tidy.
Here's what I had to modify:
Add gem 'database_cleaner' to my Gemfile.
Obviously modify spec_helper.rb:
config.use_transactional_fixtures = false
Add the following to spec_helper.rb:
config.before(:each) do
with_transaction_callbacks = example.metadata[:with_transaction_callbacks]
if with_transaction_callbacks
DatabaseCleaner.strategy = :truncation
else
DatabaseCleaner.strategy = :transaction
end
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
And lastly redo my block in registers_spec.rb to read:
describe "Registers" do
it "should inform the user to confirm account", with_transaction_callbacks: true do
[ --- 8< snip --- ]
end
end
The magic happens in the second line.
PS. This Stack Overflow topic as well as the article linked from within it also helped.

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

Resources