rspec-grape-entity 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rspec.yml +26 -0
  3. data/.github/workflows/rubocop.yml +30 -0
  4. data/.gitignore +17 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +13 -0
  7. data/Gemfile +13 -0
  8. data/LICENSE +21 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +695 -0
  11. data/Rakefile +12 -0
  12. data/bin/console +15 -0
  13. data/bin/setup +8 -0
  14. data/lib/rspec-grape-entity.rb +3 -0
  15. data/lib/rspec_grape_entity/describe_exposure.rb +125 -0
  16. data/lib/rspec_grape_entity/dsl.rb +16 -0
  17. data/lib/rspec_grape_entity/its_exposure.rb +72 -0
  18. data/lib/rspec_grape_entity/matchers/be_a_exposure_type_matcher.rb +33 -0
  19. data/lib/rspec_grape_entity/matchers/be_merged_matcher.rb +21 -0
  20. data/lib/rspec_grape_entity/matchers/be_safe_matcher.rb +21 -0
  21. data/lib/rspec_grape_entity/matchers/be_using_class_matcher.rb +21 -0
  22. data/lib/rspec_grape_entity/matchers/have_conditions_met_matcher.rb +36 -0
  23. data/lib/rspec_grape_entity/matchers/have_formatting_matcher.rb +39 -0
  24. data/lib/rspec_grape_entity/matchers/have_key_matcher.rb +21 -0
  25. data/lib/rspec_grape_entity/matchers/have_root_matcher.rb +33 -0
  26. data/lib/rspec_grape_entity/matchers/include_documentation_matcher.rb +26 -0
  27. data/lib/rspec_grape_entity/matchers/matcher_helpers.rb +24 -0
  28. data/lib/rspec_grape_entity/matchers/override_exposure_matcher.rb +21 -0
  29. data/lib/rspec_grape_entity/version.rb +5 -0
  30. data/lib/rspec_grape_entity.rb +28 -0
  31. data/rspec-grape-entity.gemspec +37 -0
  32. data/spec/describe_exposure_spec.rb +29 -0
  33. data/spec/entities/test_entity_spec.rb +150 -0
  34. data/spec/its_exposure_spec.rb +16 -0
  35. data/spec/matchers/be_a_exposure_type_matcher_spec.rb +106 -0
  36. data/spec/matchers/be_merged_matcher_spec.rb +19 -0
  37. data/spec/matchers/be_safe_matcher_spec.rb +19 -0
  38. data/spec/matchers/be_using_class_matcher_spec.rb +15 -0
  39. data/spec/matchers/have_conditions_met_matcher_spec.rb +40 -0
  40. data/spec/matchers/have_formatting_matcher_spec.rb +25 -0
  41. data/spec/matchers/have_key_matcher_spec.rb +23 -0
  42. data/spec/matchers/have_root_matcher_spec.rb +47 -0
  43. data/spec/matchers/include_documentation_matcher_spec.rb +31 -0
  44. data/spec/matchers/matcher_helpers_spec.rb +76 -0
  45. data/spec/matchers/override_exposure_matcher_spec.rb +19 -0
  46. data/spec/spec_helper.rb +21 -0
  47. data/spec/support/test_entity.rb +23 -0
  48. data/spec/support/user_entity.rb +12 -0
  49. metadata +181 -0
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe TestEntity, type: :grape_entity do
6
+ let(:object) do
7
+ OpenStruct.new id: 1,
8
+ record_status: "active",
9
+ user: OpenStruct.new,
10
+ read: true,
11
+ update: false,
12
+ destroy: false,
13
+ created_at: Time.utc(2022, 1, 1, 15, 0, 0),
14
+ updated_at: Time.now,
15
+ has_date: true
16
+ end
17
+
18
+ it { expect(described_class).to have_root("test_items").with_singular("test_item") }
19
+
20
+ context "when using its_exposure" do
21
+ let(:object_without_date) { OpenStruct.new has_date: false }
22
+
23
+ its_exposure(:id) { is_expected.to be_a_delegator_exposure }
24
+ its_exposure(:id) { is_expected.to include_documentation type: Integer, desc: "The record id" }
25
+ its_exposure(:id) { is_expected.not_to be_safe }
26
+ its_exposure(:id) { is_expected.not_to be_merged }
27
+ its_exposure(:id) { is_expected.not_to override_exposure }
28
+ its_exposure(:record_status) { is_expected.to be_a_delegator_exposure }
29
+ its_exposure(:record_status) { is_expected.to have_key :status }
30
+ its_exposure(:record_status) { is_expected.to have_conditions_met(object).with_options(all: :something) }
31
+ its_exposure(:record_status) { is_expected.to_not have_conditions_met object }
32
+ its_exposure(:record_status) { is_expected.not_to be_safe }
33
+ its_exposure(:record_status) { is_expected.not_to be_merged }
34
+ its_exposure(:record_status) { is_expected.not_to override_exposure }
35
+ its_exposure(:user) { is_expected.to be_a_represent_exposure }
36
+ its_exposure(:user) { is_expected.to be_using_class UserEntity }
37
+ its_exposure(:user) { is_expected.to have_conditions_met(object).with_options(type: :admin) }
38
+ its_exposure(:user) { is_expected.not_to have_conditions_met(object).with_options(type: :user) }
39
+ its_exposure(:user) { is_expected.not_to have_conditions_met object }
40
+ its_exposure(:custom_data) { is_expected.to be_a_block_exposure }
41
+ its_exposure(:custom_data) { is_expected.not_to be_safe }
42
+ its_exposure(:custom_data) { is_expected.to be_merged }
43
+ its_exposure(:custom_data) { is_expected.not_to override_exposure }
44
+ its_exposure(:permissions) { is_expected.to be_a_nesting_exposure }
45
+ its_exposure(:permissions) { is_expected.not_to be_safe }
46
+ its_exposure(:permissions) { is_expected.not_to be_merged }
47
+ its_exposure(:permissions) { is_expected.to override_exposure }
48
+ its_exposure("permissions.read") { is_expected.to be_a_delegator_exposure }
49
+ its_exposure("permissions.read") { is_expected.not_to be_safe }
50
+ its_exposure("permissions.read") { is_expected.not_to be_merged }
51
+ its_exposure("permissions.read") { is_expected.not_to override_exposure }
52
+ its_exposure("permissions.update") { is_expected.to be_a_delegator_exposure }
53
+ its_exposure("permissions.update") { is_expected.not_to be_safe }
54
+ its_exposure("permissions.update") { is_expected.not_to be_merged }
55
+ its_exposure("permissions.update") { is_expected.not_to override_exposure }
56
+ its_exposure("permissions.destroy") { is_expected.to be_a_delegator_exposure }
57
+ its_exposure("permissions.destroy") { is_expected.not_to be_safe }
58
+ its_exposure("permissions.destroy") { is_expected.not_to be_merged }
59
+ its_exposure("permissions.destroy") { is_expected.not_to override_exposure }
60
+ its_exposure("created_at") { is_expected.to be_a_formatter_block_exposure }
61
+ its_exposure("created_at") { is_expected.to have_formatting("2022-01-01T15:00:00Z").with_object(object) }
62
+ its_exposure("created_at") { is_expected.not_to be_safe }
63
+ its_exposure("created_at") { is_expected.not_to be_merged }
64
+ its_exposure("created_at") { is_expected.not_to override_exposure }
65
+ its_exposure("created_at") { is_expected.to have_conditions_met object }
66
+ its_exposure("created_at") { is_expected.to_not have_conditions_met object_without_date }
67
+ end
68
+
69
+ context "when using describe_exposure" do
70
+ shared_examples "has permissions" do |permission|
71
+ describe_exposure "permissions.#{permission}" do
72
+ it { is_expected.to be_a_delegator_exposure }
73
+ it { is_expected.not_to be_safe }
74
+ it { is_expected.not_to be_merged }
75
+ it { is_expected.not_to override_exposure }
76
+ end
77
+ end
78
+
79
+ describe_exposure :id do
80
+ it { is_expected.to be_a_delegator_exposure }
81
+ it { is_expected.to include_documentation type: Integer, desc: "The record id" }
82
+ it { is_expected.not_to be_safe }
83
+ it { is_expected.not_to be_merged }
84
+ it { is_expected.not_to override_exposure }
85
+ end
86
+
87
+ describe_exposure :record_status do
88
+ it { is_expected.to be_a_delegator_exposure }
89
+ it { is_expected.to have_key :status }
90
+ it { is_expected.to have_conditions_met(object).with_options(all: :something) }
91
+ it { is_expected.to_not have_conditions_met object }
92
+ it { is_expected.not_to be_safe }
93
+ it { is_expected.not_to be_merged }
94
+ it { is_expected.not_to override_exposure }
95
+ end
96
+
97
+ describe_exposure :user do
98
+ it { is_expected.to be_a_represent_exposure }
99
+ it { is_expected.to be_using_class UserEntity }
100
+
101
+ context "when type is an admin" do
102
+ it { is_expected.to have_conditions_met(object).with_options(type: :admin) }
103
+ end
104
+
105
+ context "when type is not an admin" do
106
+ it { is_expected.not_to have_conditions_met(object).with_options(type: :user) }
107
+ end
108
+
109
+ context "when no type is declared" do
110
+ it { is_expected.not_to have_conditions_met object }
111
+ end
112
+ end
113
+
114
+ describe_exposure :custom_data do
115
+ it { is_expected.to be_a_block_exposure }
116
+ it { is_expected.not_to be_safe }
117
+ it { is_expected.to be_merged }
118
+ it { is_expected.not_to override_exposure }
119
+ end
120
+
121
+ describe_exposure :permissions do
122
+ it { is_expected.to be_a_nesting_exposure }
123
+ it { is_expected.not_to be_safe }
124
+ it { is_expected.not_to be_merged }
125
+ it { is_expected.to override_exposure }
126
+ end
127
+
128
+ it_behaves_like "has permissions", "read"
129
+ it_behaves_like "has permissions", "update"
130
+ it_behaves_like "has permissions", "destroy"
131
+
132
+ describe_exposure :created_at do
133
+ it { is_expected.to be_a_formatter_block_exposure }
134
+ it { is_expected.to have_formatting("2022-01-01T15:00:00Z").with_object(object) }
135
+ it { is_expected.not_to be_safe }
136
+ it { is_expected.not_to be_merged }
137
+ it { is_expected.not_to override_exposure }
138
+
139
+ context "when has date" do
140
+ it { is_expected.to have_conditions_met object }
141
+ end
142
+
143
+ context "when does not have date" do
144
+ let(:object) { OpenStruct.new has_date: false }
145
+
146
+ it { is_expected.not_to have_conditions_met object }
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::ItsExposure do
6
+ include RSpec::Grape::Entity::DSL
7
+
8
+ let(:entity) { TestEntity }
9
+
10
+ its_exposure(:id)
11
+ its_exposure("id")
12
+ its_exposure(:id) { is_expected.to be_a Grape::Entity::Exposure::DelegatorExposure }
13
+ its_exposure(:unknown) { is_expected.to be_nil }
14
+ its_exposure("permissions.read") { is_expected.to be_a Grape::Entity::Exposure::DelegatorExposure }
15
+ its_exposure("unknown.unknown") { expect { __attribute_exposure }.to raise_error NoMethodError }
16
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::BeAExposureTypeMatcher do
6
+ include RSpec::Grape::Entity::Matchers::BeAExposureTypeMatcher
7
+
8
+ let(:entity) { TestEntity }
9
+ subject(:exposure) { entity.find_exposure attribute }
10
+
11
+ context "when a block exposure" do
12
+ let(:attribute) { :custom_data }
13
+ it { is_expected.to be_a_exposure_type :block }
14
+ it { is_expected.not_to be_a_exposure_type :delegator }
15
+ it { is_expected.not_to be_a_exposure_type :formatter }
16
+ it { is_expected.not_to be_a_exposure_type :formatter_block }
17
+ it { is_expected.not_to be_a_exposure_type :nesting }
18
+ it { is_expected.not_to be_a_exposure_type :represent }
19
+ it { is_expected.to be_a_block_exposure }
20
+ it { is_expected.not_to be_a_delegator_exposure }
21
+ it { is_expected.not_to be_a_formatter_exposure }
22
+ it { is_expected.not_to be_a_formatter_block_exposure }
23
+ it { is_expected.not_to be_a_nesting_exposure }
24
+ it { is_expected.not_to be_a_represent_exposure }
25
+ end
26
+
27
+ context "when a delegator exposure" do
28
+ let(:attribute) { :id }
29
+ it { is_expected.not_to be_a_exposure_type :block }
30
+ it { is_expected.to be_a_exposure_type :delegator }
31
+ it { is_expected.not_to be_a_exposure_type :formatter }
32
+ it { is_expected.not_to be_a_exposure_type :formatter_block }
33
+ it { is_expected.not_to be_a_exposure_type :nesting }
34
+ it { is_expected.not_to be_a_exposure_type :represent }
35
+ it { is_expected.not_to be_a_block_exposure }
36
+ it { is_expected.to be_a_delegator_exposure }
37
+ it { is_expected.not_to be_a_formatter_exposure }
38
+ it { is_expected.not_to be_a_formatter_block_exposure }
39
+ it { is_expected.not_to be_a_nesting_exposure }
40
+ it { is_expected.not_to be_a_represent_exposure }
41
+ end
42
+
43
+ context "when a formatter exposure" do
44
+ let(:attribute) { :updated_at }
45
+ it { is_expected.not_to be_a_exposure_type :block }
46
+ it { is_expected.not_to be_a_exposure_type :delegator }
47
+ it { is_expected.to be_a_exposure_type :formatter }
48
+ it { is_expected.not_to be_a_exposure_type :formatter_block }
49
+ it { is_expected.not_to be_a_exposure_type :nesting }
50
+ it { is_expected.not_to be_a_exposure_type :represent }
51
+ it { is_expected.not_to be_a_block_exposure }
52
+ it { is_expected.not_to be_a_delegator_exposure }
53
+ it { is_expected.to be_a_formatter_exposure }
54
+ it { is_expected.not_to be_a_formatter_block_exposure }
55
+ it { is_expected.not_to be_a_nesting_exposure }
56
+ it { is_expected.not_to be_a_represent_exposure }
57
+ end
58
+
59
+ context "when a formatter block exposure" do
60
+ let(:attribute) { :created_at }
61
+ it { is_expected.not_to be_a_exposure_type :block }
62
+ it { is_expected.not_to be_a_exposure_type :delegator }
63
+ it { is_expected.not_to be_a_exposure_type :formatter }
64
+ it { is_expected.to be_a_exposure_type :formatter_block }
65
+ it { is_expected.not_to be_a_exposure_type :nesting }
66
+ it { is_expected.not_to be_a_exposure_type :represent }
67
+ it { is_expected.not_to be_a_block_exposure }
68
+ it { is_expected.not_to be_a_delegator_exposure }
69
+ it { is_expected.not_to be_a_formatter_exposure }
70
+ it { is_expected.to be_a_formatter_block_exposure }
71
+ it { is_expected.not_to be_a_nesting_exposure }
72
+ it { is_expected.not_to be_a_represent_exposure }
73
+ end
74
+
75
+ context "when a nesting exposure" do
76
+ let(:attribute) { :permissions }
77
+ it { is_expected.not_to be_a_exposure_type :block }
78
+ it { is_expected.not_to be_a_exposure_type :delegator }
79
+ it { is_expected.not_to be_a_exposure_type :formatter }
80
+ it { is_expected.not_to be_a_exposure_type :formatter_block }
81
+ it { is_expected.to be_a_exposure_type :nesting }
82
+ it { is_expected.not_to be_a_exposure_type :represent }
83
+ it { is_expected.not_to be_a_block_exposure }
84
+ it { is_expected.not_to be_a_delegator_exposure }
85
+ it { is_expected.not_to be_a_formatter_exposure }
86
+ it { is_expected.not_to be_a_formatter_block_exposure }
87
+ it { is_expected.to be_a_nesting_exposure }
88
+ it { is_expected.not_to be_a_represent_exposure }
89
+ end
90
+
91
+ context "when a represent exposure" do
92
+ let(:attribute) { :user }
93
+ it { is_expected.not_to be_a_exposure_type :block }
94
+ it { is_expected.not_to be_a_exposure_type :delegator }
95
+ it { is_expected.not_to be_a_exposure_type :formatter }
96
+ it { is_expected.not_to be_a_exposure_type :formatter_block }
97
+ it { is_expected.not_to be_a_exposure_type :nesting }
98
+ it { is_expected.to be_a_exposure_type :represent }
99
+ it { is_expected.not_to be_a_block_exposure }
100
+ it { is_expected.not_to be_a_delegator_exposure }
101
+ it { is_expected.not_to be_a_formatter_exposure }
102
+ it { is_expected.not_to be_a_formatter_block_exposure }
103
+ it { is_expected.not_to be_a_nesting_exposure }
104
+ it { is_expected.to be_a_represent_exposure }
105
+ end
106
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::BeMergedMatcher do
6
+ include RSpec::Grape::Entity::Matchers::BeMergedMatcher
7
+
8
+ let(:entity) { TestEntity }
9
+
10
+ context "when merged" do
11
+ subject(:exposure) { entity.find_exposure :custom_data }
12
+ it { is_expected.to be_merged }
13
+ end
14
+
15
+ context "when not merged" do
16
+ subject(:exposure) { entity.find_exposure :id }
17
+ it { is_expected.not_to be_merged }
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::BeSafeMatcher do
6
+ include RSpec::Grape::Entity::Matchers::BeSafeMatcher
7
+
8
+ let(:entity) { TestEntity }
9
+
10
+ context "when safe" do
11
+ subject(:exposure) { entity.find_exposure :user }
12
+ it { is_expected.to be_safe }
13
+ end
14
+
15
+ context "when not safe" do
16
+ subject(:exposure) { entity.find_exposure :id }
17
+ it { is_expected.not_to be_safe }
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::BeUsingClassMatcher do
6
+ include RSpec::Grape::Entity::Matchers::BeUsingClassMatcher
7
+
8
+ let(:entity) { TestEntity }
9
+
10
+ context "when using a represent entity" do
11
+ subject(:exposure) { entity.find_exposure :user }
12
+ it { is_expected.to be_using_class UserEntity }
13
+ it { is_expected.not_to be_using_class TestEntity }
14
+ end
15
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::HaveConditionsMetMatcher do
6
+ include RSpec::Grape::Entity::Matchers::HaveConditionsMetMatcher
7
+
8
+ let(:entity) { TestEntity }
9
+ let(:object) { OpenStruct.new has_date: true }
10
+
11
+ context "when condition a symbol" do
12
+ subject(:exposure) { entity.find_exposure :record_status }
13
+
14
+ it { is_expected.to have_conditions_met(object).with_options(all: true) }
15
+ it { is_expected.to_not have_conditions_met(object) }
16
+ end
17
+
18
+ context "when condition a hash" do
19
+ subject(:exposure) { entity.find_exposure :user }
20
+
21
+ it { is_expected.to have_conditions_met(object).with_options(type: :admin) }
22
+ it { is_expected.to_not have_conditions_met(object).with_options(type: :user) }
23
+ it { is_expected.to_not have_conditions_met(object) }
24
+ end
25
+
26
+ context "when condition a proc" do
27
+ subject(:exposure) { entity.find_exposure :created_at }
28
+
29
+ let(:false_object) { OpenStruct.new date: false }
30
+
31
+ it { is_expected.to have_conditions_met(object) }
32
+ it { is_expected.not_to have_conditions_met(false_object) }
33
+ end
34
+
35
+ context "when no conditions defined" do
36
+ subject(:exposure) { entity.find_exposure :id }
37
+
38
+ it { is_expected.to have_conditions_met(object) }
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::HaveFormattingMatcher do
6
+ include RSpec::Grape::Entity::Matchers::HaveFormattingMatcher
7
+
8
+ let(:entity) { TestEntity }
9
+ let(:object) do
10
+ OpenStruct.new created_at: Time.utc(2022, 1, 22, 17, 0, 0),
11
+ updated_at: Time.utc(2022, 2, 4, 6, 0, 0)
12
+ end
13
+
14
+ context "when formatter is a symbol" do
15
+ subject(:exposure) { entity.find_exposure :updated_at }
16
+
17
+ it { is_expected.to have_formatting :iso_timestamp }
18
+ end
19
+
20
+ context "when formatter is a block" do
21
+ subject(:exposure) { entity.find_exposure :created_at }
22
+
23
+ it { is_expected.to have_formatting("2022-01-22T17:00:00Z").with_object(object) }
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::HaveKeyMatcher do
6
+ include RSpec::Grape::Entity::Matchers::HaveKeyMatcher
7
+
8
+ let(:entity) { TestEntity }
9
+
10
+ context "when alias is not defined" do
11
+ subject(:exposure) { entity.find_exposure :id }
12
+
13
+ it { is_expected.to have_key :id }
14
+ it { is_expected.not_to have_key :external_id }
15
+ end
16
+
17
+ context "when alias is defined" do
18
+ subject(:exposure) { entity.find_exposure :record_status }
19
+
20
+ it { is_expected.to have_key :status }
21
+ it { is_expected.not_to have_key :record_status }
22
+ end
23
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::HaveRootMatcher do
6
+ include RSpec::Grape::Entity::Matchers::HaveRootMatcher
7
+
8
+ context "when root is not defined" do
9
+ let(:described_class) do
10
+ Class.new Grape::Entity
11
+ end
12
+
13
+ it { expect(described_class).to have_root(nil) }
14
+ it { expect(described_class).to have_root(nil).with_singular(nil) }
15
+ it { expect(described_class).not_to have_root("tests") }
16
+ it { expect(described_class).not_to have_root("tests").with_singular(nil) }
17
+ it { expect(described_class).not_to have_root("tests").with_singular("test") }
18
+ end
19
+
20
+ context "when collection root is only defined" do
21
+ let(:described_class) do
22
+ Class.new Grape::Entity do
23
+ root "tests"
24
+ end
25
+ end
26
+
27
+ it { expect(described_class).not_to have_root(nil) }
28
+ it { expect(described_class).not_to have_root(nil).with_singular(nil) }
29
+ it { expect(described_class).to have_root("tests") }
30
+ it { expect(described_class).to have_root("tests").with_singular(nil) }
31
+ it { expect(described_class).not_to have_root("tests").with_singular("test") }
32
+ end
33
+
34
+ context "when both root and collection_root is defined" do
35
+ let(:described_class) do
36
+ Class.new Grape::Entity do
37
+ root "tests", "test"
38
+ end
39
+ end
40
+
41
+ it { expect(described_class).not_to have_root(nil) }
42
+ it { expect(described_class).not_to have_root(nil).with_singular(nil) }
43
+ it { expect(described_class).not_to have_root("tests") }
44
+ it { expect(described_class).not_to have_root("tests").with_singular(nil) }
45
+ it { expect(described_class).to have_root("tests").with_singular("test") }
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::IncludeDocumentationMatcher do
6
+ include RSpec::Grape::Entity::Matchers::IncludeDocumentationMatcher
7
+
8
+ let(:entity) { TestEntity }
9
+
10
+ context "when has documentation" do
11
+ subject(:exposure) { entity.find_exposure :id }
12
+
13
+ it { is_expected.to include_documentation type: Integer, desc: "The record id" }
14
+ it { is_expected.to include_documentation type: Integer }
15
+ it { is_expected.to include_documentation desc: "The record id" }
16
+ it { is_expected.to include_documentation :type, :desc }
17
+ it { is_expected.to include_documentation :desc }
18
+ it { is_expected.to include_documentation :type }
19
+ end
20
+
21
+ context "when does not have documentation" do
22
+ subject(:exposure) { entity.find_exposure :permissions }
23
+
24
+ it { is_expected.not_to include_documentation type: Integer, desc: "Permissions" }
25
+ it { is_expected.not_to include_documentation type: Integer }
26
+ it { is_expected.not_to include_documentation desc: "The record id" }
27
+ it { is_expected.not_to include_documentation :type, :desc }
28
+ it { is_expected.not_to include_documentation :desc }
29
+ it { is_expected.not_to include_documentation :type }
30
+ end
31
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::MatcherHelpers do
6
+ let(:entity) { TestEntity }
7
+ subject(:helper) { Class.new { extend RSpec::Grape::Entity::Matchers::MatcherHelpers } }
8
+
9
+ describe ".entity_class_name" do
10
+ subject { helper.entity_class_name entity }
11
+
12
+ context "when a class constant" do
13
+ it { is_expected.to eq "TestEntity" }
14
+ end
15
+
16
+ context "when an instance of an entity" do
17
+ let(:entity) { TestEntity.new(nil) }
18
+ it { is_expected.to eq "TestEntity" }
19
+ end
20
+ end
21
+
22
+ describe ".exposure_attribute" do
23
+ let(:exposure) { entity.find_exposure :id }
24
+ subject { helper.exposure_attribute exposure, attribute }
25
+
26
+ context "when a valid exposure attribute" do
27
+ let(:attribute) { :key }
28
+ it { is_expected.to_not be_nil }
29
+ end
30
+
31
+ context "when an invalid exposure attribute" do
32
+ let(:attribute) { :not_a_real_attribute }
33
+ it { expect { subject }.to raise_error NoMethodError }
34
+ end
35
+ end
36
+
37
+ describe ".exposure_type" do
38
+ subject { helper.exposure_type exposure_type }
39
+
40
+ context "when a block exposure" do
41
+ let(:exposure_type) { :block }
42
+ it { is_expected.to be Grape::Entity::Exposure::BlockExposure }
43
+ end
44
+
45
+ context "when a delegator exposure" do
46
+ let(:exposure_type) { :delegator }
47
+ it { is_expected.to be Grape::Entity::Exposure::DelegatorExposure }
48
+ end
49
+
50
+ context "when a formatter exposure" do
51
+ let(:exposure_type) { :formatter }
52
+ it { is_expected.to be Grape::Entity::Exposure::FormatterExposure }
53
+ end
54
+
55
+ context "when a formatter block exposure" do
56
+ let(:exposure_type) { :formatter_block }
57
+ it { is_expected.to be Grape::Entity::Exposure::FormatterBlockExposure }
58
+ end
59
+
60
+ context "when a nesting exposure" do
61
+ let(:exposure_type) { :nesting }
62
+ it { is_expected.to be Grape::Entity::Exposure::NestingExposure }
63
+ end
64
+
65
+ context "when a represent exposure" do
66
+ let(:exposure_type) { :represent }
67
+ it { is_expected.to be Grape::Entity::Exposure::RepresentExposure }
68
+ end
69
+
70
+ context "when an invalid exposure type" do
71
+ let(:exposure_type) { :invalid_exposure_type }
72
+
73
+ it { expect { subject }.to raise_error NameError }
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RSpec::Grape::Entity::Matchers::OverrideExposureMatcher do
6
+ include RSpec::Grape::Entity::Matchers::OverrideExposureMatcher
7
+
8
+ let(:entity) { TestEntity }
9
+
10
+ context "when overriding" do
11
+ subject(:exposure) { entity.find_exposure :permissions }
12
+ it { is_expected.to override_exposure }
13
+ end
14
+
15
+ context "when not overriding" do
16
+ subject(:exposure) { entity.find_exposure :id }
17
+ it { is_expected.not_to override_exposure }
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ostruct"
4
+ require "time"
5
+
6
+ require "rspec-grape-entity"
7
+
8
+ require_relative "support/user_entity"
9
+ require_relative "support/test_entity"
10
+
11
+ RSpec.configure do |config|
12
+ # Enable flags like --only-failures and --next-failure
13
+ config.example_status_persistence_file_path = ".rspec_status"
14
+
15
+ # Disable RSpec exposing methods globally on `Module` and `main`
16
+ config.disable_monkey_patching!
17
+
18
+ config.expect_with :rspec do |c|
19
+ c.syntax = :expect
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TestEntity < Grape::Entity
4
+ root "test_items", "test_item"
5
+
6
+ format_with :iso_timestamp, &:iso8601
7
+
8
+ expose :id, documentation: { type: Integer, desc: "The record id" }
9
+ expose :record_status, as: :status, if: :all
10
+ expose :user, safe: true, using: UserEntity, if: { type: :admin }
11
+ expose :custom_data, merge: true do |_, _|
12
+ {
13
+ foo: :bar
14
+ }
15
+ end
16
+ expose :permissions, override: true do
17
+ expose :read
18
+ expose :update
19
+ expose :destroy
20
+ end
21
+ expose :created_at, format_with: ->(date) { date.iso8601 }, if: ->(instance, _) { instance.has_date }
22
+ expose :updated_at, format_with: :iso_timestamp
23
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UserEntity < Grape::Entity
4
+ format_with :iso_timestamp, &:iso8601
5
+
6
+ expose :username
7
+ expose :name do
8
+ expose :first_name, as: :first, documentation: { type: String, desc: "User's last name" }
9
+ expose :last_name, as: :last, documentation: { type: String, desc: "User's last name" }
10
+ end
11
+ expose :joined_at, format_with: :iso_timestamp
12
+ end