Sunday, August 23, 2009

Closing the Unpublished Loop

‹prev | My Chain | next›

Today, I continue with the latest feature of my cookbook: suppressing draft recipes. First up is to make sure that only recipes that have been published show up in the couchdb-lucene search results. The Cucumber scenario so far:



Because I am re-using the Given steps from the scenario completed yesterday, I already have 4 of the seven steps in this scenario defined.

The step that displays all of the search results can be defined as (the sleep allows the lucene search index to build):
When /^I show all recipes via search$/ do
sleep 0.5
visit("/recipes/search?q=")
end
Last in this scenario are the two Then steps, which are:
       Then "Recipe #1 and Recipe #3" should be included in the search results
And "Recipe #2 and Recipe #4" should not be included in the search results
To define either step, I need to split the text between the quotes so that I can scan the search results:
Then /^"([^\"]*)" should be included in the search results$/ do |recipes_str|
recipes = recipes_str.split(/\s*and\s*/)
recipes.each do |recipe|
response.should have_selector("a", :content => recipe)
end
end
That step passes, but the next one fails as expected (because I am not yet excluding unpublished recipes):
Sinatra::Test is deprecated; use Rack::Test instead.
Feature: Draft vs. Published Meals and Recipes

As a cookbook dedicated to quality
So that I can present only the best meals and recipes
I want to hide drafts

Scenario: Searching for recipes # features/draft_recipes.feature:19
Given "Recipe #1", published on 2009-08-01 # features/step_definitions/draft.rb:1
And "Recipe #2", drafted on 2009-08-05 # features/step_definitions/draft.rb:1
And "Recipe #3", published on 2009-08-10 # features/step_definitions/draft.rb:1
And "Recipe #4", drafted on 2009-08-20 # features/step_definitions/draft.rb:1
When I show all recipes via search # features/step_definitions/draft.rb:31
Then "Recipe #1 and Recipe #3" should be included in the search results # features/step_definitions/draft.rb:52
And "Recipe #2 and Recipe #4" should not be included in the search results # features/step_definitions/draft.rb:59
expected following output to omit a <a>Recipe #2</a>:
...
All that is required to get that passing is to add a conditional to the couchdb-lucene transform function. With that:



Before committing this change, I first had to update nearly all of the Cucumber scenarios dealing with recipe search so that they include the published attribute. I could have made things easier on myself by treating the absence of the published attribute the same as being published. That would have been a short-term fix, but a long-term source of bugs.

The code should require an effort be made to publish documents. Without that effort, I would be inviting accidental publishing whenever the published attribute was forgotten or accidentally removed. Sure, I could work hard to ensure that all application code writing recipe documents always add a published attribute (defaulting to false), but at some point down the line, I would forget and trouble would ensue. Better to endure the short-term pain of updating a dozen Cucumber steps than to invite trouble in the future.

(commit)

The last scenario describes hiding non-published meals:
    Scenario: Navigating between meals
Given "Meal #1", published on 2009-08-01
And "Meal #2", drafted on 2009-08-05
And "Meal #3", published on 2009-08-10
And "Meal #4", drafted on 2009-08-20
When I show "Meal #1"
Then there should be no link to "Meal #2"
When I am asked for the next meal
Then "Meal #3" should be shown
And there should be no next link
And there should be a link to "Meal #1"
When I am asked for the list of meals in 2009-08
Then "Meal #1 and Meal #3" should be included
And "Meal #2 and Meal #4" should not be included
When I am asked for the list of meals in 2009
Then "Meal #1 and Meal #3" should be included
And "Meal #2 and Meal #4" should not be included
When I am asked for the homepage
Then "Meal #1 and Meal #3" should be included
And "Meal #2 and Meal #4" should not be included
Just as with the recipe search above (and navigating between recipes yesterday), the first should-omit-draft-meals step fails:
cstrom@jaynestown:~/repos/eee-code$ cucumber \
features/draft_recipes.feature:28
Sinatra::Test is deprecated; use Rack::Test instead.
Feature: Draft vs. Published Meals and Recipes

As a cookbook dedicated to quality
So that I can present only the best meals and recipes
I want to hide drafts

Scenario: Navigating between meals # features/draft_recipes.feature:28
Given "Meal #1", published on 2009-08-01 # features/step_definitions/draft.rb:1
And "Meal #2", drafted on 2009-08-05 # features/step_definitions/draft.rb:1
And "Meal #3", published on 2009-08-10 # features/step_definitions/draft.rb:1
And "Meal #4", drafted on 2009-08-20 # features/step_definitions/draft.rb:1
When I show "Meal #1" # features/step_definitions/draft.rb:29
Then there should be no link to "Meal #2" # features/step_definitions/draft.rb:42
expected following output to omit a <a>Meal #2</a>:
...
Just as with the recipe search and navigation, I can make this step pass by including only published meals in the CouchDB view:
// couch/_design/meals/views/by_date_short/map.js
function (doc) {
if (doc['type'] == 'Meal' && doc['published']) {
emit(doc['date'], {'title':doc['title'],'date':doc['date']});
}
}
In fact, I follow my way down the scenario (and up the breadcrumbs) following this same pattern: reaching a step that fails to omit unpublished meals, altering the CouchDB view, then reaching the next step that fails to omit the unpublished meal. Finally, I reach the last step and am done with the scenario:



After updating all previous meal scenarios so that the meals are published, I am that much closer to being ready to move out of beta:
cstrom@jaynestown:~/repos/eee-code$ cucumber features -i
...
36 scenarios (6 undefined, 30 passed)
325 steps (13 skipped, 35 undefined, 277 passed)
0m36.649s

(commit)

No comments:

Post a Comment