formtastic 3.1.1 → 4.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +1 -0
  3. data/.gitignore +3 -2
  4. data/.travis.yml +29 -24
  5. data/CHANGELOG.md +49 -0
  6. data/DEPRECATIONS +4 -1
  7. data/Gemfile.lock +104 -0
  8. data/{README.textile → README.md} +178 -166
  9. data/Rakefile +20 -1
  10. data/app/assets/stylesheets/formtastic.css +1 -1
  11. data/bin/appraisal +8 -0
  12. data/formtastic.gemspec +9 -15
  13. data/gemfiles/rails_5.2/Gemfile +5 -0
  14. data/gemfiles/rails_6.0/Gemfile +5 -0
  15. data/gemfiles/rails_edge/Gemfile +13 -0
  16. data/lib/formtastic.rb +9 -11
  17. data/lib/formtastic/actions.rb +6 -3
  18. data/lib/formtastic/deprecation.rb +1 -38
  19. data/lib/formtastic/engine.rb +3 -1
  20. data/lib/formtastic/form_builder.rb +11 -24
  21. data/lib/formtastic/helpers.rb +1 -1
  22. data/lib/formtastic/helpers/action_helper.rb +1 -48
  23. data/lib/formtastic/helpers/enum.rb +13 -0
  24. data/lib/formtastic/helpers/errors_helper.rb +2 -2
  25. data/lib/formtastic/helpers/fieldset_wrapper.rb +13 -9
  26. data/lib/formtastic/helpers/form_helper.rb +1 -1
  27. data/lib/formtastic/helpers/input_helper.rb +23 -77
  28. data/lib/formtastic/helpers/inputs_helper.rb +27 -22
  29. data/lib/formtastic/i18n.rb +1 -1
  30. data/lib/formtastic/inputs.rb +32 -29
  31. data/lib/formtastic/inputs/base/choices.rb +1 -1
  32. data/lib/formtastic/inputs/base/collections.rb +43 -10
  33. data/lib/formtastic/inputs/base/database.rb +7 -2
  34. data/lib/formtastic/inputs/base/errors.rb +4 -4
  35. data/lib/formtastic/inputs/base/hints.rb +1 -1
  36. data/lib/formtastic/inputs/base/html.rb +7 -6
  37. data/lib/formtastic/inputs/base/naming.rb +4 -4
  38. data/lib/formtastic/inputs/base/options.rb +2 -3
  39. data/lib/formtastic/inputs/base/timeish.rb +5 -1
  40. data/lib/formtastic/inputs/base/validations.rb +38 -12
  41. data/lib/formtastic/inputs/check_boxes_input.rb +13 -5
  42. data/lib/formtastic/inputs/color_input.rb +0 -1
  43. data/lib/formtastic/inputs/country_input.rb +3 -1
  44. data/lib/formtastic/inputs/radio_input.rb +20 -0
  45. data/lib/formtastic/inputs/select_input.rb +29 -1
  46. data/lib/formtastic/inputs/time_zone_input.rb +16 -6
  47. data/lib/formtastic/localizer.rb +20 -22
  48. data/lib/formtastic/namespaced_class_finder.rb +1 -1
  49. data/lib/formtastic/version.rb +1 -1
  50. data/lib/generators/formtastic/form/form_generator.rb +1 -1
  51. data/lib/generators/formtastic/input/input_generator.rb +46 -0
  52. data/lib/generators/templates/formtastic.rb +14 -13
  53. data/lib/generators/templates/input.rb +19 -0
  54. data/script/integration-template.rb +71 -0
  55. data/script/integration.sh +19 -0
  56. data/spec/action_class_finder_spec.rb +1 -1
  57. data/spec/actions/button_action_spec.rb +8 -8
  58. data/spec/actions/generic_action_spec.rb +60 -60
  59. data/spec/actions/input_action_spec.rb +7 -7
  60. data/spec/actions/link_action_spec.rb +10 -10
  61. data/spec/builder/custom_builder_spec.rb +36 -20
  62. data/spec/builder/error_proc_spec.rb +4 -4
  63. data/spec/builder/semantic_fields_for_spec.rb +27 -27
  64. data/spec/fast_spec_helper.rb +12 -0
  65. data/spec/generators/formtastic/form/form_generator_spec.rb +25 -25
  66. data/spec/generators/formtastic/input/input_generator_spec.rb +124 -0
  67. data/spec/generators/formtastic/install/install_generator_spec.rb +9 -9
  68. data/spec/helpers/action_helper_spec.rb +328 -10
  69. data/spec/helpers/actions_helper_spec.rb +17 -17
  70. data/spec/helpers/form_helper_spec.rb +37 -37
  71. data/spec/helpers/input_helper_spec.rb +975 -2
  72. data/spec/helpers/inputs_helper_spec.rb +120 -105
  73. data/spec/helpers/reflection_helper_spec.rb +3 -3
  74. data/spec/helpers/semantic_errors_helper_spec.rb +22 -22
  75. data/spec/i18n_spec.rb +26 -26
  76. data/spec/input_class_finder_spec.rb +1 -1
  77. data/spec/inputs/base/collections_spec.rb +76 -0
  78. data/spec/inputs/base/validations_spec.rb +480 -0
  79. data/spec/inputs/boolean_input_spec.rb +55 -55
  80. data/spec/inputs/check_boxes_input_spec.rb +155 -108
  81. data/spec/inputs/color_input_spec.rb +51 -63
  82. data/spec/inputs/country_input_spec.rb +20 -20
  83. data/spec/inputs/custom_input_spec.rb +2 -6
  84. data/spec/inputs/datalist_input_spec.rb +1 -1
  85. data/spec/inputs/date_picker_input_spec.rb +42 -42
  86. data/spec/inputs/date_select_input_spec.rb +51 -37
  87. data/spec/inputs/datetime_picker_input_spec.rb +46 -46
  88. data/spec/inputs/datetime_select_input_spec.rb +53 -37
  89. data/spec/inputs/email_input_spec.rb +5 -5
  90. data/spec/inputs/file_input_spec.rb +6 -6
  91. data/spec/inputs/hidden_input_spec.rb +18 -18
  92. data/spec/inputs/include_blank_spec.rb +8 -8
  93. data/spec/inputs/label_spec.rb +20 -20
  94. data/spec/inputs/number_input_spec.rb +112 -112
  95. data/spec/inputs/password_input_spec.rb +5 -5
  96. data/spec/inputs/phone_input_spec.rb +5 -5
  97. data/spec/inputs/placeholder_spec.rb +5 -5
  98. data/spec/inputs/radio_input_spec.rb +84 -58
  99. data/spec/inputs/range_input_spec.rb +66 -66
  100. data/spec/inputs/readonly_spec.rb +50 -0
  101. data/spec/inputs/search_input_spec.rb +5 -5
  102. data/spec/inputs/select_input_spec.rb +149 -93
  103. data/spec/inputs/string_input_spec.rb +23 -23
  104. data/spec/inputs/text_input_spec.rb +16 -16
  105. data/spec/inputs/time_picker_input_spec.rb +43 -43
  106. data/spec/inputs/time_select_input_spec.rb +67 -54
  107. data/spec/inputs/time_zone_input_spec.rb +54 -28
  108. data/spec/inputs/url_input_spec.rb +5 -5
  109. data/spec/inputs/with_options_spec.rb +7 -7
  110. data/spec/localizer_spec.rb +17 -17
  111. data/spec/namespaced_class_finder_spec.rb +2 -2
  112. data/spec/schema.rb +21 -0
  113. data/spec/spec_helper.rb +165 -253
  114. data/spec/support/custom_macros.rb +72 -75
  115. data/spec/support/shared_examples.rb +0 -1232
  116. data/spec/support/test_environment.rb +23 -9
  117. metadata +67 -174
  118. data/Appraisals +0 -29
  119. data/CHANGELOG +0 -31
  120. data/gemfiles/rails_3.2.gemfile +0 -7
  121. data/gemfiles/rails_4.0.4.gemfile +0 -7
  122. data/gemfiles/rails_4.1.gemfile +0 -7
  123. data/gemfiles/rails_4.2.gemfile +0 -7
  124. data/gemfiles/rails_4.gemfile +0 -7
  125. data/gemfiles/rails_edge.gemfile +0 -10
  126. data/lib/formtastic/util.rb +0 -53
  127. data/spec/helpers/namespaced_action_helper_spec.rb +0 -43
  128. data/spec/helpers/namespaced_input_helper_spec.rb +0 -36
  129. data/spec/support/deferred_garbage_collection.rb +0 -21
  130. data/spec/util_spec.rb +0 -66
@@ -10,1235 +10,3 @@ RSpec.shared_context 'form builder' do
10
10
  ::I18n.backend.reload!
11
11
  end
12
12
  end
13
-
14
- # TODO: move this back to spec/helpers/action_helper_spec.rb in Formtastic 4.0
15
- RSpec.shared_examples 'Action Helper' do
16
- include_context 'form builder'
17
-
18
- describe 'arguments and options' do
19
-
20
- it 'should require the first argument (the action method)' do
21
- lambda {
22
- concat(semantic_form_for(@new_post) do |builder|
23
- concat(builder.action()) # no args passed in at all
24
- end)
25
- }.should raise_error(ArgumentError)
26
- end
27
-
28
- describe ':as option' do
29
-
30
- describe 'when not provided' do
31
-
32
- it 'should default to a commit for commit' do
33
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
34
- concat(builder.action(:submit))
35
- end)
36
- output_buffer.should have_tag('form li.action.input_action', :count => 1)
37
- end
38
-
39
- it 'should default to a button for reset' do
40
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
41
- concat(builder.action(:reset))
42
- end)
43
- output_buffer.should have_tag('form li.action.input_action', :count => 1)
44
- end
45
-
46
- it 'should default to a link for cancel' do
47
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
48
- concat(builder.action(:cancel))
49
- end)
50
- output_buffer.should have_tag('form li.action.link_action', :count => 1)
51
- end
52
- end
53
-
54
- it 'should call the corresponding action class with .to_html' do
55
- [:input, :button, :link].each do |action_style|
56
- semantic_form_for(:project, :url => "http://test.host") do |builder|
57
- action_instance = double('Action instance')
58
- action_class = "#{action_style.to_s}_action".classify
59
- action_constant = "Formtastic::Actions::#{action_class}".constantize
60
-
61
- action_constant.should_receive(:new).and_return(action_instance)
62
- action_instance.should_receive(:to_html).and_return("some HTML")
63
-
64
- concat(builder.action(:submit, :as => action_style))
65
- end
66
- end
67
- end
68
-
69
- end
70
-
71
- #describe ':label option' do
72
- #
73
- # describe 'when provided' do
74
- # it 'should be passed down to the label tag' do
75
- # concat(semantic_form_for(@new_post) do |builder|
76
- # concat(builder.input(:title, :label => "Kustom"))
77
- # end)
78
- # output_buffer.should have_tag("form li label", /Kustom/)
79
- # end
80
- #
81
- # it 'should not generate a label if false' do
82
- # concat(semantic_form_for(@new_post) do |builder|
83
- # concat(builder.input(:title, :label => false))
84
- # end)
85
- # output_buffer.should_not have_tag("form li label")
86
- # end
87
- #
88
- # it 'should be dupped if frozen' do
89
- # concat(semantic_form_for(@new_post) do |builder|
90
- # concat(builder.input(:title, :label => "Kustom".freeze))
91
- # end)
92
- # output_buffer.should have_tag("form li label", /Kustom/)
93
- # end
94
- # end
95
- #
96
- # describe 'when not provided' do
97
- # describe 'when localized label is provided' do
98
- # describe 'and object is given' do
99
- # describe 'and label_str_method not :humanize' do
100
- # it 'should render a label with localized text and not apply the label_str_method' do
101
- # with_config :label_str_method, :reverse do
102
- # @localized_label_text = 'Localized title'
103
- # @new_post.stub(:meta_description)
104
- # ::I18n.backend.store_translations :en,
105
- # :formtastic => {
106
- # :labels => {
107
- # :meta_description => @localized_label_text
108
- # }
109
- # }
110
- #
111
- # concat(semantic_form_for(@new_post) do |builder|
112
- # concat(builder.input(:meta_description))
113
- # end)
114
- # output_buffer.should have_tag('form li label', /Localized title/)
115
- # end
116
- # end
117
- # end
118
- # end
119
- # end
120
- #
121
- # describe 'when localized label is NOT provided' do
122
- # describe 'and object is not given' do
123
- # it 'should default the humanized method name, passing it down to the label tag' do
124
- # ::I18n.backend.store_translations :en, :formtastic => {}
125
- # with_config :label_str_method, :humanize do
126
- # concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
127
- # concat(builder.input(:meta_description))
128
- # end)
129
- # output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
130
- # end
131
- # end
132
- # end
133
- #
134
- # describe 'and object is given' do
135
- # it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
136
- # @new_post.stub(:meta_description) # a two word method name
137
- # @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
138
- #
139
- # concat(semantic_form_for(@new_post) do |builder|
140
- # concat(builder.input(:meta_description))
141
- # end)
142
- # output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
143
- # end
144
- # end
145
- #
146
- # describe 'and object is given with label_str_method set to :capitalize' do
147
- # it 'should capitalize method name, passing it down to the label tag' do
148
- # with_config :label_str_method, :capitalize do
149
- # @new_post.stub(:meta_description)
150
- #
151
- # concat(semantic_form_for(@new_post) do |builder|
152
- # concat(builder.input(:meta_description))
153
- # end)
154
- # output_buffer.should have_tag("form li label", /#{'meta_description'.capitalize}/)
155
- # end
156
- # end
157
- # end
158
- # end
159
- #
160
- # describe 'when localized label is provided' do
161
- # before do
162
- # @localized_label_text = 'Localized title'
163
- # @default_localized_label_text = 'Default localized title'
164
- # ::I18n.backend.store_translations :en,
165
- # :formtastic => {
166
- # :labels => {
167
- # :title => @default_localized_label_text,
168
- # :published => @default_localized_label_text,
169
- # :post => {
170
- # :title => @localized_label_text,
171
- # :published => @default_localized_label_text
172
- # }
173
- # }
174
- # }
175
- # end
176
- #
177
- # it 'should render a label with localized label (I18n)' do
178
- # with_config :i18n_lookups_by_default, false do
179
- # concat(semantic_form_for(@new_post) do |builder|
180
- # concat(builder.input(:title, :label => true))
181
- # concat(builder.input(:published, :as => :boolean, :label => true))
182
- # end)
183
- # output_buffer.should have_tag('form li label', Regexp.new('^' + @localized_label_text))
184
- # end
185
- # end
186
- #
187
- # it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
188
- # with_config :i18n_lookups_by_default, false do
189
- # ::I18n.backend.store_translations :en,
190
- # :formtastic => {
191
- # :labels => {
192
- # :post => {
193
- # :title => nil,
194
- # :published => nil
195
- # }
196
- # }
197
- # }
198
- # concat(semantic_form_for(@new_post) do |builder|
199
- # concat(builder.input(:title, :label => true))
200
- # concat(builder.input(:published, :as => :boolean, :label => true))
201
- # end)
202
- # output_buffer.should have_tag('form li label', Regexp.new('^' + @default_localized_label_text))
203
- # end
204
- # end
205
- # end
206
- # end
207
- #
208
- #end
209
- #
210
- describe ':wrapper_html option' do
211
-
212
- describe 'when provided' do
213
- it 'should be passed down to the li tag' do
214
- concat(semantic_form_for(@new_post) do |builder|
215
- concat(builder.action(:submit, :wrapper_html => {:id => :another_id}))
216
- end)
217
- output_buffer.should have_tag("form li#another_id")
218
- end
219
-
220
- it 'should append given classes to li default classes' do
221
- concat(semantic_form_for(@new_post) do |builder|
222
- concat(builder.action(:submit, :wrapper_html => {:class => :another_class}))
223
- end)
224
- output_buffer.should have_tag("form li.action")
225
- output_buffer.should have_tag("form li.input_action")
226
- output_buffer.should have_tag("form li.another_class")
227
- end
228
-
229
- it 'should allow classes to be an array' do
230
- concat(semantic_form_for(@new_post) do |builder|
231
- concat(builder.action(:submit, :wrapper_html => {:class => [ :my_class, :another_class ]}))
232
- end)
233
- output_buffer.should have_tag("form li.action")
234
- output_buffer.should have_tag("form li.input_action")
235
- output_buffer.should have_tag("form li.my_class")
236
- output_buffer.should have_tag("form li.another_class")
237
- end
238
- end
239
-
240
- describe 'when not provided' do
241
- it 'should use default id and class' do
242
- concat(semantic_form_for(@new_post) do |builder|
243
- concat(builder.action(:submit))
244
- end)
245
- output_buffer.should have_tag("form li#post_submit_action")
246
- output_buffer.should have_tag("form li.action")
247
- output_buffer.should have_tag("form li.input_action")
248
- end
249
- end
250
-
251
- end
252
-
253
- end
254
-
255
- describe 'instantiating an action class' do
256
- context 'when a class does not exist' do
257
- it "should raise an error" do
258
- lambda {
259
- concat(semantic_form_for(@new_post) do |builder|
260
- builder.action(:submit, :as => :non_existant)
261
- end)
262
- }.should raise_error(Formtastic::UnknownActionError)
263
- end
264
- end
265
-
266
- context 'when a customized top-level class does not exist' do
267
- it 'should instantiate the Formtastic action' do
268
- action = double('action', :to_html => 'some HTML')
269
- Formtastic::Actions::ButtonAction.should_receive(:new).and_return(action)
270
- concat(semantic_form_for(@new_post) do |builder|
271
- builder.action(:commit, :as => :button)
272
- end)
273
- end
274
- end
275
-
276
- describe 'when a top-level (custom) action class exists' do
277
- it "should instantiate the top-level action instead of the Formtastic one" do
278
- class ::ButtonAction < Formtastic::Actions::ButtonAction
279
- end
280
-
281
- action = double('action', :to_html => 'some HTML')
282
- Formtastic::Actions::ButtonAction.should_not_receive(:new)
283
- ::ButtonAction.should_receive(:new).and_return(action)
284
-
285
- concat(semantic_form_for(@new_post) do |builder|
286
- builder.action(:commit, :as => :button)
287
- end)
288
- end
289
- end
290
-
291
- describe 'support for :as on each action' do
292
-
293
- it "should raise an error when the action does not support the :as" do
294
- lambda {
295
- concat(semantic_form_for(@new_post) do |builder|
296
- concat(builder.action(:submit, :as => :link))
297
- end)
298
- }.should raise_error(Formtastic::UnsupportedMethodForAction)
299
-
300
- lambda {
301
- concat(semantic_form_for(@new_post) do |builder|
302
- concat(builder.action(:cancel, :as => :input))
303
- end)
304
- }.should raise_error(Formtastic::UnsupportedMethodForAction)
305
-
306
- lambda {
307
- concat(semantic_form_for(@new_post) do |builder|
308
- concat(builder.action(:cancel, :as => :button))
309
- end)
310
- }.should raise_error(Formtastic::UnsupportedMethodForAction)
311
- end
312
-
313
- it "should not raise an error when the action does not support the :as" do
314
- lambda {
315
- concat(semantic_form_for(@new_post) do |builder|
316
- concat(builder.action(:cancel, :as => :link))
317
- end)
318
- }.should_not raise_error
319
-
320
- lambda {
321
- concat(semantic_form_for(@new_post) do |builder|
322
- concat(builder.action(:submit, :as => :input))
323
- end)
324
- }.should_not raise_error
325
-
326
- lambda {
327
- concat(semantic_form_for(@new_post) do |builder|
328
- concat(builder.action(:submit, :as => :button))
329
- end)
330
- }.should_not raise_error
331
-
332
- lambda {
333
- concat(semantic_form_for(@new_post) do |builder|
334
- concat(builder.action(:reset, :as => :input))
335
- end)
336
- }.should_not raise_error
337
-
338
- lambda {
339
- concat(semantic_form_for(@new_post) do |builder|
340
- concat(builder.action(:reset, :as => :button))
341
- end)
342
- }.should_not raise_error
343
- end
344
-
345
- end
346
-
347
- end
348
-
349
- end
350
-
351
- # TODO: move this back to spec/helpers/input_helper_spec.rb in Formtastic 4.0
352
- RSpec.shared_examples 'Input Helper' do
353
- include_context 'form builder'
354
-
355
- before do
356
- @errors = double('errors')
357
- @errors.stub(:[]).and_return([])
358
- @new_post.stub(:errors).and_return(@errors)
359
- end
360
-
361
- describe 'arguments and options' do
362
-
363
- it 'should require the first argument (the method on form\'s object)' do
364
- lambda {
365
- concat(semantic_form_for(@new_post) do |builder|
366
- concat(builder.input()) # no args passed in at all
367
- end)
368
- }.should raise_error(ArgumentError)
369
- end
370
-
371
- describe ':required option' do
372
-
373
- describe 'when true' do
374
-
375
- it 'should set a "required" class' do
376
- with_config :required_string, " required yo!" do
377
- concat(semantic_form_for(@new_post) do |builder|
378
- concat(builder.input(:title, :required => true))
379
- end)
380
- output_buffer.should_not have_tag('form li.optional')
381
- output_buffer.should have_tag('form li.required')
382
- end
383
- end
384
-
385
- it 'should append the "required" string to the label' do
386
- with_config :required_string, " required yo!" do
387
- concat(semantic_form_for(@new_post) do |builder|
388
- concat(builder.input(:title, :required => true))
389
- end)
390
- output_buffer.should have_tag('form li.required label', /required yo/)
391
- end
392
- end
393
- end
394
-
395
- describe 'when false' do
396
-
397
- before do
398
- @string = Formtastic::FormBuilder.optional_string = " optional yo!" # ensure there's something in the string
399
- @new_post.class.should_not_receive(:reflect_on_all_validations)
400
- end
401
-
402
- after do
403
- Formtastic::FormBuilder.optional_string = ''
404
- end
405
-
406
- it 'should set an "optional" class' do
407
- concat(semantic_form_for(@new_post) do |builder|
408
- concat(builder.input(:title, :required => false))
409
- end)
410
- output_buffer.should_not have_tag('form li.required')
411
- output_buffer.should have_tag('form li.optional')
412
- end
413
-
414
- it 'should set and "optional" class also when there is presence validator' do
415
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
416
- active_model_presence_validator([:title])
417
- ])
418
- concat(semantic_form_for(@new_post) do |builder|
419
- concat(builder.input(:title, :required => false))
420
- end)
421
- output_buffer.should_not have_tag('form li.required')
422
- output_buffer.should have_tag('form li.optional')
423
- end
424
-
425
- it 'should append the "optional" string to the label' do
426
- concat(semantic_form_for(@new_post) do |builder|
427
- concat(builder.input(:title, :required => false))
428
- end)
429
- output_buffer.should have_tag('form li.optional label', /#{@string}$/)
430
- end
431
-
432
- end
433
-
434
- describe 'when not provided' do
435
-
436
- describe 'and an object was not given' do
437
-
438
- it 'should use the default value' do
439
- Formtastic::FormBuilder.all_fields_required_by_default.should == true
440
- Formtastic::FormBuilder.all_fields_required_by_default = false
441
-
442
- concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder|
443
- concat(builder.input(:title))
444
- end)
445
- output_buffer.should_not have_tag('form li.required')
446
- output_buffer.should have_tag('form li.optional')
447
-
448
- Formtastic::FormBuilder.all_fields_required_by_default = true
449
- end
450
-
451
- end
452
-
453
- describe 'and an object with :validators_on was given (ActiveModel, Active Resource)' do
454
- before do
455
- @new_post.stub(:class).and_return(::PostModel)
456
- end
457
-
458
- after do
459
- @new_post.stub(:class).and_return(::Post)
460
- end
461
- describe 'and validates_presence_of was called for the method' do
462
- it 'should be required' do
463
-
464
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
465
- active_model_presence_validator([:title])
466
- ])
467
-
468
- @new_post.class.should_receive(:validators_on).with(:body).at_least(:once).and_return([
469
- active_model_presence_validator([:body], {:if => true})
470
- ])
471
-
472
- concat(semantic_form_for(@new_post) do |builder|
473
- concat(builder.input(:title))
474
- concat(builder.input(:body))
475
- end)
476
- output_buffer.should have_tag('form li.required')
477
- output_buffer.should_not have_tag('form li.optional')
478
- end
479
-
480
- it 'should be required when there is :on => :create option on create' do
481
- with_config :required_string, " required yo!" do
482
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
483
- active_model_presence_validator([:title], {:on => :create})
484
- ])
485
- concat(semantic_form_for(@new_post) do |builder|
486
- concat(builder.input(:title))
487
- end)
488
- output_buffer.should have_tag('form li.required')
489
- output_buffer.should_not have_tag('form li.optional')
490
- end
491
- end
492
-
493
- it 'should be required when there is :on => :save option on create' do
494
- with_config :required_string, " required yo!" do
495
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
496
- active_model_presence_validator([:title], {:on => :save})
497
- ])
498
- concat(semantic_form_for(@new_post) do |builder|
499
- concat(builder.input(:title))
500
- end)
501
- output_buffer.should have_tag('form li.required')
502
- output_buffer.should_not have_tag('form li.optional')
503
- end
504
- end
505
-
506
- it 'should be required when there is :on => :save option on update' do
507
- with_config :required_string, " required yo!" do
508
- @fred.class.should_receive(:validators_on).with(:login).at_least(:once).and_return([
509
- active_model_presence_validator([:login], {:on => :save})
510
- ])
511
- concat(semantic_form_for(@fred) do |builder|
512
- concat(builder.input(:login))
513
- end)
514
- output_buffer.should have_tag('form li.required')
515
- output_buffer.should_not have_tag('form li.optional')
516
- end
517
- end
518
-
519
- it 'should not be required when there is :on => :create option on update' do
520
- @fred.class.should_receive(:validators_on).with(:login).at_least(:once).and_return([
521
- active_model_presence_validator([:login], {:on => :create})
522
- ])
523
- concat(semantic_form_for(@fred) do |builder|
524
- concat(builder.input(:login))
525
- end)
526
- output_buffer.should_not have_tag('form li.required')
527
- output_buffer.should have_tag('form li.optional')
528
- end
529
-
530
- it 'should not be required when there is :on => :update option on create' do
531
- @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([
532
- active_model_presence_validator([:title], {:on => :update})
533
- ])
534
- concat(semantic_form_for(@new_post) do |builder|
535
- concat(builder.input(:title))
536
- end)
537
- output_buffer.should_not have_tag('form li.required')
538
- output_buffer.should have_tag('form li.optional')
539
- end
540
-
541
- it 'should be not be required if the optional :if condition is not satisifed' do
542
- presence_should_be_required(:required => false, :tag => :body, :options => { :if => false })
543
- end
544
-
545
- it 'should not be required if the optional :if proc evaluates to false' do
546
- presence_should_be_required(:required => false, :tag => :body, :options => { :if => proc { |record| false } })
547
- end
548
-
549
- it 'should be required if the optional :if proc evaluates to true' do
550
- presence_should_be_required(:required => true, :tag => :body, :options => { :if => proc { |record| true } })
551
- end
552
-
553
- it 'should not be required if the optional :unless proc evaluates to true' do
554
- presence_should_be_required(:required => false, :tag => :body, :options => { :unless => proc { |record| true } })
555
- end
556
-
557
- it 'should be required if the optional :unless proc evaluates to false' do
558
- presence_should_be_required(:required => true, :tag => :body, :options => { :unless => proc { |record| false } })
559
- end
560
-
561
- it 'should be required if the optional :if with a method string evaluates to true' do
562
- @new_post.should_receive(:required_condition).and_return(true)
563
- presence_should_be_required(:required => true, :tag => :body, :options => { :if => :required_condition })
564
- end
565
-
566
- it 'should be required if the optional :if with a method string evaluates to false' do
567
- @new_post.should_receive(:required_condition).and_return(false)
568
- presence_should_be_required(:required => false, :tag => :body, :options => { :if => :required_condition })
569
- end
570
-
571
- it 'should be required if the optional :unless with a method string evaluates to false' do
572
- @new_post.should_receive(:required_condition).and_return(false)
573
- presence_should_be_required(:required => true, :tag => :body, :options => { :unless => :required_condition })
574
- end
575
-
576
- it 'should not be required if the optional :unless with a method string evaluates to true' do
577
- @new_post.should_receive(:required_condition).and_return(true)
578
- presence_should_be_required(:required => false, :tag => :body, :options => { :unless => :required_condition })
579
- end
580
- end
581
-
582
- describe 'and validates_inclusion_of was called for the method' do
583
- it 'should be required' do
584
- @new_post.class.should_receive(:validators_on).with(:published).at_least(:once).and_return([
585
- active_model_inclusion_validator([:published], {:in => [false, true]})
586
- ])
587
- should_be_required(:tag => :published, :required => true)
588
- end
589
-
590
- it 'should not be required if allow_blank is true' do
591
- @new_post.class.should_receive(:validators_on).with(:published).at_least(:once).and_return([
592
- active_model_inclusion_validator([:published], {:in => [false, true], :allow_blank => true})
593
- ])
594
- should_be_required(:tag => :published, :required => false)
595
- end
596
- end
597
-
598
- describe 'and validates_length_of was called for the method' do
599
- it 'should be required if minimum is set' do
600
- length_should_be_required(:tag => :title, :required => true, :options => {:minimum => 1})
601
- end
602
-
603
- it 'should be required if :within is set' do
604
- length_should_be_required(:tag => :title, :required => true, :options => {:within => 1..5})
605
- end
606
-
607
- it 'should not be required if :within allows zero length' do
608
- length_should_be_required(:tag => :title, :required => false, :options => {:within => 0..5})
609
- end
610
-
611
- it 'should not be required if only :minimum is zero' do
612
- length_should_be_required(:tag => :title, :required => false, :options => {:minimum => 0})
613
- end
614
-
615
- it 'should not be required if only :minimum is not set' do
616
- length_should_be_required(:tag => :title, :required => false, :options => {:maximum => 5})
617
- end
618
-
619
- it 'should not be required if allow_blank is true' do
620
- length_should_be_required(:tag => :published, :required => false, :options => {:allow_blank => true})
621
- end
622
- end
623
-
624
- def add_presence_validator(options)
625
- @new_post.class.stub(:validators_on).with(options[:tag]).and_return([
626
- active_model_presence_validator([options[:tag]], options[:options])
627
- ])
628
- end
629
-
630
- def add_length_validator(options)
631
- @new_post.class.should_receive(:validators_on).with(options[:tag]).at_least(:once) {[
632
- active_model_length_validator([options[:tag]], options[:options])
633
- ]}
634
- end
635
-
636
- # TODO make a matcher for this?
637
- def should_be_required(options)
638
- concat(semantic_form_for(@new_post) do |builder|
639
- concat(builder.input(options[:tag]))
640
- end)
641
-
642
- if options[:required]
643
- output_buffer.should_not have_tag('form li.optional')
644
- output_buffer.should have_tag('form li.required')
645
- else
646
- output_buffer.should have_tag('form li.optional')
647
- output_buffer.should_not have_tag('form li.required')
648
- end
649
- end
650
-
651
- def presence_should_be_required(options)
652
- add_presence_validator(options)
653
- should_be_required(options)
654
- end
655
-
656
- def length_should_be_required(options)
657
- add_length_validator(options)
658
- should_be_required(options)
659
- end
660
-
661
- # TODO JF reversed this during refactor, need to make sure
662
- describe 'and there are no requirement validations on the method' do
663
- before do
664
- @new_post.class.should_receive(:validators_on).with(:title).and_return([])
665
- end
666
-
667
- it 'should not be required' do
668
- concat(semantic_form_for(@new_post) do |builder|
669
- concat(builder.input(:title))
670
- end)
671
- output_buffer.should_not have_tag('form li.required')
672
- output_buffer.should have_tag('form li.optional')
673
- end
674
- end
675
-
676
- end
677
-
678
- describe 'and an object without :validators_on' do
679
-
680
- it 'should use the default value' do
681
- Formtastic::FormBuilder.all_fields_required_by_default.should == true
682
- Formtastic::FormBuilder.all_fields_required_by_default = false
683
-
684
- concat(semantic_form_for(@new_post) do |builder|
685
- concat(builder.input(:title))
686
- end)
687
- output_buffer.should_not have_tag('form li.required')
688
- output_buffer.should have_tag('form li.optional')
689
-
690
- Formtastic::FormBuilder.all_fields_required_by_default = true
691
- end
692
-
693
- end
694
-
695
- end
696
-
697
- end
698
-
699
- describe ':as option' do
700
-
701
- describe 'when not provided' do
702
-
703
- it 'should default to a string for forms without objects unless column is password' do
704
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
705
- concat(builder.input(:anything))
706
- end)
707
- output_buffer.should have_tag('form li.string')
708
- end
709
-
710
- it 'should default to password for forms without objects if column is password' do
711
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
712
- concat(builder.input(:password))
713
- concat(builder.input(:password_confirmation))
714
- concat(builder.input(:confirm_password))
715
- end)
716
- output_buffer.should have_tag('form li.password', :count => 3)
717
- end
718
-
719
- it 'should default to a string for methods on objects that don\'t respond to "column_for_attribute"' do
720
- @new_post.stub(:method_without_a_database_column)
721
- @new_post.stub(:column_for_attribute).and_return(nil)
722
- default_input_type(nil, :method_without_a_database_column).should == :string
723
- end
724
-
725
- it 'should default to :password for methods that don\'t have a column in the database but "password" is in the method name' do
726
- @new_post.stub(:password_method_without_a_database_column)
727
- @new_post.stub(:column_for_attribute).and_return(nil)
728
- default_input_type(nil, :password_method_without_a_database_column).should == :password
729
- end
730
-
731
- 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
732
- @new_post.stub(:password_method_without_a_database_column)
733
- @new_post.stub(:column_for_attribute).and_return(nil)
734
- default_input_type(nil, :password_method_without_a_database_column).should == :password
735
- end
736
-
737
- it 'should default to :number for "integer" column with name ending in "_id"' do
738
- @new_post.stub(:aws_instance_id)
739
- @new_post.stub(:column_for_attribute).with(:aws_instance_id).and_return(double('column', :type => :integer))
740
- default_input_type(:integer, :aws_instance_id).should == :number
741
- end
742
-
743
- it 'should default to :select for associations' do
744
- @new_post.class.stub(:reflect_on_association).with(:user_id).and_return(double('ActiveRecord::Reflection::AssociationReflection'))
745
- @new_post.class.stub(:reflect_on_association).with(:section_id).and_return(double('ActiveRecord::Reflection::AssociationReflection'))
746
- default_input_type(:integer, :user_id).should == :select
747
- default_input_type(:integer, :section_id).should == :select
748
- end
749
-
750
- it 'should default to :password for :string column types with "password" in the method name' do
751
- default_input_type(:string, :password).should == :password
752
- default_input_type(:string, :hashed_password).should == :password
753
- default_input_type(:string, :password_hash).should == :password
754
- end
755
-
756
- it 'should default to :text for :text column types' do
757
- default_input_type(:text).should == :text
758
- end
759
-
760
- it 'should default to :date_select for :date column types' do
761
- default_input_type(:date).should == :date_select
762
- end
763
-
764
- it 'should default to :datetime_select for :datetime and :timestamp column types' do
765
- default_input_type(:datetime).should == :datetime_select
766
- default_input_type(:timestamp).should == :datetime_select
767
- end
768
-
769
- it 'should default to :time_select for :time column types' do
770
- default_input_type(:time).should == :time_select
771
- end
772
-
773
- it 'should default to :boolean for :boolean column types' do
774
- default_input_type(:boolean).should == :boolean
775
- end
776
-
777
- it 'should default to :string for :string column types' do
778
- default_input_type(:string).should == :string
779
- end
780
-
781
- it 'should default to :number for :integer, :float and :decimal column types' do
782
- default_input_type(:integer).should == :number
783
- default_input_type(:float).should == :number
784
- default_input_type(:decimal).should == :number
785
- end
786
-
787
- it 'should default to :country for :string columns named country' do
788
- default_input_type(:string, :country).should == :country
789
- end
790
-
791
- it 'should default to :email for :string columns matching email' do
792
- default_input_type(:string, :email).should == :email
793
- default_input_type(:string, :customer_email).should == :email
794
- default_input_type(:string, :email_work).should == :email
795
- end
796
-
797
- it 'should default to :url for :string columns named url or website' do
798
- default_input_type(:string, :url).should == :url
799
- default_input_type(:string, :website).should == :url
800
- default_input_type(:string, :my_url).should == :url
801
- default_input_type(:string, :hurl).should_not == :url
802
- end
803
-
804
- it 'should default to :phone for :string columns named phone or fax' do
805
- default_input_type(:string, :phone).should == :phone
806
- default_input_type(:string, :fax).should == :phone
807
- end
808
-
809
- it 'should default to :search for :string columns named search' do
810
- default_input_type(:string, :search).should == :search
811
- end
812
-
813
- it 'should default to :color for :string columns matching color' do
814
- default_input_type(:string, :color).should == :color
815
- default_input_type(:string, :user_color).should == :color
816
- default_input_type(:string, :color_for_image).should == :color
817
- end
818
-
819
- describe 'defaulting to file column' do
820
- Formtastic::FormBuilder.file_methods.each do |method|
821
- it "should default to :file for attributes that respond to ##{method}" do
822
- column = double('column')
823
-
824
- Formtastic::FormBuilder.file_methods.each do |test|
825
- ### TODO: Check if this is ok
826
- column.stub(method).with(test).and_return(method == test)
827
- end
828
-
829
- @new_post.should_receive(method).and_return(column)
830
-
831
- semantic_form_for(@new_post) do |builder|
832
- builder.send(:default_input_type, method).should == :file
833
- end
834
- end
835
- end
836
-
837
- end
838
- end
839
-
840
- it 'should call the corresponding input class with .to_html' do
841
- [:select, :time_zone, :radio, :date_select, :datetime_select, :time_select, :boolean, :check_boxes, :hidden, :string, :password, :number, :text, :file].each do |input_style|
842
- @new_post.stub(:generic_column_name)
843
- @new_post.stub(:column_for_attribute).and_return(double('column', :type => :string, :limit => 255))
844
- semantic_form_for(@new_post) do |builder|
845
- input_instance = double('Input instance')
846
- input_class = "#{input_style.to_s}_input".classify
847
- input_constant = "Formtastic::Inputs::#{input_class}".constantize
848
-
849
- input_constant.should_receive(:new).and_return(input_instance)
850
- input_instance.should_receive(:to_html).and_return("some HTML")
851
-
852
- concat(builder.input(:generic_column_name, :as => input_style))
853
- end
854
- end
855
- end
856
-
857
- end
858
-
859
- describe ':label option' do
860
-
861
- describe 'when provided' do
862
- it 'should be passed down to the label tag' do
863
- concat(semantic_form_for(@new_post) do |builder|
864
- concat(builder.input(:title, :label => "Kustom"))
865
- end)
866
- output_buffer.should have_tag("form li label", /Kustom/)
867
- end
868
-
869
- it 'should not generate a label if false' do
870
- concat(semantic_form_for(@new_post) do |builder|
871
- concat(builder.input(:title, :label => false))
872
- end)
873
- output_buffer.should_not have_tag("form li label")
874
- end
875
-
876
- it 'should be dupped if frozen' do
877
- concat(semantic_form_for(@new_post) do |builder|
878
- concat(builder.input(:title, :label => "Kustom".freeze))
879
- end)
880
- output_buffer.should have_tag("form li label", /Kustom/)
881
- end
882
- end
883
-
884
- describe 'when not provided' do
885
- describe 'when localized label is provided' do
886
- describe 'and object is given' do
887
- describe 'and label_str_method not :humanize' do
888
- it 'should render a label with localized text and not apply the label_str_method' do
889
- with_config :label_str_method, :reverse do
890
- @localized_label_text = 'Localized title'
891
- @new_post.stub(:meta_description)
892
- ::I18n.backend.store_translations :en,
893
- :formtastic => {
894
- :labels => {
895
- :meta_description => @localized_label_text
896
- }
897
- }
898
-
899
- concat(semantic_form_for(@new_post) do |builder|
900
- concat(builder.input(:meta_description))
901
- end)
902
- output_buffer.should have_tag('form li label', /Localized title/)
903
- end
904
- end
905
- end
906
- end
907
- end
908
-
909
- describe 'when localized label is NOT provided' do
910
- describe 'and object is not given' do
911
- it 'should default the humanized method name, passing it down to the label tag' do
912
- ::I18n.backend.store_translations :en, :formtastic => {}
913
- with_config :label_str_method, :humanize do
914
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
915
- concat(builder.input(:meta_description))
916
- end)
917
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
918
- end
919
- end
920
- end
921
-
922
- describe 'and object is given' do
923
- it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
924
- @new_post.stub(:meta_description) # a two word method name
925
- @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
926
-
927
- concat(semantic_form_for(@new_post) do |builder|
928
- concat(builder.input(:meta_description))
929
- end)
930
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
931
- end
932
- end
933
-
934
- describe 'and object is given with label_str_method set to :capitalize' do
935
- it 'should capitalize method name, passing it down to the label tag' do
936
- with_config :label_str_method, :capitalize do
937
- @new_post.stub(:meta_description)
938
-
939
- concat(semantic_form_for(@new_post) do |builder|
940
- concat(builder.input(:meta_description))
941
- end)
942
- output_buffer.should have_tag("form li label", /#{'meta_description'.capitalize}/)
943
- end
944
- end
945
- end
946
- end
947
-
948
- describe 'when localized label is provided' do
949
- before do
950
- @localized_label_text = 'Localized title'
951
- @default_localized_label_text = 'Default localized title'
952
- ::I18n.backend.store_translations :en,
953
- :formtastic => {
954
- :labels => {
955
- :title => @default_localized_label_text,
956
- :published => @default_localized_label_text,
957
- :post => {
958
- :title => @localized_label_text,
959
- :published => @default_localized_label_text
960
- }
961
- }
962
- }
963
- end
964
-
965
- it 'should render a label with localized label (I18n)' do
966
- with_config :i18n_lookups_by_default, false do
967
- concat(semantic_form_for(@new_post) do |builder|
968
- concat(builder.input(:title, :label => true))
969
- concat(builder.input(:published, :as => :boolean, :label => true))
970
- end)
971
- output_buffer.should have_tag('form li label', Regexp.new('^' + @localized_label_text))
972
- end
973
- end
974
-
975
- it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
976
- with_config :i18n_lookups_by_default, false do
977
- ::I18n.backend.store_translations :en,
978
- :formtastic => {
979
- :labels => {
980
- :post => {
981
- :title => nil,
982
- :published => nil
983
- }
984
- }
985
- }
986
- concat(semantic_form_for(@new_post) do |builder|
987
- concat(builder.input(:title, :label => true))
988
- concat(builder.input(:published, :as => :boolean, :label => true))
989
- end)
990
- output_buffer.should have_tag('form li label', Regexp.new('^' + @default_localized_label_text))
991
- end
992
- end
993
- end
994
- end
995
-
996
- end
997
-
998
- describe ':hint option' do
999
-
1000
- describe 'when provided' do
1001
-
1002
- after do
1003
- Formtastic::FormBuilder.default_hint_class = "inline-hints"
1004
- end
1005
-
1006
- it 'should be passed down to the paragraph tag' do
1007
- hint_text = "this is the title of the post"
1008
- concat(semantic_form_for(@new_post) do |builder|
1009
- concat(builder.input(:title, :hint => hint_text))
1010
- end)
1011
- output_buffer.should have_tag("form li p.inline-hints", hint_text)
1012
- end
1013
-
1014
- it 'should have a custom hint class defaulted for all forms' do
1015
- hint_text = "this is the title of the post"
1016
- Formtastic::FormBuilder.default_hint_class = "custom-hint-class"
1017
- concat(semantic_form_for(@new_post) do |builder|
1018
- concat(builder.input(:title, :hint => hint_text))
1019
- end)
1020
- output_buffer.should have_tag("form li p.custom-hint-class", hint_text)
1021
- end
1022
- end
1023
-
1024
- describe 'when not provided' do
1025
- describe 'when localized hint (I18n) is provided' do
1026
- before do
1027
- @localized_hint_text = "This is the localized hint."
1028
- @default_localized_hint_text = "This is the default localized hint."
1029
- ::I18n.backend.store_translations :en,
1030
- :formtastic => {
1031
- :hints => {
1032
- :title => @default_localized_hint_text,
1033
- }
1034
- }
1035
- end
1036
-
1037
- after do
1038
- ::I18n.backend.reload!
1039
- end
1040
-
1041
- describe 'when provided value (hint value) is set to TRUE' do
1042
- it 'should render a hint paragraph containing a localized hint (I18n)' do
1043
- with_config :i18n_lookups_by_default, false do
1044
- ::I18n.backend.store_translations :en,
1045
- :formtastic => {
1046
- :hints => {
1047
- :post => {
1048
- :title => @localized_hint_text
1049
- }
1050
- }
1051
- }
1052
- concat(semantic_form_for(@new_post) do |builder|
1053
- concat(builder.input(:title, :hint => true))
1054
- end)
1055
- output_buffer.should have_tag('form li p.inline-hints', @localized_hint_text)
1056
- end
1057
- end
1058
-
1059
- it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do
1060
- with_config :i18n_lookups_by_default, false do
1061
- concat(semantic_form_for(@new_post) do |builder|
1062
- concat(builder.input(:title, :hint => true))
1063
- end)
1064
- output_buffer.should have_tag('form li p.inline-hints', @default_localized_hint_text)
1065
- end
1066
- end
1067
- end
1068
-
1069
- describe 'when provided value (label value) is set to FALSE' do
1070
- it 'should not render a hint paragraph' do
1071
- with_config :i18n_lookups_by_default, false do
1072
- concat(semantic_form_for(@new_post) do |builder|
1073
- concat(builder.input(:title, :hint => false))
1074
- end)
1075
- output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text)
1076
- end
1077
- end
1078
- end
1079
- end
1080
-
1081
- describe 'when localized hint (I18n) is a model with attribute hints' do
1082
- it "should see the provided hash as a blank entry" do
1083
- with_config :i18n_lookups_by_default, false do
1084
- ::I18n.backend.store_translations :en,
1085
- :formtastic => {
1086
- :hints => {
1087
- :title => { # movie title
1088
- :summary => @localized_hint_text # summary of movie
1089
- }
1090
- }
1091
- }
1092
- semantic_form_for(@new_post) do |builder|
1093
- concat(builder.input(:title, :hint => true))
1094
- end
1095
- output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text)
1096
- end
1097
- end
1098
- end
1099
-
1100
- describe 'when localized hint (I18n) is not provided' do
1101
- it 'should not render a hint paragraph' do
1102
- with_config :i18n_lookups_by_default, false do
1103
- concat(semantic_form_for(@new_post) do |builder|
1104
- concat(builder.input(:title))
1105
- end)
1106
- output_buffer.should_not have_tag('form li p.inline-hints')
1107
- end
1108
- end
1109
- end
1110
- end
1111
-
1112
- end
1113
-
1114
- describe ':wrapper_html option' do
1115
-
1116
- describe 'when provided' do
1117
- it 'should be passed down to the li tag' do
1118
- concat(semantic_form_for(@new_post) do |builder|
1119
- concat(builder.input(:title, :wrapper_html => {:id => :another_id}))
1120
- end)
1121
- output_buffer.should have_tag("form li#another_id")
1122
- end
1123
-
1124
- it 'should append given classes to li default classes' do
1125
- concat(semantic_form_for(@new_post) do |builder|
1126
- concat(builder.input(:title, :wrapper_html => {:class => :another_class}, :required => true))
1127
- end)
1128
- output_buffer.should have_tag("form li.string")
1129
- output_buffer.should have_tag("form li.required")
1130
- output_buffer.should have_tag("form li.another_class")
1131
- end
1132
-
1133
- it 'should allow classes to be an array' do
1134
- concat(semantic_form_for(@new_post) do |builder|
1135
- concat(builder.input(:title, :wrapper_html => {:class => [ :my_class, :another_class ]}))
1136
- end)
1137
- output_buffer.should have_tag("form li.string")
1138
- output_buffer.should have_tag("form li.my_class")
1139
- output_buffer.should have_tag("form li.another_class")
1140
- end
1141
-
1142
- describe 'when nil' do
1143
- it 'should not put an id attribute on the div tag' do
1144
- concat(semantic_form_for(@new_post) do |builder|
1145
- concat(builder.input(:title, :wrapper_html => {:id => nil}))
1146
- end)
1147
- output_buffer.should have_tag('form li:not([id])')
1148
- end
1149
- end
1150
- end
1151
-
1152
- describe 'when not provided' do
1153
- it 'should use default id and class' do
1154
- concat(semantic_form_for(@new_post) do |builder|
1155
- concat(builder.input(:title))
1156
- end)
1157
- output_buffer.should have_tag("form li#post_title_input")
1158
- output_buffer.should have_tag("form li.string")
1159
- end
1160
- end
1161
-
1162
- end
1163
-
1164
- describe ':collection option' do
1165
-
1166
- it "should be required on polymorphic associations" do
1167
- @new_post.stub(:commentable)
1168
- @new_post.class.stub(:reflections).and_return({
1169
- :commentable => double('macro_reflection', :options => { :polymorphic => true }, :macro => :belongs_to)
1170
- })
1171
- @new_post.stub(:column_for_attribute).with(:commentable).and_return(
1172
- double('column', :type => :integer)
1173
- )
1174
- @new_post.class.stub(:reflect_on_association).with(:commentable).and_return(
1175
- double('reflection', :macro => :belongs_to, :options => { :polymorphic => true })
1176
- )
1177
- expect {
1178
- concat(semantic_form_for(@new_post) do |builder|
1179
- concat(builder.inputs do
1180
- concat(builder.input :commentable)
1181
- end)
1182
- end)
1183
- }.to raise_error(Formtastic::PolymorphicInputWithoutCollectionError)
1184
- end
1185
-
1186
- end
1187
-
1188
- end
1189
-
1190
- describe 'options re-use' do
1191
-
1192
- it 'should retain :as option when re-using the same options hash' do
1193
- my_options = { :as => :string }
1194
- output = ''
1195
-
1196
- concat(semantic_form_for(@new_post) do |builder|
1197
- concat(builder.input(:title, my_options))
1198
- concat(builder.input(:publish_at, my_options))
1199
- end)
1200
- output_buffer.should have_tag 'li.string', :count => 2
1201
- end
1202
- end
1203
-
1204
- describe 'instantiating an input class' do
1205
- context 'when a class does not exist' do
1206
- it "should raise an error" do
1207
- lambda {
1208
- concat(semantic_form_for(@new_post) do |builder|
1209
- builder.input(:title, :as => :non_existant)
1210
- end)
1211
- }.should raise_error(Formtastic::UnknownInputError)
1212
- end
1213
- end
1214
-
1215
- context 'when a customized top-level class does not exist' do
1216
-
1217
- it 'should instantiate the Formtastic input' do
1218
- input = double('input', :to_html => 'some HTML')
1219
- Formtastic::Inputs::StringInput.should_receive(:new).and_return(input)
1220
- concat(semantic_form_for(@new_post) do |builder|
1221
- builder.input(:title, :as => :string)
1222
- end)
1223
- end
1224
-
1225
- end
1226
-
1227
- describe 'when a top-level input class exists' do
1228
- it "should instantiate the top-level input instead of the Formtastic one" do
1229
- class ::StringInput < Formtastic::Inputs::StringInput
1230
- end
1231
-
1232
- input = double('input', :to_html => 'some HTML')
1233
- Formtastic::Inputs::StringInput.should_not_receive(:new)
1234
- ::StringInput.should_receive(:new).and_return(input)
1235
-
1236
- concat(semantic_form_for(@new_post) do |builder|
1237
- builder.input(:title, :as => :string)
1238
- end)
1239
- end
1240
- end
1241
-
1242
-
1243
- end
1244
- end