formtastic 3.0.0 → 3.1.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. data/.travis.yml +1 -0
  2. data/Appraisals +4 -0
  3. data/CHANGELOG +12 -22
  4. data/DEPRECATIONS +47 -0
  5. data/README.textile +9 -4
  6. data/formtastic.gemspec +3 -3
  7. data/gemfiles/rails_4.2.gemfile +7 -0
  8. data/lib/formtastic.rb +13 -7
  9. data/lib/formtastic/action_class_finder.rb +18 -0
  10. data/lib/formtastic/deprecation.rb +42 -0
  11. data/lib/formtastic/form_builder.rb +12 -6
  12. data/lib/formtastic/helpers/action_helper.rb +43 -6
  13. data/lib/formtastic/helpers/form_helper.rb +2 -2
  14. data/lib/formtastic/helpers/input_helper.rb +71 -31
  15. data/lib/formtastic/html_attributes.rb +12 -1
  16. data/lib/formtastic/input_class_finder.rb +18 -0
  17. data/lib/formtastic/inputs.rb +1 -0
  18. data/lib/formtastic/inputs/base.rb +11 -12
  19. data/lib/formtastic/inputs/base/choices.rb +1 -1
  20. data/lib/formtastic/inputs/base/collections.rb +1 -1
  21. data/lib/formtastic/inputs/base/html.rb +3 -3
  22. data/lib/formtastic/inputs/datalist_input.rb +41 -0
  23. data/lib/formtastic/inputs/file_input.rb +2 -2
  24. data/lib/formtastic/namespaced_class_finder.rb +89 -0
  25. data/lib/formtastic/util.rb +1 -1
  26. data/lib/formtastic/version.rb +1 -1
  27. data/lib/generators/templates/formtastic.rb +20 -0
  28. data/spec/action_class_finder_spec.rb +12 -0
  29. data/spec/builder/custom_builder_spec.rb +2 -2
  30. data/spec/builder/semantic_fields_for_spec.rb +4 -4
  31. data/spec/helpers/action_helper_spec.rb +9 -355
  32. data/spec/helpers/form_helper_spec.rb +11 -1
  33. data/spec/helpers/input_helper_spec.rb +1 -916
  34. data/spec/helpers/namespaced_action_helper_spec.rb +43 -0
  35. data/spec/helpers/namespaced_input_helper_spec.rb +36 -0
  36. data/spec/input_class_finder_spec.rb +10 -0
  37. data/spec/inputs/check_boxes_input_spec.rb +2 -2
  38. data/spec/inputs/datalist_input_spec.rb +61 -0
  39. data/spec/inputs/select_input_spec.rb +1 -1
  40. data/spec/localizer_spec.rb +2 -2
  41. data/spec/namespaced_class_finder_spec.rb +79 -0
  42. data/spec/spec_helper.rb +17 -7
  43. data/spec/support/custom_macros.rb +22 -4
  44. data/spec/support/shared_examples.rb +1244 -0
  45. data/spec/support/specialized_class_finder_shared_example.rb +27 -0
  46. data/spec/support/test_environment.rb +1 -1
  47. data/spec/util_spec.rb +20 -6
  48. metadata +66 -15
  49. checksums.yaml +0 -15
@@ -189,7 +189,17 @@ describe 'FormHelper' do
189
189
  describe 'with :namespace option' do
190
190
  it "should set the custom_namespace" do
191
191
  semantic_form_for(@new_post, :namespace => 'context2') do |builder|
192
- builder.custom_namespace == 'context2'
192
+ expect(builder.dom_id_namespace).to eq('context2')
193
+ end
194
+ end
195
+ end
196
+
197
+ describe 'without :namespace option' do
198
+ it 'defaults to class settings' do
199
+ expect(Formtastic::FormBuilder).to receive(:custom_namespace).and_return('context2')
200
+
201
+ semantic_form_for(@new_post) do |builder|
202
+ expect(builder.dom_id_namespace).to eq('context2')
193
203
  end
194
204
  end
195
205
  end
@@ -2,920 +2,5 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe 'Formtastic::FormBuilder#input' do
5
-
6
- include FormtasticSpecHelper
7
-
8
- before do
9
- @output_buffer = ''
10
- mock_everything
11
-
12
- @errors = double('errors')
13
- @errors.stub(:[]).and_return([])
14
- @new_post.stub(:errors).and_return(@errors)
15
- end
16
-
17
- after do
18
- ::I18n.backend.reload!
19
- end
20
-
21
- describe 'arguments and options' do
22
-
23
- it 'should require the first argument (the method on form\'s object)' do
24
- lambda {
25
- concat(semantic_form_for(@new_post) do |builder|
26
- concat(builder.input()) # no args passed in at all
27
- end)
28
- }.should raise_error(ArgumentError)
29
- end
30
-
31
- describe ':required option' do
32
-
33
- describe 'when true' do
34
-
35
- it 'should set a "required" class' do
36
- with_config :required_string, " required yo!" do
37
- concat(semantic_form_for(@new_post) do |builder|
38
- concat(builder.input(:title, :required => true))
39
- end)
40
- output_buffer.should_not have_tag('form li.optional')
41
- output_buffer.should have_tag('form li.required')
42
- end
43
- end
44
-
45
- it 'should append the "required" string to the label' do
46
- with_config :required_string, " required yo!" do
47
- concat(semantic_form_for(@new_post) do |builder|
48
- concat(builder.input(:title, :required => true))
49
- end)
50
- output_buffer.should have_tag('form li.required label', /required yo/)
51
- end
52
- end
53
- end
54
-
55
- describe 'when false' do
56
-
57
- before do
58
- @string = Formtastic::FormBuilder.optional_string = " optional yo!" # ensure there's something in the string
59
- @new_post.class.should_not_receive(:reflect_on_all_validations)
60
- end
61
-
62
- after do
63
- Formtastic::FormBuilder.optional_string = ''
64
- end
65
-
66
- it 'should set an "optional" class' do
67
- concat(semantic_form_for(@new_post) do |builder|
68
- concat(builder.input(:title, :required => false))
69
- end)
70
- output_buffer.should_not have_tag('form li.required')
71
- output_buffer.should have_tag('form li.optional')
72
- end
73
-
74
- it 'should set and "optional" class also when there is presence validator' do
75
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
76
- active_model_presence_validator([:title])
77
- ])
78
- concat(semantic_form_for(@new_post) do |builder|
79
- concat(builder.input(:title, :required => false))
80
- end)
81
- output_buffer.should_not have_tag('form li.required')
82
- output_buffer.should have_tag('form li.optional')
83
- end
84
-
85
- it 'should append the "optional" string to the label' do
86
- concat(semantic_form_for(@new_post) do |builder|
87
- concat(builder.input(:title, :required => false))
88
- end)
89
- output_buffer.should have_tag('form li.optional label', /#{@string}$/)
90
- end
91
-
92
- end
93
-
94
- describe 'when not provided' do
95
-
96
- describe 'and an object was not given' do
97
-
98
- it 'should use the default value' do
99
- Formtastic::FormBuilder.all_fields_required_by_default.should == true
100
- Formtastic::FormBuilder.all_fields_required_by_default = false
101
-
102
- concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder|
103
- concat(builder.input(:title))
104
- end)
105
- output_buffer.should_not have_tag('form li.required')
106
- output_buffer.should have_tag('form li.optional')
107
-
108
- Formtastic::FormBuilder.all_fields_required_by_default = true
109
- end
110
-
111
- end
112
-
113
- describe 'and an object with :validators_on was given (ActiveModel, Active Resource)' do
114
- before do
115
- @new_post.stub(:class).and_return(::PostModel)
116
- end
117
-
118
- after do
119
- @new_post.stub(:class).and_return(::Post)
120
- end
121
- describe 'and validates_presence_of was called for the method' do
122
- it 'should be required' do
123
-
124
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
125
- active_model_presence_validator([:title])
126
- ])
127
-
128
- @new_post.class.should_receive(:validators_on).with(:body).at_least(:once).and_return([
129
- active_model_presence_validator([:body], {:if => true})
130
- ])
131
-
132
- concat(semantic_form_for(@new_post) do |builder|
133
- concat(builder.input(:title))
134
- concat(builder.input(:body))
135
- end)
136
- output_buffer.should have_tag('form li.required')
137
- output_buffer.should_not have_tag('form li.optional')
138
- end
139
-
140
- it 'should be required when there is :on => :create option on create' do
141
- with_config :required_string, " required yo!" do
142
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
143
- active_model_presence_validator([:title], {:on => :create})
144
- ])
145
- concat(semantic_form_for(@new_post) do |builder|
146
- concat(builder.input(:title))
147
- end)
148
- output_buffer.should have_tag('form li.required')
149
- output_buffer.should_not have_tag('form li.optional')
150
- end
151
- end
152
-
153
- it 'should be required when there is :on => :save option on create' do
154
- with_config :required_string, " required yo!" do
155
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
156
- active_model_presence_validator([:title], {:on => :save})
157
- ])
158
- concat(semantic_form_for(@new_post) do |builder|
159
- concat(builder.input(:title))
160
- end)
161
- output_buffer.should have_tag('form li.required')
162
- output_buffer.should_not have_tag('form li.optional')
163
- end
164
- end
165
-
166
- it 'should be required when there is :on => :save option on update' do
167
- with_config :required_string, " required yo!" do
168
- @fred.class.should_receive(:validators_on).with(:login).at_least(:once).and_return([
169
- active_model_presence_validator([:login], {:on => :save})
170
- ])
171
- concat(semantic_form_for(@fred) do |builder|
172
- concat(builder.input(:login))
173
- end)
174
- output_buffer.should have_tag('form li.required')
175
- output_buffer.should_not have_tag('form li.optional')
176
- end
177
- end
178
-
179
- it 'should not be required when there is :on => :create option on update' do
180
- @fred.class.should_receive(:validators_on).with(:login).at_least(:once).and_return([
181
- active_model_presence_validator([:login], {:on => :create})
182
- ])
183
- concat(semantic_form_for(@fred) do |builder|
184
- concat(builder.input(:login))
185
- end)
186
- output_buffer.should_not have_tag('form li.required')
187
- output_buffer.should have_tag('form li.optional')
188
- end
189
-
190
- it 'should not be required when there is :on => :update option on create' do
191
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
192
- active_model_presence_validator([:title], {:on => :update})
193
- ])
194
- concat(semantic_form_for(@new_post) do |builder|
195
- concat(builder.input(:title))
196
- end)
197
- output_buffer.should_not have_tag('form li.required')
198
- output_buffer.should have_tag('form li.optional')
199
- end
200
-
201
- it 'should be not be required if the optional :if condition is not satisifed' do
202
- presence_should_be_required(:required => false, :tag => :body, :options => { :if => false })
203
- end
204
-
205
- it 'should not be required if the optional :if proc evaluates to false' do
206
- presence_should_be_required(:required => false, :tag => :body, :options => { :if => proc { |record| false } })
207
- end
208
-
209
- it 'should be required if the optional :if proc evaluates to true' do
210
- presence_should_be_required(:required => true, :tag => :body, :options => { :if => proc { |record| true } })
211
- end
212
-
213
- it 'should not be required if the optional :unless proc evaluates to true' do
214
- presence_should_be_required(:required => false, :tag => :body, :options => { :unless => proc { |record| true } })
215
- end
216
-
217
- it 'should be required if the optional :unless proc evaluates to false' do
218
- presence_should_be_required(:required => true, :tag => :body, :options => { :unless => proc { |record| false } })
219
- end
220
-
221
- it 'should be required if the optional :if with a method string evaluates to true' do
222
- @new_post.should_receive(:required_condition).and_return(true)
223
- presence_should_be_required(:required => true, :tag => :body, :options => { :if => :required_condition })
224
- end
225
-
226
- it 'should be required if the optional :if with a method string evaluates to false' do
227
- @new_post.should_receive(:required_condition).and_return(false)
228
- presence_should_be_required(:required => false, :tag => :body, :options => { :if => :required_condition })
229
- end
230
-
231
- it 'should be required if the optional :unless with a method string evaluates to false' do
232
- @new_post.should_receive(:required_condition).and_return(false)
233
- presence_should_be_required(:required => true, :tag => :body, :options => { :unless => :required_condition })
234
- end
235
-
236
- it 'should not be required if the optional :unless with a method string evaluates to true' do
237
- @new_post.should_receive(:required_condition).and_return(true)
238
- presence_should_be_required(:required => false, :tag => :body, :options => { :unless => :required_condition })
239
- end
240
- end
241
-
242
- describe 'and validates_inclusion_of was called for the method' do
243
- it 'should be required' do
244
- @new_post.class.should_receive(:validators_on).with(:published).at_least(:once).and_return([
245
- active_model_inclusion_validator([:published], {:in => [false, true]})
246
- ])
247
- should_be_required(:tag => :published, :required => true)
248
- end
249
-
250
- it 'should not be required if allow_blank is true' do
251
- @new_post.class.should_receive(:validators_on).with(:published).at_least(:once).and_return([
252
- active_model_inclusion_validator([:published], {:in => [false, true], :allow_blank => true})
253
- ])
254
- should_be_required(:tag => :published, :required => false)
255
- end
256
- end
257
-
258
- describe 'and validates_length_of was called for the method' do
259
- it 'should be required if minimum is set' do
260
- length_should_be_required(:tag => :title, :required => true, :options => {:minimum => 1})
261
- end
262
-
263
- it 'should be required if :within is set' do
264
- length_should_be_required(:tag => :title, :required => true, :options => {:within => 1..5})
265
- end
266
-
267
- it 'should not be required if :within allows zero length' do
268
- length_should_be_required(:tag => :title, :required => false, :options => {:within => 0..5})
269
- end
270
-
271
- it 'should not be required if only :minimum is zero' do
272
- length_should_be_required(:tag => :title, :required => false, :options => {:minimum => 0})
273
- end
274
-
275
- it 'should not be required if only :minimum is not set' do
276
- length_should_be_required(:tag => :title, :required => false, :options => {:maximum => 5})
277
- end
278
-
279
- it 'should not be required if allow_blank is true' do
280
- length_should_be_required(:tag => :published, :required => false, :options => {:allow_blank => true})
281
- end
282
- end
283
-
284
- def add_presence_validator(options)
285
- @new_post.class.stub(:validators_on).with(options[:tag]).and_return([
286
- active_model_presence_validator([options[:tag]], options[:options])
287
- ])
288
- end
289
-
290
- def add_length_validator(options)
291
- @new_post.class.should_receive(:validators_on).with(options[:tag]).at_least(:once) {[
292
- active_model_length_validator([options[:tag]], options[:options])
293
- ]}
294
- end
295
-
296
- # TODO make a matcher for this?
297
- def should_be_required(options)
298
- concat(semantic_form_for(@new_post) do |builder|
299
- concat(builder.input(options[:tag]))
300
- end)
301
-
302
- if options[:required]
303
- output_buffer.should_not have_tag('form li.optional')
304
- output_buffer.should have_tag('form li.required')
305
- else
306
- output_buffer.should have_tag('form li.optional')
307
- output_buffer.should_not have_tag('form li.required')
308
- end
309
- end
310
-
311
- def presence_should_be_required(options)
312
- add_presence_validator(options)
313
- should_be_required(options)
314
- end
315
-
316
- def length_should_be_required(options)
317
- add_length_validator(options)
318
- should_be_required(options)
319
- end
320
-
321
- # TODO JF reversed this during refactor, need to make sure
322
- describe 'and there are no requirement validations on the method' do
323
- before do
324
- @new_post.class.should_receive(:validators_on).with(:title).and_return([])
325
- end
326
-
327
- it 'should not be required' do
328
- concat(semantic_form_for(@new_post) do |builder|
329
- concat(builder.input(:title))
330
- end)
331
- output_buffer.should_not have_tag('form li.required')
332
- output_buffer.should have_tag('form li.optional')
333
- end
334
- end
335
-
336
- end
337
-
338
- describe 'and an object without :validators_on' do
339
-
340
- it 'should use the default value' do
341
- Formtastic::FormBuilder.all_fields_required_by_default.should == true
342
- Formtastic::FormBuilder.all_fields_required_by_default = false
343
-
344
- concat(semantic_form_for(@new_post) do |builder|
345
- concat(builder.input(:title))
346
- end)
347
- output_buffer.should_not have_tag('form li.required')
348
- output_buffer.should have_tag('form li.optional')
349
-
350
- Formtastic::FormBuilder.all_fields_required_by_default = true
351
- end
352
-
353
- end
354
-
355
- end
356
-
357
- end
358
-
359
- describe ':as option' do
360
-
361
- describe 'when not provided' do
362
-
363
- it 'should default to a string for forms without objects unless column is password' do
364
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
365
- concat(builder.input(:anything))
366
- end)
367
- output_buffer.should have_tag('form li.string')
368
- end
369
-
370
- it 'should default to password for forms without objects if column is password' do
371
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
372
- concat(builder.input(:password))
373
- concat(builder.input(:password_confirmation))
374
- concat(builder.input(:confirm_password))
375
- end)
376
- output_buffer.should have_tag('form li.password', :count => 3)
377
- end
378
-
379
- it 'should default to a string for methods on objects that don\'t respond to "column_for_attribute"' do
380
- @new_post.stub(:method_without_a_database_column)
381
- @new_post.stub(:column_for_attribute).and_return(nil)
382
- default_input_type(nil, :method_without_a_database_column).should == :string
383
- end
384
-
385
- it 'should default to :password for methods that don\'t have a column in the database but "password" is in the method name' do
386
- @new_post.stub(:password_method_without_a_database_column)
387
- @new_post.stub(:column_for_attribute).and_return(nil)
388
- default_input_type(nil, :password_method_without_a_database_column).should == :password
389
- end
390
-
391
- it 'should default to :password for methods on objects that don\'t respond to "column_for_attribute" but "password" is in the method name' do
392
- @new_post.stub(:password_method_without_a_database_column)
393
- @new_post.stub(:column_for_attribute).and_return(nil)
394
- default_input_type(nil, :password_method_without_a_database_column).should == :password
395
- end
396
-
397
- it 'should default to :number for "integer" column with name ending in "_id"' do
398
- @new_post.stub(:aws_instance_id)
399
- @new_post.stub(:column_for_attribute).with(:aws_instance_id).and_return(double('column', :type => :integer))
400
- default_input_type(:integer, :aws_instance_id).should == :number
401
- end
402
-
403
- it 'should default to :select for associations' do
404
- @new_post.class.stub(:reflect_on_association).with(:user_id).and_return(double('ActiveRecord::Reflection::AssociationReflection'))
405
- @new_post.class.stub(:reflect_on_association).with(:section_id).and_return(double('ActiveRecord::Reflection::AssociationReflection'))
406
- default_input_type(:integer, :user_id).should == :select
407
- default_input_type(:integer, :section_id).should == :select
408
- end
409
-
410
- it 'should default to :password for :string column types with "password" in the method name' do
411
- default_input_type(:string, :password).should == :password
412
- default_input_type(:string, :hashed_password).should == :password
413
- default_input_type(:string, :password_hash).should == :password
414
- end
415
-
416
- it 'should default to :text for :text column types' do
417
- default_input_type(:text).should == :text
418
- end
419
-
420
- it 'should default to :date_select for :date column types' do
421
- default_input_type(:date).should == :date_select
422
- end
423
-
424
- it 'should default to :datetime_select for :datetime and :timestamp column types' do
425
- default_input_type(:datetime).should == :datetime_select
426
- default_input_type(:timestamp).should == :datetime_select
427
- end
428
-
429
- it 'should default to :time_select for :time column types' do
430
- default_input_type(:time).should == :time_select
431
- end
432
-
433
- it 'should default to :boolean for :boolean column types' do
434
- default_input_type(:boolean).should == :boolean
435
- end
436
-
437
- it 'should default to :string for :string column types' do
438
- default_input_type(:string).should == :string
439
- end
440
-
441
- it 'should default to :number for :integer, :float and :decimal column types' do
442
- default_input_type(:integer).should == :number
443
- default_input_type(:float).should == :number
444
- default_input_type(:decimal).should == :number
445
- end
446
-
447
- it 'should default to :country for :string columns named country' do
448
- default_input_type(:string, :country).should == :country
449
- end
450
-
451
- it 'should default to :email for :string columns matching email' do
452
- default_input_type(:string, :email).should == :email
453
- default_input_type(:string, :customer_email).should == :email
454
- default_input_type(:string, :email_work).should == :email
455
- end
456
-
457
- it 'should default to :url for :string columns named url or website' do
458
- default_input_type(:string, :url).should == :url
459
- default_input_type(:string, :website).should == :url
460
- default_input_type(:string, :my_url).should == :url
461
- default_input_type(:string, :hurl).should_not == :url
462
- end
463
-
464
- it 'should default to :phone for :string columns named phone or fax' do
465
- default_input_type(:string, :phone).should == :phone
466
- default_input_type(:string, :fax).should == :phone
467
- end
468
-
469
- it 'should default to :search for :string columns named search' do
470
- default_input_type(:string, :search).should == :search
471
- end
472
-
473
- it 'should default to :color for :string columns matching color' do
474
- default_input_type(:string, :color).should == :color
475
- default_input_type(:string, :user_color).should == :color
476
- default_input_type(:string, :color_for_image).should == :color
477
- end
478
-
479
- describe 'defaulting to file column' do
480
- Formtastic::FormBuilder.file_methods.each do |method|
481
- it "should default to :file for attributes that respond to ##{method}" do
482
- column = double('column')
483
-
484
- Formtastic::FormBuilder.file_methods.each do |test|
485
- ### TODO: Check if this is ok
486
- column.stub(method).with(test).and_return(method == test)
487
- end
488
-
489
- @new_post.should_receive(method).and_return(column)
490
-
491
- semantic_form_for(@new_post) do |builder|
492
- builder.send(:default_input_type, method).should == :file
493
- end
494
- end
495
- end
496
-
497
- end
498
- end
499
-
500
- it 'should call the corresponding input class with .to_html' do
501
- [:select, :time_zone, :radio, :date_select, :datetime_select, :time_select, :boolean, :check_boxes, :hidden, :string, :password, :number, :text, :file].each do |input_style|
502
- @new_post.stub(:generic_column_name)
503
- @new_post.stub(:column_for_attribute).and_return(double('column', :type => :string, :limit => 255))
504
- semantic_form_for(@new_post) do |builder|
505
- input_instance = double('Input instance')
506
- input_class = "#{input_style.to_s}_input".classify
507
- input_constant = "Formtastic::Inputs::#{input_class}".constantize
508
-
509
- input_constant.should_receive(:new).and_return(input_instance)
510
- input_instance.should_receive(:to_html).and_return("some HTML")
511
-
512
- concat(builder.input(:generic_column_name, :as => input_style))
513
- end
514
- end
515
- end
516
-
517
- end
518
-
519
- describe ':label option' do
520
-
521
- describe 'when provided' do
522
- it 'should be passed down to the label tag' do
523
- concat(semantic_form_for(@new_post) do |builder|
524
- concat(builder.input(:title, :label => "Kustom"))
525
- end)
526
- output_buffer.should have_tag("form li label", /Kustom/)
527
- end
528
-
529
- it 'should not generate a label if false' do
530
- concat(semantic_form_for(@new_post) do |builder|
531
- concat(builder.input(:title, :label => false))
532
- end)
533
- output_buffer.should_not have_tag("form li label")
534
- end
535
-
536
- it 'should be dupped if frozen' do
537
- concat(semantic_form_for(@new_post) do |builder|
538
- concat(builder.input(:title, :label => "Kustom".freeze))
539
- end)
540
- output_buffer.should have_tag("form li label", /Kustom/)
541
- end
542
- end
543
-
544
- describe 'when not provided' do
545
- describe 'when localized label is provided' do
546
- describe 'and object is given' do
547
- describe 'and label_str_method not :humanize' do
548
- it 'should render a label with localized text and not apply the label_str_method' do
549
- with_config :label_str_method, :reverse do
550
- @localized_label_text = 'Localized title'
551
- @new_post.stub(:meta_description)
552
- ::I18n.backend.store_translations :en,
553
- :formtastic => {
554
- :labels => {
555
- :meta_description => @localized_label_text
556
- }
557
- }
558
-
559
- concat(semantic_form_for(@new_post) do |builder|
560
- concat(builder.input(:meta_description))
561
- end)
562
- output_buffer.should have_tag('form li label', /Localized title/)
563
- end
564
- end
565
- end
566
- end
567
- end
568
-
569
- describe 'when localized label is NOT provided' do
570
- describe 'and object is not given' do
571
- it 'should default the humanized method name, passing it down to the label tag' do
572
- ::I18n.backend.store_translations :en, :formtastic => {}
573
- with_config :label_str_method, :humanize do
574
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
575
- concat(builder.input(:meta_description))
576
- end)
577
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
578
- end
579
- end
580
- end
581
-
582
- describe 'and object is given' do
583
- it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
584
- @new_post.stub(:meta_description) # a two word method name
585
- @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
586
-
587
- concat(semantic_form_for(@new_post) do |builder|
588
- concat(builder.input(:meta_description))
589
- end)
590
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
591
- end
592
- end
593
-
594
- describe 'and object is given with label_str_method set to :capitalize' do
595
- it 'should capitalize method name, passing it down to the label tag' do
596
- with_config :label_str_method, :capitalize do
597
- @new_post.stub(:meta_description)
598
-
599
- concat(semantic_form_for(@new_post) do |builder|
600
- concat(builder.input(:meta_description))
601
- end)
602
- output_buffer.should have_tag("form li label", /#{'meta_description'.capitalize}/)
603
- end
604
- end
605
- end
606
- end
607
-
608
- describe 'when localized label is provided' do
609
- before do
610
- @localized_label_text = 'Localized title'
611
- @default_localized_label_text = 'Default localized title'
612
- ::I18n.backend.store_translations :en,
613
- :formtastic => {
614
- :labels => {
615
- :title => @default_localized_label_text,
616
- :published => @default_localized_label_text,
617
- :post => {
618
- :title => @localized_label_text,
619
- :published => @default_localized_label_text
620
- }
621
- }
622
- }
623
- end
624
-
625
- it 'should render a label with localized label (I18n)' do
626
- with_config :i18n_lookups_by_default, false do
627
- concat(semantic_form_for(@new_post) do |builder|
628
- concat(builder.input(:title, :label => true))
629
- concat(builder.input(:published, :as => :boolean, :label => true))
630
- end)
631
- output_buffer.should have_tag('form li label', Regexp.new('^' + @localized_label_text))
632
- end
633
- end
634
-
635
- it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
636
- with_config :i18n_lookups_by_default, false do
637
- ::I18n.backend.store_translations :en,
638
- :formtastic => {
639
- :labels => {
640
- :post => {
641
- :title => nil,
642
- :published => nil
643
- }
644
- }
645
- }
646
- concat(semantic_form_for(@new_post) do |builder|
647
- concat(builder.input(:title, :label => true))
648
- concat(builder.input(:published, :as => :boolean, :label => true))
649
- end)
650
- output_buffer.should have_tag('form li label', Regexp.new('^' + @default_localized_label_text))
651
- end
652
- end
653
- end
654
- end
655
-
656
- end
657
-
658
- describe ':hint option' do
659
-
660
- describe 'when provided' do
661
-
662
- after do
663
- Formtastic::FormBuilder.default_hint_class = "inline-hints"
664
- end
665
-
666
- it 'should be passed down to the paragraph tag' do
667
- hint_text = "this is the title of the post"
668
- concat(semantic_form_for(@new_post) do |builder|
669
- concat(builder.input(:title, :hint => hint_text))
670
- end)
671
- output_buffer.should have_tag("form li p.inline-hints", hint_text)
672
- end
673
-
674
- it 'should have a custom hint class defaulted for all forms' do
675
- hint_text = "this is the title of the post"
676
- Formtastic::FormBuilder.default_hint_class = "custom-hint-class"
677
- concat(semantic_form_for(@new_post) do |builder|
678
- concat(builder.input(:title, :hint => hint_text))
679
- end)
680
- output_buffer.should have_tag("form li p.custom-hint-class", hint_text)
681
- end
682
- end
683
-
684
- describe 'when not provided' do
685
- describe 'when localized hint (I18n) is provided' do
686
- before do
687
- @localized_hint_text = "This is the localized hint."
688
- @default_localized_hint_text = "This is the default localized hint."
689
- ::I18n.backend.store_translations :en,
690
- :formtastic => {
691
- :hints => {
692
- :title => @default_localized_hint_text,
693
- }
694
- }
695
- end
696
-
697
- after do
698
- ::I18n.backend.reload!
699
- end
700
-
701
- describe 'when provided value (hint value) is set to TRUE' do
702
- it 'should render a hint paragraph containing a localized hint (I18n)' do
703
- with_config :i18n_lookups_by_default, false do
704
- ::I18n.backend.store_translations :en,
705
- :formtastic => {
706
- :hints => {
707
- :post => {
708
- :title => @localized_hint_text
709
- }
710
- }
711
- }
712
- concat(semantic_form_for(@new_post) do |builder|
713
- concat(builder.input(:title, :hint => true))
714
- end)
715
- output_buffer.should have_tag('form li p.inline-hints', @localized_hint_text)
716
- end
717
- end
718
-
719
- it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do
720
- with_config :i18n_lookups_by_default, false do
721
- concat(semantic_form_for(@new_post) do |builder|
722
- concat(builder.input(:title, :hint => true))
723
- end)
724
- output_buffer.should have_tag('form li p.inline-hints', @default_localized_hint_text)
725
- end
726
- end
727
- end
728
-
729
- describe 'when provided value (label value) is set to FALSE' do
730
- it 'should not render a hint paragraph' do
731
- with_config :i18n_lookups_by_default, false do
732
- concat(semantic_form_for(@new_post) do |builder|
733
- concat(builder.input(:title, :hint => false))
734
- end)
735
- output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text)
736
- end
737
- end
738
- end
739
- end
740
-
741
- describe 'when localized hint (I18n) is a model with attribute hints' do
742
- it "should see the provided hash as a blank entry" do
743
- with_config :i18n_lookups_by_default, false do
744
- ::I18n.backend.store_translations :en,
745
- :formtastic => {
746
- :hints => {
747
- :title => { # movie title
748
- :summary => @localized_hint_text # summary of movie
749
- }
750
- }
751
- }
752
- semantic_form_for(@new_post) do |builder|
753
- concat(builder.input(:title, :hint => true))
754
- end
755
- output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text)
756
- end
757
- end
758
- end
759
-
760
- describe 'when localized hint (I18n) is not provided' do
761
- it 'should not render a hint paragraph' do
762
- with_config :i18n_lookups_by_default, false do
763
- concat(semantic_form_for(@new_post) do |builder|
764
- concat(builder.input(:title))
765
- end)
766
- output_buffer.should_not have_tag('form li p.inline-hints')
767
- end
768
- end
769
- end
770
- end
771
-
772
- end
773
-
774
- describe ':wrapper_html option' do
775
-
776
- describe 'when provided' do
777
- it 'should be passed down to the li tag' do
778
- concat(semantic_form_for(@new_post) do |builder|
779
- concat(builder.input(:title, :wrapper_html => {:id => :another_id}))
780
- end)
781
- output_buffer.should have_tag("form li#another_id")
782
- end
783
-
784
- it 'should append given classes to li default classes' do
785
- concat(semantic_form_for(@new_post) do |builder|
786
- concat(builder.input(:title, :wrapper_html => {:class => :another_class}, :required => true))
787
- end)
788
- output_buffer.should have_tag("form li.string")
789
- output_buffer.should have_tag("form li.required")
790
- output_buffer.should have_tag("form li.another_class")
791
- end
792
-
793
- it 'should allow classes to be an array' do
794
- concat(semantic_form_for(@new_post) do |builder|
795
- concat(builder.input(:title, :wrapper_html => {:class => [ :my_class, :another_class ]}))
796
- end)
797
- output_buffer.should have_tag("form li.string")
798
- output_buffer.should have_tag("form li.my_class")
799
- output_buffer.should have_tag("form li.another_class")
800
- end
801
-
802
- describe 'when nil' do
803
- it 'should not put an id attribute on the div tag' do
804
- concat(semantic_form_for(@new_post) do |builder|
805
- concat(builder.input(:title, :wrapper_html => {:id => nil}))
806
- end)
807
- output_buffer.should have_tag('form li:not([id])')
808
- end
809
- end
810
- end
811
-
812
- describe 'when not provided' do
813
- it 'should use default id and class' do
814
- concat(semantic_form_for(@new_post) do |builder|
815
- concat(builder.input(:title))
816
- end)
817
- output_buffer.should have_tag("form li#post_title_input")
818
- output_buffer.should have_tag("form li.string")
819
- end
820
- end
821
-
822
- end
823
-
824
- describe ':collection option' do
825
-
826
- it "should be required on polymorphic associations" do
827
- @new_post.stub(:commentable)
828
- @new_post.class.stub(:reflections).and_return({
829
- :commentable => double('macro_reflection', :options => { :polymorphic => true }, :macro => :belongs_to)
830
- })
831
- @new_post.stub(:column_for_attribute).with(:commentable).and_return(
832
- double('column', :type => :integer)
833
- )
834
- @new_post.class.stub(:reflect_on_association).with(:commentable).and_return(
835
- double('reflection', :macro => :belongs_to, :options => { :polymorphic => true })
836
- )
837
- expect {
838
- concat(semantic_form_for(@new_post) do |builder|
839
- concat(builder.inputs do
840
- concat(builder.input :commentable)
841
- end)
842
- end)
843
- }.to raise_error(Formtastic::PolymorphicInputWithoutCollectionError)
844
- end
845
-
846
- end
847
-
848
- end
849
-
850
- describe 'options re-use' do
851
-
852
- it 'should retain :as option when re-using the same options hash' do
853
- my_options = { :as => :string }
854
- output = ''
855
-
856
- concat(semantic_form_for(@new_post) do |builder|
857
- concat(builder.input(:title, my_options))
858
- concat(builder.input(:publish_at, my_options))
859
- end)
860
- output_buffer.should have_tag 'li.string', :count => 2
861
- end
862
-
863
-
864
- end
865
-
866
- describe 'instantiating an input class' do
867
-
868
- context 'when a class does not exist' do
869
- it "should raise an error" do
870
- lambda {
871
- concat(semantic_form_for(@new_post) do |builder|
872
- builder.input(:title, :as => :non_existant)
873
- end)
874
- }.should raise_error(Formtastic::UnknownInputError)
875
- end
876
- end
877
-
878
- context 'when a customized top-level class does not exist' do
879
-
880
- it 'should instantiate the Formtastic input' do
881
- input = double('input', :to_html => 'some HTML')
882
- Formtastic::Inputs::StringInput.should_receive(:new).and_return(input)
883
- concat(semantic_form_for(@new_post) do |builder|
884
- builder.input(:title, :as => :string)
885
- end)
886
- end
887
-
888
- end
889
-
890
- describe 'when a top-level input class exists' do
891
- it "should instantiate the top-level input instead of the Formtastic one" do
892
- class ::StringInput < Formtastic::Inputs::StringInput
893
- end
894
-
895
- input = double('input', :to_html => 'some HTML')
896
- Formtastic::Inputs::StringInput.should_not_receive(:new)
897
- ::StringInput.should_receive(:new).and_return(input)
898
-
899
- concat(semantic_form_for(@new_post) do |builder|
900
- builder.input(:title, :as => :string)
901
- end)
902
- end
903
- end
904
-
905
- describe 'when instantiated multiple times with the same input type' do
906
-
907
- it "should be cached (not calling the internal methods)" do
908
- # TODO this is really tied to the underlying implementation
909
- concat(semantic_form_for(@new_post) do |builder|
910
- builder.should_receive(:custom_input_class_name).with(:string).once.and_return(::Formtastic::Inputs::StringInput)
911
- builder.input(:title, :as => :string)
912
- builder.input(:title, :as => :string)
913
- end)
914
- end
915
-
916
- end
917
-
918
- end
919
-
5
+ it_behaves_like 'Input Helper' # from spec/support/shared_examples.rb
920
6
  end
921
-