contentful_lite 1.0.2

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