I'm hoping someone has come before me in trying to do this. I want to
use Cucumber to acceptance-test my JSON output. So far all I can do is
validate that the JSON is valid, with this step:
Then /^I should get valid JSON$/ do
assert_nothing_raised do
ActiveSupport::JSON.decode(@response.body)
end
What I'd really like to do is be able to drill down into the JSON
looking for the presence of certain elements in their correct places.
For example, if my JSON is {"foo":{"bar":"baz"}} and parses out to
{'foo' => {'bar' => 'baz'}} then I want to be able to test that
['foo']['bar'] gives me 'baz', or at least that ['foo']['bar'] exists.
Unfortunately I'm not sure how to go about writing step definitions to
do anything like this, since I haven't yet figured out a way to take a
regular expression or string and inspect a hash with it.
Anyone have any ideas? I could really use a brain-kick here.
Thanks...
--
Bill Kocik
http://bkocik.net
_______________________________________________
rspec-users mailing list
rspec...@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users
Well.. IIRC ActiveSupport::JSON.decode will return a ruby hash of the
JSON, correct? So you should be able to make expectations on it just
like a regular hash object.
json = ActiveSupport::JSON.decode(@response.body)
json['foo']['bar'].should == 'baz'.
Does that help or am I missing something about your question?
-Ben
> Well.. IIRC ActiveSupport::JSON.decode will return a ruby hash of the JSON,
> correct? So you should be able to make expectations on it just like a
> regular hash object.
You're absolutely correct - I think I did a poor job of asking my
question. Maybe a more concrete example would help. Suppose I have
this JSON:
response:{code:'200',requestId:'1234'}
I want to have a scenario like this in my Cucumber feature file:
When I go to "the statuses JSON url"
Then I should find "....." # ['response']['code']
And I should find "....." #['response']['requestId']
With a step definition like:
Then /^I should find "([^\"]*)"$/ do |the_string|
json = ActiveSupport::JSON.decode(@response.body)
assert_not_nil ...... #(something with the json obect and the_string)
end
I don't know what goes in those blanks. Cucumber is going to give me a
string it found with the regex, but I don't know what the string would
look like in my "Then I should find" line in my feature file, nor what
to do with it in my assert line in the step definition. I'm not even
sure any of this is possible.
Consider if I were dealing with XML instead of JSON - I could put an
XPath expression in my "Then I should find" line, and in my step
definition I could search the XML with the given XPath expression
using hpricot or something. With JSON and it's resultant hash, I have
no idea where to start...
--
Bill Kocik
Do you want to cherry-pick individual pieces from the JSON, i.e. you
don't care about the exact response as long as the parts you're looking
for are there? Or would it be okay to check against a known good
response?
The latter case is easier. In the former case, how about a matcher that
checks the actual response is a superset of the expected response?
[...]
> Consider if I were dealing with XML instead of JSON - I could put an
> XPath expression in my "Then I should find" line, and in my step
> definition I could search the XML with the given XPath expression
> using hpricot or something. With JSON and it's resultant hash, I have
> no idea where to start...
There's JSONPath, but I don't think a Ruby implementation exists. If you
always have "definite" paths without wildcards and recursion(?) then you
might be able to do with some simple code like this
When I go to "the statuses JSON url"
Then I should find "response.code"
Then /^I should find "([^\"]*)"$/ do |the_string|
json = ActiveSupport::JSON.decode(@response.body)
obj = traverse(json, the_string)
assert_not_nil obj
end
def traverse(json, path)
path.split('.').inject(json) do |value, selector|
value = value[selector]
end
rescue
nil
end
Michael
--
Michael Schuerig
mailto:mic...@schuerig.de
http://www.schuerig.de/michael/
Another options is to call #to_xml on the JSON hash returned by
#decode, and then use XPath since you seem to already know it,
> --
> Bill Kocik
>
> http://bkocik.net
> _______________________________________________
> rspec-users mailing list
> rspec...@rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>
--
Zach Dennis
http://www.continuousthinking.com (personal)
http://www.mutuallyhuman.com (hire me)
@zachdennis (twitter)
The upside is that I can query my JSON with arbitrary depth and
precision using XPath. Awesome.
I love having access to groups of people who are smarter than me.
Thanks for everyone's suggestions...