Using Capybara in Rails 3

What Is Capybara?

capybara

The capybara, a native of South America, is the largest rodent in the world.

Capybara makes it easier to write integration tests. Its syntax is very similar to Webrat’s. The main difference between Capybara and Webrat is that Capybara has more architectural flexibility. It works with a variety of JavaScript-enabled browser simulators and–because it’s based on Rack–it works with any Rack-compatible web application or framework. Another advantage is that Capybara is compatible with Rails 3, but Webrat isn’t. [Update: Apparently Webrat is now compatible with Rails 3.] Because Capybara is basically a more flexible Webrat, Capybara and Webrat are likely to merge.

Note: if you are from the far future (meaning about 17 minutes after this post was published) the information in this post may be out of date since it is about bleeding edge versions of Capybara and Rails 3 (Capybara 0.3.7 and Rails 3.0.0.beta3).

Installing Capybara in Rails 3

Note: I don’t use Cucumber or RSpec, so this guide shows you how to install and use Capybara all by itself in Rails 3.

Add the capybara and launchy gems to the test section of your Gemfile:

group :test do
  gem "capybara"
  gem "launchy"
end

You need the launchy gem or Capybara’s save_and_open_page method won’t work. Don’t forget to run bundle install to install these gems.

Next, create the file test/integration_test_helper.rb containing this:

require "test_helper"
require "capybara/rails"
 
module ActionController
  class IntegrationTest
    include Capybara::DSL
  end
end

For old versions of Capybara (before 1.0), replace include Capybara::DSL with include Capybara.

It’s not strictly necessary to have a separate integration_test_helper.rb file, but it helps to organize your code. This is where I keep code that I want loaded by all of my integration tests but not other types of tests. The require "capybara/rails" line loads Capybara and automatically hooks it up to Rails. After this, I explicitly mix the Capybara module into Rails’ IntegrationTest class. Otherwise, you would get errors like this:

NoMethodError: undefined method `visit' for #<YourIntegrationTest:0x2ce93c8>

Now you’re ready to create an integration test. Note that you need to require 'integration_test_helper' at the beginning of all of your integration tests.

require 'integration_test_helper' 
 
class ClubTest < ActionController::IntegrationTest
 
  test "viewing clubs" do
    visit '/clubs'
    assert page.has_content?('Listing clubs')
  end
 
end

You should be all set! rake test:integration will run your integration tests.

Using Capybara

Capybara has a clear DSL that should be very familiar to Webrat users. Here is an example of a basic integration test written using Capybara:

require 'integration_test_helper' 
 
class ClubTest < ActionController::IntegrationTest
 
  test "viewing clubs" do
    visit '/clubs'
    assert page.has_content?('Listing clubs')
  end
 
  test "adding a club" do
    visit '/clubs'
    click_link "New Club"
    assert page.has_content?('Create a new club')
    fill_in 'Name', :with => 'Capybara'
    check 'Exclusive'
    click_button 'Create Club'
    assert page.has_content?('Club was successfully created.')
    click_link "Back"
    assert page.has_content?('Listing clubs')
    assert page.has_content?('Capybara true')
    assert page.has_no_content?('Capybara false')
  end
 
end

As you can see, we can easily navigate to a page, click links, fill out forms, submit forms, and check the contents of web pages for items. Some tips:

  • Be careful; the text is case-sensitive. assert page.has_content?('Listing clubs') will not match Listing Clubs.
  • If you are an RSpec fan, Capybara allows you to write page.should have_content('foo').
  • save_and_open_page is a nifty way to see exactly what your web page looks like at a certain point. Just insert it anywhere in the test. It’s great for debugging:
require 'integration_test_helper' 
 
class ClubTest < ActionController::IntegrationTest
 
  test "viewing clubs" do
    visit '/clubs'
    save_and_open_page
    assert page.has_content?('Listing clubs')
  end
 
end
  • If you use save_and_open_page, you might want to stick capybara*.html in your .gitignore file since this method generates html files.

For more details, see the official Capybara documentation.

You can skip to the end and leave a response. Pinging is currently not allowed.

22 Responses to “Using Capybara in Rails 3”

  1. Wyatt, thanks for the info. I found this very helpful, especially the launchy gem. Without it, I would not have been able to re-write my integration setups/login macros.

    One thing that really took me for a loop was that I could not rely at all anymore on simple controller/session helpers, even simple pages that set session variables and responded head(:ok). That’s OK tho, just growing pain as it was easy for me to refactor a test only web form that does this work for me. Guess this is the price you pay in an app that has rails session set in another app. Legacy is so fun :/

  2. Also, do not forget to make a teardown method that does “Capybara.reset_sessions!” so each test does not carry over the others session.

  3. Fabio says:

    Thank you very much for this article, I tried to play with webrat but without making it work. I always had NoMethodError: undefined method `visit’ error.

    With your setup I installed and used Capybara in a few minutes.

    Cheers.

  4. techiferous says:

    @Fabio, I’m glad it helped! Thanks for letting me know. :)

  5. Andreas says:

    Hi.
    Glad to find someone who’s running Capybara without Cucumber. Do you guys know how to make Capybara+Selenium find the data in in the test database? Is there a trick?
    Selenium is using the correct database, but somehow it cannot find the data i’m putting in. I got the same problem with the ‘akephalos’ driver (htmlunit), everything works fine running the rack_test driver though.
    Here’s what i do: https://gist.github.com/674284
    Thanks a lot.

  6. techiferous says:

    Hi Andreas,

    I’m using Capybara + Selenium and it’s working for me. I’m not sure where your problem is but I did notice a couple of differences between your setup and mine. For one, I’m inheriting from ActionController::IntegrationTest and you’re inheriting from ActionDispatch::IntegrationTest. I’m not sure whether that makes a difference. Also, my driver is as follows:

    Capybara.current_driver = Capybara.javascript_driver

    which defaults to Selenium. I use FactoryGirl but for Selenium tests I decided to use fixtures because they are faster. So I’ve got the following line at the top of my tests:

    fixtures :all

    I hope you’re able to figure it out without too much trouble!

  7. Andreas says:

    Thanks a lot for your reply. Hm…. As expected, it’s a fixtures vs. FactoryGirl / Model.create thing. Using fixtures works, using FactoryGirl or just MyModel.create(…) does not. Also it did not matter, whether i tried to create the records inside a test method or in a setup-block.
    I think i read somewhere something about that selenium is using transactional somethingsomething, but could not figure out how to workaround the problem.
    The other differences you mentioned made no difference.
    Thanks for your help! Feel free to message me, if you get any more inside on the issue.

  8. Tamer Salama says:

    Thank you for the walkthrough – I was able to get it running on JRuby (after downloading and moving libxml2.dll, libxslt.dll to Nokogiri ext directory – gems\nokogiri-1.4.4-java\ext\nokogiri\).

    Appreciate it.

  9. David Wright says:

    Thanks.

    This was very useful for me to get capybara running with the ‘vanilla’ rails integration framework. (apparently [almost] everyone uses cucumber, steak, rspec, or some other alternative).

    cheers

  10. Brian says:

    Thanks for this! I know it’s from a while ago, but I’ve been trying to reduce my testing framework to a bare minimum and using capybara on it’s own is great.

    I’m down to TestUnit, factory_girl, shoulda-contexts and capybara and that give me unit, functional integrations test that I’m pretty happy with. Easy to set and quick to run.

  11. Chris says:

    Thanks for the info… I’m also this kind of person who tries to avoid using a too big stack of software, especially speaking about tests. So, I stay on Integration Testing + Capycabra

    Following you advice I’ve been able to run my integration tests with success. Then, I tried to include some javascript integration tests with envjs.

    So far I’ve not been able to have them run happilly.

    I’ve added one line to setup envjs as the default javascript driver :

    module ActionController
    class IntegrationTest
    include Capybara
    Capybara.javascript_driver = :envjs
    end
    end

    But, running test like
    page.execute_script(“$(‘a#global_btn_admin’).trigger(‘click’)”)
    I get
    Capybara::NotSupportedByDriverError

    Any help appreciated…

    Thanks

  12. techiferous says:

    @Chris I haven’t tried Capybara with env.js myself, so I can’t give you much advice. Have you tried the capybara-envjs gem? More details here: http://rubyflare.com/2010/06/12/javascript-testing-with-cucumber-capybara-and-env-js/.

  13. regularfry says:

    “include Capybara” gives me deprecation warnings now. It should be “include Capybara::DSL”.

  14. techiferous says:

    @regularfry, Thanks for caring enough to let me know. I updated the blog post so that future readers would benefit.

  15. Jo Liss says:

    Hey everyone, I’ve updated the instructions for Test::Unit in the README at https://github.com/jnicklas/capybara. Anyone still having problems, in particular with transactions (using FactoryGirl etc.), check it out, it should get you up and running in no time! :-)

  16. Mark Richman says:

    I get this error when running my tests (other methods work fine):

    NoMethodError: undefined method `click’ for #

    Here’s my test:

    test “logging in” do
    visit ‘/login’
    fill_in ‘Email’, with: ‘test@example.com’
    fill_in ‘Password’, with: ‘whatever’
    click ‘Log in’
    end

    Any ideas?

  17. techiferous says:

    Mark,

    Apparently Capybara’s DSL changed. Use click_link or click_button. See also http://stackoverflow.com/questions/8993851/why-do-i-get-undefined-method-click-for-cucumberrailsworld-in-cucumber

  18. sanyorke says:

    Hi,
    when I install the this gem, it met error, like below:
    d:\Ruby193>gem install capybara –pre
    Building native extensions. This could take a while…
    ERROR: Error installing capybara:
    ERROR: Failed to build gem native extension.

    d:/Ruby193/bin/ruby.exe extconf.rb
    checking for ffi.h… *** extconf.rb failed ***
    Could not create Makefile due to some reason, probably lack of
    necessary libraries and/or headers. Check the mkmf.log file for more
    details. You may need configuration options.

    Provided configuration options:
    –with-opt-dir
    –without-opt-dir
    –with-opt-include
    –without-opt-include=${opt-dir}/include
    –with-opt-lib
    –without-opt-lib=${opt-dir}/lib
    –with-make-prog
    –without-make-prog
    –srcdir=.
    –curdir
    –ruby=d:/Ruby193/bin/ruby
    –with-ffi_c-dir
    –without-ffi_c-dir
    –with-ffi_c-include
    –without-ffi_c-include=${ffi_c-dir}/include
    –with-ffi_c-lib
    –without-ffi_c-lib=${ffi_c-dir}/lib
    –with-libffi-config
    –without-libffi-config
    –with-pkg-config
    –without-pkg-config
    d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:381:in `try_do’: The compiler failed to generate an executable file. (RuntimeError)
    You have to install development tools first.
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:506:in `try_cpp’
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:931:in `block in have_header’
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:790:in `block in checking_for’
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:284:in `block (2 levels) in postpone’
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:254:in `open’
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:284:in `block in postpone’
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:254:in `open’
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:280:in `postpone’
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:789:in `checking_for’
    from d:/Ruby193/lib/ruby/1.9.1/mkmf.rb:930:in `have_header’
    from extconf.rb:9:in `’

    Gem files will remain installed in d:/Ruby193/lib/ruby/gems/1.9.1/gems/ffi-1.0.11 for inspection.
    Results logged to d:/Ruby193/lib/ruby/gems/1.9.1/gems/ffi-1.0.11/ext/ffi_c/gem_make.out

    ————————-

    do you anyone, how do solve this issue?

  19. techiferous says:

    @sanyorke It looks like you are having issues installing this in a Windows environment. You may have more luck asking this question on StackOverflow than here. This StackOverflow answer may point you in the right direction:

    http://stackoverflow.com/questions/5931663/installing-json-1-5-1-with-native-extensions-error

  20. surekha says:

    I am using Capybara all tags are working but some issue with session , its not redirecting to desired link but saying ‘PLease login”

  21. techiferous says:

    Hi surekha,

    I suggest taking your question to http://stackoverflow.com. You’ll find a much larger audience there and will likely get a good answer. Make sure you provide more details (such as code snippets) when you ask your question.

  22. Thomas says:

    I am playing around with capybara and selenium

    It seems to me that assert won’t work sometimes. I pretty much always need to sleep for few seconds for letting the DOM to reload.

    I don’t know if using page.should from Rspec would solve this problem.

Leave a Reply