Quick tips on Capybara

Zoe Larsen
6 min readJan 20, 2019

--

To help you have full testing coverage

TLDR;

This article is a summation of the most helpful tips and concepts that aided me in system testing with Capybara. It is not intended to be a complete and thorough guide but rather a quick overview of practices that helped make testing more enjoyable.

What is system testing

System testing is part of a suite of tests that a developer implements to ensure that their application is working properly. The tests that we will focus on specifically is system testing, which tests the integrated whole of the application. Essentially, the test will emulate a user going through the app. That will insure that all the parts of the application (views, models, controllers, helpers, and so on) are all working as expected for the end user experience.

System tests is considered black box testing since it is from the external perspective of a user who has no access or understanding of the internal working of the software. White box testing is testing the internal working of the software such as unit or integration testing.

What is capybara and how does it work

Capybara is part of the toolkit that Ruby on Rails developers use to help write system tests. It is a ruby library that helps simulate a user going through the web application. It is used in conjunction with a web driver, which is a language neutral interface that allows a developer to write programs that can control or manipulate elements in the DOM.

The key benefits from the Capybara documentation include

  • No setup necessary for Rails and Rack application. Works out of the box.
  • Intuitive API which mimics the language an actual user would use.
  • Switch the backend your tests run against from fast headless mode to an actual browser with no changes to your tests.
  • Powerful synchronization features mean you never have to manually wait for asynchronous processes to complete.

Capybara starts a browser, it can be a real browser like chrome with a selenium web driver or a headless browser. Then as your test runs through the application, most of the Capybara code base is working to ensure that asynchronous calls don’t tank your tests.

A handy visualization of that process

Even with Capybara working hard to prevent race conditions, system testing can be fraught with inexplicable failures and bugs that feel impossible to resolve. The following are some quick tips and good practices to help ease the process that is system testing.

Capybara Tips

Methods that Wait Vs Methods that DON’T Wait

Capybara has a lot of code dedicated to preventing race conditions happening from asynchronous calls. Many of the available methods will wait until it finds the element that was requested. It will keep on looking for the requested element until the default wait time has timed out then it will fail.

However not all methods will wait because it may not make sense to do so in that particular situation. Especially if you don’t know what the scope of what you are waiting for.

For example, if you are waiting for a particular page title to appear then you know the scope: One <h2/> element. If you are waiting for all the table rows, you may not know how many they are.

It’s important to know the distinction of when to use what type of method. I would err on the side of caution and use methods that wait if a particular system test is being flaky.

Asserting Elements

Before your system test runs any javascript or starts clicking on any DOM elements, you want the test to wait for any page changes or AJAX requests to resolve. This helps prevent race conditions.

Methods like has_selector? has_no_selector? are useful for making sure you are on the expected page.

def assert_first_visible_row row_text
has_selector? ".rowWrapper"
## Rest of code block.
end

Scoping

There are a lot of elements on your DOM that Capybara has to sort through. Especially if you have multiple of the same element like rows in a table. If you click on a link in a particular row then it might be hard for Capybara to find the correct row since there are many rows in a table.

Robust scoping helps avoid this problem.

within find_all(".rowWrapper")[1] do
assert_text row_text
end

Using within is great to help narrow down where you want Capybara to look on the page.

Additionally, if using normal element ids, classes or names is not working then within() supports XPath. The ability to use XPath can help you drill down when css selectors are failing.

Element matching

Capybara will match elements partially by default. This can be extremely frustrating if you have several buttons with different variations of “Submit” for a form.

<button>
Submit Now
</button>
<button>
Submit
</button>
<button>
Submit Later
</button>

Capybara will match on the first one if you use click ‘Submit’.

One way to resolve this is to pass in an argument to the click method.

click 'Submit Later', exact: true

You can also change Capybara’s default behavior in your test setup.

## Match Exact.
Capybara.exact = true
## Method `find` returns the first element and ignores the rest.
Capybara.match = :first
## Capybara will raise an error if more than one element is found.
## Helps to prevent inexplicable breaks.
Capybara.match = :one
## Return exact match if exists else will default to partial match.
Capybara.match = :prefer_exact
## Raises error if more than one match.
## Same behavior as :prefer_exact if Capybara.exact is set to false.Capybara.match = :smart

Capybara Don’ts

NO Sleeps

Don’t use sleeps() to make you tests wait for AJAX or other page elements to load.

It’s a sloppy practice and Capybara has native configurations to address waiting for elements or requests to show up such as the Capybara.default_wait_time.

Additionally you should be using the methods that wait like described in the above section.

Don’t Add Selectors just to satisfy your tests

You should write up your HTML views with concise selectors to make it easy to style and for javascript like jQuery to hook onto. However you should avoid going back after you are done and add more selectors in order to help pass your system tests.

Robust scoping within your tests should help avoid any need to add more selectors to your views.

Resources

The following are some helpful resources that helped me with system testing with Capybara.

--

--