I had seen Cucumber before but never really had any time to dabble with it and now that I have I cannot put it down! After setting up a skeleton Ruby on Rails application using Cucumber, Capybara, Devise, and FactorGirl (along with Haml, Compass, and MongoMapper) I decided to circle back and write some Cucumber features to cover the basic user interactions: sign up, confirmation, login, logout, lost password, etc. While it took me much longer than I expected my journey was very fruitful; it turns out some of the Features and their subsequent Scenarios were entirely covered by Cucumber and Capybara without me needing to write one bit of “glue code” to make them work (Cucumber calls these “step definitions”). Most of the time I spent was refactoring out step definitions over and over until I found I did not need a single one! Here is the final product from the “Signing Up” feature:
# features/authentication/signup.feature
Feature: Signing Up
In order to sign up for an account
As a guest
I need to be able to register
Scenario: Registration
Given I am on the sign up page
When I fill in "user_email" with "test@example.com"
And I fill in "user_password" with "test1234"
And I fill in "user_password_confirmation" with "test1234"
And I press "Sign Up"
Then I should see "You will receive an email with instructions"
Even after all of this I cannot be sure that I have completely covered the test but I will note that it does not require a single step definition outside of those that are provided by Capybara in the web_steps.rb convenient step definitions. Here are the other Features, Backgrounds, Scenarios, and Scenario Outlines that I used to cover the authentication class of features:
The confirmation feature:
# features/authentication/confirmation.feature
Feature:
In order activate my account
As a user
I want to be able to confirm
Background:
Given I am pending confirmation
Scenario: Confirmation
Given I received the email
When I confirm the account
Then I should find that I am confirmed
The session feature:
# features/authentication/session.feature
Feature: Session handling
In order to use the site
As a registered user
I need to be able to login and logout
Background:
Given that a confirmed user exists
Scenario Outline: Logging in
Given I am on the login page
When I fill in "user_email" with "<email>"
And I fill in "user_password" with "<password>"
And I press "Sign in"
Then I should <action>
Examples:
| email | password | action |
| minimal@example.com | test1234 | see "Signed in successfully" |
| bad@example.com | password | see "Invalid email or password" |
Scenario: Logging out
Given I am logged in
When I go to the sign out link
Then I should see "Signed out successfully"
The forgotpassword feature:
# features/authentication/forgotpassword.feature
Feature: Forgot password
In order to login
As a user
When I have forgotten my password
I should be able to reset it
Background:
Given that a confirmed user exists
Scenario Outline: Reset password request
Given I am on the forgotten password page
When I fill in "user_email" with "<email>"
And I press "Send me reset password instructions"
Then I should <action>
Examples:
| email | action |
| minimal@example.com | see "You will receive an email with instructions about how to reset your password" |
| bad@example.com | see "Email not found" |
Scenario: Reset password confirmation
Given that I have reset my password
When I follow the reset password link in my email
Then I expect to be able to reset my password
and all of the step definitions:
# features/step_definitions/authentication_steps.rb
# Confrimation
Given /^I received the email$/ do
@user.confirmed?.should be_false
end
When /^I confirm the account$/ do
visit user_confirmation_path(:confirmation_token => @user.confirmation_token)
page.should have_content("Your account was successfully confirmed")
@user.confirm!
end
Then /^I should find that I am confirmed$/ do
@user.confirmed?.should be_true
end
# Forgottenpassword
Given /^that I have a confirmed account$/ do
@user.confirmed?
end
Given /^that I have reset my password$/ do
@user.send_reset_password_instructions
end
When /^I follow the reset password link in my email$/ do
visit edit_user_password_path(:reset_password_token => @user.reset_password_token)
page.should have_content("Change your password")
end
Then /^I expect to be able to reset my password$/ do
visit edit_user_password_path(:reset_password_token => @user.reset_password_token)
fill_in 'user_password', :with => 'test1234'
fill_in 'user_password_confirmation', :with => 'test1234'
click_button('Change my password')
page.should have_content('Your password was changed successfully')
end
# Session
Given /^I am logged in$/ do
visit path_to('the login page')
fill_in('user_email', :with => @user.email)
fill_in('user_password', :with => @user.password)
click_button('Sign in')
if defined?(Spec::Rails::Matchers)
page.should have_content('Signed in successfully')
else
assert page.has_content?('Signed in successfully')
end
end
To get the minimal user, referenced in a few of the step definitions, I created a Factory:
# spec/factories/user.rb Factory.define :minimal_user, :class => User do |u| u.email 'minimal@example.com' u.password 'test1234' u.password_confirmation 'test1234' end
And added the FactoryGirl gem to the Cucumber environment:
# config/environments/cucumber.rb config.gem "factory_girl"
As you can see there is a lot here and a lot of it probably duplicates the test coverage found in the Devise gem. However, developing these Features, Scenarios, and Step Definitions has been great practice for me and warmed me up very gently to how fun Behavior Driven Design (BDD) can be.





Hello,
I am attempting to familiarize myself with cucumber and I thought it would be a great idea to test the devise plug-in. I stumbled across your blog and I am using a very similar methodology. However, I am getting stuck on the testing of log in. It seems that I can not successfully log in.
I was wondering if you have a similar problem when you followed:
Scenario Outline: Logging in
12 Given I am on the login page
13 When I fill in “user_email” with “”
14 And I fill in “user_password” with “”
15 And I press “Sign in”
16 Then I should
17 Examples:
18 | email | password | action |
19 | minimal@example.com | test1234 | see “Signed in successfully” |
20 | bad@example.com | password | see “Invalid email or password” |
I know I am passing the correct email/password combination, but continually receive, “Invalid email or password.” Any help would be appreciated.
-Darren
Hi Darren,
lines 13, 14 & 15 should be:
13 When I fill in “user_email” with “”
14 And I fill in “user_password” with “”
15 Then I should
Looks like you were just missing the link to the Examples.
Great, great article. I have been looking to do this myself recently, but so good to see someone has already had a go.
Anyway, just wanted your advise, as I am quite new to cucumber. I ran through this and am left with 2 undefined steps:
Given /^I am pending confirmation$/ do
pending # express the regexp above with the code you wish you had
end
Given /^that a confirmed user exists$/ do
pending # express the regexp above with the code you wish you had
end
Which are coming from the Backgrounds of confirmation.feature and forgotpassword.feature.
I have been trying to fill in the “pending” text, but without joy. Could you help me to resolve this?
Many thanks,
D.