The last scenario in the "Recipe Search" scenario is "Invalid search parameters":
The first undefined step,
When I search for ""
, looks suspiciously defined:When /^I search for "(.+)"$/ do |keyword|Ah, I used the one-or-more regular expression operator (
@query = "/recipes/search?q=#{keyword}"
visit(@query)
end
+
) in there, not expecting to match an empty string. Changing it to zero-or-more (*
) gets that step working. Working, but not passing:cstrom@jaynestown:~/repos/eee-code$ cucumber -n features \To fix the error, I need to move into the application specs and code. Specifically, I need to handle 400 errors from CouchDB/couchdb-lucene.
-s "Invalid search parameters"
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: Invalid search parameters
Given 5 "Yummy" recipes
And a 0.5 second wait to allow the search index to be updated
When I search for ""
HTTP status code 400 (RestClient::RequestFailed)
/usr/lib/ruby/1.8/net/http.rb:543:in `start'
./features/support/../../eee.rb:35:in `GET /recipes/search'
(eval):7:in `get'
features/recipe_search.feature:114:in `When I search for ""'
Then I should see no results
When I seach for a pre-ascii character "%1F"
Then I should see no results
And an empty query string
When I search for an invalid lucene search term like "title:ingredient:egg"
Then I should see no results
And an empty query string
1 scenario
1 failed step
3 skipped steps
4 undefined steps
2 passed steps
There is no sense in preventing the requests from going through to CouchDB. The requests are non-destructive GETs. Besides, I might be able to blacklist a handful of invalid searches, but blacklists never work in the long run. Instead I will handle errors from the
RestClient
gracefully:it "should treat couchdb errors as no-results" doA
RestClient.stub!(:get).
and_raise(Exception)
get "/recipes/search?q=title:egg"
response.should contain("No results")
end
begin/rescue
block around the RestClient
call will get this passing:beginThis also satisfies the requirement of the scenario step.
data = RestClient.get couchdb_url
@results = JSON.parse(data)
rescue Exception
@results = { 'total_rows' => 0 }
end
So now, it is on to trying to break the search with non-ascii characters. Unfortunately, this does not work in the least:
When I seach for a pre-ascii character "%1F"It seems that
bad URI(is not URI?): /recipes/search?q= (URI::InvalidURIError)
/usr/lib/ruby/1.8/uri/common.rb:436:in `split'
/usr/lib/ruby/1.8/uri/common.rb:485:in `parse'
/usr/lib/ruby/1.8/uri/common.rb:608:in `URI'
(eval):7:in `get'
features/recipe_search.feature:116:in `When I seach for a pre-ascii character "%1F"'
URU::parse
, upon which Webrat relies, does not work with invalid characters:>> URI::parse("http://example.org/\t")Ah well, I will have to remove that step and hope that the earlier invalid /
URI::InvalidURIError: bad URI(is not URI?): http://example.org/
from /usr/lib/ruby/1.8/uri/common.rb:436:in `split'
from /usr/lib/ruby/1.8/uri/common.rb:485:in `parse'
from (irb):16
RestClient::RequestFailed
rescue will cover this case as well (it should).So the next step in the scenario is to see an empty query string. When a search fails, it is good form to provide a search field with the failing query string for editing by the user. Adding this, and then checking for an empty string, is a nice way to verify this step:
Then /^I should see an empty query string$/ doMaking this example pass is done with some simple Haml:
response.should have_selector("input[@name=query][@value='']")
end
%form{:method => "get", :action => "/recipes/search"}Last up is to handle invalid couchdb-lucene query strings (the double fielded "title:ingredient:egg" is used). As written, the scenario treats such a query as empty when displaying the "try again" no results page. It may be better form to display a helpful warning to the user, but this should be OK—users should not be mucking with couchdb-lucene fielded search much, if at all.
%input{:type => "text", :value => @query, :name => "query", :size => 31, :maxlength => 2048}
%input{:type => "submit", :value => "Search", :name => "s"}
The example in the Sintra application code borrows from the empty query string scenario to verify the query string displayed to the user:
it "should treat couchdb-lucene errors as an empty query" doGetting this example to pass is a simple matter of setting the
RestClient.stub!(:get).
and_raise(Exception)
get "/recipes/search?q=title:egg"
response.should have_selector("input[@name=query][@value='']")
end
@query
to the empty string when handing RestClient
exceptions:beginThat code not only gets the Sinatra application's specification to pass, but also the scenario as well:
data = RestClient.get couchdb_url
@results = JSON.parse(data)
rescue Exception
@query = ""
@results = { 'total_rows' => 0 }
end
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: Invalid search parameters
Given 5 "Yummy" recipes
And a 0.5 second wait to allow the search index to be updated
When I search for ""
Then I should see no results
And I should see an empty query string
When I search for an invalid lucene search term like "title:ingredient:egg"
Then I should see no results
And I should see an empty query string
1 scenario
8 passed steps
(commit)
That about does it for the recipe search scenarios. Some clean-up work will be required. Tomorrow.
No comments:
Post a Comment