Given I Am Signed in Using capybara-webkit

Inspired by the blog post “Capybara, Cucumber and How the Cookie Crumbles”:http://collectiveidea.com/blog/archives/2012/01/05/capybara-cucumber-and-how-the-cookie-crumbles/, I wanted to write a Cucumber step that signs a user directly into my application, without the need to navigate to a log-in page and submit a form. I am not thrilled about the stubbing and monkey patching discussed in that post, and I am also not concerned about doing something that is specific to the “capybara-webkit”:https://github.com/thoughtbot/capybara-webkit driver used on my current project. The result is a capybara-webkit specific way of bypassing authentication from my Cucumber features.

The previously mentioned blog post sets a cookie with a token that identifies the logged in user. I decided to simply use the user’s ID instead:

  def current_user
    return @current_user if defined?(@current_user)

    if Rails.env.test? && cookies[:test_user_id]
      @current_user = User.find(cookies[:test_user_id])
    end
  end

Allowing a production user to be automatically signed into the application just by having their user ID in a cookie is an exceedingly poor idea; thus, the check to only allow this type of login to work in the @test@ environment.

Now all the Cucumber step needs to do is to set a cookie with the appropriate user ID:

  When /^I am signed in as "([^"]*)"$/ do |email|
    user_id = User.find_by_email!(email).id
    page.driver.browser.set_cookie(
      "test_user_id=#{user_id}; path=/; domain=localhost")
  end

Now when the next request is made from the test, the specified user will be set in the @current_user@ call.

h3. Notes

* This particular test suite is configured to access the web server using @http://localhost:8888@. I first tried setting the domain in the cookie to be @127.0.0.1@, but it was not working. I am not sure what the default Capybara configuration is, but if you run into issues try both @127.0.0.1@ and @localhost@ as the domain in the cookie.
* In addition to the user ID I also need to fake out several more cookies that the application sets when a user signs in using the normal form. I ran into some trouble setting these until I escaped the values with @CGI.escape@:

  page.driver.browser.set_cookie(
    "#{key}=#{CGI.escape(value.to_s)}; path=/; domain=localhost")

* The version of capybara-webkit I am using is a little older; it appears that a new interface for setting/getting cookies has been added in the form of a @cookies@ method on the “Capybara::Driver::Webkit class”:http://www.rubydoc.info/gems/capybara-webkit/0.12.1/Capybara/Driver/Webkit. I haven’t used this interface yet so I can’t speak to how it may differ the approach described above.