Running the Cucumber scenario from yesterday, I find that all of the steps are currently undefined:
jaynestown% cucumber features/ingredient_index.feature:7 -sThe first two steps in that scenario can be defined with:
Sinatra::Test is deprecated; use Rack::Test instead.
Feature: Ingredient index for recipes
As a user curious about ingredients or recipes
I want to see a list of ingredients
So that I can see a sample of recipes in the cookbook using a particular ingredient
Scenario: A couple of recipes sharing an ingredient
Given a "Cookie" recipe with "butter" and "chocolate chips"
And a "Pancake" recipe with "flour" and "chocolate chips"
When I visit the ingredients page
Then I should see the "chocolate chips" ingredient
And "chocolate chips" recipes should include "Cookie" and "Pancake"
And I should see the "flour" ingredient
And "flour" recipes should include only "Pancake"
1 scenario (1 undefined)
7 steps (7 undefined)
0m0.540s
You can implement step definitions for undefined steps with these snippets:
Given /^a "([^\"]*)" recipe with "([^\"]*)" and "([^\"]*)"$/ do |arg1, arg2, arg3|
pending
end
When /^I visit the ingredients page$/ do
pending
end
...
Given /^a "([^\"]*)" recipe with "([^\"]*)" and "([^\"]*)"$/ do |title, ing1, ing2|Nothing too difficult in there—build a hash describing the recipe and then putting into the CouchDB database.
date = Date.new(2009, 9, 30)
permalink = date.to_s + "-" + title.downcase.gsub(/\W/, '-')
recipe = {
:title => title,
:type => 'Recipe',
:published => true,
:date => date,
:preparations => [{'ingredient' => {'name' => ing1}},
{'ingredient' => {'name' => ing2}}]
}
RestClient.put "#{@@db}/#{permalink}",
recipe.to_json,
:content_type => 'application/json'
end
Next, I define the step to visit the ingredient index page that I created yesterday:
When /^I visit the ingredients page$/ doEasy enough. Except:
visit "/ingredients"
end
jaynestown% cucumber features/ingredient_index.featureAh, the
Sinatra::Test is deprecated; use Rack::Test instead.
Feature: Ingredient index for recipes
As a user curious about ingredients or recipes
I want to see a list of ingredients
So that I can see a sample of recipes in the cookbook using a particular ingredient
Scenario: A couple of recipes sharing an ingredient # features/ingredient_index.feature:7
Given a "Cookie" recipe with "butter" and "chocolate chips" # features/step_definitions/ingredient_index.rb:1
And a "Pancake" recipe with "flour" and "chocolate chips" # features/step_definitions/ingredient_index.rb:1
When I visit the ingredients page # features/step_definitions/ingredient_index.rb:22
Resource not found (RestClient::ResourceNotFound)
/usr/lib/ruby/1.8/net/http.rb:543:in `start'
./features/support/../../eee.rb:227:in `GET /ingredients'
(eval):7:in `get'
features/ingredient_index.feature:11:in `When I visit the ingredients page'
Then I should see the "chocolate chips" ingredient # features/ingredient_index.feature:12
And "chocolate chips" recipes should include "Cookie" and "Pancake" # features/ingredient_index.feature:13
And I should see the "flour" ingredient # features/ingredient_index.feature:14
And "flour" recipes should include only "Pancake" # features/ingredient_index.feature:15
RestClient::ResourceNotFound
exception is being raised because I have not put the CouchDB map/reduce required by the Sinatra action:get '/ingredients' doI am using the couch_docs gem to load design documents into the CouchDB test database, so all I need to do is create
url = "#{@@db}/_design/recipes/_view/by_ingredients?group=true"
data = RestClient.get url
@ingredients = JSON.parse(data)['rows']
"<title>EEE Cooks: Ingredient Index</title>"
end
couch/_design/recipes/views/by_ingredients/map.js
:function (doc) {And
if (doc['published']) {
for (var i in doc['preparations']) {
var ingredient = doc['preparations'][i]['ingredient']['name'];
var value = [doc['_id'], doc['title']];
emit(ingredient, {"id":doc['_id'],"title":doc['title']});
}
}
}
couch/_design/recipes/views/by_ingredients/reduce.js
:function(keys, values, rereduce) {With that, I have the first three steps in this scenario passing. That means it is time to work my way into the code to start implementing the next step. The Sinatra action is already done (yesterday), so it is time to start on the Haml template:
if (rereduce) {
var ret = [];
for (var i=0; i<values.length; i++) {
ret = ret.concat(values[i]);
}
return ret;
}
else {
return values;
}
}
describe "ingredients.haml" doFrom my work the other night, I know that the CouchDB view will return an ingredient list of the form:
#...
end
before(:each) doGiven that, I expect to find a list of two ingredients:
@ingredients = [{'butter' =>
[
['recipe-id-1', 'title 1'],
['recipe-id-2', 'title 2']
]
},
{'sugar' =>
[
['recipe-id-2', 'title 2']
]
}]
end
it "should have a list fo ingredients" doI can get that to pass with:
render("/views/ingredients.haml")
response.should have_selector("p .ingredient", :count => 2)
end
= @ingredients.each do |ingredient|Last up tonight, I would like to include the recipe titles in the Haml output:
%p
%span.ingredient
= ingredient.keys.first
it "should have a list of recipes using the ingredients" doI can get that passing with:
render("/views/ingredients.haml")
response.should have_selector("p", :content => 'title 1, title 2')
end
= @ingredients.each do |ingredient|At this point, I am well on my way to completing the template. Hopefully I can finish it off tomorrow.
%p
%span.ingredient
= ingredient.keys.first
%span.recipes
= ingredient.values.first.map{|recipe| recipe[1]}.join(", ")