Falling Leaves: the Ardes blog
Nick Rutherford

Switching an old test set from webrat to capybara might not have been the smartest of moves, but scoped steps which work are very alluring.

A couple of snags I stumbled upon today, which may be handy to someone, relate to rack-test, sessions, and http request methods.

For a more comprehensive introduction see Tim Riley's post.

First of all take the following example

Given I am logged in as an admin
When I go to "bulletin/volumes/"
And I follow "New Article"

This worked fine with webrat, but with capybara (and rack-test) as soon as the page changed the user lost their logged-in-ness, no log-out being performed, the session was just being lost by the testing framework.

While flailing around for a solution, or even better for the problem, I noted that named paths worked just fine. The culprit, it turns out, is the lack of a leading /. Laugh, cry, or curse profusely.

Given I am logged in as an admin
When I go to "/bulletin/volumes/"
And I follow "New Article"

The strange part is that both load the same page content (save_and_open), but one with the right session and one apparently starting a new one. An oddity of webrat => rack-test I suppose.

Also on the authentication features but a somewhat different topic is logging out. Log out links are popular, and with a restful setup this often means using :method => :delete.

Webrat gives a couple of options here, one is using Rails's test-unit get/post/put/delete methods, another is simply letting it figure out that the link has the :method => :delete javascript and using said method rather than get (looking at how it does this requires a strong stomach).

While capybara doesn't strictly support these shenanigans (progressive-enhancement and unobtrusive javascript are lauded) it does still act as an enabler. cucumber-rails has taken it upon itself to mimic webrat's javascript-hacked-link-spotting functionality, though myself I used another approach, sending the request directly.

This isn't necessarily a better idea, the work-arounds work and you could @javascript the scenario so it's executed fully, but it does give rise to the following discovery.

Capybara doesn't provide put and delete HTTP methods as part of its top level api; it is driver agnostic, and when using drivers backed by a web browser (selenium, for example) those browsers can't send put and delete requests (it's not a Rails testing framework, so faking it isn't applicable).

Still, rack-test does provide these methods, so if you don't mind your step being driver-specific (and thanks to tagging you shouldn't) you can do something like the following:

When /^I HTTP delete to the session path$/ do
  rack_test_session_wrapper = Capybara.current_session.driver
  rack_test_session_wrapper.process :delete, admin_session_path #[capybara](http://github.com/jnicklas/capybara) wrapper which will pass along the current rack env
end

#process is the important bit, if you just use delete path in your stepdef you'll get a delete request to the correct url, but it won't send the current rack environment so you'll lose your session, which in my case meant the user was not logged out, since the app didn't know who it was supposed to be logging out.

Now, on to those other broken stepdefs!

2 Responses to “Capybara attack: rack-test, lost sessions and http request methods ”

  1. HP

    HP Says:

    Wow, nicely explained. I’m just thinking of changing from from webrat to capybara. I didn’t know how to begin, but after reading your post I will give it a try.

  2. FredO

    FredO Says:

    Whoa! Thank you. Thank you. Thank you. I have been wrapped around the axle with this logging-in/logging-out issue, and yours is the best explanation that I have stumbled upon so far.

    Mille grazi.