[rspec-users] Test JSON with Cucumber

Michael Schuerig michael at schuerig.de
Mon May 11 18:03:54 EDT 2009

On Monday 11 May 2009, Bill Kocik wrote:
> On Mon, May 11, 2009 at 4:32 PM, Ben Mabey <ben at benmabey.com> wrote:
> > 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

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 

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

def traverse(json, path)
  path.split('.').inject(json) do |value, selector|
    value = value[selector]


Michael Schuerig
mailto:michael at schuerig.de

More information about the rspec-users mailing list