This is my first time writing a test using RSpec with Capybara. Heres what I have so far:
require 'capybara/rspec'
describe "the signin process" do
before :each do
User.make(:email => 'test#test.com', :password => 'thisisatest')
end
it 'signs me in' do
visit 'sessions/new'
within("session") do
fill_in 'user email', :with => 'test#test.com'
fill_in 'password', :with => 'thisisatest'
end
click_link 'login'
expect(page).to have_content 'Thank You'
end
end
Here is the message i got when I ran the test:
the signin process
signs me in (FAILED - 1)
Failures:
1) the signin process signs me in
Failure/Error: User.make(:email => 'yedidyaweiner#gmail.com', :password => 'Shabbos!78')
NameError:
uninitialized constant User
# ./spec/features/sign_in_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 0.0006 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/features/sign_in_spec.rb:8 # the signin process signs me in
How can i fix this so the test passes? any suggestion on how to better write a test?
require 'spec_helper'
describe "The signin process" do
let!(:user) { User.create email: 'test#test.com', password: 'secret' }
it 'signs me in' do
visit 'sessions/new'
within("session") do
fill_in 'user email', with: user.email
fill_in 'password', with: user.password
end
click_link 'login'
expect(page).to have_content 'Thank You'
end
end
Related
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.
I am using Rspec, Capybara and Devise. I need to be able to sign in.
My test:
describe "POST #create" do
context "with valid params" do
it "creates a new Poll" do
#user = FactoryGirl.create(:user)
visit new_user_session_path
fill_in "user_email", :with => #user.email
fill_in "user_password", :with => "qwerty"
click_button "commitSignIn"
visit '/'
expect(page).to have_selector('.signin_username') # OK
binding.pry
end
end
end
In the Pry console, I tried to output current_user:
[1] pry(#<RSpec::ExampleGroups::PollsController::POSTCreate::WithValidParams>)> put current_user
NameError: undefined local variable or method `current_user' for #<RSpec::ExampleGroups::PollsController::POSTCreate::WithValidParams:0x00000008011c08>
from /home/kalinin/.rvm/gems/ruby-2.0.0-p598/gems/rspec-expectations-3.3.0/lib/rspec/matchers.rb:966:in `method_missing'
For further tests I need the current_user set.
Here's how I have included the Devise::TestHelpers:
# spec/spec_helper.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.include Devise::TestHelpers, type: :helper
config.include ApplicationHelper
end
I moved mine into a shared_context:
shared_context 'login' do
def log_in_with_user(user, options={})
email = options[:email] || user.email
password = options[:password] || user.password
# Do login with new, valid user account
visit new_user_session_path
fill_in "user_email", with: email
fill_in "user_password", with: password, exact: true
click_button "Log In"
end
end
Then in your test you can do:
describe "POST #create" do
include_context 'login'
let(:current_user) { FactoryGirl.create(:user) }
before do
log_in_with_user current_user
end
context "with valid params" do
it "creates a new Poll" do
visit '/'
expect(page).to have_selector('.signin_username') # OK
binding.pry
end
end
end
I'm trying requests tests with Capybara and it doesnt seem to work. This is my test file:
describe "Sessions", :type => :request do
let(:company) { FactoryGirl.create(:company) }
let(:user) { FactoryGirl.create(:admin, company_id: company.id ) }
describe "login page" do
it "signs me in" do
visit '/users/sign_in'
within("#new_user") do
fill_in 'Email', :with => user.email
fill_in 'Password', :with => user.password
end
click_button 'Sign in'
expect(page).to have_content 'Agenda'
end
end
end
Throws the following Error:
Failure/Error: expect(page).to have_content 'Agenda'
expected #has_content?("Agenda") to return true, got false
Im not sure if the problem is at logging in or at redirecting. But if i change the last line in the test for this:
expect(page).to have_content 'Invalid email'
I get the same Error.
Thanks in advance.
UPDATE:
i'm using devise for login
Simplest thing is to use screenshot_and_save_page to take a screenshot of the page just before the failing test, maybe you can determine what the problem is there.
I don't understand why the first of the following test passes while the second does not. Obviously, it's because I'm using a block in the first one, but what does it actually do compared to the second scenario?
require 'spec_helper'
feature "Edit user account" do
let(:user) { FactoryGirl.create(:user) }
before(:each) do
sign_in_as!(user)
visit '/settings'
end
scenario 'A user should be able to update their login info with current password' do
fill_in 'user_first_name', :with => 'Mario'
fill_in 'user_email', :with => 'mario#bross.com'
fill_in 'user_password', :with => 'goshrooms'
fill_in 'user_current_password', :with => 'ilovebananas'
click_button 'Update'
user.reload do |u|
u.first_name.should eq 'Mario'
u.email.should eq 'mario#bross.com'
u.password.should eq 'goshrooms'
end
current_path.should eq '/settings'
page.should have_content('You updated your account successfully.')
end
scenario "A user should be able to update their login info with current password" do
fill_in "user_password", :with => "magical"
fill_in "user_current_password", :with => 'ilovebananas'
click_button "Update"
current_path.should eq "/settings"
user.reload.password.should eq "magical"
end
end
When running the tests I get:
1) Edit user account A user should be able to update their login info with current password
Failure/Error: user.reload.password.should eq "magical"
expected: "magical"
got: "ilovebananas"
(compared using ==)
As mentioned in the comments above, password is not a field in the DB. So instead of testing on password, I tested on the encrypted_password field.
feature "* Edit user account:" do
let(:user) { FactoryGirl.create(:user) }
before(:each) do
visit "/login"
fill_in "user_email", :with => user.email
fill_in "user_password", :with => "ilovebananas"
click_button "Sign in"
visit '/settings'
#old_encrypted_password = user.encrypted_password
end
scenario 'A user should be able to update their info with current password' do
....
user.reload.encrypted_password.should_not eq #old_encrypted_password
end
end
A couple tests I have are failing all of a sudden and I'm not sure why. Here are my tests that are failing:
Failures:
1) Users signup success should make a new user
Failure/Error: response.should render_template('users/show')
Expected block to return true value.
# ./spec/requests/users_spec.rb:33:in `block (5 levels) in <top (required)>'
# ./spec/requests/users_spec.rb:26:in `block (4 levels) in <top (required)>'
2) Users sign in/out success should sign a user in and out
Failure/Error: controller.should be_signed_in
expected signed_in? to return true, got false
# ./spec/requests/users_spec.rb:67:in `block (4 levels) in <top (required)>'
And here are the tests:
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 render_template('users/show')
end.should change(User, :count).by(1)
end
describe "success" do
it "should sign a user in and out" do
user = Factory(:user)
visit signin_path
fill_in "Email", :with => user.email
fill_in "Password", :with => user.password
click_button
controller.should be_signed_in
click_link "Sign out"
controller.should_not be_signed_in
end
end
The thing is it passed before and the only thing I did was change the theme (css) of my app. I double checked it in production and it works perfectly. A user does get signedin/out and it does get created. Only the test is failing. Why would this be?
Do you have some uniqueness constraint on the users table? Since you aren't using a factory there you might be trying to create a user already in your DB