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' }