Thursday, May 7, 2009

Fixing a Mistake That Should Have Been Caught By a Spec

‹prev | My Chain | next›

By completing the implementation of the recipe search scenarios, I inadvertently broke an earlier scenario:
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
And I should not be able to go to a next page
When I click the previous page
Then I should see 20 results
And I should be able to go to a previous page
When I click the next page
Then I should see 10 results
When I visit page -1
Then I should see page 1
When I visit page "foo"
Then I should see page 1
When I visit page 4
Then I should see page 1
expected following output to contain a <.pagination span.current>1</.pagination span.current> 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">
<a href="/recipes/search?q=yummy&page=3">« Previous</a><a href="/recipes/search?q=yummy&page=1">1</a><a href="/recipes/search?q=yummy&page=2">2</a><a href="/recipes/search?q=yummy&page=3">3</a><a href="/recipes/search?q=yummy&page=5">Next »</a>
</div>
</body></html>
(Spec::Expectations::ExpectationNotMetError)
features/recipe_search.feature:73:in `Then I should see page 1'

1 scenario
1 failed step
19 passed steps
I am expecting that when the user navigates beyond the pagination window (e.g. through a URL hack), the application will redirect the user to the first page of the search. That is not happening—the user is seeing an empty page 5 instead.

Looking at the code, the redirect occurs if the total rows are zero:
  if @results['total_rows'] == 0 && page > 1
redirect("/recipes/search?q=#{@query}")
return
end
That is where I made my mistake. I do not want to redirect when there are no results. I want to redirect when there are results, but none on the current page.

I am a little annoyed with myself that I never made an example describing this behavior. I did drive the behavior with an example, but glossed over the redirect, only testing the behavior after the redirect.

I can rectify that, but the test is a little ugly:
    it "should redirect without pagination after navigating beyond the pagination window" do
RestClient.stub!(:get).
and_return('{"total_rows":1,"skip":0,"limit":20,"rows":[]}')

get "/recipes/search?q=egg&page=2"

response.status.should == 302
response.headers["Location"].should == "/recipes/search?q=egg"
end
The ugliness comes from testing the redirect. If I were doing this with Rails, I could specify that the response.should redirect_to(...), but this is the best I could come up with a Sinatra app.

With code to implement that example in place, I have better coverage and I have all of my tests and scenarios passing. Most of the time.

More on that tomorrow.

(commit)

No comments:

Post a Comment