formtastic-rails3 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.textile +558 -0
  3. data/Rakefile +103 -0
  4. data/generators/form/USAGE +16 -0
  5. data/generators/form/form_generator.rb +120 -0
  6. data/generators/form/templates/view__form.html.erb +5 -0
  7. data/generators/form/templates/view__form.html.haml +4 -0
  8. data/generators/formtastic/formtastic_generator.rb +24 -0
  9. data/generators/formtastic/templates/formtastic.css +144 -0
  10. data/generators/formtastic/templates/formtastic.rb +54 -0
  11. data/generators/formtastic/templates/formtastic_changes.css +10 -0
  12. data/generators/formtastic_stylesheets/formtastic_stylesheets_generator.rb +16 -0
  13. data/lib/formtastic.rb +1724 -0
  14. data/lib/formtastic/i18n.rb +32 -0
  15. data/lib/formtastic/layout_helper.rb +10 -0
  16. data/lib/generators/formtastic/form/form_generator.rb +85 -0
  17. data/lib/generators/formtastic/form/templates/_form.html.erb +5 -0
  18. data/lib/generators/formtastic/form/templates/_form.html.haml +4 -0
  19. data/lib/generators/formtastic/install/install_generator.rb +23 -0
  20. data/lib/generators/formtastic/install/templates/formtastic.css +144 -0
  21. data/lib/generators/formtastic/install/templates/formtastic.rb +58 -0
  22. data/lib/generators/formtastic/install/templates/formtastic_changes.css +10 -0
  23. data/lib/locale/en.yml +8 -0
  24. data/spec/buttons_spec.rb +149 -0
  25. data/spec/commit_button_spec.rb +377 -0
  26. data/spec/custom_builder_spec.rb +62 -0
  27. data/spec/custom_macros.rb +460 -0
  28. data/spec/defaults_spec.rb +20 -0
  29. data/spec/error_proc_spec.rb +27 -0
  30. data/spec/errors_spec.rb +85 -0
  31. data/spec/form_helper_spec.rb +110 -0
  32. data/spec/i18n_spec.rb +131 -0
  33. data/spec/include_blank_spec.rb +70 -0
  34. data/spec/input_spec.rb +632 -0
  35. data/spec/inputs/boolean_input_spec.rb +93 -0
  36. data/spec/inputs/check_boxes_input_spec.rb +167 -0
  37. data/spec/inputs/country_input_spec.rb +80 -0
  38. data/spec/inputs/currency_input_spec.rb +80 -0
  39. data/spec/inputs/date_input_spec.rb +143 -0
  40. data/spec/inputs/datetime_input_spec.rb +259 -0
  41. data/spec/inputs/file_input_spec.rb +33 -0
  42. data/spec/inputs/hidden_input_spec.rb +52 -0
  43. data/spec/inputs/numeric_input_spec.rb +44 -0
  44. data/spec/inputs/password_input_spec.rb +46 -0
  45. data/spec/inputs/radio_input_spec.rb +152 -0
  46. data/spec/inputs/select_input_spec.rb +470 -0
  47. data/spec/inputs/string_input_spec.rb +47 -0
  48. data/spec/inputs/text_input_spec.rb +33 -0
  49. data/spec/inputs/time_input_spec.rb +128 -0
  50. data/spec/inputs/time_zone_input_spec.rb +102 -0
  51. data/spec/inputs_spec.rb +395 -0
  52. data/spec/label_spec.rb +48 -0
  53. data/spec/layout_helper_spec.rb +42 -0
  54. data/spec/semantic_errors_spec.rb +98 -0
  55. data/spec/semantic_fields_for_spec.rb +44 -0
  56. data/spec/spec.opts +2 -0
  57. data/spec/spec_helper.rb +238 -0
  58. metadata +205 -0
@@ -0,0 +1,377 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ describe 'SemanticFormBuilder#commit_button' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ActiveSupport::SafeBuffer.new
10
+ mock_everything
11
+ end
12
+
13
+ describe 'when used on any record' do
14
+
15
+ before do
16
+ @new_post.stub!(:new_record?).and_return(false)
17
+ semantic_form_for(@new_post) do |builder|
18
+ concat(builder.commit_button)
19
+ end
20
+ end
21
+
22
+ it 'should render a commit li' do
23
+ output_buffer.should have_tag('li.commit')
24
+ end
25
+
26
+ it 'should render an input with a type attribute of "submit"' do
27
+ output_buffer.should have_tag('li.commit input[@type="submit"]')
28
+ end
29
+
30
+ it 'should render an input with a name attribute of "commit"' do
31
+ output_buffer.should have_tag('li.commit input[@name="commit"]')
32
+ end
33
+
34
+ it 'should pass options given in :button_html to the button' do
35
+ @new_post.stub!(:new_record?).and_return(false)
36
+ semantic_form_for(@new_post) do |builder|
37
+ concat(builder.commit_button('text', :button_html => {:class => 'my_class', :id => 'my_id'}))
38
+ end
39
+
40
+ output_buffer.should have_tag('li.commit input#my_id')
41
+ output_buffer.should have_tag('li.commit input.my_class')
42
+ end
43
+
44
+ end
45
+
46
+ describe "its accesskey" do
47
+
48
+ it 'should allow nil default' do
49
+ with_config :default_commit_button_accesskey, nil do
50
+ output_buffer.should_not have_tag('li.commit input[@accesskey]')
51
+ end
52
+ end
53
+
54
+ it 'should use the default if set' do
55
+ with_config :default_commit_button_accesskey, 's' do
56
+ @new_post.stub!(:new_record?).and_return(false)
57
+ semantic_form_for(@new_post) do |builder|
58
+ concat(builder.commit_button('text', :button_html => {}))
59
+ end
60
+ output_buffer.should have_tag('li.commit input[@accesskey="s"]')
61
+ end
62
+ end
63
+
64
+ it 'should use the value set in options over the default' do
65
+ with_config :default_commit_button_accesskey, 's' do
66
+ @new_post.stub!(:new_record?).and_return(false)
67
+ semantic_form_for(@new_post) do |builder|
68
+ concat(builder.commit_button('text', :accesskey => 'o'))
69
+ end
70
+ output_buffer.should_not have_tag('li.commit input[@accesskey="s"]')
71
+ output_buffer.should have_tag('li.commit input[@accesskey="o"]')
72
+ end
73
+ end
74
+
75
+ it 'should use the value set in button_html over options' do
76
+ with_config :default_commit_button_accesskey, 's' do
77
+ @new_post.stub!(:new_record?).and_return(false)
78
+ semantic_form_for(@new_post) do |builder|
79
+ concat(builder.commit_button('text', :accesskey => 'o', :button_html => {:accesskey => 't'}))
80
+ end
81
+ output_buffer.should_not have_tag('li.commit input[@accesskey="s"]')
82
+ output_buffer.should_not have_tag('li.commit input[@accesskey="o"]')
83
+ output_buffer.should have_tag('li.commit input[@accesskey="t"]')
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ describe 'when the first option is a string and the second is a hash' do
90
+
91
+ before do
92
+ @new_post.stub!(:new_record?).and_return(false)
93
+ semantic_form_for(@new_post) do |builder|
94
+ concat(builder.commit_button("a string", :button_html => { :class => "pretty"}))
95
+ end
96
+ end
97
+
98
+ it "should render the string as the value of the button" do
99
+ output_buffer.should have_tag('li input[@value="a string"]')
100
+ end
101
+
102
+ it "should deal with the options hash" do
103
+ output_buffer.should have_tag('li input.pretty')
104
+ end
105
+
106
+ end
107
+
108
+ describe 'when the first option is a hash' do
109
+
110
+ before do
111
+ @new_post.stub!(:new_record?).and_return(false)
112
+ semantic_form_for(@new_post) do |builder|
113
+ concat(builder.commit_button(:button_html => { :class => "pretty"}))
114
+ end
115
+ end
116
+
117
+ it "should deal with the options hash" do
118
+ output_buffer.should have_tag('li input.pretty')
119
+ end
120
+
121
+ end
122
+
123
+ describe 'label' do
124
+
125
+ # No object
126
+ describe 'when used without object' do
127
+ describe 'when explicit label is provided' do
128
+ it 'should render an input with the explicitly specified label' do
129
+ semantic_form_for(:post, :url => 'http://example.com') do |builder|
130
+ concat(builder.commit_button("Click!"))
131
+ end
132
+ output_buffer.should have_tag('li.commit input[@value="Click!"][@class~="submit"]')
133
+ end
134
+ end
135
+
136
+ describe 'when no explicit label is provided' do
137
+ describe 'when no I18n-localized label is provided' do
138
+ before do
139
+ ::I18n.backend.store_translations :en, :formtastic => {:submit => 'Submit {{model}}'}
140
+ end
141
+
142
+ after do
143
+ ::I18n.backend.store_translations :en, :formtastic => {:submit => nil}
144
+ end
145
+
146
+ it 'should render an input with default I18n-localized label (fallback)' do
147
+ semantic_form_for(:post, :url => 'http://example.com') do |builder|
148
+ concat(builder.commit_button)
149
+ end
150
+ output_buffer.should have_tag('li.commit input[@value="Submit Post"][@class~="submit"]')
151
+ end
152
+ end
153
+
154
+ describe 'when I18n-localized label is provided' do
155
+ before do
156
+ ::I18n.backend.store_translations :en,
157
+ :formtastic => {
158
+ :actions => {
159
+ :submit => 'Custom Submit',
160
+ :post => {
161
+ :submit => 'Custom Submit {{model}}'
162
+ }
163
+ }
164
+ }
165
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
166
+ end
167
+
168
+ it 'should render an input with localized label (I18n)' do
169
+ semantic_form_for(:post, :url => 'http://example.com') do |builder|
170
+ concat(builder.commit_button)
171
+ end
172
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Submit Post"][@class~="submit"]})
173
+ end
174
+
175
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
176
+ ::I18n.backend.store_translations :en,
177
+ :formtastic => {
178
+ :actions => {
179
+ :post => {
180
+ :submit => nil
181
+ }
182
+ }
183
+ }
184
+ semantic_form_for(:post, :url => 'http://example.com') do |builder|
185
+ concat(builder.commit_button)
186
+ end
187
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Submit"][@class~="submit"]})
188
+ end
189
+
190
+ end
191
+ end
192
+ end
193
+
194
+ # New record
195
+ describe 'when used on a new record' do
196
+ before do
197
+ @new_post.stub!(:new_record?).and_return(true)
198
+ end
199
+
200
+ describe 'when explicit label is provided' do
201
+ it 'should render an input with the explicitly specified label' do
202
+ semantic_form_for(@new_post) do |builder|
203
+ concat(builder.commit_button("Click!"))
204
+ end
205
+ output_buffer.should have_tag('li.commit input[@value="Click!"][@class~="create"]')
206
+ end
207
+ end
208
+
209
+ describe 'when no explicit label is provided' do
210
+ describe 'when no I18n-localized label is provided' do
211
+ before do
212
+ ::I18n.backend.store_translations :en, :formtastic => {:create => 'Create {{model}}'}
213
+ end
214
+
215
+ after do
216
+ ::I18n.backend.store_translations :en, :formtastic => {:create => nil}
217
+ end
218
+
219
+ it 'should render an input with default I18n-localized label (fallback)' do
220
+ semantic_form_for(@new_post) do |builder|
221
+ concat(builder.commit_button)
222
+ end
223
+ output_buffer.should have_tag('li.commit input[@value="Create Post"][@class~="create"]')
224
+ end
225
+ end
226
+
227
+ describe 'when I18n-localized label is provided' do
228
+ before do
229
+ ::I18n.backend.store_translations :en,
230
+ :formtastic => {
231
+ :actions => {
232
+ :create => 'Custom Create',
233
+ :post => {
234
+ :create => 'Custom Create {{model}}'
235
+ }
236
+ }
237
+ }
238
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
239
+ end
240
+
241
+ after do
242
+ ::I18n.backend.store_translations :en, :formtastic => nil
243
+ end
244
+
245
+ it 'should render an input with localized label (I18n)' do
246
+ semantic_form_for(@new_post) do |builder|
247
+ concat(builder.commit_button)
248
+ end
249
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create Post"][@class~="create"]})
250
+ end
251
+
252
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
253
+ ::I18n.backend.store_translations :en,
254
+ :formtastic => {
255
+ :actions => {
256
+ :post => {
257
+ :create => nil
258
+ }
259
+ }
260
+ }
261
+ semantic_form_for(@new_post) do |builder|
262
+ concat(builder.commit_button)
263
+ end
264
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create"][@class~="create"]})
265
+ ::I18n.backend.store_translations :en, :formtastic => nil
266
+
267
+ end
268
+
269
+ end
270
+ end
271
+ end
272
+
273
+ # Existing record
274
+ describe 'when used on an existing record' do
275
+ before do
276
+ @new_post.stub!(:new_record?).and_return(false)
277
+ end
278
+
279
+ describe 'when explicit label is provided' do
280
+ it 'should render an input with the explicitly specified label' do
281
+ semantic_form_for(@new_post) do |builder|
282
+ concat(builder.commit_button("Click!"))
283
+ end
284
+ output_buffer.should have_tag('li.commit input[@value="Click!"][@class~="update"]')
285
+ end
286
+ end
287
+
288
+ describe 'when no explicit label is provided' do
289
+ describe 'when no I18n-localized label is provided' do
290
+ before do
291
+ ::I18n.backend.store_translations :en, :formtastic => {:update => 'Save {{model}}'}
292
+ end
293
+
294
+ after do
295
+ ::I18n.backend.store_translations :en, :formtastic => {:update => nil}
296
+ end
297
+
298
+ it 'should render an input with default I18n-localized label (fallback)' do
299
+ semantic_form_for(@new_post) do |builder|
300
+ concat(builder.commit_button)
301
+ end
302
+ output_buffer.should have_tag('li.commit input[@value="Save Post"][@class~="update"]')
303
+ end
304
+ end
305
+
306
+ describe 'when I18n-localized label is provided' do
307
+ before do
308
+ ::I18n.backend.store_translations :en,
309
+ :formtastic => {
310
+ :actions => {
311
+ :update => 'Custom Save',
312
+ :post => {
313
+ :update => 'Custom Save {{model}}'
314
+ }
315
+ }
316
+ }
317
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
318
+ end
319
+
320
+ it 'should render an input with localized label (I18n)' do
321
+ semantic_form_for(@new_post) do |builder|
322
+ concat(builder.commit_button)
323
+ end
324
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Save Post"][@class~="update"]})
325
+ end
326
+
327
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
328
+ ::I18n.backend.store_translations :en,
329
+ :formtastic => {
330
+ :actions => {
331
+ :post => {
332
+ :update => nil
333
+ }
334
+ }
335
+ }
336
+ semantic_form_for(@new_post) do |builder|
337
+ concat(builder.commit_button)
338
+ end
339
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Save"][@class~="update"]})
340
+ ::I18n.backend.store_translations :en, :formtastic => {}
341
+ end
342
+
343
+ end
344
+ end
345
+ end
346
+ end
347
+
348
+ describe 'when the model is two words' do
349
+ before do
350
+ output_buffer = ''
351
+
352
+ class ::UserPost
353
+ extend ActiveModel::Naming
354
+
355
+ def id
356
+ end
357
+
358
+ def self.human_name
359
+ "Userpost" # Rails does crappy human_name
360
+ end
361
+ end
362
+
363
+ @new_user_post = ::UserPost.new
364
+
365
+ @new_user_post.stub!(:new_record?).and_return(true)
366
+ semantic_form_for(@new_user_post, :url => '') do |builder|
367
+ concat(builder.commit_button())
368
+ end
369
+ end
370
+
371
+ it "should render the string as the value of the button" do
372
+ output_buffer.should have_tag('li input[@value="Create User post"]')
373
+ end
374
+
375
+ end
376
+
377
+ end
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ describe 'Formtastic::SemanticFormHelper.builder' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ class MyCustomFormBuilder < ::Formtastic::SemanticFormBuilder
9
+ def awesome_input(method, options)
10
+ self.text_field(method)
11
+ end
12
+ end
13
+
14
+ before do
15
+ @output_buffer = ActiveSupport::SafeBuffer.new
16
+ mock_everything
17
+ end
18
+
19
+ it 'is the Formtastic::SemanticFormBuilder by default' do
20
+ ::Formtastic::SemanticFormHelper.builder.should == ::Formtastic::SemanticFormBuilder
21
+ end
22
+
23
+ it 'can be configured to use your own custom form builder' do
24
+ # Set it to a custom builder class
25
+ ::Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
26
+ ::Formtastic::SemanticFormHelper.builder.should == MyCustomFormBuilder
27
+
28
+ # Reset it to the default
29
+ ::Formtastic::SemanticFormHelper.builder = ::Formtastic::SemanticFormBuilder
30
+ ::Formtastic::SemanticFormHelper.builder.should == ::Formtastic::SemanticFormBuilder
31
+ end
32
+
33
+ describe "when using a custom builder" do
34
+
35
+ before do
36
+ @new_post.stub!(:title)
37
+ ::Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
38
+ end
39
+
40
+ after do
41
+ ::Formtastic::SemanticFormHelper.builder = ::Formtastic::SemanticFormBuilder
42
+ end
43
+
44
+ describe "semantic_form_for" do
45
+
46
+ it "should yeild and instance of the custom builder" do
47
+ semantic_form_for(@new_post) do |builder|
48
+ builder.class.should == MyCustomFormBuilder
49
+ end
50
+ end
51
+
52
+ it "should allow me to call my custom input" do
53
+ semantic_form_for(@new_post) do |builder|
54
+ concat(builder.input(:title, :as => :awesome))
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,460 @@
1
+ module CustomMacros
2
+
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+
9
+ def it_should_have_input_wrapper_with_class(class_name)
10
+ it "should have input wrapper with class '#{class_name}'" do
11
+ output_buffer.should have_tag("form li.#{class_name}")
12
+ end
13
+ end
14
+
15
+ def it_should_have_input_wrapper_with_id(id_string)
16
+ it "should have input wrapper with id '#{id_string}'" do
17
+ output_buffer.should have_tag("form li##{id_string}")
18
+ end
19
+ end
20
+
21
+ def it_should_not_have_a_label
22
+ it "should not have a label" do
23
+ output_buffer.should_not have_tag("form li label")
24
+ end
25
+ end
26
+
27
+ def it_should_have_a_nested_fieldset
28
+ it "should have a nested_fieldset" do
29
+ output_buffer.should have_tag("form li fieldset")
30
+ end
31
+ end
32
+
33
+ def it_should_have_label_with_text(string_or_regex)
34
+ it "should have a label with text '#{string_or_regex}'" do
35
+ output_buffer.should have_tag("form li label", string_or_regex)
36
+ end
37
+ end
38
+
39
+ def it_should_have_label_for(element_id)
40
+ it "should have a label for ##{element_id}" do
41
+ output_buffer.should have_tag("form li label[@for='#{element_id}']")
42
+ end
43
+ end
44
+
45
+ def it_should_have_input_with_id(element_id)
46
+ it "should have an input with id '#{element_id}'" do
47
+ output_buffer.should have_tag("form li input##{element_id}")
48
+ end
49
+ end
50
+
51
+ def it_should_have_input_with_type(input_type)
52
+ it "should have a #{input_type} input" do
53
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
54
+ end
55
+ end
56
+
57
+ def it_should_have_input_with_name(name)
58
+ it "should have an input named #{name}" do
59
+ output_buffer.should have_tag("form li input[@name=\"#{name}\"]")
60
+ end
61
+ end
62
+
63
+ def it_should_have_textarea_with_name(name)
64
+ it "should have an input named #{name}" do
65
+ output_buffer.should have_tag("form li textarea[@name=\"#{name}\"]")
66
+ end
67
+ end
68
+
69
+ def it_should_have_textarea_with_id(element_id)
70
+ it "should have an input with id '#{element_id}'" do
71
+ output_buffer.should have_tag("form li textarea##{element_id}")
72
+ end
73
+ end
74
+
75
+ def it_should_use_default_text_field_size_when_method_has_no_database_column(as)
76
+ it 'should use default_text_field_size when method has no database column' do
77
+ @new_post.stub!(:column_for_attribute).and_return(nil) # Return a nil column
78
+
79
+ semantic_form_for(@new_post) do |builder|
80
+ concat(builder.input(:title, :as => as))
81
+ end
82
+ output_buffer.should have_tag("form li input[@size='#{Formtastic::SemanticFormBuilder.default_text_field_size}']")
83
+ end
84
+ end
85
+
86
+ def it_should_apply_custom_input_attributes_when_input_html_provided(as)
87
+ it 'it should apply custom input attributes when input_html provided' do
88
+ semantic_form_for(@new_post) do |builder|
89
+ concat(builder.input(:title, :as => as, :input_html => { :class => 'myclass' }))
90
+ end
91
+ output_buffer.should have_tag("form li input.myclass")
92
+ end
93
+ end
94
+
95
+ def it_should_apply_custom_for_to_label_when_input_html_id_provided(as)
96
+ it 'it should apply custom for to label when input_html :id provided' do
97
+ semantic_form_for(@new_post) do |builder|
98
+ concat(builder.input(:title, :as => as, :input_html => { :id => 'myid' }))
99
+ end
100
+ output_buffer.should have_tag('form li label[@for="myid"]')
101
+ end
102
+ end
103
+
104
+ def it_should_have_maxlength_matching_column_limit
105
+ it 'should have a maxlength matching column limit' do
106
+ @new_post.column_for_attribute(:title).limit.should == 50
107
+ output_buffer.should have_tag("form li input[@maxlength='50']")
108
+ end
109
+ end
110
+
111
+ def it_should_use_default_text_field_size_for_columns_longer_than_default_text_field_size(as)
112
+ it 'should use default_text_field_size for columns longer than default_text_field_size' do
113
+ default_size = Formtastic::SemanticFormBuilder.default_text_field_size
114
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => as, :limit => default_size * 2))
115
+
116
+ semantic_form_for(@new_post) do |builder|
117
+ concat(builder.input(:title, :as => as))
118
+ end
119
+
120
+ output_buffer.should have_tag("form li input[@size='#{default_size}']")
121
+ end
122
+ end
123
+
124
+ def it_should_use_column_size_for_columns_shorter_than_default_text_field_size(as)
125
+ it 'should use the column size for columns shorter than default_text_field_size' do
126
+ column_limit_shorted_than_default = 1
127
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => as, :limit => column_limit_shorted_than_default))
128
+
129
+ semantic_form_for(@new_post) do |builder|
130
+ concat(builder.input(:title, :as => as))
131
+ end
132
+
133
+ output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
134
+ end
135
+ end
136
+
137
+ def it_should_apply_error_logic_for_input_type(type)
138
+ describe 'when there are errors on the object for this method' do
139
+ before do
140
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
141
+ @errors = mock('errors')
142
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
143
+ @new_post.stub!(:errors).and_return(@errors)
144
+ end
145
+
146
+ it 'should apply an errors class to the list item' do
147
+ semantic_form_for(@new_post) do |builder|
148
+ concat(builder.input(:title, :as => type))
149
+ end
150
+ output_buffer.should have_tag('form li.error')
151
+ end
152
+
153
+ it 'should not wrap the input with the Rails default error wrapping' do
154
+ semantic_form_for(@new_post) do |builder|
155
+ concat(builder.input(:title, :as => type))
156
+ end
157
+ output_buffer.should_not have_tag('div.fieldWithErrors')
158
+ end
159
+
160
+ it 'should render a paragraph for the errors' do
161
+ ::Formtastic::SemanticFormBuilder.inline_errors = :sentence
162
+ semantic_form_for(@new_post) do |builder|
163
+ concat(builder.input(:title, :as => type))
164
+ end
165
+ output_buffer.should have_tag('form li.error p.inline-errors')
166
+ end
167
+
168
+ it 'should not display an error list' do
169
+ ::Formtastic::SemanticFormBuilder.inline_errors = :list
170
+ semantic_form_for(@new_post) do |builder|
171
+ concat(builder.input(:title, :as => type))
172
+ end
173
+ output_buffer.should have_tag('form li.error ul.errors')
174
+ end
175
+ end
176
+
177
+ describe 'when there are no errors on the object for this method' do
178
+ before do
179
+ semantic_form_for(@new_post) do |builder|
180
+ concat(builder.input(:title, :as => type))
181
+ end
182
+ end
183
+
184
+ it 'should not apply an errors class to the list item' do
185
+ output_buffer.should_not have_tag('form li.error')
186
+ end
187
+
188
+ it 'should not render a paragraph for the errors' do
189
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
190
+ end
191
+
192
+ it 'should not display an error list' do
193
+ output_buffer.should_not have_tag('form li.error ul.errors')
194
+ end
195
+ end
196
+
197
+ describe 'when no object is provided' do
198
+ before do
199
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
200
+ concat(builder.input(:title, :as => type))
201
+ end
202
+ end
203
+
204
+ it 'should not apply an errors class to the list item' do
205
+ output_buffer.should_not have_tag('form li.error')
206
+ end
207
+
208
+ it 'should not render a paragraph for the errors' do
209
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
210
+ end
211
+
212
+ it 'should not display an error list' do
213
+ output_buffer.should_not have_tag('form li.error ul.errors')
214
+ end
215
+ end
216
+ end
217
+
218
+ def it_should_call_find_on_association_class_when_no_collection_is_provided(as)
219
+ it "should call find on the association class when no collection is provided" do
220
+ ::Author.should_receive(:find)
221
+ semantic_form_for(@new_post) do |builder|
222
+ concat(builder.input(:author, :as => as))
223
+ end
224
+ end
225
+ end
226
+
227
+ def it_should_use_the_collection_when_provided(as, countable)
228
+ describe 'when the :collection option is provided' do
229
+
230
+ before do
231
+ @authors = ::Author.find(:all) * 2
232
+ output_buffer.replace '' # clears the output_buffer from the before block, hax!
233
+ end
234
+
235
+ it 'should not call find() on the parent class' do
236
+ ::Author.should_not_receive(:find)
237
+ semantic_form_for(@new_post) do |builder|
238
+ concat(builder.input(:author, :as => as, :collection => @authors))
239
+ end
240
+ end
241
+
242
+ it 'should use the provided collection' do
243
+ semantic_form_for(@new_post) do |builder|
244
+ concat(builder.input(:author, :as => as, :collection => @authors))
245
+ end
246
+ output_buffer.should have_tag("form li.#{as} #{countable}", :count => @authors.size + (as == :select ? 1 : 0))
247
+ end
248
+
249
+ describe 'and the :collection is an array of strings' do
250
+ before do
251
+ @categories = [ 'General', 'Design', 'Development', 'Quasi-Serious Inventions' ]
252
+ end
253
+
254
+ it "should use the string as the label text and value for each #{countable}" do
255
+ semantic_form_for(@new_post) do |builder|
256
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
257
+ end
258
+
259
+ @categories.each do |value|
260
+ output_buffer.should have_tag("form li.#{as}", /#{value}/)
261
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value}']")
262
+ end
263
+ end
264
+
265
+ if as == :radio
266
+ it 'should generate a sanitized label for attribute' do
267
+ @bob.stub!(:category_name).and_return(@categories)
268
+ semantic_form_for(@new_post) do |builder|
269
+ builder.semantic_fields_for(@bob) do |bob_builder|
270
+ concat(bob_builder.input(:category_name, :as => as, :collection => @categories))
271
+ end
272
+ end
273
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_general']")
274
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_design']")
275
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_development']")
276
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_quasiserious_inventions']")
277
+ end
278
+ end
279
+ end
280
+
281
+ describe 'and the :collection is a hash of strings' do
282
+ before do
283
+ @categories = { 'General' => 'gen', 'Design' => 'des','Development' => 'dev' }
284
+ end
285
+
286
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
287
+ semantic_form_for(@new_post) do |builder|
288
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
289
+ end
290
+
291
+ @categories.each do |label, value|
292
+ output_buffer.should have_tag("form li.#{as}", /#{label}/)
293
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value}']")
294
+ end
295
+ end
296
+ end
297
+
298
+ describe 'and the :collection is an array of arrays' do
299
+ before do
300
+ @categories = { 'General' => 'gen', 'Design' => 'des', 'Development' => 'dev' }.to_a
301
+ end
302
+
303
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
304
+ semantic_form_for(@new_post) do |builder|
305
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
306
+ end
307
+
308
+ @categories.each do |text, value|
309
+ label = as == :select ? :option : :label
310
+ output_buffer.should have_tag("form li.#{as} #{label}", /#{text}/i)
311
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value.to_s}']")
312
+ output_buffer.should have_tag("form li.#{as} #{countable}#post_category_name_#{value.to_s}") if as == :radio
313
+ end
314
+ end
315
+ end
316
+
317
+ if as == :radio
318
+ describe 'and the :collection is an array of arrays with boolean values' do
319
+ before do
320
+ @choices = { 'Yeah' => true, 'Nah' => false }.to_a
321
+ end
322
+
323
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
324
+ semantic_form_for(@new_post) do |builder|
325
+ concat(builder.input(:category_name, :as => as, :collection => @choices))
326
+ end
327
+
328
+ output_buffer.should have_tag("form li.#{as} #{countable}#post_category_name_true")
329
+ output_buffer.should have_tag("form li.#{as} #{countable}#post_category_name_false")
330
+ end
331
+ end
332
+ end
333
+
334
+ describe 'and the :collection is an array of symbols' do
335
+ before do
336
+ @categories = [ :General, :Design, :Development ]
337
+ end
338
+
339
+ it "should use the symbol as the label text and value for each #{countable}" do
340
+ semantic_form_for(@new_post) do |builder|
341
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
342
+ end
343
+
344
+ @categories.each do |value|
345
+ label = as == :select ? :option : :label
346
+ output_buffer.should have_tag("form li.#{as} #{label}", /#{value}/i)
347
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value.to_s}']")
348
+ end
349
+ end
350
+ end
351
+
352
+ describe 'and the :collection is an OrderedHash of strings' do
353
+ before do
354
+ @categories = ActiveSupport::OrderedHash.new('General' => 'gen', 'Design' => 'des','Development' => 'dev')
355
+ end
356
+
357
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
358
+ semantic_form_for(@new_post) do |builder|
359
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
360
+ end
361
+
362
+ @categories.each do |label, value|
363
+ output_buffer.should have_tag("form li.#{as}", /#{label}/)
364
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value}']")
365
+ end
366
+ end
367
+
368
+ end
369
+
370
+ describe 'when the :label_method option is provided' do
371
+
372
+ describe 'as a symbol' do
373
+ before do
374
+ semantic_form_for(@new_post) do |builder|
375
+ concat(builder.input(:author, :as => as, :label_method => :login))
376
+ end
377
+ end
378
+
379
+ it 'should have options with text content from the specified method' do
380
+ ::Author.find(:all).each do |author|
381
+ output_buffer.should have_tag("form li.#{as}", /#{author.login}/)
382
+ end
383
+ end
384
+ end
385
+
386
+ describe 'as a proc' do
387
+ before do
388
+ semantic_form_for(@new_post) do |builder|
389
+ concat(builder.input(:author, :as => as, :label_method => Proc.new {|a| a.login.reverse }))
390
+ end
391
+ end
392
+
393
+ it 'should have options with the proc applied to each' do
394
+ ::Author.find(:all).each do |author|
395
+ output_buffer.should have_tag("form li.#{as}", /#{author.login.reverse}/)
396
+ end
397
+ end
398
+ end
399
+
400
+ end
401
+
402
+ describe 'when the :label_method option is not provided' do
403
+ ::Formtastic::SemanticFormBuilder.collection_label_methods.each do |label_method|
404
+
405
+ describe "when the collection objects respond to #{label_method}" do
406
+ before do
407
+ @fred.stub!(:respond_to?).and_return { |m| m.to_s == label_method }
408
+ ::Author.find(:all).each { |a| a.stub!(label_method).and_return('The Label Text') }
409
+
410
+ semantic_form_for(@new_post) do |builder|
411
+ concat(builder.input(:author, :as => as))
412
+ end
413
+ end
414
+
415
+ it "should render the options with #{label_method} as the label" do
416
+ ::Author.find(:all).each do |author|
417
+ output_buffer.should have_tag("form li.#{as}", /The Label Text/)
418
+ end
419
+ end
420
+ end
421
+
422
+ end
423
+ end
424
+
425
+ describe 'when the :value_method option is provided' do
426
+
427
+ describe 'as a symbol' do
428
+ before do
429
+ semantic_form_for(@new_post) do |builder|
430
+ concat(builder.input(:author, :as => as, :value_method => :login))
431
+ end
432
+ end
433
+
434
+ it 'should have options with values from specified method' do
435
+ ::Author.find(:all).each do |author|
436
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login}']")
437
+ end
438
+ end
439
+ end
440
+
441
+ describe 'as a proc' do
442
+ before do
443
+ semantic_form_for(@new_post) do |builder|
444
+ concat(builder.input(:author, :as => as, :value_method => Proc.new {|a| a.login.reverse }))
445
+ end
446
+ end
447
+
448
+ it 'should have options with the proc applied to each value' do
449
+ ::Author.find(:all).each do |author|
450
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login.reverse}']")
451
+ end
452
+ end
453
+ end
454
+ end
455
+
456
+ end
457
+ end
458
+
459
+ end
460
+ end