I've got a simple spec
describe "Workers" do
describe "user attempts to view workers" do
context "admin logged in" do
end
context "non-logged in user" do
before do
visit workers_path
end
it "should redirect to home page" do
page.should have_content 'You are not authorized to access this page.'
end
end
end
end
This passes just fine. If I add save_and_open_page, the test run terminates and the output says "Process finished with exit code 0", but says nothing of the test status.
describe "Workers" do
describe "user attempts to view workers" do
context "admin logged in" do
end
context "non-logged in user" do
before do
visit workers_path
end
it "should redirect to home page" do
save_and_open_page
page.should have_content 'You are not authorized to access this page.'
end
end
end
end
Capybara: 2.1.0
launchy: 2.3.0
rspec: 2.13.0
rails: 3.2.13
Must have been a bad install of launchy. I downgraded to launchy 2.2.0 and everything worked, then I upgraded (back) to launchy 2.3.0 and things seem to be working fine.
Related
I am experiencing strange very test behavior, with logged in state being handled inconsistently.
The spec logs a user in, visits a (nested or un-nested) index page, and checks that the correct content is displayed. Records are fetched asynchronously, though I don't think this should have an impact.
When each spec is run individually, they each pass. When all specs are run together, they fail because the expected content is missing. Using save_and_open_page reveals this is because the login page is being rendered, rather than the expected index page.
Why does rspec think the user is not signed in when all specs are run together, yet each spec passes individually?
The tests look something like this
let(:user) {create :user}
let(:team) {create :team}
let(:country) {create :country}
before :each do
login_as( user, scope: :user )
end
describe 'unnested' do
it 'should have the expected content', :js do
visit users_path
is_expected.to have_content "some content on the page"
end
end
describe 'nested by team' do
it 'should have the expected content', :js do
visit team_users_path(team)
is_expected.to have_content "some content on the page"
end
end
describe 'nested by nationality' do
it 'should have the expected content', :js do
visit country_users_path(country)
is_expected.to have_content "some content on the page"
end
end
The specs all require javascript (I don't know whether that is important here).
Authentication is handled by Devise, and my rails_helper.rb includes
config.append_after(:each) do
DatabaseCleaner.clean
Warden.test_reset!
end
Why does rspec think the user is not signed in when all specs are run together, yet each spec passes individually?
It took a long time to get to the bottom of this. Posting this hear in case it is of help to anyone else encountering the same issue.
After much searching I eventually found this small mention that login_as may not work with Poltergeist when js is enabled on your test scenarios.
I tried the suggested fix to deal with shared DB connections. Unfortunately this resulted in the following errors:
PG::DuplicatePstatement at /session/users/signin
ERROR: prepared statement "a1" already exists
I tried using the Transactional Capybara gem, but this did not seem to work well with Poltergeist.
Eventually I abandonned login_as completely, and instead wrote a short method that visits the login page, fills in email and password, and logs in that way.
This solution appears to be working. It adds a little overhead, so I'm only using it for tests with JS.
If you are using Capybara gem then there is no need to use :js with test cases
What I did if this helps-
scenario "visit with user signed in" do
user = FactoryGirl.create(:user)
login_as(user, :scope => :user)
visit "/"
expect(current_path).to eq('/')
expect(page).to have_title "Some Random Title"
end
The other way you can login user using feature specs like-
feature 'User signs in' do
before :each do
#user = FactoryGirl.create(:user)
end
scenario "Signing in with correct credentials" do
visit "/"
fill_in "Email", with: #user.email
fill_in "Password", with: #user.password
click_button "Log In"
expect(current_path).to eq("/login/useremail/verification")
expect(page).to have_content "Signed in successfully"
end
end
If your pages are ajax then refer to this https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara
I am trying to test what happens after logging in through Devise gem. For example, I have the controller to go to student_dashboard_path after users successfully login.
How can I test this with Capybara and Rspec?
I currently have this in:
/spec/features/user_signs_in_sees_dashboard_spec.rb
require 'rails_helper'
feature 'User sign in' do
scenario 'successfully from sign in page and sees student dashboard' do
sign_in
visit student_dashboard_path
expect(current_path).to eq(student_dashboard_path)
end
end
and I have this in:
/spec/support/features/sign_in.rb
module Features
def sign_in
visit user_session_path
fill_in 'Email', with: User.first.email
fill_in 'Password', with: User.first.password
click_button 'Log in'
end
end
and I am getting this error message:
1) User signs in successfully from sign in and sees dashboard
Failure/Error: expect(current_path).to eq(student_dashboard_path)
expected: "/student/dashboard"
got: "/student/login"
I am not sure why I am not able to log in and see the student dashboard.
I'm leaving my original answer below for anyone still on Capybara < 2.5.0 but in 2.5.0 you can now do
expect(page).to have_current_path(<expected path>)
and it will use Capybara's waiting behavior while checking for the path
---- Below is only for Capybara version < 2.5.0
expect(current_path).to eq(...) doesn't wait for the path to change, it just compares to the current path at the time it's called. If you put a sleep after the click button I bet it works. A better solution would be to have something like
expect(page).to have_text('You are now logged in')
after the click_button. That would cause capybara to wait until the log in has completed, the page loads (and the logged in notice appears), and therefore until the current_path has changed too.
Use capybara save_and_open_page in middle to figure out if the fields are properly set. If you work on the same machine you can switch to selenium to test out on the real browser.
Also be sure that this code does not need any JS to work because default capybara matchers will not be able to run it.
this code
describe "HomePages" do
subject {page}
before { visit root_path }
describe "navigation" do
describe "click signup" do
before {find_button('Sign up').click}
current_path.should == sign_up_path
end
end
end
Gives me this error
#<NameError: undefined local variable or methodcurrent_path' for #>`
I'm using capybara version 1.1.2
What am I doing wrong?
I moved them into a describe block and it worked.
I try to pass this friendship features specs using Capybara, Rspec and FactoryGirls on Rails.
For some reason I can't understand why, I'm always getting failing at this error. Looks like the session is not being destroyed after running a test.
1) Friendships user requests friendship signed in POST /:username/friendships requests friendship
Failure/Error: page.should have_content 'Successfully requested friendship.'
expected there to be text "Successfully requested friendship." in "× You are already signed in. meeter Messages Notifications Settings Settings Logout Explore Dates nearby Suggestions You Messages Notifications Friends Publish Help No ideas found with your criteria."
# ./spec/features/friendships_spec.rb:32:in `block (5 levels) in <top (required)>'
Complete spec
require 'spec_helper'
include Warden::Test::Helpers
Warden.test_mode!
describe "Friendships" do
before(:each) do
#user = FactoryGirl.create(:user, :male)
#friend = FactoryGirl.create(:user, :female)
end
describe "GET /:username/friendships" do
pending "display friendships"
end
context "user requests friendship" do
context "signed in" do
after(:each) do
Warden.test_reset!
end
describe "POST /:username/friendships" do
it "requests friendship" do
login_as(#user, scope: :user)
visit user_path(#friend)
click_button 'Request Friendship'
page.should have_content 'Successfully requested friendship.'
logout(#user)
end
pending "friend receives confirmation notification"
end
describe "POST /:username/friendships/cancels" do
pending "cancels a friendship request sent"
end
end
context "not signed in" do
describe "POST /:username/friendships" do
it "requests friendship" do
visit user_path(#friend)
click_button 'Request Friendship'
page.should have_content 'You need to sign in first to continue.'
end
end
end
end
Any idea how to pass this?
I have a spec for testing a controller as below
require 'spec_helper'
describe ProductsController do
setup :activate_authlogic
describe "user not logged in" do
it "should not GET index" do
get :index
response.should redirect_to(login_path)
end
end
describe "user logged in" do
before(:each) do
UserSession.create :username => "rohit", :password => "test123"
end
it "should GET index" do
get :index
response.should redirect_to(products_path)
end
end
end
I have also used this line in spec_helper.rb
require "authlogic/testcase"
The test for "user not logged in passes" but for "user logged in" fails with
'ProductsController user is logged in should GET index' FAILED
expected redirect to "/products", got no redirect
It seems normal, because You fetch the '/products' url with a logged user. Then He see this page. He is not redirect to the page he see.
Each test are independant. No state are save in previous test.