contentful_lite 1.0.2

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.
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ContentfulLite::EntriesArray do
4
+ let(:response) { JSON.parse(File.read('fixtures/entries/all.json')) }
5
+ let(:instance) { ContentfulLite::EntriesArray.new(response) }
6
+
7
+ describe 'should create an array of entries' do
8
+ it { expect(instance.first).to be_an ContentfulLite::Entry }
9
+ it { expect(instance.last).to be_an ContentfulLite::Entry }
10
+ it { expect(instance.sample).to be_an ContentfulLite::Entry }
11
+
12
+ it 'should solve the linked assets' do
13
+ expect(instance[4].fields['image']).to be_an ContentfulLite::Asset
14
+ expect(instance[4].fields['image'].url).to eq '//images.ctfassets.net/cfexampleapi/4hlteQAXS8iS0YCMU6QMWg/2a4d826144f014109364ccf5c891d2dd/jake.png'
15
+ end
16
+
17
+ it 'should solve the nested mutually-related entries' do
18
+ expect(instance[5].fields['bestFriend']).to be_an ContentfulLite::Entry
19
+ expect(instance[5].fields['bestFriend'].fields['bestFriend']).to eq instance[5]
20
+ end
21
+
22
+ it 'should properly serialize the nested mutually-related entries' do
23
+ friend = instance[5].as_json['fields']['bestFriend']
24
+ expect(friend['sys']['type']).to eq('Entry')
25
+ expect(friend['sys']['id']).to eq('nyancat')
26
+ expect(friend['fields']['bestFriend']['sys']['type']).to eq('Link')
27
+ expect(friend['fields']['bestFriend']['sys']['id']).to eq('happycat')
28
+ end
29
+
30
+ context 'with an array of references' do
31
+ let(:response) { JSON.parse(File.read('fixtures/entries/all_with_reference_array.json')) }
32
+
33
+ it 'should solve the linked assets' do
34
+ expect(instance[4].fields['images'].first).to be_an ContentfulLite::Asset
35
+ expect(instance[4].fields['images'].first.url).to eq '//images.ctfassets.net/cfexampleapi/4hlteQAXS8iS0YCMU6QMWg/2a4d826144f014109364ccf5c891d2dd/jake.png'
36
+ end
37
+
38
+ it 'should solve the nested mutually-related entries' do
39
+ expect(instance[5].fields['friends'].first).to be_an ContentfulLite::Entry
40
+ expect(instance[5].fields['friends'].first.fields['friends'].first).to eq instance[5]
41
+ end
42
+
43
+ it 'should properly serialize the nested mutually-related entries' do
44
+ friend = instance[5].as_json['fields']['friends'].first
45
+ expect(friend['sys']['type']).to eq('Entry')
46
+ expect(friend['sys']['id']).to eq('nyancat')
47
+ expect(friend['fields']['friends'].first['sys']['type']).to eq('Link')
48
+ expect(friend['fields']['friends'].first['sys']['id']).to eq('happycat')
49
+ end
50
+ end
51
+
52
+ context 'with multiple locales' do
53
+ let(:response) { JSON.parse(File.read('fixtures/entries/all_with_locales.json')) }
54
+
55
+ it { expect(instance[5].fields(locale: 'tlh')['name']).to eq("Quch vIghro'") }
56
+
57
+ it 'should solve the linked assets' do
58
+ expect(instance[4].fields['image']).to be_an ContentfulLite::Asset
59
+ expect(instance[4].fields['image'].url).to eq '//images.ctfassets.net/cfexampleapi/4hlteQAXS8iS0YCMU6QMWg/2a4d826144f014109364ccf5c891d2dd/jake.png'
60
+ end
61
+
62
+ it 'should solve the nested mutually-related entries' do
63
+ expect(instance[5].fields['bestFriend']).to be_an ContentfulLite::Entry
64
+ expect(instance[5].fields['bestFriend'].fields['bestFriend']).to eq instance[5]
65
+ end
66
+ end
67
+
68
+ context 'when include nesting is not enough' do
69
+ let(:response) { JSON.parse(File.read('fixtures/entries/all_without_includes.json')) }
70
+
71
+ it { expect(instance.first).to be_an ContentfulLite::Entry }
72
+ it { expect(instance.last).to be_an ContentfulLite::Entry }
73
+ it { expect(instance.sample).to be_an ContentfulLite::Entry }
74
+
75
+ it 'should create links for the assets' do
76
+ expect(instance[4].fields['image']).to be_an ContentfulLite::Link
77
+ expect(instance[4].fields['image'].type).to eq :asset
78
+ expect(instance[4].fields['image'].id).to eq 'jake'
79
+ end
80
+
81
+ it 'should solve the nested mutually-related entries' do
82
+ expect(instance[5].fields['bestFriend']).to be_an ContentfulLite::Link
83
+ expect(instance[5].fields['bestFriend'].type).to eq :entry
84
+ expect(instance[5].fields['bestFriend'].id).to eq 'nyancat'
85
+ end
86
+ end
87
+
88
+ describe 'serializing' do
89
+ subject { Marshal.load(Marshal.dump(instance)) }
90
+
91
+ it { expect(subject.first.id).to eq(instance.first.id) }
92
+ it { expect(subject.first.fields).to eq(instance.first.fields) }
93
+ it { expect(subject.last.id).to eq(instance.last.id) }
94
+ it { expect(subject.last.fields).to eq(instance.last.fields) }
95
+
96
+ it 'should solve the nested mutually-related entries' do
97
+ expect(subject[5].fields['bestFriend']).to be_an ContentfulLite::Entry
98
+ expect(subject[5].fields['bestFriend'].fields['bestFriend']).to eq subject[5]
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ContentfulLite::EntryMapping do
4
+ let(:base_class) { Class.new.include(described_class) }
5
+ let!(:inherited_class) { Class.new(base_class) { content_type_id 'inherited_type' } }
6
+
7
+ describe '#get_class' do
8
+ subject { base_class.get_class(content_type) }
9
+
10
+ context 'for an existing content_type_id' do
11
+ let(:content_type) { 'inherited_type' }
12
+ it { is_expected.to eq(inherited_class) }
13
+ end
14
+
15
+ context 'for an invalid content_type_id' do
16
+ let(:content_type) { 'invalid_type' }
17
+ it { is_expected.to eq(base_class) }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ContentfulLite::Entry do
4
+ let(:entry_hash) { JSON.parse(File.read('fixtures/entries/nyancat.json')) }
5
+ let(:instance) { ContentfulLite::Entry.new(entry_hash) }
6
+
7
+ describe '#attributes' do
8
+ it { expect(instance.content_type_id).to eq 'cat' }
9
+ it { expect(instance.fields).to be_a Hash }
10
+ end
11
+
12
+ describe '#contentful_link' do
13
+ subject { instance.contentful_link }
14
+
15
+ it { is_expected.to eq 'https://app.contentful.com/spaces/cfexampleapi/entries/nyancat' }
16
+ end
17
+
18
+ describe 'Class methods' do
19
+ describe '#field_reader' do
20
+ let(:entry_class) do
21
+ Class.new(ContentfulLite::Entry) do
22
+ field_reader :name, localizable: true
23
+ field_reader :color, :bestFriend, :friends
24
+ field_reader :spayed, default: true
25
+ end
26
+ end
27
+ subject { entry_class.new(entry_hash) }
28
+
29
+ it { expect(subject.color).to eq 'rainbow' }
30
+ it { expect(subject.bestFriend).to be_a ContentfulLite::Link }
31
+ it { expect(subject.bestFriend.id).to eq 'happycat' }
32
+ it { expect(subject.spayed).to eq true }
33
+
34
+ context 'when the spayed field is nil' do
35
+ before { entry_hash['fields']['spayed'] = nil }
36
+
37
+ it 'falls back to the provided default' do
38
+ expect(subject.spayed).to eq true
39
+ end
40
+ end
41
+
42
+ context 'when the spayed field is set to false' do
43
+ before { entry_hash['fields']['spayed'] = false }
44
+
45
+ it { expect(subject.spayed).to eq false }
46
+ end
47
+
48
+ context 'with multiple locales' do
49
+ let(:entry_hash) { JSON.parse(File.read('fixtures/entries/nyancat_with_locales.json')) }
50
+
51
+ it { expect(subject.name).to eq 'Nyan Cat' }
52
+ it { expect(subject.color).to eq 'rainbow' }
53
+ it { expect(subject.color(locale: 'tlh')).to eq 'rainbow' }
54
+ it { expect(subject.with_locale('tlh') { subject.color }).to eq 'rainbow' }
55
+ it { expect(subject.bestFriend).to be_a ContentfulLite::Link }
56
+ it { expect(subject.bestFriend.id).to eq 'happycat' }
57
+ it { expect(subject.name(locale: 'tlh')).to eq 'Nyan vIghro\'' }
58
+ it { expect(subject.with_locale('tlh') { subject.name }).to eq 'Nyan vIghro\'' }
59
+ end
60
+
61
+ context 'with an array of references' do
62
+ let(:entry_hash) { JSON.parse(File.read('fixtures/entries/reference_array.json')) }
63
+
64
+ it { expect(subject.friends.first).to be_a ContentfulLite::Link }
65
+ it { expect(subject.friends.last).to be_a ContentfulLite::Link }
66
+ end
67
+ end
68
+ end
69
+
70
+ describe 'serializing' do
71
+ subject { Marshal.load(Marshal.dump(instance)) }
72
+
73
+ it { expect(subject.id).to eq(instance.id) }
74
+ it { expect(subject.created_at).to eq(instance.created_at) }
75
+ it { expect(subject.updated_at).to eq(instance.updated_at) }
76
+ it { expect(subject.retrieved_at).to eq(instance.retrieved_at) }
77
+ it { expect(subject.locale).to eq(instance.locale) }
78
+ it { expect(subject.revision).to eq(instance.revision) }
79
+ it { expect(subject.space_id).to eq(instance.space_id) }
80
+ it { expect(subject.environment_id).to eq(instance.environment_id) }
81
+ it { expect(subject.content_type_id).to eq(instance.content_type_id) }
82
+ it { expect(subject.fields).to eq(instance.fields) }
83
+ end
84
+ end
data/spec/link_spec.rb ADDED
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ContentfulLite::Link do
4
+ let(:entry_hash) { JSON.parse(File.read('fixtures/entries/nyancat.json')) }
5
+ subject { ContentfulLite::Link.new(entry_hash['fields']['bestFriend']) }
6
+
7
+ describe '#attributes' do
8
+ it { expect(subject.type).to eq :entry }
9
+ it { expect(subject.id).to eq 'happycat' }
10
+
11
+ context 'when converting from an Entry' do
12
+ let(:entry) { ContentfulLite::Entry.new(entry_hash) }
13
+ subject { ContentfulLite::Link.new(entry) }
14
+
15
+ it { expect(subject.type).to eq :entry }
16
+ it { expect(subject.id).to eq 'nyancat' }
17
+ end
18
+
19
+ context 'when converting from an Asset' do
20
+ let(:asset_hash) { JSON.parse(File.read('fixtures/assets/nyancat.json')) }
21
+ let(:asset) { ContentfulLite::Asset.new(asset_hash) }
22
+ subject { ContentfulLite::Link.new(asset) }
23
+
24
+ it { expect(subject.type).to eq :asset }
25
+ it { expect(subject.id).to eq 'nyancat' }
26
+ end
27
+ end
28
+
29
+ describe '#==' do
30
+ let(:other_id) { 'happycat' }
31
+ let(:other_type) { 'Entry' }
32
+ let(:comparison) { ContentfulLite::Link.new( 'sys' => { 'linkType' => other_type, 'id' => other_id } ) }
33
+
34
+ it { is_expected.to eq comparison }
35
+
36
+ context 'when the id is different' do
37
+ let(:other_id) { 'other' }
38
+
39
+ it { is_expected.not_to eq comparison }
40
+ end
41
+
42
+ context 'when the type is different' do
43
+ let(:other_id) { 'asset' }
44
+
45
+ it { is_expected.not_to eq comparison }
46
+ end
47
+
48
+ context 'when the class is different' do
49
+ let(:comparison) { OpenStruct.new(id: other_id, type: :entry) }
50
+
51
+ it { is_expected.not_to eq comparison }
52
+ end
53
+ end
54
+
55
+ describe '#as_json' do
56
+ it { expect(subject.as_json).to eq(entry_hash['fields']['bestFriend']) }
57
+
58
+ context 'when rails is passing some other parameters as hash' do
59
+ let(:hash) { { template: "something", status: 200 } }
60
+
61
+ it 'should not throw errors' do
62
+ expect(subject.as_json(hash)).to eq(entry_hash['fields']['bestFriend'])
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,27 @@
1
+ if ENV['COVERAGE']
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ end
5
+
6
+ require 'webmock/rspec'
7
+ require 'vcr'
8
+ require 'contentful_lite'
9
+
10
+ VCR.configure do |config|
11
+ config.cassette_library_dir = 'fixtures/vcr_cassettes'
12
+ config.hook_into :webmock
13
+
14
+ config.default_cassette_options = { record: :once }
15
+ end
16
+
17
+ RSpec.configure do |config|
18
+ # Enable flags like --only-failures and --next-failure
19
+ config.example_status_persistence_file_path = '.rspec_status'
20
+
21
+ # Disable RSpec exposing methods globally on `Module` and `main`
22
+ config.disable_monkey_patching!
23
+
24
+ config.expect_with :rspec do |c|
25
+ c.syntax = :expect
26
+ end
27
+ end
@@ -0,0 +1,366 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ContentfulLite::Validations::Entry do
4
+ def create_validable_model(validation_method, options)
5
+ klass = Class.new do
6
+ include ContentfulLite::Validations::Entry
7
+ attr_reader :fake_field
8
+ attr_accessor :locale
9
+ send(validation_method, :fake_field, options)
10
+
11
+ def initialize(value)
12
+ @fake_field = value
13
+ @locale = :en
14
+ end
15
+
16
+ def with_locale(locale)
17
+ @locale = locale unless locale.nil?
18
+ yield
19
+ ensure
20
+ @locale = :en
21
+ end
22
+ end
23
+ allow(klass).to receive(:model_name).and_return ActiveModel::Name.new(klass, nil, 'FakeClasss')
24
+ allow(klass).to receive(:human_attribute_name).and_return 'fake_field'
25
+ klass
26
+ end
27
+
28
+ shared_context 'multiple locales support' do
29
+ before do # Mock Entry localization, as it is part of the entry class and not the validations module
30
+ allow(fake_model).to receive(:locales).and_return(%i[en es])
31
+ allow(fake_model).to receive(:fake_field) { value[fake_model.locale] }
32
+ end
33
+ end
34
+
35
+ let(:model_class) { create_validable_model(:validates_presence_of, {}) }
36
+ let(:fake_model) { model_class.new(value) }
37
+
38
+ describe '#valid?' do
39
+ include_context 'multiple locales support'
40
+ let(:value) { { en: 'valid', es: 'valid' } }
41
+ subject { fake_model.valid?(locale: :es) }
42
+
43
+ it { is_expected.to be_truthy }
44
+
45
+ context 'when the other locale has invalid content' do
46
+ let(:value) { { en: nil, es: 'valid' } }
47
+ it { is_expected.to be_truthy }
48
+ end
49
+
50
+ context 'when that locale has invalid content' do
51
+ let(:value) { { en: 'valid', es: nil } }
52
+ it { is_expected.to be_falsey }
53
+ end
54
+
55
+ context 'when both locales have invalid content' do
56
+ let(:value) { { en: nil, es: nil } }
57
+ it { is_expected.to be_falsey }
58
+ end
59
+ end
60
+
61
+ describe '#valid_for_all_locales?' do
62
+ include_context 'multiple locales support'
63
+ let(:value) { { en: 'valid', es: 'valid' } }
64
+ subject { fake_model.valid_for_all_locales? }
65
+
66
+ it { is_expected.to be_truthy }
67
+
68
+ context 'when first locale has invalid content' do
69
+ let(:value) { { en: nil, es: 'valid' } }
70
+ it { is_expected.to be_falsey }
71
+ end
72
+
73
+ context 'when second locale has invalid content' do
74
+ let(:value) { { en: 'valid', es: nil } }
75
+ it { is_expected.to be_falsey }
76
+ end
77
+
78
+ context 'when both locales have invalid content' do
79
+ let(:value) { { en: nil, es: nil } }
80
+ it { is_expected.to be_falsey }
81
+ end
82
+ end
83
+
84
+ describe '#errors' do
85
+ include_context 'multiple locales support'
86
+ let(:value) { { en: 'valid', es: 'valid' } }
87
+ subject(:en) { fake_model.tap(&:valid_for_all_locales?).errors(locale: :en)[:fake_field] }
88
+ subject(:es) { fake_model.tap(&:valid_for_all_locales?).errors(locale: :es)[:fake_field] }
89
+
90
+ it { expect(en).to be_empty }
91
+ it { expect(es).to be_empty }
92
+
93
+ context 'when first locale has invalid content' do
94
+ let(:value) { { en: nil, es: 'valid' } }
95
+ it { expect(en).to eq ["can't be blank"] }
96
+ it { expect(es).to be_empty }
97
+ end
98
+
99
+ context 'when second locale has invalid content' do
100
+ let(:value) { { en: 'valid', es: nil } }
101
+
102
+ it { expect(en).to be_empty }
103
+ it { expect(es).to eq ["can't be blank"] }
104
+ end
105
+
106
+ context 'when both locales have invalid content' do
107
+ let(:value) { { en: nil, es: nil } }
108
+
109
+ it { expect(en).to eq ["can't be blank"] }
110
+ it { expect(es).to eq ["can't be blank"] }
111
+ end
112
+ end
113
+
114
+ describe '.validates_included_asset' do
115
+ subject { fake_model.tap(&:valid?).errors[:fake_field] }
116
+
117
+ let(:asset) { ContentfulLite::Asset.new(JSON.parse(File.read('fixtures/assets/nyancat.json'))) }
118
+ let(:model_class) do
119
+ create_validable_model(:validates_included_asset, options)
120
+ end
121
+ let(:value) { nil }
122
+ let(:options) { {} }
123
+
124
+ describe 'allow_blank' do
125
+ context 'when value is nil and blank is allowed' do
126
+ let(:options) { { allow_blank: true } }
127
+
128
+ it { is_expected.to be_empty }
129
+ end
130
+
131
+ context 'when value is nil and blank is not allowed' do
132
+ let(:options) { { allow_blank: false } }
133
+
134
+ it { is_expected.to eq ['value is blank'] }
135
+ end
136
+
137
+ context 'when value is [] and blank is allowed' do
138
+ let(:options) { { allow_blank: true } }
139
+ let(:value) { [] }
140
+
141
+ it { is_expected.to be_empty }
142
+ end
143
+
144
+ context 'when value is [] and blank is not allowed' do
145
+ let(:options) { { allow_blank: false } }
146
+ let(:value) { [] }
147
+
148
+ it { is_expected.to eq ['value is blank'] }
149
+ end
150
+
151
+ context 'when value exists and blank is not allowed' do
152
+ let(:value) { asset }
153
+
154
+ it { is_expected.to be_empty }
155
+ end
156
+ end
157
+
158
+ describe 'array' do
159
+ context 'when value is not an array as expected' do
160
+ let(:value) { asset }
161
+ it { is_expected.to be_empty }
162
+ end
163
+
164
+ context 'when value is an array as expected' do
165
+ let(:value) { [asset] }
166
+ let(:options) { { array: true } }
167
+ it { is_expected.to be_empty }
168
+ end
169
+
170
+ context 'when value is not an asset or array' do
171
+ let(:value) { Object.new }
172
+ it { is_expected.to eq ['value is not a published asset'] }
173
+ end
174
+
175
+ context 'when value is an array with other objects' do
176
+ let(:value) { [asset, Object.new] }
177
+ let(:options) { { array: true } }
178
+ it { is_expected.to eq ['value[1] is not a published asset'] }
179
+ end
180
+
181
+ context 'when expects and array and has single value' do
182
+ let(:value) { asset }
183
+ let(:options) { { array: true } }
184
+ it { is_expected.to eq ['value is not an array'] }
185
+ end
186
+
187
+ context 'when expects a single value and has an array' do
188
+ let(:value) { [asset] }
189
+ it { is_expected.to eq ['value is not a published asset'] }
190
+ end
191
+ end
192
+
193
+ describe 'type' do
194
+ context 'when value is an image as expected' do
195
+ let(:options) { { type: :image } }
196
+ let(:value) { asset }
197
+ it { is_expected.to be_empty }
198
+ end
199
+
200
+ context 'when value is an image and expects a video' do
201
+ let(:options) { { type: :video } }
202
+ let(:value) { asset }
203
+ it { is_expected.to eq ['value has an invalid asset type. Expecting video'] }
204
+ end
205
+
206
+ context 'when values array has an image and expects only videos' do
207
+ let(:options) { { type: :video, array: true } }
208
+ let(:value) { [asset] }
209
+ it { is_expected.to eq ['value[0] has an invalid asset type. Expecting video'] }
210
+ end
211
+ end
212
+ end
213
+
214
+ describe '.validates_included_entry' do
215
+ subject { fake_model.tap(&:valid?).errors[:fake_field] }
216
+
217
+ let(:entry) { ContentfulLite::Entry.new(JSON.parse(File.read('fixtures/entries/nyancat.json'))) }
218
+ let(:model_class) do
219
+ create_validable_model(:validates_included_entry, options)
220
+ end
221
+ let(:value) { nil }
222
+ let(:options) { {} }
223
+
224
+ describe 'allow_blank' do
225
+ context 'when value is nil and blank is allowed' do
226
+ let(:options) { { allow_blank: true } }
227
+
228
+ it { is_expected.to be_empty }
229
+ end
230
+
231
+ context 'when value is nil and blank is not allowed' do
232
+ let(:options) { { allow_blank: false } }
233
+
234
+ it { is_expected.to eq ['value is blank'] }
235
+ end
236
+
237
+ context 'when value is [] and blank is allowed' do
238
+ let(:options) { { allow_blank: true } }
239
+ let(:value) { [] }
240
+
241
+ it { is_expected.to be_empty }
242
+ end
243
+
244
+ context 'when value is [] and blank is not allowed' do
245
+ let(:options) { { allow_blank: false } }
246
+ let(:value) { [] }
247
+
248
+ it { is_expected.to eq ['value is blank'] }
249
+ end
250
+
251
+ context 'when value exists and blank is not allowed' do
252
+ let(:value) { entry }
253
+
254
+ it { is_expected.to be_empty }
255
+ end
256
+ end
257
+
258
+ describe 'array' do
259
+ context 'when value is not an array as expected' do
260
+ let(:value) { entry }
261
+ it { is_expected.to be_empty }
262
+ end
263
+
264
+ context 'when value is an array as expected' do
265
+ let(:value) { [entry] }
266
+ let(:options) { { array: true } }
267
+ it { is_expected.to be_empty }
268
+ end
269
+
270
+ context 'when value is not an entry or array' do
271
+ let(:value) { Object.new }
272
+ it { is_expected.to eq ['value is not a published entry'] }
273
+ end
274
+
275
+ context 'when value is an array with other objects' do
276
+ let(:value) { [entry, Object.new] }
277
+ let(:options) { { array: true } }
278
+ it { is_expected.to eq ['value[1] is not a published entry'] }
279
+ end
280
+
281
+ context 'when expects and array and has single value' do
282
+ let(:value) { entry }
283
+ let(:options) { { array: true } }
284
+ it { is_expected.to eq ['value is not an array'] }
285
+ end
286
+
287
+ context 'when expects a single value and has an array' do
288
+ let(:value) { [entry] }
289
+ it { is_expected.to eq ['value is not a published entry'] }
290
+ end
291
+ end
292
+
293
+ describe 'invalid child' do
294
+ before { expect(entry).to receive(:valid?).and_return false }
295
+
296
+ context 'when the entry is invalid' do
297
+ let(:value) { entry }
298
+
299
+ it { is_expected.to eq ['value has invalid child entry nyancat'] }
300
+ end
301
+
302
+ context 'when is array and one of the entries is invalid' do
303
+ let(:value) { [entry] }
304
+ let(:options) { { array: true } }
305
+
306
+ it { is_expected.to eq ['value has invalid child entry nyancat'] }
307
+ end
308
+ end
309
+
310
+ context 'child is invalid only for a different locale' do
311
+ before do
312
+ allow(entry).to receive(:valid?).and_return true
313
+ allow(entry).to receive(:valid?).with(locale: :es).and_return false
314
+ end
315
+ let(:value) { entry }
316
+ it { is_expected.to be_empty }
317
+
318
+ context 'when calling validation and checking errors for that locale' do
319
+ subject { fake_model.tap{ |_| fake_model.valid?(locale: :es) }.errors(locale: :es)[:fake_field] }
320
+ it { is_expected.to eq ['value has invalid child entry nyancat'] }
321
+ end
322
+ end
323
+
324
+ context 'child is invalid only for the current locale' do
325
+ before do
326
+ allow(entry).to receive(:valid?).and_return true
327
+ allow(entry).to receive(:valid?).with(locale: :en).and_return false
328
+ end
329
+ let(:value) { entry }
330
+ it { is_expected.to eq ['value has invalid child entry nyancat'] }
331
+ end
332
+
333
+ describe 'allowed_models' do
334
+ let(:cat_entry) { cat_class.new(JSON.parse(File.read('fixtures/entries/nyancat.json'))) }
335
+ let(:cat_class) { Class.new(ContentfulLite::Entry) }
336
+
337
+ context 'when the entry is an allowed_model' do
338
+ let(:value) { cat_entry }
339
+ let(:options) { { allowed_models: [cat_class] } }
340
+
341
+ it { is_expected.to be_empty }
342
+ end
343
+
344
+ context 'when the entry is not an allowed_model' do
345
+ let(:value) { entry }
346
+ let(:options) { { allowed_models: [cat_class] } }
347
+
348
+ it { is_expected.to eq ["value has an invalid entry model. Expecting #{options[:allowed_models]}"] }
349
+ end
350
+
351
+ context 'when is array and all entries are allowed_models' do
352
+ let(:value) { [cat_entry] }
353
+ let(:options) { { allowed_models: [cat_class], array: true } }
354
+
355
+ it { is_expected.to be_empty }
356
+ end
357
+
358
+ context 'when is array and one entry is not an allowed_model' do
359
+ let(:value) { [cat_entry, entry] }
360
+ let(:options) { { allowed_models: [cat_class], array: true } }
361
+
362
+ it { is_expected.to eq ["value[1] has an invalid entry model. Expecting #{options[:allowed_models]}"] }
363
+ end
364
+ end
365
+ end
366
+ end