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
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.