mongoid-spec 4.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +373 -0
- data/Rakefile +17 -0
- data/lib/matchers/accept_nested_attributes.rb +67 -0
- data/lib/matchers/allow_mass_assignment.rb +102 -0
- data/lib/matchers/associations.rb +330 -0
- data/lib/matchers/be_dynamic_document.rb +26 -0
- data/lib/matchers/be_mongoid_document.rb +26 -0
- data/lib/matchers/be_stored_in.rb +50 -0
- data/lib/matchers/have_field.rb +90 -0
- data/lib/matchers/have_index_for.rb +63 -0
- data/lib/matchers/have_timestamps.rb +61 -0
- data/lib/matchers/validations.rb +81 -0
- data/lib/matchers/validations/acceptance_of.rb +9 -0
- data/lib/matchers/validations/associated.rb +19 -0
- data/lib/matchers/validations/confirmation_of.rb +22 -0
- data/lib/matchers/validations/custom_validation_of.rb +47 -0
- data/lib/matchers/validations/exclusion_of.rb +49 -0
- data/lib/matchers/validations/format_of.rb +71 -0
- data/lib/matchers/validations/inclusion_of.rb +49 -0
- data/lib/matchers/validations/length_of.rb +147 -0
- data/lib/matchers/validations/numericality_of.rb +90 -0
- data/lib/matchers/validations/presence_of.rb +9 -0
- data/lib/matchers/validations/uniqueness_of.rb +82 -0
- data/lib/matchers/validations/with_message.rb +27 -0
- data/lib/mongoid-rspec.rb +1 -0
- data/lib/mongoid/rspec.rb +40 -0
- data/lib/mongoid/rspec/version.rb +5 -0
- data/spec/models/article.rb +29 -0
- data/spec/models/comment.rb +6 -0
- data/spec/models/log.rb +9 -0
- data/spec/models/movie_article.rb +8 -0
- data/spec/models/permalink.rb +5 -0
- data/spec/models/person.rb +10 -0
- data/spec/models/profile.rb +16 -0
- data/spec/models/record.rb +5 -0
- data/spec/models/site.rb +9 -0
- data/spec/models/user.rb +37 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/unit/accept_nested_attributes_spec.rb +12 -0
- data/spec/unit/associations_spec.rb +42 -0
- data/spec/unit/be_dynamic_document_spec.rb +22 -0
- data/spec/unit/be_mongoid_document_spec.rb +25 -0
- data/spec/unit/be_stored_in.rb +54 -0
- data/spec/unit/document_spec.rb +16 -0
- data/spec/unit/have_index_for_spec.rb +46 -0
- data/spec/unit/have_timestamps_spec.rb +71 -0
- data/spec/unit/validations_spec.rb +54 -0
- data/spec/validators/ssn_validator.rb +16 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2db94999da51dbfed3ab87f523aa9d5a28608918
|
4
|
+
data.tar.gz: 95298ae001c5e3dce8a60f1f224dc6a197042f3d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28cf8f5ec27d608d91f6de5f2ba455447f01e9a2610db82aa6601b6ffd61d983cf721365f98d81d0653a46b391240a8e6f15cddc00f907485912cf149cd55eaa
|
7
|
+
data.tar.gz: 90ca7b34ab2492dffde3add00cf94b3b7444b20198feb8844d284f6b16ec1d6d586d08df76b4d4dddd52e89a8a01cf11fe6c73d91488005899322b40b9dfa217
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Evan Sagge
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,373 @@
|
|
1
|
+
# [mongoid-rspec]
|
2
|
+
|
3
|
+
[![Build Status][travis_badge]][travis]
|
4
|
+
[![Gem Version][rubygems_badge]][rubygems]
|
5
|
+
[![Code Climate][codeclimate_badge]][codeclimate]
|
6
|
+
|
7
|
+
mongoid-rspec provides a collection of RSpec-compatible matchers that help to test Mongoid documents.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Drop this line into your Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
group :test do
|
15
|
+
gem 'mongoid-rspec'
|
16
|
+
end
|
17
|
+
|
18
|
+
```
|
19
|
+
|
20
|
+
### Compatibility
|
21
|
+
|
22
|
+
There's no stable version, that provides support for Mongoid 6. But for a time being you can use HEAD version:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem 'mongoid-rspec', github: 'mongoid-rspec/mongoid-rspec'
|
26
|
+
```
|
27
|
+
|
28
|
+
If you're using old version of mongoid, then you have to specify particular vesrion of mongoid-rspec. Use compatibility matrix to find out, which version suits your case.
|
29
|
+
|
30
|
+
|
31
|
+
| mongoid version | mongoid-rspec version |
|
32
|
+
|-----------------|-------------------------|
|
33
|
+
| 5.x | [3.0.0][mongoid5] |
|
34
|
+
| 4.x | [2.1.0][mongoid4] |
|
35
|
+
| 3.x | [1.13.0][mongoid3] |
|
36
|
+
| 2.x | [1.4.5][mongoid2] |
|
37
|
+
|
38
|
+
## Configuration
|
39
|
+
|
40
|
+
### Rails
|
41
|
+
|
42
|
+
Add to your `rails_helper.rb` file
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
require 'mongoid-rspec'
|
46
|
+
|
47
|
+
RSpec.configure do |config|
|
48
|
+
config.include Mongoid::Matchers, type: :model
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
### Other
|
53
|
+
|
54
|
+
Add to your `spec_helper.rb` file
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
require 'mongoid-rspec'
|
58
|
+
|
59
|
+
RSpec.configure do |config|
|
60
|
+
config.include Mongoid::Matchers
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
## Matchers
|
65
|
+
|
66
|
+
### be_mongoid_document
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class Post
|
70
|
+
include Mongoid::Document
|
71
|
+
end
|
72
|
+
|
73
|
+
RSpec.describe Post, type: :model do
|
74
|
+
it { is_expected.to be_mongoid_document }
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
### be_dynamic_document
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
class User
|
82
|
+
include Mongoid::Document
|
83
|
+
include Mongoid::Attributes::Dynamic
|
84
|
+
end
|
85
|
+
|
86
|
+
RSpec.describe User, type: :model do
|
87
|
+
it { is_expected.to be_dynamic_document }
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
### have_timestamps
|
92
|
+
|
93
|
+
With full timestamps
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
class Log
|
97
|
+
include Mongoid::Document
|
98
|
+
include Mongoid::Timestamps
|
99
|
+
end
|
100
|
+
|
101
|
+
RSpec.describe Log, type: :model do
|
102
|
+
it { is_expected.to have_timestamps }
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
With short timestamps
|
107
|
+
```ruby
|
108
|
+
class User
|
109
|
+
include Mongoid::Document
|
110
|
+
include Mongoid::Timestamps::Short
|
111
|
+
end
|
112
|
+
|
113
|
+
RSpec.describe User, type: :model do
|
114
|
+
it { is_expected.to have_timestamps.shortened }
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
With only creating or updating timestamps
|
119
|
+
```ruby
|
120
|
+
class Admin
|
121
|
+
include Mongoid::Document
|
122
|
+
include Mongoid::Timestamps::Create
|
123
|
+
include Mongoid::Timestamps::Update
|
124
|
+
end
|
125
|
+
|
126
|
+
RSpec.describe Admin, type: :model do
|
127
|
+
it { is_expected.to have_timestamps.for(:creating) }
|
128
|
+
it { is_expected.to have_timestamps.for(:updating) }
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
With short creating or updating timestamps
|
133
|
+
```ruby
|
134
|
+
class Post
|
135
|
+
include Mongoid::Document
|
136
|
+
include Mongoid::Timestamps::Create::Short
|
137
|
+
end
|
138
|
+
|
139
|
+
RSpec.describe Short, type: :model do
|
140
|
+
it { is_expected.to have_timestamps.for(:creating).shortened }
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
### be_stored_in
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
class Post
|
148
|
+
include Mongoid::Document
|
149
|
+
|
150
|
+
store_in database: 'db1', collection: 'messages', client: 'secondary'
|
151
|
+
end
|
152
|
+
|
153
|
+
RSpec.describe Post, type: :model do
|
154
|
+
it { is_expected.to be_stored_in(database: 'db1', collection: 'messages', client: 'secondary') }
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
It checks only those options, that you specify. For instance, test in example below will pass, even though expectation contains only `database` option
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
class Comment
|
162
|
+
include Mongoid::Document
|
163
|
+
|
164
|
+
store_in database: 'db2', collection: 'messages'
|
165
|
+
end
|
166
|
+
|
167
|
+
RSpec.describe Comment, type: :model do
|
168
|
+
it { is_expected.to be_stored_in(database: 'db2') }
|
169
|
+
end
|
170
|
+
```
|
171
|
+
|
172
|
+
It works fine with lambdas and procs.
|
173
|
+
```ruby
|
174
|
+
class User
|
175
|
+
include Mongoid::Document
|
176
|
+
|
177
|
+
store_in database: ->{ Thread.current[:database] }
|
178
|
+
end
|
179
|
+
|
180
|
+
RSpec.describe Post, type: :model do
|
181
|
+
it do
|
182
|
+
Thread.current[:database] = 'db3'
|
183
|
+
is_expected.to be_stored_in(database: 'db3')
|
184
|
+
|
185
|
+
Thread.current[:database] = 'db4'
|
186
|
+
is_expected.to be_stored_in(database: 'db4')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
```
|
190
|
+
|
191
|
+
### have_index_for
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
class Article
|
195
|
+
index({ title: 1 }, { unique: true, background: true, drop_dups: true })
|
196
|
+
index({ title: 1, created_at: -1 })
|
197
|
+
index({ category: 1 })
|
198
|
+
end
|
199
|
+
|
200
|
+
RSpec.describe Article, type: :model do
|
201
|
+
it do
|
202
|
+
is_expected
|
203
|
+
.to have_index_for(title: 1)
|
204
|
+
.with_options(unique: true, background: true, drop_dups: true)
|
205
|
+
end
|
206
|
+
it { is_expected.to have_index_for(title: 1, created_at: -1) }
|
207
|
+
it { is_expected.to have_index_for(category: 1) }
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
### Field Matchers
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
RSpec.describe Article do
|
215
|
+
it { is_expected.to have_field(:published).of_type(Boolean).with_default_value_of(false) }
|
216
|
+
it { is_expected.to have_field(:allow_comments).of_type(Boolean).with_default_value_of(true) }
|
217
|
+
it { is_expected.not_to have_field(:allow_comments).of_type(Boolean).with_default_value_of(false) }
|
218
|
+
it { is_expected.not_to have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }
|
219
|
+
end
|
220
|
+
|
221
|
+
RSpec.describe User do
|
222
|
+
it { is_expected.to have_fields(:email, :login) }
|
223
|
+
it { is_expected.to have_field(:s).with_alias(:status) }
|
224
|
+
it { is_expected.to have_fields(:birthdate, :registered_at).of_type(DateTime) }
|
225
|
+
end
|
226
|
+
```
|
227
|
+
|
228
|
+
### Association Matchers
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
RSpec.describe User do
|
232
|
+
it { is_expected.to have_many(:articles).with_foreign_key(:author_id).ordered_by(:title) }
|
233
|
+
|
234
|
+
it { is_expected.to have_one(:record) }
|
235
|
+
#can verify autobuild is set to true
|
236
|
+
it { is_expected.to have_one(:record).with_autobuild }
|
237
|
+
|
238
|
+
it { is_expected.to have_many :comments }
|
239
|
+
|
240
|
+
#can also specify with_dependent to test if :dependent => :destroy/:destroy_all/:delete is set
|
241
|
+
it { is_expected.to have_many(:comments).with_dependent(:destroy) }
|
242
|
+
#can verify autosave is set to true
|
243
|
+
it { is_expected.to have_many(:comments).with_autosave }
|
244
|
+
|
245
|
+
it { is_expected.to embed_one :profile }
|
246
|
+
|
247
|
+
it { is_expected.to have_and_belong_to_many(:children) }
|
248
|
+
it { is_expected.to have_and_belong_to_many(:children).of_type(User) }
|
249
|
+
end
|
250
|
+
|
251
|
+
RSpec.describe Profile do
|
252
|
+
it { is_expected.to be_embedded_in(:user).as_inverse_of(:profile) }
|
253
|
+
end
|
254
|
+
|
255
|
+
RSpec.describe Article do
|
256
|
+
it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles) }
|
257
|
+
it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index }
|
258
|
+
it { is_expected.to embed_many(:comments) }
|
259
|
+
end
|
260
|
+
|
261
|
+
RSpec.describe Comment do
|
262
|
+
it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments) }
|
263
|
+
it { is_expected.to belong_to(:user).as_inverse_of(:comments) }
|
264
|
+
end
|
265
|
+
|
266
|
+
RSpec.describe Record do
|
267
|
+
it { is_expected.to belong_to(:user).as_inverse_of(:record) }
|
268
|
+
end
|
269
|
+
|
270
|
+
RSpec.describe Site do
|
271
|
+
it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.asc).with_counter_cache }
|
272
|
+
end
|
273
|
+
```
|
274
|
+
|
275
|
+
### Validation Matchers
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
RSpec.describe Site do
|
279
|
+
it { is_expected.to validate_presence_of(:name) }
|
280
|
+
it { is_expected.to validate_uniqueness_of(:name) }
|
281
|
+
end
|
282
|
+
|
283
|
+
RSpec.describe User do
|
284
|
+
it { is_expected.to validate_presence_of(:login) }
|
285
|
+
it { is_expected.to validate_uniqueness_of(:login).scoped_to(:site) }
|
286
|
+
it { is_expected.to validate_uniqueness_of(:email).case_insensitive.with_message("is already taken") }
|
287
|
+
it { is_expected.to validate_format_of(:login).to_allow("valid_login").not_to_allow("invalid login") }
|
288
|
+
it { is_expected.to validate_associated(:profile) }
|
289
|
+
it { is_expected.to validate_exclusion_of(:login).to_not_allow("super", "index", "edit") }
|
290
|
+
it { is_expected.to validate_inclusion_of(:role).to_allow("admin", "member") }
|
291
|
+
it { is_expected.to validate_confirmation_of(:email) }
|
292
|
+
it { is_expected.to validate_presence_of(:age).on(:create, :update) }
|
293
|
+
it { is_expected.to validate_numericality_of(:age).on(:create, :update) }
|
294
|
+
it { is_expected.to validate_inclusion_of(:age).to_allow(23..42).on([:create, :update]) }
|
295
|
+
it { is_expected.to validate_presence_of(:password).on(:create) }
|
296
|
+
it { is_expected.to validate_presence_of(:provider_uid).on(:create) }
|
297
|
+
it { is_expected.to validate_inclusion_of(:locale).to_allow([:en, :ru]) }
|
298
|
+
end
|
299
|
+
|
300
|
+
RSpec.describe Article do
|
301
|
+
it { is_expected.to validate_length_of(:title).within(8..16) }
|
302
|
+
end
|
303
|
+
|
304
|
+
RSpec.describe Profile do
|
305
|
+
it { is_expected.to validate_numericality_of(:age).greater_than(0) }
|
306
|
+
end
|
307
|
+
|
308
|
+
RSpec.describe MovieArticle do
|
309
|
+
it { is_expected.to validate_numericality_of(:rating).to_allow(:greater_than => 0).less_than_or_equal_to(5) }
|
310
|
+
it { is_expected.to validate_numericality_of(:classification).to_allow(:even => true, :only_integer => true, :nil => false) }
|
311
|
+
end
|
312
|
+
|
313
|
+
RSpec.describe Person do
|
314
|
+
# in order to be able to use the custom_validate matcher, the custom validator class (in this case SsnValidator)
|
315
|
+
# should redefine the kind method to return :custom, i.e. "def self.kind() :custom end"
|
316
|
+
it { is_expected.to custom_validate(:ssn).with_validator(SsnValidator) }
|
317
|
+
end
|
318
|
+
```
|
319
|
+
|
320
|
+
### Mass Assignment Matcher
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
RSpec.describe User do
|
324
|
+
it { is_expected.to allow_mass_assignment_of(:login) }
|
325
|
+
it { is_expected.to allow_mass_assignment_of(:email) }
|
326
|
+
it { is_expected.to allow_mass_assignment_of(:age) }
|
327
|
+
it { is_expected.to allow_mass_assignment_of(:password) }
|
328
|
+
it { is_expected.to allow_mass_assignment_of(:password) }
|
329
|
+
it { is_expected.to allow_mass_assignment_of(:role).as(:admin) }
|
330
|
+
|
331
|
+
it { is_expected.not_to allow_mass_assignment_of(:role) }
|
332
|
+
end
|
333
|
+
```
|
334
|
+
|
335
|
+
### Accepts Nested Attributes Matcher
|
336
|
+
|
337
|
+
```ruby
|
338
|
+
RSpec.describe User do
|
339
|
+
it { is_expected.to accept_nested_attributes_for(:articles) }
|
340
|
+
it { is_expected.to accept_nested_attributes_for(:comments) }
|
341
|
+
end
|
342
|
+
|
343
|
+
RSpec.describe Article do
|
344
|
+
it { is_expected.to accept_nested_attributes_for(:permalink) }
|
345
|
+
end
|
346
|
+
```
|
347
|
+
|
348
|
+
## Known issues
|
349
|
+
|
350
|
+
accept_nested_attributes_for matcher must test options [issue 91](https://github.com/mongoid-rspec/mongoid-rspec/issues/91).
|
351
|
+
|
352
|
+
## Acknowledgement
|
353
|
+
|
354
|
+
Thanks to [Durran Jordan][durran] for providing the changes necessary to make
|
355
|
+
this compatible with mongoid 2.0.0.rc, and for other [contributors](https://github.com/mongoid-rspec/mongoid-rspec/contributors)
|
356
|
+
to this project.
|
357
|
+
|
358
|
+
[mongoid-rspec]: https://github.com/mongoid-rspec/mongoid-rspec "A collection of RSpec-compatible matchers that help to test Mongoid documents."
|
359
|
+
|
360
|
+
[durran]: https://github.com/durran
|
361
|
+
[mongoid2]: https://rubygems.org/gems/mongoid-rspec/versions/1.4.5
|
362
|
+
[mongoid3]: https://rubygems.org/gems/mongoid-rspec/versions/1.13.0
|
363
|
+
[mongoid4]: https://rubygems.org/gems/mongoid-rspec/versions/2.1.0
|
364
|
+
[mongoid5]: https://rubygems.org/gems/mongoid-rspec/versions/3.0.0
|
365
|
+
|
366
|
+
[travis_badge]: http://img.shields.io/travis/mongoid-rspec/mongoid-rspec.svg?style=flat
|
367
|
+
[travis]: https://travis-ci.org/mongoid-rspec/mongoid-rspec
|
368
|
+
|
369
|
+
[rubygems_badge]: http://img.shields.io/gem/v/mongoid-rspec.svg?style=flat
|
370
|
+
[rubygems]: http://rubygems.org/gems/mongoid-rspec
|
371
|
+
|
372
|
+
[codeclimate_badge]: http://img.shields.io/codeclimate/github/mongoid-rspec/mongoid-rspec.svg?style=flat
|
373
|
+
[codeclimate]: https://codeclimate.com/github/mongoid-rspec/mongoid-rspec
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
11
|
+
spec.pattern = "./spec/**/*_spec.rb"
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
15
|
+
spec.pattern = "./spec/**/*_spec.rb"
|
16
|
+
spec.rcov = true
|
17
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers # :nodoc:
|
3
|
+
|
4
|
+
# Ensures that the model can accept nested attributes for the specified
|
5
|
+
# association.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
# it { should accept_nested_attributes_for(:articles) }
|
9
|
+
#
|
10
|
+
def accept_nested_attributes_for(attribute)
|
11
|
+
AcceptNestedAttributesForMatcher.new(attribute)
|
12
|
+
end
|
13
|
+
|
14
|
+
class AcceptNestedAttributesForMatcher
|
15
|
+
|
16
|
+
def initialize(attribute)
|
17
|
+
@attribute = attribute.to_s
|
18
|
+
@options = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def matches?(subject)
|
22
|
+
@subject = subject
|
23
|
+
match?
|
24
|
+
end
|
25
|
+
|
26
|
+
def failure_message
|
27
|
+
"Expected #{expectation} (#{@problem})"
|
28
|
+
end
|
29
|
+
|
30
|
+
def negative_failure_message
|
31
|
+
"Did not expect #{expectation}"
|
32
|
+
end
|
33
|
+
|
34
|
+
alias :failure_message_when_negated :negative_failure_message
|
35
|
+
|
36
|
+
def description
|
37
|
+
description = "accepts_nested_attributes_for :#{@attribute}"
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
def match?
|
42
|
+
exists?
|
43
|
+
end
|
44
|
+
|
45
|
+
def exists?
|
46
|
+
if config
|
47
|
+
true
|
48
|
+
else
|
49
|
+
@problem = 'is not declared'
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def config
|
55
|
+
model_class.nested_attributes["#{@attribute}_attributes"]
|
56
|
+
end
|
57
|
+
|
58
|
+
def model_class
|
59
|
+
@subject.class
|
60
|
+
end
|
61
|
+
|
62
|
+
def expectation
|
63
|
+
"#{model_class.name} to accept nested attributes for #{@attribute}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|