rspec-grape-entity 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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