Wednesday, September 9, 2009

Enjoying Cucumber

‹prev | My Chain | next›

This is the fun part.

After several days of working deep in the code—including a couple of CouchDB views—I get to work my way out to the Cucumber scenario to mark steps as complete. If I am lucky/good I can verify that each step is complete without another code change.

I finished up yesterday by putting my new Sinatra helper methods, which determine if the current recipe is an update to a previous recipe or has itself been updated, into the recipe Haml template:
= recipe_updated_by(@recipe['_id'])
= recipe_update_of(@recipe['_id'])

- if @recipe['preparations']
The <div> tags around the helpers will have no children if the helpers return nil (e.g. the recipes have not been updated/do not replace old recipes). Empty <div> tags never hurt anyone.

The next Cucumber step in need of definition is that which describes marking one recipe as an update of another. Recalling that an update document has an updates attribute listing versions of a particular recipe, the most recent last, this definition does the trick:
When /^the "([^\"]*)" recipe is marked as update of the "([^\"]*)" recipe$/ do |arg1, arg2|
update = {
:type => "Update",
:name => "buttermilk pancakes",
:updates => [
{ :id => @permalink_identified_by[arg2] },
{ :id => @permalink_identified_by[arg1] }


RestClient.put "#{@@db}/buttermilk_pancake_updates",
:content_type => 'application/json'
Indeed, that step now passes. The next step, visiting the recipe with a particular ingredient in it, can be defined as:
When /^I visit the recipe with "([^\"]*)" in it$/ do |ingredient|
visit "/recipes/#{@permalink_identified_by[ingredient]}"
The @permalink_identified_by hash was defined in a previous step to make lookup easy.

At this point all steps in this scenario are defined, so does it pass? Sadly, no:
cstrom@jaynestown:~/repos/eee-code$ cucumber -s \
Sinatra::Test is deprecated; use Rack::Test instead.
Feature: Updating recipes in our cookbook

As an author
I want to mark recipes as replacing old one
So that I can record improvements and retain previous attempts for reference

Scenario: A previous version of the recipe
Given a "Buttermilk Pancake" recipe with "buttermilk" in it
And a "Buttermilk Pancake" recipe on another day with "lowfat milk" in it
When the "buttermilk" recipe is marked as update of the "lowfat milk" recipe
And I visit the recipe with "buttermilk" in it
Then I should see a link to the previous recipe with "lowfat milk" in it
expected following output to contain a <a>the previous recipe with "lowfat milk" in it</a> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "">
<title>EEE Cooks</title>
<link href="/stylesheets/style.css" rel="stylesheet" type="text/css">

<span class="update-of">This is an update of a previous recipe: <a href="/recipes/2000-09-05-buttermilk-pancake">September 5, 2000</a></span>
<ul class="preparations">
Ah, the step definition is coming from a previous feature, which is slurping up too much too much of the text ("the previous recipe with "lowfat milk" in it"—everything after "Then I should see a link to"). Rather than attempting to resolve the conflict, I will rewrite the step to read:
    Then I should see that the recipe is an update to the recipe with "lowfat milk" in it
Making use again of the handy @permalink_identified_by lookup, this step can be defined as:
Then /^I should see that the recipe is an update to the recipe with "([^\"]*)" in it$/ do |ingredient|
response.should have_selector(".update-of a",
:href => "/recipes/#{@permalink_identified_by[ingredient]}")
After defining a similar step for the converse (the recipe that has an update), I have the entire scenario passing:

Although this scenario is done, the feature is not quite complete. Up tomorrow, I will start work on the last scenario: suppressing old recipes from couchdb-lucene search results.

No comments:

Post a Comment