Tuesday, May 5, 2009

Cleaning Up a Mess of My Own Making

‹prev | My Chain | next›

First up today is cleaning up some of the mess that I left behind. When I run all of the Cucumber scenarios, I see many failing steps now:
cstrom@jaynestown:~/repos/eee-code$ cucumber -n features -s "Paginating results"
Feature: Search for recipes

So that I can find one recipe among many
As a web user
I want to be able search recipes

Scenario: Paginating results
Given 50 yummy recipes
And a 0.5 second wait to allow the search index to be updated
When I search for "yummy"
Then I should see 20 results
expected following output to contain a <table td a/> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
<table><tr>
<th>
<a href="/recipes/search?q=yummy&sort=sort_title" id="sort-by-name">Name</a>
</th>
<th>
<a href="/recipes/search?q=yummy&sort=sort_date&order=desc" id="sort-by-date">Date</a>
</th>
<th>
<a href="/recipes/search?q=yummy&sort=sort_prep" id="sort-by-prep">Prep</a>
</th>
<th>
<a href="/recipes/search?q=yummy&sort=sort_ingredient" id="sort-by-ingredients">Ingredients</a>
</th>
</tr></table>
<div class="pagination">
<span class="inactive">« Previous</span><a href="/recipes/search?q=yummy&page=2">Next »</a>
</div>
</body></html>
(Spec::Expectations::ExpectationNotMetError)
features/recipe_search.feature:57:in `Then I should see 20 results'
Hunh? This step passed previously—there were plenty of matching recipes before, so where did they go?

The answer is in the CouchDB log:
[couchdb-lucene] ERROR Error updating index.
org.mozilla.javascript.EcmaError: TypeError: Cannot read property "length" from undefined (userFun#38)
at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3557)
at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3535)
...
Ah, this is coming from sort-by-number-of-ingredients indexed field:
  ret.field('sort_ingredient', doc['preparations'].length, 'yes', 'not_analyzed');
This is being tripped when there are no ingredient preparation fields—something that might happen when drafting a recipe, so it is worth fixing:
  var ingredient_count = doc['preparations'] ? doc['preparations'].length : 0;
ret.field('sort_ingredient', ingredient_count, 'yes', 'not_analyzed');
Even with that fixed, the scenario is still not passing:
cstrom@jaynestown:~/repos/eee-code$ cucumber -n features -s "Paginating results"
Feature: Search for recipes

So that I can find one recipe among many
As a web user
I want to be able search recipes

Scenario: Paginating results
Given 50 yummy recipes
And a 0.5 second wait to allow the search index to be updated
When I search for "yummy"
Then I should see 20 results
And I should see 3 pages of results
And I should not be able to go to a previous page
When I click page 3
Then I should see 10 results
expected following output to contain a <table td a/> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
<table>
<tr>
<th>
<a href="/recipes/search?q=yummy&sort=sort_title" id="sort-by-name">Name</a>
</th>
<th>
<a href="/recipes/search?q=yummy&sort=sort_date&order=desc" id="sort-by-date">Date</a>
</th>
<th>
<a href="/recipes/search?q=yummy&sort=sort_prep" id="sort-by-prep">Prep</a>
</th>
<th>
<a href="/recipes/search?q=yummy&sort=sort_ingredient" id="sort-by-ingredients">Ingredients</a>
</th>
</tr>
<tr class="row0">
<td>
<a href="/recipes/id-40-yummy">yummy recipe 40</a>
</td>
<td>
<span class="date">2009-04-22</span>
</td>
<td>
<span class="prep">0</span>
</td>
<td>
<span class="ingredients"></span>
</td>
</tr>
<tr class="row1">
...
Counting out the number of rows in the results I find eleven, not the expected 10. My fencepost fix from the other night uncovered an accidental step passage tonight. The fix is an easy one. Easy, but my mistake should have been obvious from the start. In the recipe creation step, I create recipes in the range 0..50—51 including the zero. Changing it to 1..50, all specs and all Cucumber scenarios are passing:



(commit)

There still remains some work in the Recipe Search scenario: (1) No matching results and (2) Invalid search parameters.

Most of the "No matching results" scenario steps are already implemented:



All that remains is verifying that no results are displayed. The two scenario steps can be defined as:
Then /^I should see no results$/ do
response.should have_selector("p.no-results")
end

Then /^no result headings$/ do
response.should_not have_selector("th")
end
I can describe the desired behavior in the Sinatra app as:
    it "should display a helpful message when no results" do
RestClient.stub!(:get).
and_return('{"total_rows":0,"skip":0,"limit":20,"rows":[]}')

get "/recipes/search?q=title:egg"

response.should contain("No results")
end
To make this example pass, a simple ternary will suffice:
  haml @results['total_rows'] == 0 ? :no_results : :search
Well, that, plus a simple Haml template suffice to get things working.

With that, I have another scenario complete and only one more to go in the recipe search feature. Even better, I have exactly 100 passing steps!



(commit)

No comments:

Post a Comment