spec/grape_entity/entity_spec.rb in grape-entity-0.9.0 vs spec/grape_entity/entity_spec.rb in grape-entity-0.10.0
- old
+ new
@@ -28,13 +28,11 @@
expect { subject.expose :name, as: :foo }.not_to raise_error
end
it 'makes sure that :format_with as a proc cannot be used with a block' do
# rubocop:disable Style/BlockDelimiters
- # rubocop:disable Lint/EmptyBlock
expect { subject.expose :name, format_with: proc {} do p 'hi' end }.to raise_error ArgumentError
- # rubocop:enable Lint/EmptyBlock
# rubocop:enable Style/BlockDelimiters
end
it 'makes sure unknown options are not silently ignored' do
expect { subject.expose :name, unknown: nil }.to raise_error ArgumentError
@@ -212,10 +210,134 @@
end
end
end
end
+ context 'with :default option' do
+ let(:a) { nil }
+ let(:b) { nil }
+ let(:c) { 'value' }
+
+ context 'when model is a PORO' do
+ let(:model) { Model.new(a, b, c) }
+
+ before do
+ stub_const 'Model', Class.new
+ Model.class_eval do
+ attr_accessor :a, :b, :c
+
+ def initialize(a, b, c)
+ @a = a
+ @b = b
+ @c = c
+ end
+ end
+ end
+
+ context 'when default option is not provided' do
+ it 'exposes attributes values' do
+ subject.expose(:a)
+ subject.expose(:b)
+ subject.expose(:c)
+ expect(subject.represent(model).serializable_hash).to eq(a: nil, b: nil, c: 'value')
+ end
+ end
+
+ context 'when default option is set' do
+ it 'exposes default values for attributes' do
+ subject.expose(:a, default: 'a')
+ subject.expose(:b, default: 'b')
+ subject.expose(:c, default: 'c')
+ expect(subject.represent(model).serializable_hash).to eq(a: 'a', b: 'b', c: 'value')
+ end
+ end
+
+ context 'when default option is set and block passed' do
+ it 'return default value if block returns nil' do
+ subject.expose(:a, default: 'a') do |_obj, _options|
+ nil
+ end
+ subject.expose(:b)
+ subject.expose(:c)
+ expect(subject.represent(model).serializable_hash).to eq(a: 'a', b: nil, c: 'value')
+ end
+
+ it 'return value from block if block returns a value' do
+ subject.expose(:a, default: 'a') do |_obj, _options|
+ 100
+ end
+ subject.expose(:b)
+ subject.expose(:c)
+ expect(subject.represent(model).serializable_hash).to eq(a: 100, b: nil, c: 'value')
+ end
+ end
+ end
+
+ context 'when model is a hash' do
+ let(:model) { { a: a, b: b, c: c } }
+
+ context 'when expose_nil option is not provided' do
+ it 'exposes nil attributes' do
+ subject.expose(:a)
+ subject.expose(:b)
+ subject.expose(:c)
+ expect(subject.represent(model).serializable_hash).to eq(a: nil, b: nil, c: 'value')
+ end
+ end
+
+ context 'when expose_nil option is true' do
+ it 'exposes nil attributes' do
+ subject.expose(:a, expose_nil: true)
+ subject.expose(:b, expose_nil: true)
+ subject.expose(:c)
+ expect(subject.represent(model).serializable_hash).to eq(a: nil, b: nil, c: 'value')
+ end
+ end
+
+ context 'when expose_nil option is false' do
+ it 'does not expose nil attributes' do
+ subject.expose(:a, expose_nil: false)
+ subject.expose(:b, expose_nil: false)
+ subject.expose(:c)
+ expect(subject.represent(model).serializable_hash).to eq(c: 'value')
+ end
+
+ it 'is only applied per attribute' do
+ subject.expose(:a, expose_nil: false)
+ subject.expose(:b)
+ subject.expose(:c)
+ expect(subject.represent(model).serializable_hash).to eq(b: nil, c: 'value')
+ end
+
+ it 'raises an error when applied to multiple attribute exposures' do
+ expect { subject.expose(:a, :b, :c, expose_nil: false) }.to raise_error ArgumentError
+ end
+ end
+ end
+
+ context 'with nested structures' do
+ let(:model) { { a: a, b: b, c: { d: nil, e: nil, f: { g: nil, h: nil } } } }
+
+ context 'when expose_nil option is false' do
+ it 'does not expose nil attributes' do
+ subject.expose(:a, expose_nil: false)
+ subject.expose(:b)
+ subject.expose(:c) do
+ subject.expose(:d, expose_nil: false)
+ subject.expose(:e)
+ subject.expose(:f) do
+ subject.expose(:g, expose_nil: false)
+ subject.expose(:h)
+ end
+ end
+
+ expect(subject.represent(model).serializable_hash).to eq(b: nil, c: { e: nil, f: { h: nil } })
+ end
+ end
+ end
+ end
+
context 'with a block' do
it 'errors out if called with multiple attributes' do
expect { subject.expose(:name, :email) { true } }.to raise_error ArgumentError
end
@@ -1135,10 +1257,22 @@
representation = subject.represent(OpenStruct.new(user: {}),
only: %i[id name user], except: [:nephew], serializable: true)
expect(representation).to eq(id: nil, name: nil, user: { id: nil, name: nil, email: nil })
end
end
+
+ context 'when NameError happens in a parameterized block_exposure' do
+ before do
+ subject.expose :raise_no_method_error do |_|
+ foo
+ end
+ end
+
+ it 'does not cause infinite loop' do
+ expect { subject.represent({}, serializable: true) }.to raise_error(NameError)
+ end
+ end
end
end
describe '.present_collection' do
it 'make the objects accessible' do
@@ -1579,10 +1713,10 @@
expose(:value) { |_, o| o[:attr_path].join('/') }
end
end
fresh_class.class_eval do
- expose :characteristics, using: EntitySpec::NoPathCharacterEntity, attr_path: proc { nil }
+ expose :characteristics, using: EntitySpec::NoPathCharacterEntity, attr_path: proc {}
end
expect(subject.serializable_hash).to eq(
characteristics: [
{ key: 'key', value: 'value' }