require 'spec_helper' require 'grape_entity' describe Grape::Entity do subject { Class.new(Grape::API) } def app subject end describe '#present' do it 'sets the object as the body if no options are provided' do inner_body = nil subject.get '/example' do present(abc: 'def') inner_body = body end get '/example' expect(inner_body).to eql(abc: 'def') end it 'calls through to the provided entity class if one is given' do entity_mock = Object.new allow(entity_mock).to receive(:represent) subject.get '/example' do present Object.new, with: entity_mock end get '/example' end it 'pulls a representation from the class options if it exists' do entity = Class.new(Grape::Entity) allow(entity).to receive(:represent).and_return("Hiya") subject.represent Object, with: entity subject.get '/example' do present Object.new end get '/example' expect(last_response.body).to eq('Hiya') end it 'pulls a representation from the class options if the presented object is a collection of objects' do entity = Class.new(Grape::Entity) allow(entity).to receive(:represent).and_return("Hiya") class TestObject end class FakeCollection def first TestObject.new end end subject.represent TestObject, with: entity subject.get '/example' do present [TestObject.new] end subject.get '/example2' do present FakeCollection.new end get '/example' expect(last_response.body).to eq("Hiya") get '/example2' expect(last_response.body).to eq("Hiya") end it 'pulls a representation from the class ancestor if it exists' do entity = Class.new(Grape::Entity) allow(entity).to receive(:represent).and_return("Hiya") subclass = Class.new(Object) subject.represent Object, with: entity subject.get '/example' do present subclass.new end get '/example' expect(last_response.body).to eq('Hiya') end it 'automatically uses Klass::Entity if that exists' do some_model = Class.new entity = Class.new(Grape::Entity) allow(entity).to receive(:represent).and_return("Auto-detect!") some_model.const_set :Entity, entity subject.get '/example' do present some_model.new end get '/example' expect(last_response.body).to eq('Auto-detect!') end it 'automatically uses Klass::Entity based on the first object in the collection being presented' do some_model = Class.new entity = Class.new(Grape::Entity) allow(entity).to receive(:represent).and_return("Auto-detect!") some_model.const_set :Entity, entity subject.get '/example' do present [some_model.new] end get '/example' expect(last_response.body).to eq('Auto-detect!') end it 'does not run autodetection for Entity when explicitely provided' do entity = Class.new(Grape::Entity) some_array = Array.new subject.get '/example' do present some_array, with: entity end expect(some_array).not_to receive(:first) get '/example' end it 'does not use #first method on ActiveRecord::Relation to prevent needless sql query' do entity = Class.new(Grape::Entity) some_relation = Class.new some_model = Class.new allow(entity).to receive(:represent).and_return("Auto-detect!") allow(some_relation).to receive(:first) allow(some_relation).to receive(:klass).and_return(some_model) some_model.const_set :Entity, entity subject.get '/example' do present some_relation end expect(some_relation).not_to receive(:first) get '/example' expect(last_response.body).to eq('Auto-detect!') end it 'autodetection does not use Entity if it is not a presenter' do some_model = Class.new entity = Class.new some_model.class.const_set :Entity, entity subject.get '/example' do present some_model end get '/example' expect(entity).not_to receive(:represent) end it 'adds a root key to the output if one is given' do inner_body = nil subject.get '/example' do present({ abc: 'def' }, root: :root) inner_body = body end get '/example' expect(inner_body).to eql(root: { abc: 'def' }) end [:json, :serializable_hash].each do |format| it 'presents with #{format}' do entity = Class.new(Grape::Entity) entity.root "examples", "example" entity.expose :id subject.format format subject.get '/example' do c = Class.new do attr_reader :id def initialize(id) @id = id end end present c.new(1), with: entity end get '/example' expect(last_response.status).to eq(200) expect(last_response.body).to eq('{"example":{"id":1}}') end it 'presents with #{format} collection' do entity = Class.new(Grape::Entity) entity.root "examples", "example" entity.expose :id subject.format format subject.get '/examples' do c = Class.new do attr_reader :id def initialize(id) @id = id end end examples = [c.new(1), c.new(2)] present examples, with: entity end get '/examples' expect(last_response.status).to eq(200) expect(last_response.body).to eq('{"examples":[{"id":1},{"id":2}]}') end end it 'presents with xml' do entity = Class.new(Grape::Entity) entity.root "examples", "example" entity.expose :name subject.format :xml subject.get '/example' do c = Class.new do attr_reader :name def initialize(args) @name = args[:name] || "no name set" end end present c.new(name: "johnnyiller"), with: entity end get '/example' expect(last_response.status).to eq(200) expect(last_response.headers['Content-type']).to eq("application/xml") expect(last_response.body).to eq <<-XML johnnyiller XML end it 'presents with json' do entity = Class.new(Grape::Entity) entity.root "examples", "example" entity.expose :name subject.format :json subject.get '/example' do c = Class.new do attr_reader :name def initialize(args) @name = args[:name] || "no name set" end end present c.new(name: "johnnyiller"), with: entity end get '/example' expect(last_response.status).to eq(200) expect(last_response.headers['Content-type']).to eq("application/json") expect(last_response.body).to eq('{"example":{"name":"johnnyiller"}}') end it 'presents with jsonp utilising Rack::JSONP' do require 'rack/contrib' # Include JSONP middleware subject.use Rack::JSONP entity = Class.new(Grape::Entity) entity.root "examples", "example" entity.expose :name # Rack::JSONP expects a standard JSON response subject.format :json subject.get '/example' do c = Class.new do attr_reader :name def initialize(args) @name = args[:name] || "no name set" end end present c.new(name: "johnnyiller"), with: entity end get '/example?callback=abcDef' expect(last_response.status).to eq(200) expect(last_response.headers['Content-type']).to eq("application/javascript") expect(last_response.body).to eq('abcDef({"example":{"name":"johnnyiller"}})') end context "present with multiple entities" do it "present with multiple entities using optional symbol" do user = Class.new do attr_reader :name def initialize(args) @name = args[:name] || "no name set" end end user1 = user.new(name: 'user1') user2 = user.new(name: 'user2') entity = Class.new(Grape::Entity) entity.expose :name subject.format :json subject.get '/example' do present :page, 1 present :user1, user1, with: entity present :user2, user2, with: entity end get '/example' expect_response_json = { "page" => 1, "user1" => { "name" => "user1" }, "user2" => { "name" => "user2" } } expect(JSON(last_response.body)).to eq(expect_response_json) end end end end