All good developers should write tests, and anyone with a high stake in a web app should write acceptance tests. Acceptance tests use a web driver like Capybara to test the full functionality of your web app by interacting directly with view elements the same way a user would (clicking links, filling out forms, etc.)

My only problem with acceptance tests is that they can be a bit slow, so i’m always looking for ways to speed mine up. One of my pain points is since everything is done via manual interaction with a headless website, any test requiring a logged in user (most of them) also requires that before it is run, Capybara must log the user in by visiting the sign in path and entering valid credentials. While I still think manual sign in should be tested, it doesn’t need to be tested every single time we run another test.

If you’re doing authentication with Devise to speed things up a bit we can stub out a logged in user with Warden’s built in test helpers.

It works like this when you’re running a non-acceptance test we want to use Devise’s sign_in helper since we have direct access to the request object (not available during capybara/acceptance tests). All other times we want to use Warden’s login_as method.

Here is an example of as_userand as_visitor helpers that do just that:

include Devise::TestHelpers

# gives us the login_as(@user) method when request object is not present
include Warden::Test::Helpers
Warden.test_mode!

# Will run the given code as the user passed in
def as_user(user=nil, &block)
  current_user = user || Factory.create(:user)
  if request.present?
    sign_in(current_user)
  else
    login_as(current_user, :scope => :user)
  end
  block.call if block.present?
  return self
end


def as_visitor(user=nil, &block)
  current_user = user || Factory.stub(:user)
  if request.present?
    sign_out(current_user)
  else
    logout(:user)
  end
  block.call if block.present?
  return self
end

I then needed to call Warden.test_reset! after each test to ensure correct functionality

RSpec.configure do |config|
  config.after(:each) { Warden.test_reset! }
end

Then in my tests (shown here with capybara/rspec, I can simply log in a user like this:

let(:user) { Factory.create(:user) }

# To use the methods you can call
# methods directly on them like this:

scenario 'works while logged in' do
  as_user(user).visit teach_path
  # ...

# Or you can pass the code you wish
# to run in a block:

scenario 'creating a class' do
  as_user(user) do
     visit teach_path
     click_link('Create')
     current_path.should == new_course_path
     fill_in 'course_title',       :with => course_stub.title
     fill_in 'course_teaser',      :with => course_stub.teaser
     fill_in 'course_experience',  :with => course_stub.experience
     click_button 'Submit'
     # ...

It’s that simple. With a few lines of code I was able to speed up my tests and keep all expected behavior. For more details on how this works, you can go to the wiki page I created: https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara . Good luck and happy testing!