zerosum dirt(nap)

evolution through a series of accidents

zerosum dirt(nap)

Easy Rails OAuth Integration Testing

March 19, 2011 by nap · Comments

A long while back I wrote a post about Twitter auth integration testing using Cucumber. Back then OAuth was just beginning to see widespread use, but it was nowhere near as popular as it seems to be today. In my latest side project, all logins are from Twitter or Facebook because there’s simply no need for local accounts (due to the nature of the app). But that also means that we needed an easy way to support third-party authentication in our integration tests.

We’re using OmniAuth to handle auth here, which is absolutely awesome. And we’re also using the equally-awesome Capybara for integration testing. Cucumber is no longer part of my standard testing repertoire. I could go into a long rambling post as to why, but chances are you already have some pretty good ideas about that. If you haven’t felt that pain, and Cucumber works for you, that’s great. Seriously. I’m extremely happy for you.

On the other hand, if you’re dissatisfied… Capy 1.0 comes with a swanky new minimalist RSpec-friendly acceptance testing DSL that you really ought to take a look at. The 1.0 gem hasn’t been released yet, but you can pull it into your project directly from the GitHub source if you specify it in your Gemfile. It’s really quite nice and simple, and I’m very happy with it so far.

If you want OAuth integration testing to be easy, you’ll want to make sure you’re using the OmniAuth 0.2.0 or later. Among it’s many fine features is a new integration test_mode that makes testing OAuth logins less sucky than it’s ever been before. Fortunately for us, Capybara and OmniAuth go together like giant chocholate swamp rat and creamy peanut butter. It pretty much works right out of the box.

To demonstrate, let’s add a nice little integration auth helper method that we can use in our request specs to log a user in (I like to put this in spec/support/integration_spec_helper.rb):

module IntegrationSpecHelper
  def login_with_oauth(service = :twitter)
    visit "/auth/#{service}"
  end
end

Now, in your spec_helper.rb, add the following:

RSpec.configure do |config|
  # ...
  config.include IntegrationSpecHelper, :type => :request
end

Capybara.default_host = 'http://example.org'

OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:twitter, {
  :uid => '12345',
  :nickname => 'zapnap'
})

Finally, let’s take a look at an example RSpec request spec that leverages this helper to test a workflow where a user login is required:

feature 'testing oauth' do
  scenario 'should create a new tiger' do
    login_with_oauth
    visit new_tiger_path

    fill_in 'tiger_name', :with => 'Charlie'
    fill_in 'tiger_blood', :with => 'yes'
    
    click_on 'Create Tiger'
    
    page.should have_content("Thanks! You are a winner!")
  end
end

That’s it. OmniAuth’s test mode automatically mocks out the authentication workflow, allowing us to supply our own auth results hash. Requests made to the usual /auth/provider URL will redirect immediately to the provider callback, which means we never have to hit the actual provider while testing (which also means that webmock or fakeweb remain happy).

This might seem simple, and it is. And that’s kind of a big deal. So now we can get back to writing stuff that isn’t plumbing and focusing on solving real problems ;).

blog comments powered by Disqus