can_assets_examples.rb 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. RSpec.shared_examples 'ApplicationModel::CanAssets' do |associations: [], selectors: [], own_attributes: true|
  3. subject { create(described_class.name.underscore, updated_by_id: admin.id) }
  4. let(:admin) { create(:admin) }
  5. describe '#assets (for supplying model data to front-end framework)' do
  6. shared_examples 'own asset attributes' do
  7. it 'returns a hash with own asset attributes' do
  8. expect(subject.assets({})[described_class.to_app_model])
  9. .to include(subject.id => hash_including(subject.attributes_with_association_ids))
  10. end
  11. end
  12. include_examples 'own asset attributes' if own_attributes
  13. context 'when given a non-empty hash' do
  14. let(:hash) { { described_class.to_app_model => { foo: 'bar' } } }
  15. it 'deep-merges assets into it, in place' do
  16. expect { subject.assets(hash) }
  17. .to change { hash }
  18. .to(hash.deep_merge(subject.assets({})))
  19. end
  20. end
  21. Array(associations).each do |association|
  22. describe "for ##{association} association" do
  23. let(:reflection) { described_class.reflect_on_association(association) }
  24. shared_examples 'single association' do
  25. subject { create(described_class.name.underscore, association => single) }
  26. let(:single) { create(reflection.class_name.underscore) }
  27. it 'returns a hash with its asset attributes' do
  28. expect(subject.assets({})).to include(single.assets({}))
  29. end
  30. context 'after association has been modified' do
  31. it 'does not use a cached value' do
  32. subject.assets({})
  33. single.update(updated_by_id: User.last.id)
  34. expect(subject.assets({}).dig(reflection.klass.to_app_model, single.id))
  35. .to include(single.attributes_with_association_ids)
  36. end
  37. end
  38. end
  39. shared_examples 'collection association' do
  40. subject { create(described_class.name.underscore, association => collection) }
  41. let(:collection) { create_list(reflection.class_name.underscore, 5) }
  42. let(:collection_assets) { collection.reduce({}) { |assets_hash, single| single.assets(assets_hash) } }
  43. it 'returns a hash with their asset attributes' do
  44. expect(subject.assets({})[reflection.klass.to_app_model]).to include(collection_assets[reflection.klass.to_app_model])
  45. end
  46. context 'after association has been modified' do
  47. it 'does not use a cached value' do
  48. subject.assets({})
  49. collection.first.update(updated_by_id: User.last.id)
  50. expect(subject.assets({}).dig(reflection.klass.to_app_model, collection.first.id))
  51. .to include(collection.first.attributes_with_association_ids)
  52. end
  53. end
  54. end
  55. if described_class.reflect_on_association(association).macro.in?(%i[has_one belongs_to])
  56. include_examples 'single association'
  57. else
  58. include_examples 'collection association'
  59. end
  60. end
  61. end
  62. Array(selectors).each do |s|
  63. subject { create(described_class.name.underscore, s => selector) }
  64. let(:selector) { { 'ticket.priority_id' => { operator: 'is', value: [1, 2] } } }
  65. let(:priorities_assets) { Ticket::Priority.first(2).reduce({}) { |asset_hash, priority| priority.assets(asset_hash) } }
  66. describe "for objects referenced in ##{s}" do
  67. it 'returns a hash with their asset attributes' do
  68. expect(subject.assets({})).to include(priorities_assets)
  69. end
  70. end
  71. end
  72. end
  73. end