I'm new to Rspec, but I've managed to put together a working (at least in my tests so far) setup that lets me test various behavior in logged in/logged out states using FactoryGirl + Devise and Warden helpers. The flow follows these basic steps:
I've looked a lot of code examples to get this working, but I've yet to find a complete round trip and although I know this is working in my setup, I am wondering if it's the proper way, specifically, am I am duplicating anything unnecessarily (like user sign in tear downs) or creating future unexpected behavior.
Here is the relevant code for each step and a sample test:
spec/factories.rb
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "person #{n}"}
sequence(:email) { |n| "person#{n}@example.com" }
password 'foobar'
password_confirmation 'foobar'
confirmed_at Time.now
sequence(:id) { |n| n }
end
end
spec/rails_helper.rb
...
# Add login/logout helpers from Devise
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
# Include Warden test helpers specifically for login/logout
config.include Warden::Test::Helpers
# Add capybara DSL
config.include Capybara::DSL
# Tear down signed in user after each test
config.after :each do
Warden.test_reset!
end
spec/views/static_pages (sample test)
RSpec.describe 'static_pages home, signed in', type: :view do
before(:each) do
@user = build(:user)
login_as(@user)
end
it 'should display the correct links when signed in' do
visit root_path
# links which persist in both states
expect(page).to have_link('Site Title', href: root_path, count: 1)
# links which drop out after login
expect(page).not_to have_link('Login', href: new_user_session_path)
expect(page).not_to have_link('Join', href: signup_path)
# links which are added after login
expect(page).to have_link('Add Item', href: new_item_path)
expect(page).to have_link('My Items', href: myitems_path)
end
end
Your setup is totally OK. One thing as @Greg Tarsa said is that you may want to perform such kind of tests at feature level. Another thing from me is that one should use one single spec to test one single thing e.g. it should be single (or several) expect
in it
block. But it's not strict rule - it's up to you to decide.
And I made some refactoring of your setup with previous tips and feature-style syntax. Maybe it would be useful:
background do
@user = build(:user)
login_as(@user)
visit root_path
end
scenario "links persist in both states" do
expect(page).to have_link('Site Title', href: root_path, count: 1)
end
scenario "links dropped out after login" do
expect(page).not_to have_link('Login', href: new_user_session_path)
expect(page).not_to have_link('Join', href: signup_path)
end
scenario "links added after login" do
expect(page).to have_link('Add Item', href: new_item_path)
expect(page).to have_link('My Items', href: myitems_path)
end