Capybara Basics For Automated testing of Ruby on Rails Application

Automated Testing is an integral part of large scale production Ruby on Rails applications. A solid Integration test suite ensures that the integration between various components of the application is smooth and seamless. An integration test generally spans multiple controllers and actions, tying them all together to ensure they work together as expected. It tests more completely than either unit or functional tests do, exercising the entire stack, from the dispatcher to the database. Capybara comes in handy in simulating the testing in real user environment. In this blog we will explore various ways by which we can strengthen our apps with Capybara.

    • Capybara is an integration testing tool for rack based web applications. It simulates how a user would interact with a website.
    • Capybara helps in testing your web application as a real user would do. It is independent of the driver that is running your tests and comes with Rack::Test and Selenium support built in. For other drivers, you need to include their respective gem.
Capybara requires Ruby 1.9.3 or later and can be installed as a gem by listing in your gem file and then installing bundle or it may be installed directly by typing:
gem install capybara
  • Include capybara in your helper file:
    require 'capybara/rails'
Using Capybara with Rspec
Integrating capybara with rspec is fairly simple. Lets go through a step by step process to understand the integration. The following test simulates a login in a real user environment.
  • Include capybara’s rspec directory
    require 'capybara/rspec'
  • Capybara specs are required to be placed in spec/features
  • Here is a simple test to test the login page working.
    describe "Login" do
    before :each do
    user = User.create(:email => ''”,:password => 'password')
    it "logs the user in" do
    visit login_path
    fill_in "Email", with:
    fill_in "Password", with: 'kanwal_enbake'
    click_button "Sign in"
    page.should have_content "success"
    The test source code is fairly simple to understand and implement so I will not be going into the details here.
Testing Javascript with Capybara
  • By default Capybara uses the :rack_test driver, which is fast but limited as it does not support JavaScript. So you need to switch to Capybara.javascript_driver(:selenium by default) by using :js => true. For instance: describe “example of testing js”, :js => true do it “tests js with default js driver” do end it “tests js with one specific driver” , :driver => :webkit do end end
  • To make Capybara available in all test cases deriving fromActionDispatch::IntegrationTest : describe ActionDispatch::IntegrationTest include Capybara::DSL end
  • You may sometimes, want to switch default driver and want to run everything in selenium, you could do:Capybara.default_driver = :selenium
  • In any case – provided you are using Rspec or Cucumber – if you want use faster :rack_test as your default_driver, and use JavaScript-capable driver only for selective test cases, you can use :js => true for Rspec and @javascript for Cucumber. By default, JavaScript tests are run using the :selenium driver. You can change this setting by Capybara.javascript_driver.
  • You can also, particularly in before or after blocks, change driver temporarily: Capybara.current_driver = :webkit
  • Capybara.use_default_driver would switch back to default driver
Note: switching the driver creates a new session, so you may not be able to switch in the middle of a test.
Techniques and Trivial Testing Tasks
  • visit(‘/projects’)
  • visit(post_comments_path(post))
Clicking links and buttons
  • click_link(‘id-of-link’)
  • click_link(‘Link Text’)
  • click_button(‘Save’)
  • click(‘Link Text’) # Click either a link or a button
  • click(‘Button Value’)
Interacting with forms
  • fill_in(‘First Name’, :with => ‘John’)
  • fill_in(‘Password’, :with => ‘Seekrit’)
  • fill_in(‘Description’, :with => ‘Really Long Text…’)
  • choose(‘A Radio Button’)
  • check(‘A Checkbox’)
  • uncheck(‘A Checkbox’)
  • attach_file(‘Image’, ‘/path/to/image.jpg’)
  • select(‘Option’, :from => ‘Select Box’)
  • within(“//li[@id=’employee’]”) do fill_in ‘Name’, :with => ‘Jimmy’ end
  • within(:css, “li#employee”) do fill_in ‘Name’, :with => ‘Jimmy’ end
  • within_fieldset(‘Employee’) do fill_in ‘Name’, :with => ‘Jimmy’ end
  • within_table(‘Employee’) do fill_in ‘Name’, :with => ‘Jimmy’ end
  • page.has_xpath?(‘//table/tr’)
  • page.has_css?(‘table’)
  • page.has_content?(‘foo’)
  • page.should have_xpath(‘//table/tr’)
  • page.should have_css(‘table’)
  • page.should have_content(‘foo’)
  • page.should have_no_content(‘foo’)
  • find_field(‘First Name’).value
  • find_link(‘Hello’).visible?
  • find_button(‘Send’).click
  • find(‘//table/tr’).click
  • locate(“//*[@id=’overlay'”).find(“//h1″).click
  • all(‘a’).each { |a| a[:href] }
  • current_path.should == post_comments_path(post)
    • result = page.evaluate_script(‘4 + 4′)
    • page.execute_script(“$(‘#id_of_anything’)”).click
Note: unlike page.evaluate_script, page.execute_script do not return anything. You have to explicitly perform action to make it return a value Debugging
  • save_and_open_page
  • page.save_screenshot(‘screenshot.png’) *driver specfic
Asynchronous JavaScript
  • click_link(‘foo’)
  • click_link(‘bar’)
  • page.should have_content(‘baz’)
  • page.should_not have_xpath(‘//a’)
  • page.should have_no_xpath(‘//a’)
XPath and CSS
  • within(:css, ‘ul li’) { … }
  • find(:css, ‘ul li’).text
  • locate(:css, ‘input#name’).value
  • Capybara.default_selector = :css
  • within(‘ul li’) { … }
  • find(‘ul li’).text
  • locate(‘input#name’).value
Calling remote servers
  • Normally Capybara expects to be testing an in-process Rack application, but you can also use it to talk to a web server running anywhere on the internet, by setting app_host: Capybara.current_driver = :selenium Capybara.app_host =
I hope the blog gives a good introduction of adding capybara tests to your rails apps. Its just the tip of the iceberg and the possibilities are endless. Lets make our apps more robust and flexible .. :).