Friday, April 24, 2009

Pagination, Page 3

‹prev | My Chain | next›

Continuing pagination work, I need to get previous and next links working. I also never actually put links in the a tags, so I will get that working as well.

To get the href working, I add an href expectation to the first pagination expectation from last night:
  it "should have a link to other pages" do
pagination('foo', 0, 20, 41).
should have_selector("a",
:content => "2",
:href => "/recipes/search?q=foo&page=2")
end
To drive development of the next / previous link, I write the following examples:
  it "should have a link to the next page if before the last page" do
pagination('foo', 20, 20, 41).
should have_selector("a", :content => "Next »")
end
it "should not have a link to the next page if on the last page" do
pagination('foo', 40, 20, 41).
should have_selector("span", :content => "Next »")
end
it "should have a link to the previous page if past the first page" do
pagination('foo', 20, 20, 41).
should have_selector("a", :content => "« Previous")
end
it "should not have a link to the next page if on the first page" do
pagination('foo', 0, 20, 41).
should have_selector("span", :content => "« Previous")
end
Working through each of these examples, I end up with the following, longish implementation:
    def pagination(query, skip, limit, total)
last_page = (total + limit - 1) / limit
current_page = skip / limit + 1

link = "/recipes/search?q=#{query}"

links = []

links <<
if current_page == 1
%Q|<span class="inactive">« Previous</span>|
else
%Q|<a href="#{link}&page=#{current_page - 1}">« Previous</a>|
end

links << (1..last_page).map do |page|
%Q|<a href="#{link}&page=#{page}">#{page}</a>|
end

links <<
if current_page == last_page
%Q|<span class="inactive">Next »</span>|
else
%Q|<a href="#{link}&page=#{current_page + 1}">Next »</a>|
end

%Q|<div class="pagination">#{links.join}</div>|
end
I can DRY that up some, especially the conditionals around the previous / next links. For now, I will get it done and worry about doing it right another day. At least the repetition is small and all contained within a single method.

The addition of the query parameter to the pagination helper requires a bunch of clean-up in both specs and code. Once that is done, it is back on out to the cucumber feature:
    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
To verify that I should not be able to go to a previous page, I use the following:
Then /^I should not be able to go to a previous page$/ do
response.should have_selector(".pagination span", :content => "« Previous")
end
Running the spec, I find my final failure for today:
cstrom@jaynestown:~/repos/eee-code$ cucumber features/recipe_search.feature -n -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 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>Name</th>
<th>Date</th>
</tr>
<tr class="row0">
<td>
<a href="/recipes/id-0-yummy">yummy recipe 0</a>
</td>
<td>2009-04-22</td>
</tr>
<tr class="row1">
<td>
<a href="/recipes/id-1-yummy">yummy recipe 1</a>
</td>
<td>2009-04-22</td>
</tr>
<tr class="row0">
...
Still on recipe 0? Oops, I have yet to connect the page parameters to the RestClient calls to couchdb-lucene.

I do not mind stopping with a failing test. Quite the opposite, I know exactly where to start tomorrow.

No comments:

Post a Comment