collectiveidea / json_spec

Easily handle JSON in RSpec and Cucumber
rubygems.org/gems/json_spec
MIT License
917 stars 114 forks source link

MultiJson Load errors on be_json_eql matchers #43

Open bradherman opened 11 years ago

bradherman commented 11 years ago

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'
laserlemon commented 11 years ago

What's your JSON?

laserlemon commented 11 years ago

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

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

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 commented 11 years ago

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.

laserlemon commented 11 years ago

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
bradherman commented 11 years ago
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:
laserlemon commented 11 years ago

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?

alexpylko commented 11 years ago

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