Wednesday, September 2, 2009

Slow, Slow, Slow... Done!

‹prev | My Chain | next›

I begin today with 9 of 17 steps passing in my mini-calendar Cucumber scenario. Slightly more than half done and completing one scenario per day has made for frustrating progress of late. Hopefully today will prove more fruitful.

For reference, the legacy site displays the mini-calendar as:



The Cucumber scenario currently fails when trying to navigate between months on the calendar (clicking the less-than sign). So far, the calendar always displays the month with the most recent meal in it. Any expectation that an older month should display fails:
cstrom@jaynestown:~/repos/eee-code$ cucumber -is      features/mini_calendar.feature
Sinatra::Test is deprecated; use Rack::Test instead.
Feature: Mini-calendar

As a curious web user
I want to see a calendar indicating the most recent meals and recipes
So that I can have a sense of how active the site is

Scenario: Navigating through months
Given a "Test" meal enjoyed on 2009-08-23
And a "Test" meal enjoyed on 2009-08-15
And a "Test" meal enjoyed on 2009-08-01
And a "Test" meal enjoyed on 2009-06-23
When I visit the mini-calendar
Then I should see the calendar for August 2009
And there should be 3 links to meals
And there should not be a link to the next month
When I click on the link to the previous month
Then I should see the calendar for July 2009
expected following output to contain a <h1>July 2009</h1> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>EEE Cooks</title>
<link href="/stylesheets/style.css" rel="stylesheet" type="text/css">
</head>
<html><body>
<div id="header">
<div id="eee-header-logo">
<a href="/">
<img alt="Home" src="/images/eee_corner.png"></a>
</div>
</div>
<h1>
<span class="previous">
<a href="/mini/2009/06"><</a>
</span>
August 2009
<span class="next">
>
</span>
</h1>
<table id="mini-calendar">
...
</body></html>
</html>
(Spec::Expectations::ExpectationNotMetError)
features/mini_calendar.feature:18:in `Then I should see the calendar for July 2009'
And there should be no links to meals
And there should be a link to the next month
When I click on the link to the previous month
Then I should see the calendar for June 2009
And there should be 1 links to meals
And there should be a link to the next month
And there should not be a link to the previous month

Failing Scenarios:
cucumber features/mini_calendar.feature:7 # Scenario: Navigating through months

1 scenario (1 failed)
17 steps (1 failed, 2 skipped, 5 undefined, 9 passed)
0m0.727s
The month with the last meal in it (the only month that the mini-calendar currently displays) is derived from the meals/count_by_month CouchDB view:
get %r{/mini/.*} do
url = "#{@@db}/_design/meals/_view/count_by_month?group=true"
data = RestClient.get url
@count_by_month = JSON.parse(data)['rows']
@month = @count_by_month.last['key']

url = "#{@@db}/_design/meals/_view/by_date_short?" +
"startkey=%22#{@month.sub(/\d\d$/, '')}00%22&" +
"endkey=%22#{@month.sub(/\d\d$/, '')}99%22"
data = RestClient.get url
@meals_by_date = JSON.parse(data)['rows'].inject({ }) do |memo, m|
memo[m['value']['date']] = m['value']['title']
memo
end

haml :mini_calendar
end
In turn, the mini_calendar Haml template uses @month to draw the correct month view. The RSpec example that drove the current behavior is:
    it "should display the month" do
get "/mini/"
last_response.
should have_selector("h1", :content => "August 2009")
end
What I want is, given a /mini/2009/07 URL (instead of /mini/) to display July of 2009 instead of the default month. In other words, I want:
    it "should display requested month" do
get "/mini/2009/07"
last_response.
should have_selector("h1", :content => "July 2009")
end
That example fails because "August 2009" always displays, but I can get it to pass by slurping the date string into a RegExp and judicious use of a ternary when calculating the current month:
get %r{/mini/(.*)} do |date_str|
url = "#{@@db}/_design/meals/_view/count_by_month?group=true"
data = RestClient.get url
@count_by_month = JSON.parse(data)['rows']
@month = date_str == '' ? @count_by_month.last['key'] : date_str

...
In addition to getting that example passing, I earn a passing Cucumber step as well:



Yay! One more step done... but wait! Those next two steps describe existing functionality (now that the proper month is showing). I can define them as:
Then /^there should be no links to meals$/ do
response.should_not have_selector("table a")
end

Then /^there should be a link to the next month$/ do
response.should have_selector("a", :content => ">")
end
Those Cucumber steps pass, as does the previous skipped, I-should-see-June step:



Wheee! I am making progress now. In fact, that next undefined step looks very similar to the already passing "there should be 3 links to meals" step. So I change:
Then /^there should be 3 links to meals$/ do
response.should have_selector("td a", :count => 3)
end
To:
Then /^there should be (\d) links to meals$/ do |count|
response.should have_selector("td a", :count => count.to_i)
end
That gets me down to the very last step (the previously skipped step passes). Again, the functionality has already been driven into the code, so I can verify it in Cucumber with:
Then /^there should not be a link to the previous month$/ do
response.should_not have_selector("a", :content => "<")
end
And, just like that, I have gone from extremely slow progress to done:



Often the last 20% is the hardest. In this case, as is often the case with Cucumber, the hard part got done first. I feel much better now than I did yesterday. Tomorrow I will get started with styling the mini-calendar. Then: deployment of the new feature to the beta site.

No comments:

Post a Comment