We know how helpful it is to have the application test code maintained in the same place as the developed code. Today, there are many alternatives for web-based automation tools, however many people struggle to make that a reality due to various reasons. When creating tests we should aim for tests that are modular, easy to write, and easy to maintain. Tests as expected to give good and fast feedback on code quality in the Agile and TDD environments.
Capybara brings good news to those who have Ruby as the language that is followed for their application codebase. Capybara is a web-based automation testing framework that helps create functional tests which simulate how the users interact with the application. Let us discuss the benefits of using Capybara here.
No Setup is Required
Capybara is a library written in Ruby language. This makes it easy to simulate how a user interacts with your AUT.
Capybara requires Ruby 2.5.0 or later. To install, add this line to your Gemfile
and run bundle install
:
gem 'capybara'
If you are testing a Rails app, add this line to your test helper file:
require 'capybara/rails'
If the application you are testing is a Rack app, but not Rails, set Capybara.app to your Rack app:
Capybara.app = MyRackApp
Talks with many different drivers.
Very much like Watir, Capybara is a library/gem worked to be utilized on top of a fundamental web-based driver. You can seamlessly choose between Selenium, Webkit, or pure Ruby drivers.
If you need to test JavaScript, or if your app interacts with (or is located at) a remote URL, you’ll need to use a different driver. If using Rails 5.0+, but not using the Rails system tests from 5.1, you’ll probably also want to swap the “server” used to launch your app to Puma in order to match Rails defaults.
Capybara.server = :puma # Until your setup is working Capybara.server = :puma, { Silent: true } # To clean up your test output
Here are some of the web drivers supported by Capybara:
- rack::test:
It uses the rack::test driver by design. This driver is much faster than other drivers, but it doesn’t support JavaScript and can’t access HTTP resources outside of the application for which the tests are written (Rails app, Sinatra app). - selenium-webdriver:
Capybara is compatible with selenium-webdriver, a web-based automation system. It supports JavaScript, can access HTTP resources outside of the program and can be configured for headless testing, which is particularly useful in CI scenarios. To make use of this driver, you’ll need to do the following:Capybara.default_driver = :selenium
- capybara-webkit:
The capybara-webkit driver can be used for true headless testing with JavaScript support (gem). It makes use of QtWebKit and is much faster than Selenium because it does not load the entire browser. To make use of this driver, you must first add:Capybara.default_driver = :webkit
This means, your tests run against from fast headless mode to an actual browser with no changes to your tests.
Offers a user-friendly Domain-Specific Language
Capybara provides an intuitive API that mimics the language an actual user would use. The DSL (Domain Specific Language) is used to describe the actions executed by the web driver. Capybara tries to locate the relevant element in the DOM and execute the action, such as click button, enter text, etc., when the page is loaded using the DSL (and web driver). This gives Capybara the possibility to pair with Cucumber for BDD, RSpec, Test::Unit, Minitest, and Minitest::Spec.
Capybara can only locate visible elements by default. Since a real user will be unable to communicate with non-visible components, this is the case.
In Capybara, all searches are case-sensitive. Capybara heavily relies on XPath, which does not help case insensitivity.
- Navigation
If you use a spec_helper you can mention the host in the Capybara properties.Capybara.default_driver = :selenium_chrome
Then use
Capybara.app_host ='https://google.com'visit
to navigate.visit '/'
- Click link/button
click_link('id-of-link') click_link('Link Text') click_button('Save') click_on('Link Text') # clicks on either links or buttons click_on('Button Value')
- Text Field
fill_in('First Name', with: 'John')
- Radio Button
choose('A Radio Button')
- CheckBox
check('A Checkbox') uncheck('A Checkbox')
- Dropdown
select('Option', from: 'Select Box')
- Upload File
attach_file('File', '/path/to/image.jpg')
Finders
If you ever need to locate a button in order to click on it, but the method click_button
isn’t enough, or if you need to find the value entered into a textbox, or find a piece of text inside another segment, Capybara has a variety of Finders built-in.
find_field
find_link
find_button
find
by xpath [find(:xpath)
]
To use XPath selectors, change this configuration value:Capybara.default_selector = :xpath
The selector type can be specified, if necessary:
find(:xpath, 'actual_xpath'
Matching to avoid Ambiguity
At your disposal are two options, Capybara.exact
and Capybara.match
.
Exactness
Capybara.exact
and the exact
option work together with the is
expression inside the XPath gem. When exact
is true, all is
expressions match exactly, when it is false, they allow substring matches. Many of the selectors built into Capybara use the is
expression. This way you can specify whether you want to allow substring matches or not. Capybara.exact
is false by default.
click_link("Password") # also matches "Password confirmation" Capybara.exact = true click_link("Password") # does not match "Password confirmation" click_link("Password", exact: false) # can be overridden
Strategy
Using Capybara.match
and the equivalent match
option, you can control how Capybara behaves when multiple elements all match the locator. There are four different strategies allowed by Capybara:
- first: Just picks the first element that matches.
- one: Raises an error if more than one matching element is found.
- smart: If
exact
istrue
, raises an error if more than one matching element is found, just likeone
. Ifexact
isfalse
, it will first try to find an exact match. An error is raised if more than one element is found. If no elements are found, a new search is performed which includes partial matches. If that search also returns multiple matches, an error is raised. - prefer_exact: If multiple matches are found, some exact, and some not, then the first exact match is returned.
The default for Capybara.match
is :smart
. To emulate the behavior in Capybara 2.0.x, set Capybara.match
to :one
. To emulate the behaviour in Capybara 1.x, set Capybara.match
to :prefer_exact
.
DSL also supports other frequently used actions such as Querying, Scoping, Working with windows, Scripting and Modals.
Tackle the asynchronous web with powerful synchronization
Capybara will never have you manually wait for asynchronous processes to complete. This means you can forget all those nasty explicit waits.
Capybara has an internal mechanism for handling asynchronous loading of parts of the page. A good example is clicking on some part of the page that causes JavaScript to be executed and creates a new element on the page.
click_link('hello') click_link('world')
Let’s pretend that clicking the link ‘hello’ initiates an asynchronous process, such as an Ajax request, that adds the link ‘world.’ Since the relation does not yet exist, the second argument is likely to fail.
Capybara, on the other hand, has a method for dealing with these circumstances that allows it to retry locating the element for a short period of time before throwing a mistake. The default time is 2 seconds, but this can be changed.
There is no one-size-fits-all solution to these problems. On the one hand, it’s a good idea to keep the wait mechanism’s ambiguity secret from the test script’s author so that the syntax is simpler and easier to understand. On the other hand, getting more leverage over the wait process and managing it yourself is often preferable.
In any case, the script’s unexpected failures are often caused by this wait problem. This is most likely a sign that the implementation is experiencing performance or other problems.
Capybara also supports JavaScript execution via:
page.execute_script()
where JavaScript code can be passed like this:
page.execute_script("$('#area button.primary').click()")
Visual regression testing with Capybara
In drivers that support it, you can save a screenshot:
page.save_screenshot('screenshot.png')
Screenshots are saved to Capybara.save_path
, relative to the app directory. If you have required capybara/rails
, Capybara.save_path
will default to tmp/capybara
.
Percy Capybara lets you take all the time you’ve spent building your feature tests and expand them with screenshots and visual regression tests to cover all the visual changes in your app, even behind complex UI states.
Let Capybara test-swim into your Ruby waters
Therefore, if Ruby is the language used in your application don’t think twice but jump into using Capybara for automation testing as it has a very supportive DSL that saves time in grabbing those elements and it works with the popular test frameworks like Cucumber, RSpec, and Minitest. Therefore, let this be a start of having the tests in the same code base as your application and reap all the benefits that Capybara has to deliver. Good Luck!