formtastic 1.2.5 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +2 -0
  3. data/.yardopts +1 -0
  4. data/CHANGELOG +279 -0
  5. data/Gemfile +3 -0
  6. data/README.textile +155 -172
  7. data/RELEASE_PROCESS +7 -0
  8. data/Rakefile +52 -0
  9. data/app/assets/stylesheets/formtastic.css +275 -0
  10. data/app/assets/stylesheets/formtastic_ie6.css +27 -0
  11. data/app/assets/stylesheets/formtastic_ie7.css +17 -0
  12. data/formtastic.gemspec +51 -0
  13. data/lib/formtastic.rb +21 -1960
  14. data/lib/formtastic/engine.rb +7 -0
  15. data/lib/formtastic/form_builder.rb +83 -0
  16. data/lib/formtastic/helpers.rb +16 -0
  17. data/lib/formtastic/helpers/buttons_helper.rb +277 -0
  18. data/lib/formtastic/helpers/errors_helper.rb +113 -0
  19. data/lib/formtastic/helpers/fieldset_wrapper.rb +75 -0
  20. data/lib/formtastic/helpers/file_column_detection.rb +16 -0
  21. data/lib/formtastic/helpers/form_helper.rb +198 -0
  22. data/lib/formtastic/helpers/input_helper.rb +366 -0
  23. data/lib/formtastic/helpers/inputs_helper.rb +392 -0
  24. data/lib/formtastic/helpers/reflection.rb +33 -0
  25. data/lib/formtastic/helpers/semantic_form_helper.rb +11 -0
  26. data/lib/formtastic/html_attributes.rb +21 -0
  27. data/lib/formtastic/i18n.rb +1 -0
  28. data/lib/formtastic/inputs.rb +31 -0
  29. data/lib/formtastic/inputs/base.rb +61 -0
  30. data/lib/formtastic/inputs/base/associations.rb +31 -0
  31. data/lib/formtastic/inputs/base/choices.rb +103 -0
  32. data/lib/formtastic/inputs/base/collections.rb +94 -0
  33. data/lib/formtastic/inputs/base/database.rb +17 -0
  34. data/lib/formtastic/inputs/base/errors.rb +58 -0
  35. data/lib/formtastic/inputs/base/fileish.rb +23 -0
  36. data/lib/formtastic/inputs/base/grouped_collections.rb +77 -0
  37. data/lib/formtastic/inputs/base/hints.rb +31 -0
  38. data/lib/formtastic/inputs/base/html.rb +52 -0
  39. data/lib/formtastic/inputs/base/labelling.rb +55 -0
  40. data/lib/formtastic/inputs/base/naming.rb +42 -0
  41. data/lib/formtastic/inputs/base/options.rb +18 -0
  42. data/lib/formtastic/inputs/base/stringish.rb +35 -0
  43. data/lib/formtastic/inputs/base/timeish.rb +128 -0
  44. data/lib/formtastic/inputs/base/validations.rb +166 -0
  45. data/lib/formtastic/inputs/base/wrapping.rb +40 -0
  46. data/lib/formtastic/inputs/boolean_input.rb +96 -0
  47. data/lib/formtastic/inputs/check_boxes_input.rb +179 -0
  48. data/lib/formtastic/inputs/country_input.rb +66 -0
  49. data/lib/formtastic/inputs/date_input.rb +14 -0
  50. data/lib/formtastic/inputs/datetime_input.rb +9 -0
  51. data/lib/formtastic/inputs/email_input.rb +40 -0
  52. data/lib/formtastic/inputs/file_input.rb +42 -0
  53. data/lib/formtastic/inputs/hidden_input.rb +66 -0
  54. data/lib/formtastic/inputs/number_input.rb +118 -0
  55. data/lib/formtastic/inputs/numeric_input.rb +21 -0
  56. data/lib/formtastic/inputs/password_input.rb +40 -0
  57. data/lib/formtastic/inputs/phone_input.rb +41 -0
  58. data/lib/formtastic/inputs/radio_input.rb +157 -0
  59. data/lib/formtastic/inputs/range_input.rb +119 -0
  60. data/lib/formtastic/inputs/search_input.rb +40 -0
  61. data/lib/formtastic/inputs/select_input.rb +210 -0
  62. data/lib/formtastic/inputs/string_input.rb +34 -0
  63. data/lib/formtastic/inputs/text_input.rb +47 -0
  64. data/lib/formtastic/inputs/time_input.rb +14 -0
  65. data/lib/formtastic/inputs/time_zone_input.rb +48 -0
  66. data/lib/formtastic/inputs/url_input.rb +40 -0
  67. data/lib/formtastic/localized_string.rb +105 -0
  68. data/lib/formtastic/railtie.rb +5 -7
  69. data/lib/formtastic/semantic_form_builder.rb +11 -0
  70. data/lib/formtastic/util.rb +6 -19
  71. data/lib/formtastic/version.rb +3 -0
  72. data/lib/generators/formtastic/install/install_generator.rb +28 -6
  73. data/lib/generators/templates/_form.html.erb +10 -4
  74. data/lib/generators/templates/_form.html.haml +8 -4
  75. data/lib/generators/templates/formtastic.rb +25 -32
  76. data/lib/locale/en.yml +1 -0
  77. data/lib/tasks/verify_rcov.rb +44 -0
  78. data/sample/basic_inputs.html +182 -0
  79. data/sample/config.ru +69 -0
  80. data/sample/index.html +14 -0
  81. data/spec/builder/custom_builder_spec.rb +109 -0
  82. data/spec/builder/error_proc_spec.rb +27 -0
  83. data/spec/builder/errors_spec.rb +193 -0
  84. data/spec/builder/semantic_fields_for_spec.rb +88 -0
  85. data/spec/helpers/buttons_helper_spec.rb +150 -0
  86. data/spec/helpers/commit_button_helper_spec.rb +470 -0
  87. data/spec/helpers/form_helper_spec.rb +135 -0
  88. data/spec/helpers/input_helper_spec.rb +837 -0
  89. data/spec/helpers/inputs_helper_spec.rb +562 -0
  90. data/spec/helpers/semantic_errors_helper_spec.rb +112 -0
  91. data/spec/i18n_spec.rb +199 -0
  92. data/spec/inputs/boolean_input_spec.rb +184 -0
  93. data/spec/inputs/check_boxes_input_spec.rb +375 -0
  94. data/spec/inputs/country_input_spec.rb +133 -0
  95. data/spec/inputs/custom_input_spec.rb +52 -0
  96. data/spec/inputs/date_input_spec.rb +110 -0
  97. data/spec/inputs/datetime_input_spec.rb +115 -0
  98. data/spec/inputs/email_input_spec.rb +55 -0
  99. data/spec/inputs/file_input_spec.rb +59 -0
  100. data/spec/inputs/hidden_input_spec.rb +120 -0
  101. data/spec/inputs/include_blank_spec.rb +70 -0
  102. data/spec/inputs/label_spec.rb +104 -0
  103. data/spec/inputs/number_input_spec.rb +487 -0
  104. data/spec/inputs/numeric_input_spec.rb +41 -0
  105. data/spec/inputs/password_input_spec.rb +69 -0
  106. data/spec/inputs/phone_input_spec.rb +55 -0
  107. data/spec/inputs/placeholder_spec.rb +71 -0
  108. data/spec/inputs/radio_input_spec.rb +234 -0
  109. data/spec/inputs/range_input_spec.rb +477 -0
  110. data/spec/inputs/search_input_spec.rb +55 -0
  111. data/spec/inputs/select_input_spec.rb +545 -0
  112. data/spec/inputs/string_input_spec.rb +163 -0
  113. data/spec/inputs/text_input_spec.rb +158 -0
  114. data/spec/inputs/time_input_spec.rb +155 -0
  115. data/spec/inputs/time_zone_input_spec.rb +87 -0
  116. data/spec/inputs/url_input_spec.rb +55 -0
  117. data/spec/spec.opts +2 -0
  118. data/spec/spec_helper.rb +361 -0
  119. data/spec/support/custom_macros.rb +656 -0
  120. data/spec/support/deferred_garbage_collection.rb +21 -0
  121. data/spec/support/deprecation.rb +6 -0
  122. data/spec/support/test_environment.rb +30 -0
  123. metadata +306 -88
  124. data/generators/form/USAGE +0 -16
  125. data/generators/form/form_generator.rb +0 -111
  126. data/generators/formtastic/formtastic_generator.rb +0 -26
  127. data/init.rb +0 -5
  128. data/lib/formtastic/layout_helper.rb +0 -12
  129. data/lib/generators/formtastic/form/form_generator.rb +0 -84
  130. data/lib/generators/templates/formtastic.css +0 -145
  131. data/lib/generators/templates/formtastic_changes.css +0 -14
  132. data/lib/generators/templates/rails2/_form.html.erb +0 -5
  133. data/lib/generators/templates/rails2/_form.html.haml +0 -4
  134. data/rails/init.rb +0 -2
@@ -0,0 +1,562 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'Formtastic::FormBuilder#inputs' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ describe 'with a block (block forms syntax)' do
14
+
15
+ describe 'when no options are provided' do
16
+ before do
17
+ output_buffer.replace 'before_builder' # clear the output buffer and sets before_builder
18
+ concat(semantic_form_for(@new_post) do |builder|
19
+ @inputs_output = builder.inputs do
20
+ concat('hello')
21
+ end
22
+ end)
23
+ end
24
+
25
+ it 'should output just the content wrapped in inputs, not the whole template' do
26
+ output_buffer.should =~ /before_builder/
27
+ @inputs_output.should_not =~ /before_builder/
28
+ end
29
+
30
+ it 'should render a fieldset inside the form, with a class of "inputs"' do
31
+ output_buffer.should have_tag("form fieldset.inputs")
32
+ end
33
+
34
+ it 'should render an ol inside the fieldset' do
35
+ output_buffer.should have_tag("form fieldset.inputs ol")
36
+ end
37
+
38
+ it 'should render the contents of the block inside the ol' do
39
+ output_buffer.should have_tag("form fieldset.inputs ol", /hello/)
40
+ end
41
+
42
+ it 'should not render a legend inside the fieldset' do
43
+ output_buffer.should_not have_tag("form fieldset.inputs legend")
44
+ end
45
+
46
+ it 'should render a fieldset even if no object is given' do
47
+ concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder|
48
+ @inputs_output = builder.inputs do
49
+ concat('bye')
50
+ end
51
+ end)
52
+ output_buffer.should have_tag("form fieldset.inputs ol", /bye/)
53
+ end
54
+ end
55
+
56
+ describe 'when a :for option is provided' do
57
+
58
+ before do
59
+ @new_post.stub!(:respond_to?).and_return(true, true)
60
+ @new_post.stub!(:author).and_return(@bob)
61
+ end
62
+
63
+ it 'should render nested inputs' do
64
+ @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
65
+
66
+ concat(semantic_form_for(@new_post) do |builder|
67
+ inputs = builder.inputs :for => [:author, @bob] do |bob_builder|
68
+ concat(bob_builder.input(:login))
69
+ end
70
+ concat(inputs)
71
+ end)
72
+ output_buffer.should have_tag("form fieldset.inputs #post_author_attributes_login")
73
+ output_buffer.should_not have_tag("form fieldset.inputs #author_login")
74
+ end
75
+
76
+ it 'should concat rendered nested inputs to the template' do
77
+ @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
78
+
79
+ concat(semantic_form_for(@new_post) do |builder|
80
+ builder.inputs :for => [:author, @bob] do |bob_builder|
81
+ concat(bob_builder.input(:login))
82
+ end
83
+ end)
84
+
85
+ output_buffer.should have_tag("form fieldset.inputs #post_author_attributes_login")
86
+ output_buffer.should_not have_tag("form fieldset.inputs #author_login")
87
+
88
+ end
89
+
90
+ describe "as a symbol representing the association name" do
91
+
92
+ it 'should nest the inputs with an _attributes suffix on the association name' do
93
+ concat(semantic_form_for(@new_post) do |post|
94
+ inputs = post.inputs :for => :author do |author|
95
+ concat(author.input(:login))
96
+ end
97
+ concat(inputs)
98
+ end)
99
+ output_buffer.should have_tag("form input[@name='post[author_attributes][login]']")
100
+ end
101
+
102
+ end
103
+
104
+ describe "as a symbol representing a has_many association name" do
105
+ before do
106
+ @new_post.stub!(:authors).and_return([@bob, @fred])
107
+ @new_post.stub!(:authors_attributes=)
108
+ end
109
+
110
+ it 'should nest the inputs with a fieldset, legend and :name input for each item' do
111
+ concat(semantic_form_for(@new_post) do |post|
112
+ post.inputs :for => :authors, :name => '%i' do |author|
113
+ concat(author.input(:login))
114
+ end
115
+ end)
116
+
117
+ output_buffer.should have_tag("form fieldset.inputs", :count => 2)
118
+ output_buffer.should have_tag("form fieldset.inputs legend", :count => 2)
119
+ output_buffer.should have_tag("form fieldset.inputs legend", "1", :count => 1)
120
+ output_buffer.should have_tag("form fieldset.inputs legend", "2")
121
+ output_buffer.should have_tag("form input[@name='post[authors_attributes][0][login]']")
122
+ output_buffer.should have_tag("form input[@name='post[authors_attributes][1][login]']")
123
+ output_buffer.should_not have_tag('form fieldset[@name]')
124
+ end
125
+ end
126
+
127
+ describe 'as an array containing the a symbole for the association name and the associated object' do
128
+
129
+ it 'should nest the inputs with an _attributes suffix on the association name' do
130
+ concat(semantic_form_for(@new_post) do |post|
131
+ inputs = post.inputs :for => [:author, @new_post.author] do |author|
132
+ concat(author.input(:login))
133
+ end
134
+ concat(inputs)
135
+ end)
136
+ output_buffer.should have_tag("form input[@name='post[author_attributes][login]']")
137
+ end
138
+
139
+ end
140
+
141
+ describe 'as an associated object' do
142
+
143
+ it 'should not nest the inputs with an _attributes suffix' do
144
+ concat(semantic_form_for(@new_post) do |post|
145
+ inputs = post.inputs :for => @new_post.author do |author|
146
+ concat(author.input(:login))
147
+ end
148
+ concat(inputs)
149
+ end)
150
+ output_buffer.should have_tag("form input[@name='post[author][login]']")
151
+ end
152
+
153
+ end
154
+
155
+ it 'should raise an error if :for and block with no argument is given' do
156
+ semantic_form_for(@new_post) do |builder|
157
+ proc {
158
+ builder.inputs(:for => [:author, @bob]) do
159
+ #
160
+ end
161
+ }.should raise_error(ArgumentError, 'You gave :for option with a block to inputs method, ' <<
162
+ 'but the block does not accept any argument.')
163
+ end
164
+ end
165
+
166
+ it 'should pass options down to semantic_fields_for' do
167
+ @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
168
+
169
+ concat(semantic_form_for(@new_post) do |builder|
170
+ inputs = builder.inputs :for => [:author, @bob], :for_options => { :index => 10 } do |bob_builder|
171
+ concat(bob_builder.input(:login))
172
+ end
173
+ concat(inputs)
174
+ end)
175
+
176
+ output_buffer.should have_tag('form fieldset ol li #post_author_attributes_10_login')
177
+ end
178
+
179
+ it 'should not add builder as a fieldset attribute tag' do
180
+ concat(semantic_form_for(@new_post) do |builder|
181
+ inputs = builder.inputs :for => [:author, @bob], :for_options => { :index => 10 } do |bob_builder|
182
+ concat('input')
183
+ end
184
+ concat(inputs)
185
+ end)
186
+
187
+ output_buffer.should_not have_tag('fieldset[@builder="Formtastic::Helpers::FormHelper"]')
188
+ end
189
+
190
+ it 'should send parent_builder as an option to allow child index interpolation' do
191
+ concat(semantic_form_for(@new_post) do |builder|
192
+ builder.instance_variable_set('@nested_child_index', 0)
193
+ inputs = builder.inputs :for => [:author, @bob], :name => 'Author #%i' do |bob_builder|
194
+ concat('input')
195
+ end
196
+ concat(inputs)
197
+ end)
198
+
199
+ output_buffer.should have_tag('fieldset legend', 'Author #1')
200
+ end
201
+
202
+ it 'should also provide child index interpolation when nested child index is a hash' do
203
+ concat(semantic_form_for(@new_post) do |builder|
204
+ builder.instance_variable_set('@nested_child_index', :author => 10)
205
+ inputs = builder.inputs :for => [:author, @bob], :name => 'Author #%i' do |bob_builder|
206
+ concat('input')
207
+ end
208
+ concat(inputs)
209
+ end)
210
+
211
+ output_buffer.should have_tag('fieldset legend', 'Author #11')
212
+ end
213
+ end
214
+
215
+ describe 'when a :name or :title option is provided' do
216
+ describe 'and is a string' do
217
+ before do
218
+ @legend_text = "Advanced options"
219
+ @legend_text_using_name = "Advanced options 2"
220
+ @legend_text_using_title = "Advanced options 3"
221
+ @nested_forms_legend_text = "This is a nested form title"
222
+ concat(semantic_form_for(@new_post) do |builder|
223
+ inputs = builder.inputs @legend_text do
224
+ end
225
+ concat(inputs)
226
+ inputs = builder.inputs :name => @legend_text_using_name do
227
+ end
228
+ concat(inputs)
229
+ inputs = builder.inputs :title => @legend_text_using_title do
230
+ end
231
+ concat(inputs)
232
+ inputs = builder.inputs @nested_forms_legend_text, :for => :authors do |nf|
233
+ end
234
+ concat(inputs)
235
+ end)
236
+ end
237
+
238
+ it 'should render a fieldset with a legend inside the form' do
239
+ output_buffer.should have_tag("form fieldset legend", /^#{@legend_text}$/)
240
+ output_buffer.should have_tag("form fieldset legend", /^#{@legend_text_using_name}$/)
241
+ output_buffer.should have_tag("form fieldset legend", /^#{@legend_text_using_title}$/)
242
+ output_buffer.should have_tag("form fieldset legend", /^#{@nested_forms_legend_text}$/)
243
+ end
244
+ end
245
+
246
+ describe 'and is a symbol' do
247
+ before do
248
+ @localized_legend_text = "Localized advanced options"
249
+ @localized_legend_text_using_name = "Localized advanced options 2"
250
+ @localized_legend_text_using_title = "Localized advanced options 3"
251
+ @localized_nested_forms_legend_text = "This is a localized nested form title"
252
+ ::I18n.backend.store_translations :en, :formtastic => {
253
+ :titles => {
254
+ :post => {
255
+ :advanced_options => @localized_legend_text,
256
+ :advanced_options_using_name => @localized_legend_text_using_name,
257
+ :advanced_options_using_title => @localized_legend_text_using_title,
258
+ :nested_forms_title => @localized_nested_forms_legend_text
259
+ }
260
+ }
261
+ }
262
+ concat(semantic_form_for(@new_post) do |builder|
263
+ inputs = builder.inputs :advanced_options do
264
+ end
265
+ concat(inputs)
266
+ inputs =builder.inputs :name => :advanced_options_using_name do
267
+ end
268
+ concat(inputs)
269
+ inputs = builder.inputs :title => :advanced_options_using_title do
270
+ end
271
+ concat(inputs)
272
+ inputs = builder.inputs :nested_forms_title, :for => :authors do |nf|
273
+ end
274
+ concat(inputs)
275
+ end)
276
+ end
277
+
278
+ it 'should render a fieldset with a localized legend inside the form' do
279
+ output_buffer.should have_tag("form fieldset legend", /^#{@localized_legend_text}$/)
280
+ output_buffer.should have_tag("form fieldset legend", /^#{@localized_legend_text_using_name}$/)
281
+ output_buffer.should have_tag("form fieldset legend", /^#{@localized_legend_text_using_title}$/)
282
+ output_buffer.should have_tag("form fieldset legend", /^#{@localized_nested_forms_legend_text}$/)
283
+ end
284
+ end
285
+ end
286
+
287
+ describe 'when other options are provided' do
288
+ before do
289
+ @id_option = 'advanced'
290
+ @class_option = 'wide'
291
+
292
+ concat(semantic_form_for(@new_post) do |builder|
293
+ builder.inputs :id => @id_option, :class => @class_option do
294
+ end
295
+ end)
296
+ end
297
+
298
+ it 'should pass the options into the fieldset tag as attributes' do
299
+ output_buffer.should have_tag("form fieldset##{@id_option}")
300
+ output_buffer.should have_tag("form fieldset.#{@class_option}")
301
+ end
302
+ end
303
+
304
+ end
305
+
306
+ describe 'without a block' do
307
+
308
+ before do
309
+ ::Post.stub!(:reflections).and_return({:author => mock('reflection', :options => {}, :macro => :belongs_to),
310
+ :comments => mock('reflection', :options => {}, :macro => :has_many) })
311
+ ::Author.stub!(:find).and_return([@fred, @bob])
312
+
313
+ @new_post.stub!(:title)
314
+ @new_post.stub!(:body)
315
+ @new_post.stub!(:author_id)
316
+
317
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :string, :limit => 255))
318
+ @new_post.stub!(:column_for_attribute).with(:body).and_return(mock('column', :type => :text))
319
+ @new_post.stub!(:column_for_attribute).with(:created_at).and_return(mock('column', :type => :datetime))
320
+ @new_post.stub!(:column_for_attribute).with(:author).and_return(nil)
321
+ end
322
+
323
+ describe 'with no args (quick forms syntax)' do
324
+ before do
325
+ concat(semantic_form_for(@new_post) do |builder|
326
+ concat(builder.inputs)
327
+ end)
328
+ end
329
+
330
+ it 'should render a form' do
331
+ output_buffer.should have_tag('form')
332
+ end
333
+
334
+ it 'should render a fieldset inside the form' do
335
+ output_buffer.should have_tag('form > fieldset.inputs')
336
+ end
337
+
338
+ it 'should not render a legend in the fieldset' do
339
+ output_buffer.should_not have_tag('form > fieldset.inputs > legend')
340
+ end
341
+
342
+ it 'should render an ol in the fieldset' do
343
+ output_buffer.should have_tag('form > fieldset.inputs > ol')
344
+ end
345
+
346
+ it 'should render a list item in the ol for each column and reflection' do
347
+ # Remove the :has_many macro and :created_at column
348
+ count = ::Post.content_columns.size + ::Post.reflections.size - 2
349
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li', :count => count)
350
+ end
351
+
352
+ it 'should render a string list item for title' do
353
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li.string')
354
+ end
355
+
356
+ it 'should render a text list item for body' do
357
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li.text')
358
+ end
359
+
360
+ it 'should render a select list item for author_id' do
361
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li.select', :count => 1)
362
+ end
363
+
364
+ it 'should not render timestamps inputs by default' do
365
+ output_buffer.should_not have_tag('form > fieldset.inputs > ol > li.datetime')
366
+ end
367
+
368
+ context "with a polymorphic association" do
369
+
370
+ before do
371
+ @new_post.stub!(:commentable)
372
+ @new_post.class.stub!(:reflections).and_return({
373
+ :commentable => mock('macro_reflection', :options => { :polymorphic => true }, :macro => :belongs_to)
374
+ })
375
+ @new_post.stub!(:column_for_attribute).with(:commentable).and_return(
376
+ mock('column', :type => :integer)
377
+ )
378
+ end
379
+
380
+ it 'should not render an input for the polymorphic association (the collection class cannot be guessed)' do
381
+ concat(semantic_form_for(@new_post) do |builder|
382
+ concat(builder.inputs)
383
+ end)
384
+ output_buffer.should_not have_tag('li#post_commentable_input')
385
+ end
386
+
387
+ end
388
+ end
389
+
390
+ describe 'with column names as args (short hand forms syntax)' do
391
+ describe 'and an object is given' do
392
+ it 'should render a form with a fieldset containing two list items' do
393
+ concat(semantic_form_for(@new_post) do |builder|
394
+ concat(builder.inputs(:title, :body))
395
+ end)
396
+
397
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li', :count => 2)
398
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li.string')
399
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li.text')
400
+ end
401
+ end
402
+
403
+ describe 'and no object is given' do
404
+ it 'should render a form with a fieldset containing two list items' do
405
+ concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
406
+ concat(builder.inputs(:title, :body))
407
+ end)
408
+
409
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li.string', :count => 2)
410
+ end
411
+ end
412
+
413
+ context "with a polymorphic association" do
414
+
415
+ it 'should raise an error for polymorphic associations (the collection class cannot be guessed)' do
416
+ @new_post.stub!(:commentable)
417
+ @new_post.class.stub!(:reflections).and_return({
418
+ :commentable => mock('macro_reflection', :options => { :polymorphic => true }, :macro => :belongs_to)
419
+ })
420
+ @new_post.stub!(:column_for_attribute).with(:commentable).and_return(
421
+ mock('column', :type => :integer)
422
+ )
423
+ @new_post.class.stub!(:reflect_on_association).with(:commentable).and_return(
424
+ mock('reflection', :macro => :belongs_to, :options => { :polymorphic => true })
425
+ )
426
+
427
+ expect {
428
+ concat(semantic_form_for(@new_post) do |builder|
429
+ concat(builder.inputs :commentable)
430
+ end)
431
+ }.to raise_error(Formtastic::PolymorphicInputWithoutCollectionError)
432
+ end
433
+
434
+ end
435
+
436
+ end
437
+
438
+ describe 'when a :for option is provided' do
439
+ describe 'and an object is given' do
440
+ it 'should render nested inputs' do
441
+ @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
442
+ concat(semantic_form_for(@new_post) do |builder|
443
+ concat(builder.inputs(:login, :for => @bob))
444
+ end)
445
+
446
+ output_buffer.should have_tag("form fieldset.inputs #post_author_login")
447
+ output_buffer.should_not have_tag("form fieldset.inputs #author_login")
448
+ end
449
+ end
450
+
451
+ describe 'and no object is given' do
452
+ it 'should render nested inputs' do
453
+ concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder|
454
+ concat(builder.inputs(:login, :for => @bob))
455
+ end)
456
+ output_buffer.should have_tag("form fieldset.inputs #project_author_login")
457
+ output_buffer.should_not have_tag("form fieldset.inputs #project_login")
458
+ end
459
+ end
460
+ end
461
+
462
+ describe 'with column names and an options hash as args' do
463
+ before do
464
+ concat(semantic_form_for(@new_post) do |builder|
465
+ @legend_text_using_option = "Legendary Legend Text"
466
+ @legend_text_using_arg = "Legendary Legend Text 2"
467
+ concat(builder.inputs(:title, :body, :name => @legend_text_using_option, :id => "my-id"))
468
+ concat(builder.inputs(@legend_text_using_arg, :title, :body, :id => "my-id-2"))
469
+ end)
470
+ end
471
+
472
+ it 'should render a form with a fieldset containing two list items' do
473
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li', :count => 4)
474
+ end
475
+
476
+ it 'should pass the options down to the fieldset' do
477
+ output_buffer.should have_tag('form > fieldset#my-id.inputs')
478
+ end
479
+
480
+ it 'should use the special :name option as a text for the legend tag' do
481
+ output_buffer.should have_tag('form > fieldset#my-id.inputs > legend', /^#{@legend_text_using_option}$/)
482
+ output_buffer.should have_tag('form > fieldset#my-id-2.inputs > legend', /^#{@legend_text_using_arg}$/)
483
+ end
484
+ end
485
+
486
+ end
487
+
488
+ describe 'nesting' do
489
+
490
+ context "when not nested" do
491
+ it "should not wrap the inputs in an li block" do
492
+ concat(semantic_form_for(@new_post) do |builder|
493
+ concat(builder.inputs do
494
+ end)
495
+ end)
496
+ output_buffer.should_not have_tag('form > li')
497
+ end
498
+ end
499
+
500
+ context "when nested (with block)" do
501
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
502
+ concat(semantic_form_for(@new_post) do |builder|
503
+ concat(builder.inputs do
504
+ concat(builder.inputs do
505
+ end)
506
+ end)
507
+ end)
508
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol')
509
+ end
510
+ end
511
+
512
+ context "when nested (with block and :for)" do
513
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
514
+ concat(semantic_form_for(@new_post) do |builder|
515
+ concat(builder.inputs do
516
+ concat(builder.inputs(:for => :author) do |author_builder|
517
+ end)
518
+ end)
519
+ end)
520
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol')
521
+ end
522
+ end
523
+
524
+ context "when nested (without block)" do
525
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
526
+ concat(semantic_form_for(@new_post) do |builder|
527
+ concat(builder.inputs do
528
+ concat(builder.inputs(:title))
529
+ end)
530
+ end)
531
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol')
532
+ end
533
+ end
534
+
535
+ context "when nested (without block, with :for)" do
536
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
537
+ concat(semantic_form_for(@new_post) do |builder|
538
+ concat(builder.inputs do
539
+ concat(builder.inputs(:name, :for => :author))
540
+ end)
541
+ end)
542
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol')
543
+ end
544
+ end
545
+
546
+ context "when double nested" do
547
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
548
+ concat(semantic_form_for(@new_post) do |builder|
549
+ concat(builder.inputs do
550
+ concat(builder.inputs do
551
+ concat(builder.inputs do
552
+ end)
553
+ end)
554
+ end)
555
+ end)
556
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol > li > fieldset.inputs > ol')
557
+ end
558
+ end
559
+
560
+ end
561
+
562
+ end