Articles

Faster feature specs with authentication
Make specs more efficient to write and execute

I love writing feature specs with Rspec and Capybara. In fact, I prefer this way over using cucumber. The process is cleaner and faster for me and works well for the actual project I’m working on.

Most of the features of the RoR app I’m working on require authentification, so normally that implies that, for each feature spec, I have to make capybara execute all the authentication steps.

But this repetition can become inconvenient, because it slows down the tests, while authentication is already covered by its own integration tests.

Is there a faster, lighter way to make this authentication happen ?

After some search, I discovered that Devise doesn’t provide authentication helpers for integration/feature specs, which is justified as it contradicts the idea of full-stack testing.

But warden, on which Devise is based, provides this functionality.

Here we go with an example

Beware: when you use this technique, you don’t write full integration tests anymore in favor of taking a shortcut. A useful one IMHO as long as you know what you do.

This means you already should have authentication well tested, with its complete set of integration tests.

A barebones example

# file: spec/features/admin_users_datatable.rb 

require 'spec_helper'

# including some warden magic:
include Warden::Test::Helpers             

# telling warden we are testing stuff:
Warden.test_mode!                         

feature "(...)" do
  context "(...)" do
    before(:each) do
      admin = FactoryGirl.create(:admin)

      # our instant magic authentication:
      login_as(admin , :scope => :user)   
    end

    scenario "(...)", js: true do
      visit admin_users_path
      # (...)
    end
  end
end

A working example, with some more flesh around bones

# file: spec/features/admin_users_datatable.rb

require 'spec_helper'
include Warden::Test::Helpers
Warden.test_mode!

feature "admin searching for a specific user" do
  context "when logged in as admin" do
    before(:each) do
      admin = FactoryGirl.create(:admin)
      login_as(admin , :scope => :user)
      user1 = FactoryGirl.create(:user, email: 'foo@foo.com')
      user2 = FactoryGirl.create(:user, email: 'bar@bar.com')
    end

    scenario "admin searches for a specific user", js: true do
      visit manage_users_path
      page.body.should     have_content 'foo@foo.com'
      page.body.should     have_content 'bar@bar.com'
      fill_in 'Search', with: 'foo'
      page.body.should     have_content 'foo@foo.com'
      page.body.should_not have_content 'bar@bar.com'
    end
  end
end

More info

Posted January 16, 2013
Blog comments powered by Disqus.
author Daniel Reszka
Crafted with by Daniel Reszka who lives and works in Berlin building useful things. You should follow him on social media.