Skip to content

Instantly share code, notes, and snippets.

@jsmestad
Created February 2, 2012 00:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsmestad/1720538 to your computer and use it in GitHub Desktop.
Save jsmestad/1720538 to your computer and use it in GitHub Desktop.
require File.expand_path('../exceptions', __FILE__)
# Supports the following matchers:
#
# describe '/api/account.json' do
# subject { json_response }
# before { get '/api/account.json' }
# it { should have_json(:email).of_type(String) }
# it { should have_json(:posts).of_type(Array).inside_of('account') }
# it { should have_json(:review).of_type(Hash).inside_of('account/profile') }
# end
#
RSpec::Matchers.define :have_json do |name|
diffable
match do |json|
begin
@obj = value_at_json_path(json, @path)["#{name}"]
@obj != nil && (@type_class.present? ? @obj.kind_of?(@type_class) : true)
rescue Response::Matchers::MissingPathError
false
end
end
chain :of_type do |type_class|
@type_class = type_class
end
chain :inside_of do |path|
@path = path
end
failure_message_for_should do |json|
message = "expected JSON signature to include attribute '#{name}'"
message << %( of type #{@type_class}) if @type_class
message << %( at path "#{@path}") if @path
message << %(, but it was #{@obj.inspect})
message
end
failure_message_for_should_not do |json|
message = "expected JSON signature to exclude attribute '#{name}'"
message << %( of type #{@type_class}) if @type_class
message << %( at path "#{@path}") if @path
message << %(, but it was #{@obj.inspect})
message
end
description do
message = "contain the JSON signature for '#{name.to_s}'"
message << %( of type #{@type_class}) if @type_class.present?
message << %( at path "#{@path}") if @path.present?
message
end
# Begin internal helpers
def value_at_json_path(json, path)
return json unless path
json_path_to_keys(path).inject(json) do |value, key|
case value
when Hash, Array then value.fetch(key){ missing_json_path!(path) }
else missing_json_path!(path)
end
end
end
def json_path_to_keys(path)
path.split("/").map{|k| k =~ /^\d+$/ ? k.to_i : k }
end
def missing_json_path!(path)
raise Response::Matchers::MissingPathError.new(path)
end
end
@jsmestad
Copy link
Author

jsmestad commented Feb 2, 2012

Output looks like

:public is no longer used to avoid overloading Module#public, use :public_folder instead
        from /Users/justinsmestad/.rbenv/versions/1.9.3-p0/lib/ruby/gems/1.9.1/gems/resque-1.19.0/lib/resque/server.rb:12:in `<class:Server>'
Run filtered including {:locations=>{"./spec/api/account/profiles_api_spec.rb"=>[28]}}

/v1/account.json
  profile updates
    the return payload
      should contain the JSON signature for 'biography' of type String

Finished in 17.28 seconds
1 example, 0 failures

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment