Project was generated from rails3-devise-rspec-cucumber-template with some modifications to get by a couple of errors caused by edge rails.
rails new deals -m https://raw.github.com/RailsApps/rails3-application-templates/master/rails3-devise-rspec-cucumber-template.rb -T
git clone git@github.com:jspooner/Deals-BDD-Example.git
switch to tag
update database.yml.template
update gem file for sqlite or mysql
$ bundle install
$ rake db:create
$ rake db:migrate
$ RAILS_ENV=test rake db:migrate
$ rake db:seed
rake cucumber:wip
2 scenarios (2 failed)
15 steps (2 failed, 8 skipped, 1 undefined, 4 passed)
0m1.388s
You can implement step definitions for undefined steps with these snippets:
Then /^the deal should be saved$/ do
pending # express the regexp above with the code you wish you had
end
$ touch /features/step_definitions/deal_steps.rb
Then /^the deal should be saved$/ do
pending # express the regexp above with the code you wish you had
end
p. Ok let’s make this pass
Can’t find mapping from “the new deal page” to a path.
Now, go and add a mapping in /Users/jonathanspooner/Dropbox/active/bdd/deals/features/support/paths.rb (RuntimeError)
p. We don’t need to add anything to paths.rb because we can just use the catch all path.
begin
page_name =~ /the (.*) page/
…
rescue Object => e
raise “Can’t find mapping from \”#{page_name}\" to a path.\n" +
“Now, go and add a mapping in #{__FILE__}”
end
h3. Let’s make the mapping work for “the new deal page”
routes.rb
resources :deals
and run rake cucumber:wip
Scenario: Create a new deal # features/deals/create_deals.feature:12
Given I am on the new deal page # features/step_definitions/web_steps.rb:44
uninitialized constant DealsController (ActionController::RoutingError)
./features/step_definitions/web_steps.rb:45:in `/^(?:|I )am on (.+)$/’
features/deals/create_deals.feature:13:in `Given I am on the new deal page’
p. Now the mapping works and cucumber is driving the next step. It wants a DealsController!
Okay let’s cheat a little and use a rails generator to speed things up.
BDD want’s us todo this
* rails g controller Deals new
* rake cucumber:wip
* RED When I fill in “Title” with “Mega skateboard deals”
* Add form to new.html
* rake cucumber:wip
* RED And I press “Create Deal”
* Add DealsController#create
This would be the right method with a very custom feature but this one is SUPER basic so we’ll skip a few steps and use the scaffold generator.
* be rails g scaffold deals title:string start_date:datetime end_date:datetime quantity:integer description:text number_sold:integer
h4. No let’s drop a down a gear and take a look at our specs.
* Add default value for number_sold in 20110823170906_create_deals.rb
* Add a spec for our default values.
/spec/models/deal_spec.rb
describe “init” do
it { Deal.new.number_sold.should eql(0) }
it { Deal.new.quantity.should eql(0) }
end
* rake db:migrate
* RAILS_ENV=test rake db:migrate
* rake spec
h4. Look at the deals_controller_spec
* rake spec:controllers
* Let’s use FactoryGirl to make our lives easier later.
* Why FactoryGirl?
/spec/factory.rb
Factory.define :deal do |d|
d.title ‘Mega Skateboard deal’
d.start_date (Date.today-5).to_date
d.end_date (Date.today+5).to_date
d.description ‘Mega ramp skateboard by Jake Brown is on sale.’
d.quantity 100
d.number_sold 0
end
/spec/controllers/deals_controller_spec.rb
* “deal = Deal.create! valid_attributes” and replace with “deal = Factory(:deal)”
Update valid_attributes to use FactoryGirl
def valid_attributes
{}
end
def valid_attributes
Factory.attributes_for(:deal)
end
* rake spec – Everything should be green
* now back to the BDD cycle
- rake spec:controllers
When I fill in “Start date” with “2011/9/1”
cannot fill in, no text field, text area or password field with id, name, or label ‘Start date’ found (Capybara::ElementNotFound)
We’ll update datetime_select with text_field for start_date and end_date.
Then the deal should be saved
TODO (Cucumber::Pending)
./features/step_definitions/deal_steps.rb:2:in `/^the deal should be saved$/’
features/deals/create_deals.feature:19:in `Then the deal should be saved’
/features/step_definitions/deal_steps.rb
Then /^the deal should be saved$/ do
page.should have_content(“Deal was successfully created.”)
end
Looks Green!
Scenario: Create a new deal
Given I am on the new deal page
When I fill in “Title” with “Mega skateboard deals”
When I fill in “Start date” with “2011/9/1”
When I fill in “End date” with “2011/9/1”
When I fill in “Quantity” with “1000”
And I press “Create Deal”
Then the deal should be saved
Then I should see “Mega skateboard deals”
Then I should see “Title can’t be blank”
Looks like this should be valid so let’s drop down a gear and update the Deal model.
describe “validation” do
it { Deal.new.should have(1).errors_on(:title) }
end
Deal validation
Failure/Error: it { Deal.new.should have(1).errors_on(:title) }
expected 1 errors on :title, got 0
- ./spec/models/deal_spec.rb:9:in `block (3 levels) in <top (required)>’
Finished in 1.73 seconds
16 examples, 0 failures
Looking Green! Let’s go back up to Cucumber.
The —wip switch was used, so I didn’t expect anything to pass. These scenarios passed:
(::) passed scenarios (::)
Let’s remove that @wip tag from the .feature file
Looks good. Time to commit and move on to the home_page.feature
- Move @wip from completed steps.
- add @wip to home_steps.rb
- create /features/step_definitions/home_steps.rb
- add @wip tag to home_page.feature
Background:
Given there are 4 past 4 current and 2 future deals # features/step_definitions/home_steps.rb:1
TODO (Cucumber::Pending)
./features/step_definitions/home_steps.rb:2:in `/^there are (\d+) past (\d+) current and (\d+) future deals$/’
features/home/home_page.feature:7:in `Given there are 4 past 4 current and 2 future deals’
- variables
- FactoryGirl
$ touch features/step_definitions/home_steps.rb
- past these steps
Given I am on the home page
Then I should see 4 deals
TODO (Cucumber::Pending)
./features/step_definitions/home_steps.rb:14:in `/^I should see (\d+) deals$/’
features/home/home_page.feature:11:in `Then I should see 4 deals’
Then /^I should see (\d+) deals$/ do |arg1|
page.should have_selector(“div.deal”, :count => arg1)
end
Scenario: Create a new deal
Given I am on the home page
Then I should see 4 deals
expected css “div.deal” to return something (RSpec::Expectations::ExpectationNotMetError)
Let’s drop down a gear and update the model.
Add named scope for current deals.
describe “queries” do
before(:each) do
past = Factory(:deal, { :start_date => 30.days.ago, :end_date => 29.days.ago })
@current = Factory(:deal, { :start_date => 5.days.ago, :end_date => 5.days.from_now })
@future = Factory(:deal, { :start_date => 5.days.from_now, :end_date => 10.days.from_now })
end
it "should find current deals" do
deals = Deal.current
deals.should have(1).item
deals.first.should eql(
current)
end
end
Failure/Error: deals = Deal.current
NoMethodError:
undefined method `current’ for #
Let’s add this to app/models/deal.rb
scope :current
Deal queries should find current deals
Failure/Error: deals.should have(1).item
expected 1 item, got 3
Ok now we need to get the query right.
scope :current, where(“Date(start_date) <= ? AND Date(end_date) >= ?”, Date.today.to_date, Date.today.to_date)Finished in 0.1878 seconds
17 examples, 0 failures
We need a lambda around the query so the date isn’t cashed.
scope :current, lambda{ where(“Date(start_date) <= ? AND Date(end_date) >= ?”, Date.today.to_date, Date.today.to_date)}
Finished in 0.1878 seconds
17 examples, 0 failures
Looks Green! Let’s bounce back up to cucumber.
Scenario: Create a new deal
Given I am on the home page
Then I should see 4 deals
!We need to display the deals on the home page.
/spec/controllers/home_controller_spec.rb
it “should set the current deals” do
deal = Factory(:deal)
get :index
assigns(:deals).should eq([deal])
end
1) HomeController GET ‘index’ should set the current deals
Failure/Error: assigns(:deals).should eq([deal])
………………..
Finished in 0.42225 seconds
20 examples, 0 failures
open app/views/home/index.html
<% @deals.each do |deal| >
<= deal.title %>
<% end %>
and pop back up to cucumber
Looks Green! Almost!
Let’s update the step_definition to look for links to /deals/
Then /^I should see (\d+) links to deals$/ do |arg1|
page.should have_selector(“div.deal a[href^=‘/deals/’]”, :count => arg1)
end
Then I should see 4 links to deals # features/step_definitions/home_steps.rb:13
expected css “div.deal a[href^=‘/deals/’]” to return something (RSpec::Expectations::ExpectationNotMetError)
<% @deals.each do |deal| >
<= link_to deal.title, deal %>
<% end %>
Looks Green!
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
This application requires this gem:
To use this application, you will need:
- The Ruby language (version 1.8.7 or 1.9.2)
- Rails (version 3.0.4 or newer)
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
This is the only documentation.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
If you make improvements to this application, please share with others.
- Fork the project on GitHub.
- Make your feature addition or bug fix.
- Commit with Git.
- Send the author a pull request.
If you add functionality to this application, create an alternative implementation, or build an application that is similar, please contact me and I’ll add a note to the README so that others can find your work.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.