Five Ridiculously Awesome Cucumber (and Webrat) Features

Josh Clayton

Cucumber, if you haven’t heard, is the Next Big Thing™. It affords developers the ability to write human-readable integration tests. Even though it’s only at version 0.3.101, it’s full-featured with a handful of hidden gems. Here are five of my favorites.

Running Targeted Features with Cucumber Profiles

In a Rails application, if a RAILS_ROOT/cucumber.yml file is present, you can store named Cucumber profiles. This becomes handy if you’re running your features in different environments (e.g. Selenium or a simulated browser).

Here’s an example cucumber.yml file:

default: >
  --format pretty -r features/support/env.rb -r features/support/plain.rb
  -r features/step_definitions features
selenium: >
  -r features/support/env.rb -r features/support/selenium.rb
  -r features/step_definitions features
html_output: >
  --format html -r features/support/env.rb -r features/support/plain.rb
  -r features/step_definitions features

Within your terminal, you can run:

cucumber -p html_output

Tagging Scenarios

Another handy Cucumber feature is the ability to tag scenarios. Tagging a scenario is achieved by simply adding @tagname above the scenario definition, as such:

@tagname
Scenario: User is not signed up
  Given no user exists with an email of "email@person.com"
  When I go to the sign in page
  And I sign in as "email@person.com/password"
  Then I should see "Bad email or password"
  And I should not be signed in

To run scenarios with a specific tag:

cucumber --tags @tagname

To exclude scenarios with a certain tag, prefix the tag with a tilde:

cucumber --tags ~@wip

A common tag name that Cucumber supports out of the box is @wip (work in progress) and provides rake tasks to accommodate using this pattern:

rake cucumber:wip # runs only scenarios with a wip tag
rake cucumber:ok # runs all scenarios without a wip tag

One thing to note here is that Cucumber will exit with a status of 1 if your @wip-tagged scenarios pass (it’s a reminder that they’re not works in progress anymore since they pass).

Assigning Data with Tables

Cucumber supports the use of tables, which can be handy for any number of things; my favorite uses are populating fields in a form and instantiating an ActiveRecord object with values defined.

Webrat gives us a step definition for filling in form fields (within features/step_definitions/webrat_steps.rb) and can be used as such:

When I fill in the following:
  | First Name            | John                 |
  | Last Name             | Doe                  |
  | Email                 | john.doe@example.com |
  | Password              | password             |
  | Password Confirmation | password             |

With an ActiveRecord object and FactoryBot:

# step
Given a customer exists with the following attributes:
  | Name      | Huge Local Company |
  | Code      | HLC                |
# step definition
Factory.factories.each do |name, factory|
  Given /^an? #{name} exists with the following attributes:$/ do |attrs_table|
    attrs = {}
    attrs_table.raw.each do |(attr, value)|
      sanitized_attr = attr.gsub(/\s+/, "-").underscore
      attrs[sanitized_attr.to_sym] = value
    end
    Factory(name, attrs)
  end
end

Segregating Selenium and Simulated Browser Steps

If you’ve been ambitious enough to get your features running with Selenium, you already know that doing so can add a significant amount of time to your tests. Webrat is kind enough to provide you execution blocks that run in specific modes, which makes for some snappier tests when you do run features with Webrat.

For example, within a step that outlines signing in:

webrat.automate do
  When %{I sign in as "#{email}/#{password}"}
end

webrat.simulate do
  visit "/session",
        :post,
        :session => {:email => email, :password => password}
end

Webrat will determine if you’re simulating a browser and execute webrat.simulate if that’s the case; otherwise, it’ll run the code within the webrat.automate block. This can be really helpful if you’re testing the ability to delete an item (especially if there’s a confirmation dialog).

Displaying Page Responses within a Scenario

If you’re having trouble getting a feature to pass and want to view the page, you can add in a step to have it save the result HTML and open the page in your default browser.

Scenario: User is not signed up
  Given no user exists with an email of "email@person.com"
  When I go to the sign in page
  Then show me the page # saves the HTML of that page and opens the file
  And I sign in as "email@person.com/password"
  Then I should see "Bad email or password"
  And I should be signed out
  Then show me the page # more HTML output

This tends to be much more convenient than adding this into your step definition:

puts response.body.inspect

There are, as always, a couple of caveats. The HTML it generates won’t be relative to your public folder so Javascript and CSS probably won’t load correctly. It also doesn’t persist form values, so if you run it after a step like ‘I fill in “field” with “value”’, it won’t keep that data. It also creates a timestamped html file within your RAILS_ROOT folder. A simple fix to ensure this doesn’t get committed with git would be to add the following line to your .gitignore file in the project:

webrat-*.html

Finally

Don’t forget to read the docs! They cover everything you’d ever want to know about Cucumber and how to use it effectively. I’ve listed only a handful of awesome features Cucumber and Webrat have to offer, but each has helped me in one way or another over the course of the past year. Hopefully they’ll be as much use to you as they were me.

What’s next

Ruby Science

Detect emerging problems in your codebase with. We’ll deliver solutions for fixing them, and demonstrate techniques for building a Ruby on Rails application that will be fun to work on for years to come.

Grab a free sample of Ruby Science today!