json_spec icon indicating copy to clipboard operation
json_spec copied to clipboard

MultiJson Load errors on be_json_eql matchers

Open bradherman opened this issue 12 years ago • 9 comments
trafficstars

in my tests:

this passes

it {should be_json_eql(@league.id).at_path('id')}

this throws MultiJson load error

it {should be_json_eql(@league.href).at_path('href')}

Failure/Error: it {should be_json_eql(@league.href).at_path('href')}
 MultiJson::LoadError:
   795: unexpected token at 'http://0.0.0.0/api/leagues/259?post=3000'

bradherman avatar Jun 06 '13 20:06 bradherman

What's your JSON?

laserlemon avatar Jun 06 '13 20:06 laserlemon

JSON strings must be quoted with double quotes, not single. That may be your issue.

laserlemon avatar Jun 06 '13 20:06 laserlemon

{
  "meta": {},
  "leagues": [
    {
      "id": 1,
      "name": "NFL/Football",
      "href": "http://0.0.0.0:5000/api/leagues/1"
    }
  ]
}

bradherman avatar Jun 06 '13 21:06 bradherman

I'm inspecting now and it's weird. Check this out:

def parse_json(json, path = nil)
  ruby = MultiJson.decode("[#{json}]").first
  puts "GOT RUBY: #{ruby}"
  v = value_at_json_path(ruby, path)
  puts "GOT VALUE: #{v}"
  v
rescue MultiJson::DecodeError => e
  puts "GOT ERROR"
  MultiJson.decode(json)
end

gives

GOT RUBY: {"meta"=>{"version"=>1, "href"=>"http://0.0.0.0:3000/api"}, "leagues"=>"http://0.0.0.0:3000/api/leagues", "teams"=>"http://0.0.0.0:3000/api/teams", "rosters"=>"http://0.0.0.0:3000/api/rosters", "players"=>"http://0.0.0.0:3000/api/players"}
GOT VALUE: http://0.0.0.0:3000/api/teams
GOT ERROR

bradherman avatar Jun 06 '13 21:06 bradherman

It's picking up an error even though there isn't one. If I rescue the MultiJson.decode(json) with the @v (value_at_json_path return value), it works and all tests pass.

bradherman avatar Jun 06 '13 21:06 bradherman

Try running it with this:

def parse_json(json, path = nil)
  puts "GOT JSON: #{json}"
  puts "GOT PATH: #{path}"
  ruby = MultiJson.decode("[#{json}]").first
  puts "GOT RUBY: #{ruby}"
  v = value_at_json_path(ruby, path)
  puts "GOT VALUE: #{v}"
  v
rescue MultiJson::DecodeError => e
  puts "GOT ERROR"
  MultiJson.decode(json)
end

laserlemon avatar Jun 07 '13 14:06 laserlemon

GOT JSON: {"meta":{},"id":313,"href":"http://0.0.0.0:3000/api/leagues/313","name":"League0","teams":[{"id":732,"full_name":" Colts","href":"http://0.0.0.0:3000/api/teams/732"}]}
GOT PATH: name
GOT RUBY: {"meta"=>{}, "id"=>313, "href"=>"http://0.0.0.0:3000/api/leagues/313", "name"=>"League0", "teams"=>[{"id"=>732, "full_name"=>" Colts", "href"=>"http://0.0.0.0:3000/api/teams/732"}]}
GOT VALUE: League0
GOT JSON: {"meta":{},"id":313,"href":"http://0.0.0.0:3000/api/leagues/313","name":"League0","teams":[{"id":732,"full_name":" Colts","href":"http://0.0.0.0:3000/api/teams/732"}]}
GOT PATH: teams
GOT RUBY: {"meta"=>{}, "id"=>313, "href"=>"http://0.0.0.0:3000/api/leagues/313", "name"=>"League0", "teams"=>[{"id"=>732, "full_name"=>" Colts", "href"=>"http://0.0.0.0:3000/api/teams/732"}]}
GOT VALUE: [{"id"=>732, "full_name"=>" Colts", "href"=>"http://0.0.0.0:3000/api/teams/732"}]
GOT JSON: {"meta":{},"id":313,"href":"http://0.0.0.0:3000/api/leagues/313","name":"League0","teams":[{"id":732,"full_name":" Colts","href":"http://0.0.0.0:3000/api/teams/732"}]}
GOT PATH: href
GOT RUBY: {"meta"=>{}, "id"=>313, "href"=>"http://0.0.0.0:3000/api/leagues/313", "name"=>"League0", "teams"=>[{"id"=>732, "full_name"=>" Colts", "href"=>"http://0.0.0.0:3000/api/teams/732"}]}
GOT VALUE: http://0.0.0.0:3000/api/leagues/313
GOT JSON: http://0.0.0.0:3000/api/leagues/313
GOT PATH:
GOT ERROR
  2) Api::LeaguesController#show valid id passed response
     Failure/Error: it {should be_json_eql(@league.href).   at_path('href')}
     MultiJson::LoadError:

bradherman avatar Jun 07 '13 17:06 bradherman

I think I figured it out (and should have a long time ago). The JSON matchers are meant to compare JSON to JSON. Above, you're comparing JSON to Ruby. So when you give an expected string to the matcher, the matcher figures you're giving it JSON. So it's trying to parse "http://0.0.0.0:3000/api/leagues/313" as if it were JSON. Of course, that won't work and bombs how you're seeing. Does that make sense?

laserlemon avatar Jun 07 '13 17:06 laserlemon

Try this it {should be_json_eql(@league.href.to_json).at_path('href')}

alexpylko avatar Jul 13 '13 17:07 alexpylko