Skip to content

Instantly share code, notes, and snippets.

@morhekil
Created June 22, 2014 06:00
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 morhekil/16c57ea5d9a2a0f25547 to your computer and use it in GitHub Desktop.
Save morhekil/16c57ea5d9a2a0f25547 to your computer and use it in GitHub Desktop.
custom RSpec 3 matcher for Grape Entities
# Custom RSpec 3 matcher to easily test validity of Grape API responses based on Grape::Entity serializers.
# It is assumed that all entities are defined as nested classes, which is the recommended approach, see
# the last example at https://github.com/intridea/grape#grape-entities
#
# HOW TO USE
# ----------
#
# 1. Require this file in your test environment.
#
# 2. To verify that a given JSON hash is the correct representation of a single model:
# expect(json['user']).to represent_entity_of(user)
#
# 3. To verify that a given JSON array of hashes is the correct representation of an array of models:
# expect(json['users']).to represent_array_of(users)
#
class GrapeEntityMatcher < Struct.new(:target)
def represents?(actual)
klass = target.class
if !klass.const_defined?('Entity')
raise ArgumentError, "#{klass} does not have nested Entity"
end
entity = klass.const_get('Entity').new(target)
actual == entity.serializable_hash.stringify_keys
end
end
RSpec::Matchers.define :represent_entity_of do |target|
match do |actual|
GrapeEntityMatcher.new(target).represents? actual
end
end
RSpec::Matchers.define :represent_array_of do |targets|
match do |actual_orig|
return false if actual.size != targets.size
actual = actual_orig.clone
targets.all? do |item|
match = actual.find { |t| GrapeEntityMatcher.new(item).represents? t }
match ? (actual.delete(match) && true) : false
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment