Cucumber: Switching from Webrat to Capybara

Published on and tagged with cucumber  ruby on rails  testing

My current testing tool of choice is Cucumber. Cucumber itself integrates well with other tools. One of those tools is Webrat, which allows you to access your application without a browser and to perform actions like clicking on a link or filling out forms. It works fine with Rails 2.3.x, but not with Rails 3 (at least I was not able to make it work, and on RailsPlugins.org the current version of Webrat, 0.7.2.beta.1, is listed as “Maybe [working] with Rails 3”). Fortunately, there is an alternative working with both Rails versions: Capybara. And so I decided to make the switch from Webrat to Capybara.

Before making the switch, I recommend to run your Cucumber tests to ensure all tests pass:

$ cucumber features

As usual when adding new dependencies, you have to modify the Gemfile of your app. Replace the Webrat entry with:

gem "capybara", "0.3.9"

and run:

$ bundle update

With Capybara installed, you have to setup Cucumber to use Capybara by running one of the following commands:

// Rails 2.3.9
$ script/generate cucumber --rspec --capybara

// Rails 3.0.0
$ rails generate cucumber:install --rspec --capybara

Now, you are ready to run the tests again. If you are lucky, all tests pass, which means there is nothing more to do. However, I think it is more likely you will get a bunch of errors and maybe even some failing tests.

The errors I got were “undefined method” errors. They are relatively easy to fix by replacing the no longer existing Webrat methods with their Capybara counterparts. In the following code block I list some examples:

# Webrat
field_with_id('openid_identifier').value.should =~ /invalid OpenID/
# Capybara
find_field('openid_identifier').value.should =~ /invalid OpenID/

# Webrat
response.should contain('Previous')
# Capybara
page.should have_content('Previous')

# Webrat
assert_have_selector('.author', :count => 1)
# Capybara
page.should have_css('.author', :count => 1)

# Webrat
assert_have_xpath("//span[@id='#{id}']", :content => expected_count)
# Capybara
page.should have_xpath("//span[@id='#{id}']", :text => expected_count)

The trickiest part to fix was the failing test. To test some “remember me” functionality I manually set a cookie, and this no longer worked with Capybara:

cookies[:remember_me_id] = remember_me_id

After some searching I found a Gist from Nicholas Rutherford in which he dealt with cookies. Thanks to his code I could set my cookie with the following snippet:

cookies = Capybara.current_session.driver.current_session.instance_variable_get(:@rack_mock_session).cookie_jar
cookies[:remember_me_id] = remember_me_id

And with that, my switch to Capybara was complete. Any questions?

11 comments baked

  • Bruno

    Thank you!
    I needed to access my cookies from within cucumber steps and your code helped me!

  • Eddie

    Nice article Daniel.

    Although I don’t develop with RoR (or know about Webrat), I was just curious for your thoughts on Selenium for automated testing.

    The no-browser way sounds like a performance perk on the local machine, but must add effort to test case generation. I also find that seeing the browser pages can help troubleshooting when cases do fail.

  • cakebaker

    @Bruno: I’m glad this article was helpful for you.

    @Eddie: I think Selenium is a tool a web developer should have in his/her toolbox, especially if you develop applications with a lot of Ajax/Javascript functionality. Being able to run your tests in the “real” environment (the browser) is essential for testing such applications. Plus it helps to ensure cross-browser compatibility, a tedious task if you have to do it manually…

    But all this comes with a price: perfomance (as you already mentioned). Running Selenium tests is very slow compared to browser-less tests.

    I hope this satisfies your curiosity.

  • Ryan

    Great article! Thank you, it’s exactly what I was looking for!

  • cakebaker

    @Ryan: You are welcome!

  • Mike Blyth

    Thanks for the good summary. It was nice to have the examples of Webrat–>Capybara changes in one place. The other issues I found in making the change were

    * Spork would not run after I ran the install cucumber –capybara. It said it had to be bootstrapped, but then trying to bootstrap it said it was already bootstrapped. The solution was to edit features/support/env.rb and remove all the spork stuff, then run bootstrap again.

    * Some tests failed because the did not match the case of the output. Webrat does case-insensitive searches, but Capybara only has case-sensitive ones. So, on a mysterious failure, be sure that the case is correct.

  • cakebaker

    @Mike: Thanks for your comment and the additional tips!

  • Jon Kern

    Great savings! Through a bizarre chain of events, I ended up having to recreate an older rails app (v2.3.5), and was having a devil of a time getting the webrat cukes passing again. Stupid things like click_button yielded errors of the NoMethodError nil.[] crap.

    This article made it easy to switch over to Capybara (which I use on Rails 3 apps). Thanks!

  • fahim

    i m new to this field …….wat is diff bet webrat and capybara???
    if both are same then which one should i use??????
    waiting for ur reply

  • cakebaker

    @fahim: Probably the biggest difference between those two projects is that Capybara is actively developed whereas webrat seems to be inactive. So I would use Capybara.

  • Jarrett Gibbs

    Cucumber and webrat serve as a powerful combination of tools for testing your web applications, but in its most common mode webrat can only test your application locally. Is it possible, you may ask, to use webrat to test a remote web site? The answer is yes, with a little tweaking. Webrat has a configuration option that tells it to use mechanize (a screen-scraping tool for ruby) instead of the built-in rails view testing system.

© daniel hofstetter. Licensed under a Creative Commons License