I left off yesterday with a failing Cucumber step, making it easy to know where to start today:
cstrom@jaynestown:~/repos/eee-code$ cucumber -n features -s "Browsing a meal in a given month"I barely even glanced at the failure yesterday, but today I notice that the
Feature: Browse Meals
So that I can find meals made on special occasions
As a person interested in finding meals
I want to browse meals by date
Scenario: Browsing a meal in a given month
Given a "Even Fried, They Won't Eat It" meal enjoyed in May of 2009
And a "Salad. Mmmm." meal enjoyed in April of 2009
When I view the list of meals prepared in May of 2009
Then I should see the "Even Fried, They Won't Eat It" meal among the meals of this month
And I should not see the "Salad. Mmmm." meal among the meals of this month
And I should not see a link to June of 2009
When I follow the link to the list of meals in April of 2009
Then I should not see the "Even Fried, They Won't Eat It" meal among the meals of this month
And I should see the "Salad. Mmmm." meal among the meals of this month
expected following output to contain a <h2>Salad. Mmmm.</h2> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
<h1>Meals from 2009</h1>
<div class="navigation">
|
</div>
<ul>
<li>
<a href="/meals/id-2009-05-01">Even Fried, They Won't Eat It</a>
</li>
</ul>
</body></html>
(Spec::Expectations::ExpectationNotMetError)
features/browse_meals.feature:28:in `And I should see the "Salad. Mmmm." meal among the meals of this month'
And I should not see a link to February of 2009
And I should see a link to May of 2009
1 scenario
1 failed step
2 undefined steps
8 passed steps
H1
title is describing "Meals from 2009" rather than "Meals from April, 2009". Somehow the link being followed to "to the list of meals in April of 2009" is taking Cucumber to the list of meals in 2009 instead.Before in-depth investigation of the helper responsible for those links, I think now is a good time to align the language of the helper with its usage. Specifically, it should be less year-oriented and more date fragment-oriented:
def link_to_year_in_set(current, couch_view, options={})The more date fragment oriented rewrite:
compare_years = options[:previous] ?
Proc.new { |year, current_year| year < current_year} :
Proc.new { |year, current_year| year > current_year}
next_result = couch_view.
send(options[:previous] ? :reverse : :map).
detect{|result| compare_years[result['key'].to_i, current.to_i]}
if next_result
%Q|<a href="/meals/#{next_result['key']}">#{next_result['key']}</a>|
else
""
end
end
def link_to_adjacent_view_date(current, couch_view, options={})After updating various specs and consuming Haml templates to use the renamed function, I take a closer look at the link output. The CouchDB by_month map-reduce views that are of the form (after being parsed into Ruby):
compare = options[:previous] ?
Proc.new { |date_fragment, current| date_fragment < current} :
Proc.new { |date_fragment, current| date_fragment > current}
next_result = couch_view.
send(options[:previous] ? :reverse : :map).
detect{|result| compare[result['key'], current.to_s]}
if next_result
%Q|<a href="/meals/#{next_result['key']}">#{next_result['key']}</a>|
else
""
end
end
{"value"=>3, "key"=>"2009-04"}The value indicates the total number of meals in the month indicated by the key (in the above example, there were 3 meals from April of 2009).
Looking back to the output of the helper, I would end up with the following for the "2009-04" example:
<a href="/meals/2009-04">2009-04</a>The problem is that the Sinatra app does not recognize "/meals/2009-04" as a by-month URL because the dash does match the RegExp:
get %r{/meals/(\d+)/(\d+)} do |year, month|That URL does match the by-year action (which completely ignores the month portion of the URL):
...
end
get %r{/meals/(\d+)} do |year|Yet again, Cucumber has caught a composition error on my part. The individual components all work according to specification—one can easily make the case that the URL "/meal/2009-04" is a valid by-month URL—but the assembly of those pieces into a whole missed a vital piece of information.
...
end
I could address this oversight by making the URL accept dashes or by making the helper replace dashes with slashes. I opt for the latter—I simply prefer the simplicity of an all slash URL.
The example that I use to describe this behavior, including a by-month context, is:
context "couchdb view by_month" doThat fails, as expected, because the
before(:each) do
@count_by_month = [{"key" => "2009-04", "value" => 3},
{"key" => "2009-05", "value" => 3}]
end
it "should link to the next month after the current one" do
link_to_adjacent_view_date("2009-04", @count_by_month).
should have_selector("a",
:href => "/meals/2009/05")
end
end
href
still has a dash in it:cstrom@jaynestown:~/repos/eee-code$ spec spec/eee_helpers_spec.rbTo make it pass, I add a computation of the
.............................F
1)
'link_to_adjacent_view_date couchdb view by_year should link to the next month after the current one' FAILED
expected following output to contain a <a href='/meals/2009/05'/> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><a href="/meals/2009-05">2009-05</a></body></html>
./spec/eee_helpers_spec.rb:228:
Finished in 0.025192 seconds
30 examples, 1 failure
next_uri
to the helper:def link_to_adjacent_view_date(current, couch_view, options={})Not only does that make that example pass, but, working my way back out to the Cucumber scenario, I find that all currently defined step are passing as well!
compare = options[:previous] ?
Proc.new { |date_fragment, current| date_fragment < current} :
Proc.new { |date_fragment, current| date_fragment > current}
next_result = couch_view.
send(options[:previous] ? :reverse : :map).
detect{|result| compare[result['key'], current.to_s]}
if next_result
next_uri = next_result['key'].gsub(/-/, '/')
%Q|<a href="/meals/#{next_uri}">#{next_result['key']}</a>|
else
""
end
end
Even better, those last two steps are trivial to implement:
Then /^I should not see a link to February of 2009$/ doAnd now the entire scenario is passing:
response.should_not have_selector("a", :content => "2009-02")
end
Then /^I should see a link to May of 2009$/ do
response.should have_selector("a", :content => "2009-05")
end
cstrom@jaynestown:~/repos/eee-code$ cucumber -n features \Yay!
-s "Browsing a meal in a given month"
Feature: Browse Meals
So that I can find meals made on special occasions
As a person interested in finding meals
I want to browse meals by date
Scenario: Browsing a meal in a given month
Given a "Even Fried, They Won't Eat It" meal enjoyed in May of 2009
And a "Salad. Mmmm." meal enjoyed in April of 2009
When I view the list of meals prepared in May of 2009
Then I should see the "Even Fried, They Won't Eat It" meal among the meals of this month
And I should not see the "Salad. Mmmm." meal among the meals of this month
And I should not see a link to June of 2009
When I follow the link to the list of meals in April of 2009
Then I should not see the "Even Fried, They Won't Eat It" meal among the meals of this month
And I should see the "Salad. Mmmm." meal among the meals of this month
And I should not see a link to February of 2009
And I should see a link to May of 2009
1 scenario
11 passed steps
(commit)
My red-green-refactor development cycle has gotten me to green. There is a definite opportunity to refactor the should / should not see a link to steps. I will tackle that next before working my way onto the next scenario.
No comments:
Post a Comment