Down the rabbithole

ekov @

Acceptance testing with Cucumber and Capybara

One of my first tasks as a developer was to migrate endless tests from Twist to Cucumber. Since then, I have written and refactored countless more, but I never had to set up Cucumber testing from zero. Until now. It was really not complicated, but it took me a while to get everything going. This is what I’ve come up with.

Prerequisites *

Bundler — the Ruby equivalent of npm. Just gem install bundler. phantomjs — get it from homebrew: brew install phantomjs

What to test? *

I’m prioritising main user stories — Can they log in and out? Can they navigate the page? Do they see the right content? Are more items loaded after they scroll a table? Can they submit forms and create items (e.g. messages, events)? Do the actions they perform have the right effect? Can they view and download invoices? …and so forth. I have an excel sheet for them — this way, even non-coders can add (request) test cases; and it’s a good way to track progress. One thing is for sure though: whenever something breaks, if it wasn’t tested before, I write a test for it.

Setup *

I will demo what I did for testing a simple sign in on our client-facing dashboard. I chose Selenium webdriver, because that’s what I’m used to, but Poltergeist looks very promising as well. I might try it out and compare experiences.

Our directory structure will look something like this:

	|-- sign.feature
	|-- step_definitions/
		|-- sign.rb
	|-- support/
		|-- env.rb

First of all, let’s be secure and not push secrets to GitHub, even if it’s a private repo. Let’s keep them local or on the CI. For this, we have a .secrets file that will hold our secrets. (Replace with your own – btw these creds are fake.)

export TEST_PW=CorrectHorseBatteryStaple

Let’s put this file in our .gitignore, to avoid pushing it accidentally.

# .gitignore


For JS developers, our Gemfile is basically what package.json’s dependencies or requirements.txt does. Once we have it, we can run bundle install and it installs all dependencies.

# Gemfile

source ""
gem 'rake'
group(:test) do
	gem 'cucumber'
  gem 'capybara'
  gem 'rspec'
  gem 'poltergeist'
  gem 'selenium-webdriver'
  gem 'chromedriver-helper'

I think about the Rakefile as the scripts part of a package.json.
It enables us to call rake features from the command line, which in turn will run all our tests.

# Rakefile

require 'cucumber'
require 'cucumber/rake/task'

task default: :features do |t|
  t.cucumber_opts = "--format pretty"

Some more configuration in env.rb, and we are good to go. Here, we register a webdriver for the tests to run against, and configure an app_host, which will be our base url.

# features/support/env.rb

require 'capybara'
require 'capybara/cucumber'

Capybara.register_driver :selenium do |app|, :browser => :chrome)

Capybara.configure do |config|
  config.default_driver = :selenium
  config.app_host = ''


Ready for our first feature test? *

Features are written in Gherkin, an easy-to-read templating language that goes well with Cucumber.

# features/sign.feature

Feature: Sign in

  Scenario: Sign in and see cats
    Given I am on the Sign in page
    When I sign in
    Then I should see cats

These Given, When and Then steps are regular expressions, and they can be matched to step definitions like this:

# features/step_definitions/sign.rb

Given /^I am on the Sign in page$/ do
  visit('/sign-in') # we already have the base_url from env.rb
  expect(page).to have_content('Sign in') # let's check if this really works

And /^I sign in$/ do
  fill_in 'email', :with => $test_user
  fill_in 'password', :with => $test_pw

Then /^I should see (cats|dogs)$/ do |things|
  expect(page).to have_content(things) # in our case, it will look for 'cats'.

Read more about expects and other matchers here.

That’s it, running rake features should fire up a Chrome browser, visit, sign in successfully, and report the results in the command line.

Previous: Creating a custom ProtonMail theme