formtastic 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/test_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 = ''
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,27 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ describe 'Rails field_error_proc' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ it "should not be overridden globally for all form builders" do
14
+ current_field_error_proc = ::ActionView::Base.field_error_proc
15
+
16
+ semantic_form_for(@new_post) do |builder|
17
+ ::ActionView::Base.field_error_proc.should_not == current_field_error_proc
18
+ end
19
+
20
+ ::ActionView::Base.field_error_proc.should == current_field_error_proc
21
+
22
+ form_for(@new_post) do |builder|
23
+ ::ActionView::Base.field_error_proc.should == current_field_error_proc
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,78 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ describe 'SemanticFormBuilder#errors_on' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
12
+ @errors = mock('errors')
13
+ @new_post.stub!(:errors).and_return(@errors)
14
+ end
15
+
16
+ describe 'when there are errors' do
17
+ before do
18
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
19
+ end
20
+
21
+ it 'should render a paragraph with the errors joined into a sentence when inline_errors config is :sentence' do
22
+ Formtastic::SemanticFormBuilder.inline_errors = :sentence
23
+ semantic_form_for(@new_post) do |builder|
24
+ builder.errors_on(:title).should have_tag('p.inline-errors', @title_errors.to_sentence)
25
+ end
26
+ end
27
+
28
+ it 'should render an unordered list with the class errors when inline_errors config is :list' do
29
+ Formtastic::SemanticFormBuilder.inline_errors = :list
30
+ semantic_form_for(@new_post) do |builder|
31
+ builder.errors_on(:title).should have_tag('ul.errors')
32
+ @title_errors.each do |error|
33
+ builder.errors_on(:title).should have_tag('ul.errors li', error)
34
+ end
35
+ end
36
+ end
37
+
38
+ it 'should return nil when inline_errors config is :none' do
39
+ Formtastic::SemanticFormBuilder.inline_errors = :none
40
+ semantic_form_for(@new_post) do |builder|
41
+ builder.errors_on(:title).should be_nil
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ describe 'when there are no errors (nil)' do
48
+ before do
49
+ @errors.stub!(:[]).with(:title).and_return(nil)
50
+ end
51
+
52
+ it 'should return nil when inline_errors config is :sentence, :list or :none' do
53
+ [:sentence, :list, :none].each do |config|
54
+ Formtastic::SemanticFormBuilder.inline_errors = config
55
+ semantic_form_for(@new_post) do |builder|
56
+ builder.errors_on(:title).should be_nil
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ describe 'when there are no errors (empty array)' do
63
+ before do
64
+ @errors.stub!(:[]).with(:title).and_return([])
65
+ end
66
+
67
+ it 'should return nil when inline_errors config is :sentence, :list or :none' do
68
+ [:sentence, :list, :none].each do |config|
69
+ Formtastic::SemanticFormBuilder.inline_errors = config
70
+ semantic_form_for(@new_post) do |builder|
71
+ builder.errors_on(:title).should be_nil
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ end
78
+
@@ -0,0 +1,110 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ describe 'SemanticFormHelper' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ describe '#semantic_form_for' do
14
+
15
+ it 'yields an instance of SemanticFormBuilder' do
16
+ semantic_form_for(:post, ::Post.new, :url => '/hello') do |builder|
17
+ builder.class.should == Formtastic::SemanticFormBuilder
18
+ end
19
+ end
20
+
21
+ it 'adds a class of "formtastic" to the generated form' do
22
+ semantic_form_for(:post, ::Post.new, :url => '/hello') do |builder|
23
+ end
24
+ output_buffer.should have_tag("form.formtastic")
25
+ end
26
+
27
+ it 'adds class matching the object name to the generated form when a symbol is provided' do
28
+ semantic_form_for(:post, ::Post.new, :url => '/hello') do |builder|
29
+ end
30
+ output_buffer.should have_tag("form.post")
31
+
32
+ semantic_form_for(:project, :url => '/hello') do |builder|
33
+ end
34
+ output_buffer.should have_tag("form.project")
35
+ end
36
+
37
+ it 'adds class matching the object\'s class to the generated form when an object is provided' do
38
+ semantic_form_for(@new_post) do |builder|
39
+ end
40
+ output_buffer.should have_tag("form.post")
41
+ end
42
+
43
+ describe 'allows :html options' do
44
+ before(:each) do
45
+ semantic_form_for(:post, ::Post.new, :url => '/hello', :html => { :id => "something-special", :class => "something-extra", :multipart => true }) do |builder|
46
+ end
47
+ end
48
+
49
+ it 'to add a id of "something-special" to generated form' do
50
+ output_buffer.should have_tag("form#something-special")
51
+ end
52
+
53
+ it 'to add a class of "something-extra" to generated form' do
54
+ output_buffer.should have_tag("form.something-extra")
55
+ end
56
+
57
+ it 'to add enctype="multipart/form-data"' do
58
+ output_buffer.should have_tag('form[@enctype="multipart/form-data"]')
59
+ end
60
+ end
61
+
62
+ it 'can be called with a resource-oriented style' do
63
+ semantic_form_for(@new_post) do |builder|
64
+ builder.object.class.should == ::Post
65
+ builder.object_name.should == "post"
66
+ end
67
+ end
68
+
69
+ it 'can be called with a generic style and instance variable' do
70
+ semantic_form_for(:post, @new_post, :url => new_post_path) do |builder|
71
+ builder.object.class.should == ::Post
72
+ builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
73
+ end
74
+ end
75
+
76
+ it 'can be called with a generic style and inline object' do
77
+ semantic_form_for(:post, ::Post.new, :url => new_post_path) do |builder|
78
+ builder.object.class.should == ::Post
79
+ builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ describe '#semantic_fields_for' do
86
+ it 'yields an instance of SemanticFormBuilder' do
87
+ semantic_fields_for(:post, ::Post.new, :url => '/hello') do |builder|
88
+ builder.class.should == Formtastic::SemanticFormBuilder
89
+ end
90
+ end
91
+ end
92
+
93
+ describe '#semantic_form_remote_for' do
94
+ it 'yields an instance of SemanticFormBuilder' do
95
+ semantic_form_remote_for(:post, ::Post.new, :url => '/hello') do |builder|
96
+ builder.class.should == Formtastic::SemanticFormBuilder
97
+ end
98
+ end
99
+ end
100
+
101
+ describe '#semantic_form_for_remote' do
102
+ it 'yields an instance of SemanticFormBuilder' do
103
+ semantic_remote_form_for(:post, ::Post.new, :url => '/hello') do |builder|
104
+ builder.class.should == Formtastic::SemanticFormBuilder
105
+ end
106
+ end
107
+ end
108
+
109
+ end
110
+
@@ -0,0 +1,70 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ describe "*select: options[:include_blank]" do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+
12
+ @new_post.stub!(:author_id).and_return(nil)
13
+ @new_post.stub!(:publish_at).and_return(nil)
14
+
15
+ @select_input_types = {
16
+ :select => :author,
17
+ :datetime => :publish_at,
18
+ :date => :publish_at,
19
+ :time => :publish_at
20
+ }
21
+ end
22
+
23
+ describe 'when :include_blank is not set' do
24
+ it 'blank value should be included if the default value specified in config is true' do
25
+ ::Formtastic::SemanticFormBuilder.include_blank_for_select_by_default = true
26
+ @select_input_types.each do |as, attribute|
27
+ semantic_form_for(@new_post) do |builder|
28
+ concat(builder.input(attribute, :as => as))
29
+ end
30
+ output_buffer.should have_tag("form li select option[@value='']", "")
31
+ end
32
+ end
33
+
34
+ it 'blank value should not be included if the default value specified in config is false' do
35
+ ::Formtastic::SemanticFormBuilder.include_blank_for_select_by_default = false
36
+ @select_input_types.each do |as, attribute|
37
+ semantic_form_for(@new_post) do |builder|
38
+ concat(builder.input(attribute, :as => as))
39
+ end
40
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
41
+ end
42
+ end
43
+
44
+ after do
45
+ ::Formtastic::SemanticFormBuilder.include_blank_for_select_by_default = true
46
+ end
47
+ end
48
+
49
+ describe 'when :include_blank is set to false' do
50
+ it 'should not have a blank option' do
51
+ @select_input_types.each do |as, attribute|
52
+ semantic_form_for(@new_post) do |builder|
53
+ concat(builder.input(attribute, :as => as, :include_blank => false))
54
+ end
55
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
56
+ end
57
+ end
58
+ end
59
+
60
+ describe 'when :include_blank => true is set' do
61
+ it 'should have a blank select option' do
62
+ @select_input_types.each do |as, attribute|
63
+ semantic_form_for(@new_post) do |builder|
64
+ concat(builder.input(attribute, :as => as, :include_blank => true))
65
+ end
66
+ output_buffer.should have_tag("form li select option[@value='']", "")
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,2157 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ describe 'SemanticFormBuilder#input' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ describe 'with inline order customization' do
14
+ it 'should allow input, hints, errors as order' do
15
+ Formtastic::SemanticFormBuilder.inline_order = [:input, :hints, :errors]
16
+
17
+ semantic_form_for(@new_post) do |builder|
18
+ builder.should_receive(:inline_input_for).once.ordered
19
+ builder.should_receive(:inline_hints_for).once.ordered
20
+ builder.should_receive(:inline_errors_for).once.ordered
21
+ concat(builder.input(:title))
22
+ end
23
+ end
24
+
25
+ it 'should allow hints, input, errors as order' do
26
+ Formtastic::SemanticFormBuilder.inline_order = [:hints, :input, :errors]
27
+
28
+ semantic_form_for(@new_post) do |builder|
29
+ builder.should_receive(:inline_hints_for).once.ordered
30
+ builder.should_receive(:inline_input_for).once.ordered
31
+ builder.should_receive(:inline_errors_for).once.ordered
32
+ concat(builder.input(:title))
33
+ end
34
+ end
35
+ end
36
+
37
+ describe 'arguments and options' do
38
+
39
+ it 'should require the first argument (the method on form\'s object)' do
40
+ lambda {
41
+ semantic_form_for(@new_post) do |builder|
42
+ concat(builder.input()) # no args passed in at all
43
+ end
44
+ }.should raise_error(ArgumentError)
45
+ end
46
+
47
+ describe ':required option' do
48
+
49
+ describe 'when true' do
50
+
51
+ before do
52
+ @string = Formtastic::SemanticFormBuilder.required_string = " required yo!" # ensure there's something in the string
53
+ @new_post.class.should_not_receive(:reflect_on_all_validations)
54
+ end
55
+
56
+ after do
57
+ Formtastic::SemanticFormBuilder.required_string = %{<abbr title="required">*</abbr>}
58
+ end
59
+
60
+ it 'should set a "required" class' do
61
+ semantic_form_for(@new_post) do |builder|
62
+ concat(builder.input(:title, :required => true))
63
+ end
64
+ output_buffer.should_not have_tag('form li.optional')
65
+ output_buffer.should have_tag('form li.required')
66
+ end
67
+
68
+ it 'should append the "required" string to the label' do
69
+ semantic_form_for(@new_post) do |builder|
70
+ concat(builder.input(:title, :required => true))
71
+ end
72
+ output_buffer.should have_tag('form li.required label', /#{@string}$/)
73
+ end
74
+
75
+ end
76
+
77
+ describe 'when false' do
78
+
79
+ before do
80
+ @string = Formtastic::SemanticFormBuilder.optional_string = " optional yo!" # ensure there's something in the string
81
+ @new_post.class.should_not_receive(:reflect_on_all_validations)
82
+ end
83
+
84
+ after do
85
+ Formtastic::SemanticFormBuilder.optional_string = ''
86
+ end
87
+
88
+ it 'should set an "optional" class' do
89
+ semantic_form_for(@new_post) do |builder|
90
+ concat(builder.input(:title, :required => false))
91
+ end
92
+ output_buffer.should_not have_tag('form li.required')
93
+ output_buffer.should have_tag('form li.optional')
94
+ end
95
+
96
+ it 'should append the "optional" string to the label' do
97
+ semantic_form_for(@new_post) do |builder|
98
+ concat(builder.input(:title, :required => false))
99
+ end
100
+ output_buffer.should have_tag('form li.optional label', /#{@string}$/)
101
+ end
102
+
103
+ end
104
+
105
+ describe 'when not provided' do
106
+
107
+ describe 'and an object was not given' do
108
+
109
+ it 'should use the default value' do
110
+ Formtastic::SemanticFormBuilder.all_fields_required_by_default.should == true
111
+ Formtastic::SemanticFormBuilder.all_fields_required_by_default = false
112
+
113
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
114
+ concat(builder.input(:title))
115
+ end
116
+ output_buffer.should_not have_tag('form li.required')
117
+ output_buffer.should have_tag('form li.optional')
118
+
119
+ Formtastic::SemanticFormBuilder.all_fields_required_by_default = true
120
+ end
121
+
122
+ end
123
+
124
+ describe 'and an object was given' do
125
+
126
+ describe 'and the validation reflection plugin is available' do
127
+
128
+ before do
129
+ @new_post.class.stub!(:method_defined?).with(:reflect_on_validations_for).and_return(true)
130
+ end
131
+
132
+ describe 'and validates_presence_of was called for the method' do
133
+ it 'should be required' do
134
+ @new_post.class.should_receive(:reflect_on_validations_for).with(:title).and_return([
135
+ mock('MacroReflection', :macro => :validates_presence_of, :name => :title, :options => nil)
136
+ ])
137
+ @new_post.class.should_receive(:reflect_on_validations_for).with(:body).and_return([
138
+ mock('MacroReflection', :macro => :validates_presence_of, :name => :body, :options => {:if => true})
139
+ ])
140
+
141
+ semantic_form_for(@new_post) do |builder|
142
+ concat(builder.input(:title))
143
+ concat(builder.input(:body))
144
+ end
145
+ output_buffer.should have_tag('form li.required')
146
+ output_buffer.should_not have_tag('form li.optional')
147
+ end
148
+
149
+ it 'should be not be required if the optional :if condition is not satisifed' do
150
+ should_be_required(:required => false, :options => { :if => false })
151
+ end
152
+
153
+ it 'should not be required if the optional :if proc evaluates to false' do
154
+ should_be_required(:required => false, :options => { :if => proc { |record| false } })
155
+ end
156
+
157
+ it 'should be required if the optional :if proc evaluates to true' do
158
+ should_be_required(:required => true, :options => { :if => proc { |record| true } })
159
+ end
160
+
161
+ it 'should not be required if the optional :unless proc evaluates to true' do
162
+ should_be_required(:required => false, :options => { :unless => proc { |record| true } })
163
+ end
164
+
165
+ it 'should be required if the optional :unless proc evaluates to false' do
166
+ should_be_required(:required => true, :options => { :unless => proc { |record| false } })
167
+ end
168
+
169
+ it 'should be required if the optional :if with a method string evaluates to true' do
170
+ @new_post.should_receive(:required_condition).and_return(true)
171
+ should_be_required(:required => true, :options => { :if => :required_condition })
172
+ end
173
+
174
+ it 'should be required if the optional :if with a method string evaluates to false' do
175
+ @new_post.should_receive(:required_condition).and_return(false)
176
+ should_be_required(:required => false, :options => { :if => :required_condition })
177
+ end
178
+
179
+ it 'should not be required if the optional :unless with a method string evaluates to false' do
180
+ @new_post.should_receive(:required_condition).and_return(false)
181
+ should_be_required(:required => true, :options => { :unless => :required_condition })
182
+ end
183
+
184
+ it 'should be required if the optional :unless with a method string evaluates to true' do
185
+ @new_post.should_receive(:required_condition).and_return(true)
186
+ should_be_required(:required => false, :options => { :unless => :required_condition })
187
+ end
188
+ end
189
+
190
+ # TODO make a matcher for this?
191
+ def should_be_required(options)
192
+ @new_post.class.should_receive(:reflect_on_validations_for).with(:body).and_return([
193
+ mock('MacroReflection', :macro => :validates_presence_of, :name => :body, :options => options[:options])
194
+ ])
195
+
196
+ semantic_form_for(@new_post) do |builder|
197
+ concat(builder.input(:body))
198
+ end
199
+
200
+ if options[:required]
201
+ output_buffer.should_not have_tag('form li.optional')
202
+ output_buffer.should have_tag('form li.required')
203
+ else
204
+ output_buffer.should have_tag('form li.optional')
205
+ output_buffer.should_not have_tag('form li.required')
206
+ end
207
+ end
208
+
209
+ describe 'and validates_presence_of was not called for the method' do
210
+ before do
211
+ @new_post.class.should_receive(:reflect_on_validations_for).with(:title).and_return([])
212
+ end
213
+
214
+ it 'should not be required' do
215
+ semantic_form_for(@new_post) do |builder|
216
+ concat(builder.input(:title))
217
+ end
218
+ output_buffer.should_not have_tag('form li.required')
219
+ output_buffer.should have_tag('form li.optional')
220
+ end
221
+ end
222
+
223
+ end
224
+
225
+ describe 'and the validation reflection plugin is not available' do
226
+
227
+ it 'should use the default value' do
228
+ Formtastic::SemanticFormBuilder.all_fields_required_by_default.should == true
229
+ Formtastic::SemanticFormBuilder.all_fields_required_by_default = false
230
+
231
+ semantic_form_for(@new_post) do |builder|
232
+ concat(builder.input(:title))
233
+ end
234
+ output_buffer.should_not have_tag('form li.required')
235
+ output_buffer.should have_tag('form li.optional')
236
+
237
+ Formtastic::SemanticFormBuilder.all_fields_required_by_default = true
238
+ end
239
+
240
+ end
241
+
242
+ end
243
+
244
+ end
245
+
246
+ end
247
+
248
+ describe ':as option' do
249
+
250
+ describe 'when not provided' do
251
+
252
+ it 'should default to a string for forms without objects unless column is password' do
253
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
254
+ concat(builder.input(:anything))
255
+ end
256
+ output_buffer.should have_tag('form li.string')
257
+ end
258
+
259
+ it 'should default to password for forms without objects if column is password' do
260
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
261
+ concat(builder.input(:password))
262
+ concat(builder.input(:password_confirmation))
263
+ concat(builder.input(:confirm_password))
264
+ end
265
+ output_buffer.should have_tag('form li.password', :count => 3)
266
+ end
267
+
268
+ it 'should default to a string for methods on objects that don\'t respond to "column_for_attribute"' do
269
+ @new_post.stub!(:method_without_a_database_column)
270
+ @new_post.stub!(:column_for_attribute).and_return(nil)
271
+ default_input_type(nil, :method_without_a_database_column).should == :string
272
+ end
273
+
274
+ it 'should default to :password for methods that don\'t have a column in the database but "password" is in the method name' do
275
+ @new_post.stub!(:password_method_without_a_database_column)
276
+ @new_post.stub!(:column_for_attribute).and_return(nil)
277
+ default_input_type(nil, :password_method_without_a_database_column).should == :password
278
+ end
279
+
280
+ 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
281
+ @new_post.stub!(:password_method_without_a_database_column)
282
+ @new_post.stub!(:column_for_attribute).and_return(nil)
283
+ default_input_type(nil, :password_method_without_a_database_column).should == :password
284
+ end
285
+
286
+ it 'should default to :select for column names ending in "_id"' do
287
+ default_input_type(:integer, :user_id).should == :select
288
+ default_input_type(:integer, :section_id).should == :select
289
+ end
290
+
291
+ it 'should default to :password for :string column types with "password" in the method name' do
292
+ default_input_type(:string, :password).should == :password
293
+ default_input_type(:string, :hashed_password).should == :password
294
+ default_input_type(:string, :password_hash).should == :password
295
+ end
296
+
297
+ it 'should default to :text for :text column types' do
298
+ default_input_type(:text).should == :text
299
+ end
300
+
301
+ it 'should default to :date for :date column types' do
302
+ default_input_type(:date).should == :date
303
+ end
304
+
305
+ it 'should default to :datetime for :datetime and :timestamp column types' do
306
+ default_input_type(:datetime).should == :datetime
307
+ default_input_type(:timestamp).should == :datetime
308
+ end
309
+
310
+ it 'should default to :time for :time column types' do
311
+ default_input_type(:time).should == :time
312
+ end
313
+
314
+ it 'should default to :boolean for :boolean column types' do
315
+ default_input_type(:boolean).should == :boolean
316
+ end
317
+
318
+ it 'should default to :string for :string column types' do
319
+ default_input_type(:string).should == :string
320
+ end
321
+
322
+ it 'should default to :numeric for :integer, :float and :decimal column types' do
323
+ default_input_type(:integer).should == :numeric
324
+ default_input_type(:float).should == :numeric
325
+ default_input_type(:decimal).should == :numeric
326
+ end
327
+
328
+ it 'should default to :country for :string columns named country' do
329
+ default_input_type(:string, :country).should == :country
330
+ end
331
+
332
+ describe 'defaulting to file column' do
333
+ Formtastic::SemanticFormBuilder.file_methods.each do |method|
334
+ it "should default to :file for attributes that respond to ##{method}" do
335
+ @new_post.stub!(:column_for_attribute).and_return(nil)
336
+ column = mock('column')
337
+
338
+ Formtastic::SemanticFormBuilder.file_methods.each do |test|
339
+ column.stub!(:respond_to?).with(test).and_return(method == test)
340
+ end
341
+
342
+ @new_post.should_receive(method).and_return(column)
343
+
344
+ semantic_form_for(@new_post) do |builder|
345
+ builder.send(:default_input_type, method).should == :file
346
+ end
347
+ end
348
+ end
349
+
350
+ end
351
+ end
352
+
353
+ it 'should call the corresponding input method' do
354
+ [:select, :time_zone, :radio, :date, :datetime, :time, :boolean, :check_boxes, :hidden].each do |input_style|
355
+ @new_post.stub!(:generic_column_name)
356
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
357
+ semantic_form_for(@new_post) do |builder|
358
+ builder.should_receive(:"#{input_style}_input").once.and_return("fake HTML output from #input")
359
+ concat(builder.input(:generic_column_name, :as => input_style))
360
+ end
361
+ end
362
+
363
+ Formtastic::SemanticFormBuilder::INPUT_MAPPINGS.keys.each do |input_style|
364
+ @new_post.stub!(:generic_column_name)
365
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
366
+ semantic_form_for(@new_post) do |builder|
367
+ builder.should_receive(:input_simple).once.and_return("fake HTML output from #input")
368
+ concat(builder.input(:generic_column_name, :as => input_style))
369
+ end
370
+ end
371
+ end
372
+
373
+ end
374
+
375
+ describe ':label option' do
376
+
377
+ describe 'when provided' do
378
+ it 'should be passed down to the label tag' do
379
+ semantic_form_for(@new_post) do |builder|
380
+ concat(builder.input(:title, :label => "Kustom"))
381
+ end
382
+ output_buffer.should have_tag("form li label", /Kustom/)
383
+ end
384
+
385
+ it 'should not generate a label if false' do
386
+ semantic_form_for(@new_post) do |builder|
387
+ concat(builder.input(:title, :label => false))
388
+ end
389
+ output_buffer.should_not have_tag("form li label")
390
+ end
391
+
392
+ it 'should be dupped if frozen' do
393
+ semantic_form_for(@new_post) do |builder|
394
+ concat(builder.input(:title, :label => "Kustom".freeze))
395
+ end
396
+ output_buffer.should have_tag("form li label", /Kustom/)
397
+ end
398
+ end
399
+
400
+ describe 'when not provided' do
401
+ describe 'when localized label is NOT provided' do
402
+ describe 'and object is not given' do
403
+ it 'should default the humanized method name, passing it down to the label tag' do
404
+ Formtastic::SemanticFormBuilder.label_str_method = :humanize
405
+
406
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
407
+ concat(builder.input(:meta_description))
408
+ end
409
+
410
+ output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
411
+ end
412
+ end
413
+
414
+ describe 'and object is given' do
415
+ it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
416
+ @new_post.stub!(:meta_description) # a two word method name
417
+ @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
418
+
419
+ semantic_form_for(@new_post) do |builder|
420
+ concat(builder.input(:meta_description))
421
+ end
422
+
423
+ output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
424
+ end
425
+ end
426
+ end
427
+
428
+ describe 'when localized label is provided' do
429
+ before do
430
+ @localized_label_text = 'Localized title'
431
+ @default_localized_label_text = 'Default localized title'
432
+ ::I18n.backend.store_translations :en,
433
+ :formtastic => {
434
+ :labels => {
435
+ :title => @default_localized_label_text,
436
+ :published => @default_localized_label_text,
437
+ :post => {
438
+ :title => @localized_label_text,
439
+ :published => @default_localized_label_text
440
+ }
441
+ }
442
+ }
443
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
444
+ end
445
+
446
+ it 'should render a label with localized label (I18n)' do
447
+ semantic_form_for(@new_post) do |builder|
448
+ concat(builder.input(:title, :label => true))
449
+ concat(builder.input(:published, :as => :boolean, :label => true))
450
+ end
451
+ output_buffer.should have_tag('form li label', @localized_label_text)
452
+ end
453
+
454
+ it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
455
+ ::I18n.backend.store_translations :en,
456
+ :formtastic => {
457
+ :labels => {
458
+ :post => {
459
+ :title => nil,
460
+ :published => nil
461
+ }
462
+ }
463
+ }
464
+ semantic_form_for(@new_post) do |builder|
465
+ concat(builder.input(:title, :label => true))
466
+ concat(builder.input(:published, :as => :boolean, :label => true))
467
+ end
468
+ output_buffer.should have_tag('form li label', @default_localized_label_text)
469
+ end
470
+ end
471
+ end
472
+
473
+ end
474
+
475
+ describe ':hint option' do
476
+
477
+ describe 'when provided' do
478
+ it 'should be passed down to the paragraph tag' do
479
+ hint_text = "this is the title of the post"
480
+ semantic_form_for(@new_post) do |builder|
481
+ concat(builder.input(:title, :hint => hint_text))
482
+ end
483
+ output_buffer.should have_tag("form li p.inline-hints", hint_text)
484
+ end
485
+ end
486
+
487
+ describe 'when not provided' do
488
+ describe 'when localized hint (I18n) is provided' do
489
+ before do
490
+ @localized_hint_text = "This is the localized hint."
491
+ @default_localized_hint_text = "This is the default localized hint."
492
+ ::I18n.backend.store_translations :en,
493
+ :formtastic => {
494
+ :hints => {
495
+ :title => @default_localized_hint_text,
496
+ :post => {
497
+ :title => @localized_hint_text
498
+ }
499
+ }
500
+ }
501
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
502
+ end
503
+
504
+ describe 'when provided value (hint value) is set to TRUE' do
505
+ it 'should render a hint paragraph containing a localized hint (I18n)' do
506
+ semantic_form_for(@new_post) do |builder|
507
+ concat(builder.input(:title, :hint => true))
508
+ end
509
+ output_buffer.should have_tag('form li p.inline-hints', @localized_hint_text)
510
+ end
511
+
512
+ it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do
513
+ ::I18n.backend.store_translations :en,
514
+ :formtastic => {
515
+ :hints => {
516
+ :post => {
517
+ :title => nil
518
+ }
519
+ }
520
+ }
521
+ semantic_form_for(@new_post) do |builder|
522
+ concat(builder.input(:title, :hint => true))
523
+ end
524
+ output_buffer.should have_tag('form li p.inline-hints', @default_localized_hint_text)
525
+ end
526
+ end
527
+
528
+ describe 'when provided value (label value) is set to FALSE' do
529
+ it 'should not render a hint paragraph' do
530
+ semantic_form_for(@new_post) do |builder|
531
+ concat(builder.input(:title, :hint => false))
532
+ end
533
+ output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text)
534
+ end
535
+ end
536
+ end
537
+
538
+ describe 'when localized hint (I18n) is not provided' do
539
+ it 'should not render a hint paragraph' do
540
+ semantic_form_for(@new_post) do |builder|
541
+ concat(builder.input(:title))
542
+ end
543
+ output_buffer.should_not have_tag('form li p.inline-hints')
544
+ end
545
+ end
546
+ end
547
+
548
+ end
549
+
550
+ describe ':wrapper_html option' do
551
+
552
+ describe 'when provided' do
553
+ it 'should be passed down to the li tag' do
554
+ semantic_form_for(@new_post) do |builder|
555
+ concat(builder.input(:title, :wrapper_html => {:id => :another_id}))
556
+ end
557
+ output_buffer.should have_tag("form li#another_id")
558
+ end
559
+
560
+ it 'should append given classes to li default classes' do
561
+ semantic_form_for(@new_post) do |builder|
562
+ concat(builder.input(:title, :wrapper_html => {:class => :another_class}, :required => true))
563
+ end
564
+ output_buffer.should have_tag("form li.string")
565
+ output_buffer.should have_tag("form li.required")
566
+ output_buffer.should have_tag("form li.another_class")
567
+ output_buffer.should have_tag("form li.title")
568
+ end
569
+
570
+ it 'should allow classes to be an array' do
571
+ semantic_form_for(@new_post) do |builder|
572
+ concat(builder.input(:title, :wrapper_html => {:class => [ :my_class, :another_class ]}))
573
+ end
574
+ output_buffer.should have_tag("form li.string")
575
+ output_buffer.should have_tag("form li.my_class")
576
+ output_buffer.should have_tag("form li.another_class")
577
+ output_buffer.should have_tag("form li.title")
578
+ end
579
+ end
580
+
581
+ describe 'when not provided' do
582
+ it 'should use default id and class' do
583
+ semantic_form_for(@new_post) do |builder|
584
+ concat(builder.input(:title))
585
+ end
586
+ output_buffer.should have_tag("form li#post_title_input")
587
+ output_buffer.should have_tag("form li.string")
588
+ output_buffer.should have_tag("form li.title")
589
+ end
590
+ end
591
+
592
+ end
593
+ end
594
+
595
+ describe ':as any type of input' do
596
+
597
+ it 'should create a list item for each input' do
598
+ semantic_form_for(@new_post) do |builder|
599
+ concat(builder.input(:title))
600
+ concat(builder.input(:body))
601
+ end
602
+ output_buffer.should have_tag('form li', :count => 2)
603
+ end
604
+
605
+ describe 'when there are errors on the object for this method' do
606
+ before do
607
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
608
+ @errors = mock('errors')
609
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
610
+ @new_post.stub!(:errors).and_return(@errors)
611
+ end
612
+
613
+ it 'should apply an errors class to the list item' do
614
+ semantic_form_for(@new_post) do |builder|
615
+ concat(builder.input(:title))
616
+ end
617
+ output_buffer.should have_tag('form li.error')
618
+ end
619
+
620
+ it 'should not wrap the input with the Rails default error wrapping' do
621
+ semantic_form_for(@new_post) do |builder|
622
+ concat(builder.input(:title))
623
+ end
624
+ output_buffer.should_not have_tag('div.fieldWithErrors')
625
+ end
626
+
627
+ it 'should render a paragraph for the errors' do
628
+ Formtastic::SemanticFormBuilder.inline_errors = :sentence
629
+ semantic_form_for(@new_post) do |builder|
630
+ concat(builder.input(:title))
631
+ end
632
+ output_buffer.should have_tag('form li.error p.inline-errors')
633
+ end
634
+
635
+ it 'should not display an error list' do
636
+ Formtastic::SemanticFormBuilder.inline_errors = :list
637
+ semantic_form_for(@new_post) do |builder|
638
+ concat(builder.input(:title))
639
+ end
640
+ output_buffer.should have_tag('form li.error ul.errors')
641
+ end
642
+ end
643
+
644
+ describe 'when there are no errors on the object for this method' do
645
+ before do
646
+ semantic_form_for(@new_post) do |builder|
647
+ concat(builder.input(:title))
648
+ end
649
+ end
650
+
651
+ it 'should not apply an errors class to the list item' do
652
+ output_buffer.should_not have_tag('form li.error')
653
+ end
654
+
655
+ it 'should not render a paragraph for the errors' do
656
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
657
+ end
658
+
659
+ it 'should not display an error list' do
660
+ output_buffer.should_not have_tag('form li.error ul.errors')
661
+ end
662
+ end
663
+
664
+ describe 'when no object is provided' do
665
+ before do
666
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
667
+ concat(builder.input(:title))
668
+ end
669
+ end
670
+
671
+ it 'should not apply an errors class to the list item' do
672
+ output_buffer.should_not have_tag('form li.error')
673
+ end
674
+
675
+ it 'should not render a paragraph for the errors' do
676
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
677
+ end
678
+
679
+ it 'should not display an error list' do
680
+ output_buffer.should_not have_tag('form li.error ul.errors')
681
+ end
682
+ end
683
+ end
684
+
685
+ # Test string_mappings: :string, :password and :numeric
686
+ string_mappings = Formtastic::SemanticFormBuilder::INPUT_MAPPINGS.slice(*Formtastic::SemanticFormBuilder::STRING_MAPPINGS)
687
+ string_mappings.each do |type, template_method|
688
+ describe ":as => #{type.inspect}" do
689
+
690
+ before do
691
+ @new_post.stub!(:title)
692
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => 50))
693
+
694
+ semantic_form_for(@new_post) do |builder|
695
+ concat(builder.input(:title, :as => type))
696
+ end
697
+ end
698
+
699
+ it "should have a #{type} class on the wrapper" do
700
+ output_buffer.should have_tag("form li.#{type}")
701
+ end
702
+
703
+ it 'should have a post_title_input id on the wrapper' do
704
+ output_buffer.should have_tag('form li#post_title_input')
705
+ end
706
+
707
+ it 'should generate a label for the input' do
708
+ output_buffer.should have_tag('form li label')
709
+ output_buffer.should have_tag('form li label[@for="post_title"]')
710
+ output_buffer.should have_tag('form li label', /Title/)
711
+ end
712
+
713
+ input_type = template_method.to_s.split('_').first
714
+
715
+ it "should generate a #{input_type} input" do
716
+ output_buffer.should have_tag("form li input")
717
+ output_buffer.should have_tag("form li input#post_title")
718
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
719
+ output_buffer.should have_tag("form li input[@name=\"post[title]\"]")
720
+ end
721
+
722
+ unless type == :numeric
723
+ it 'should have a maxlength matching the column limit' do
724
+ @new_post.column_for_attribute(:title).limit.should == 50
725
+ output_buffer.should have_tag("form li input[@maxlength='50']")
726
+ end
727
+
728
+ it 'should use default_text_field_size for columns longer than default_text_field_size' do
729
+ default_size = Formtastic::SemanticFormBuilder.default_text_field_size
730
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => default_size * 2))
731
+
732
+ semantic_form_for(@new_post) do |builder|
733
+ concat(builder.input(:title, :as => type))
734
+ end
735
+
736
+ output_buffer.should have_tag("form li input[@size='#{default_size}']")
737
+ end
738
+
739
+ it 'should use the column size for columns shorter than default_text_field_size' do
740
+ column_limit_shorted_than_default = 1
741
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => column_limit_shorted_than_default))
742
+
743
+ semantic_form_for(@new_post) do |builder|
744
+ concat(builder.input(:title, :as => type))
745
+ end
746
+
747
+ output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
748
+ end
749
+ end
750
+
751
+ it 'should use default_text_field_size for methods without database columns' do
752
+ default_size = Formtastic::SemanticFormBuilder.default_text_field_size
753
+ @new_post.stub!(:column_for_attribute).and_return(nil) # Return a nil column
754
+
755
+ semantic_form_for(@new_post) do |builder|
756
+ concat(builder.input(:title, :as => type))
757
+ end
758
+
759
+ output_buffer.should have_tag("form li input[@size='#{default_size}']")
760
+ end
761
+
762
+ it 'should use input_html to style inputs' do
763
+ semantic_form_for(@new_post) do |builder|
764
+ concat(builder.input(:title, :as => type, :input_html => { :class => 'myclass' }))
765
+ end
766
+ output_buffer.should have_tag("form li input.myclass")
767
+ end
768
+
769
+ it 'should consider input_html :id in labels' do
770
+ semantic_form_for(@new_post) do |builder|
771
+ concat(builder.input(:title, :as => type, :input_html => { :id => 'myid' }))
772
+ end
773
+ output_buffer.should have_tag('form li label[@for="myid"]')
774
+ end
775
+
776
+ it 'should generate input and labels even if no object is given' do
777
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
778
+ concat(builder.input(:title, :as => type))
779
+ end
780
+
781
+ output_buffer.should have_tag('form li label')
782
+ output_buffer.should have_tag('form li label[@for="project_title"]')
783
+ output_buffer.should have_tag('form li label', /Title/)
784
+
785
+ output_buffer.should have_tag("form li input")
786
+ output_buffer.should have_tag("form li input#project_title")
787
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
788
+ output_buffer.should have_tag("form li input[@name=\"project[title]\"]")
789
+ end
790
+
791
+ end
792
+ end
793
+
794
+ # Test other mappings that are not strings: :text and :file.
795
+ other_mappings = Formtastic::SemanticFormBuilder::INPUT_MAPPINGS.except(*Formtastic::SemanticFormBuilder::STRING_MAPPINGS)
796
+ other_mappings.each do |type, template_method|
797
+ describe ":as => #{type.inspect}" do
798
+
799
+ before do
800
+ @new_post.stub!(:body)
801
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type))
802
+
803
+ semantic_form_for(@new_post) do |builder|
804
+ concat(builder.input(:body, :as => type))
805
+ end
806
+ end
807
+
808
+ it "should have a #{type} class on the wrapper" do
809
+ output_buffer.should have_tag("form li.#{type}")
810
+ end
811
+
812
+ it 'should have a post_title_input id on the wrapper' do
813
+ output_buffer.should have_tag('form li#post_body_input')
814
+ end
815
+
816
+ it 'should generate a label for the input' do
817
+ output_buffer.should have_tag('form li label')
818
+ output_buffer.should have_tag('form li label[@for="post_body"]')
819
+ output_buffer.should have_tag('form li label', /Body/)
820
+ end
821
+
822
+ input_type = template_method.to_s.gsub(/_field|_/, '')
823
+
824
+ if template_method.to_s =~ /_field$/ # password_field
825
+
826
+ it "should generate a #{input_type} input" do
827
+ output_buffer.should have_tag("form li input")
828
+ output_buffer.should have_tag("form li input#post_body")
829
+ output_buffer.should have_tag("form li input[@name=\"post[body]\"]")
830
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
831
+ end
832
+
833
+ it 'should use input_html to style inputs' do
834
+ semantic_form_for(@new_post) do |builder|
835
+ concat(builder.input(:title, :as => type, :input_html => { :class => 'myclass' }))
836
+ end
837
+ output_buffer.should have_tag("form li input.myclass")
838
+ end
839
+
840
+ else # text_area
841
+
842
+ it "should generate a #{input_type} input" do
843
+ output_buffer.should have_tag("form li #{input_type}")
844
+ output_buffer.should have_tag("form li #{input_type}#post_body")
845
+ output_buffer.should have_tag("form li #{input_type}[@name=\"post[body]\"]")
846
+ end
847
+
848
+ it 'should use input_html to style inputs' do
849
+ semantic_form_for(@new_post) do |builder|
850
+ concat(builder.input(:title, :as => type, :input_html => { :class => 'myclass' }))
851
+ end
852
+ output_buffer.should have_tag("form li #{input_type}.myclass")
853
+ end
854
+
855
+ end
856
+
857
+ describe 'when no object is given' do
858
+ before(:each) do
859
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
860
+ concat(builder.input(:title, :as => type))
861
+ end
862
+ end
863
+
864
+ it 'should generate input' do
865
+ if template_method.to_s =~ /_field$/ # password_field
866
+ output_buffer.should have_tag("form li input")
867
+ output_buffer.should have_tag("form li input#project_title")
868
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
869
+ output_buffer.should have_tag("form li input[@name=\"project[title]\"]")
870
+ else
871
+ output_buffer.should have_tag("form li #{input_type}")
872
+ output_buffer.should have_tag("form li #{input_type}#project_title")
873
+ output_buffer.should have_tag("form li #{input_type}[@name=\"project[title]\"]")
874
+ end
875
+ end
876
+
877
+ it 'should generate labels' do
878
+ output_buffer.should have_tag('form li label')
879
+ output_buffer.should have_tag('form li label[@for="project_title"]')
880
+ output_buffer.should have_tag('form li label', /Title/)
881
+ end
882
+ end
883
+
884
+ end
885
+ end
886
+
887
+ describe ":as => :hidden" do
888
+ before do
889
+ @new_post.stub!(:secret)
890
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
891
+
892
+ semantic_form_for(@new_post) do |builder|
893
+ concat(builder.input(:secret, :as => :hidden))
894
+ end
895
+ end
896
+
897
+ it "should have a hidden class on the wrapper" do
898
+ output_buffer.should have_tag('form li.hidden')
899
+ end
900
+
901
+ it 'should have a post_hidden_input id on the wrapper' do
902
+ output_buffer.should have_tag('form li#post_secret_input')
903
+ end
904
+
905
+ it 'should not generate a label for the input' do
906
+ output_buffer.should_not have_tag('form li label')
907
+ end
908
+
909
+ it "should generate a input field" do
910
+ output_buffer.should have_tag("form li input#post_secret")
911
+ output_buffer.should have_tag("form li input[@type=\"hidden\"]")
912
+ output_buffer.should have_tag("form li input[@name=\"post[secret]\"]")
913
+ end
914
+
915
+ it "should not render inline errors" do
916
+ @errors = mock('errors')
917
+ @errors.stub!(:[]).with(:secret).and_return(["foo", "bah"])
918
+ @new_post.stub!(:errors).and_return(@errors)
919
+
920
+ semantic_form_for(@new_post) do |builder|
921
+ concat(builder.input(:secret, :as => :hidden))
922
+ end
923
+
924
+ output_buffer.should_not have_tag("form li p.inline-errors")
925
+ output_buffer.should_not have_tag("form li ul.errors")
926
+ end
927
+
928
+ end
929
+
930
+ describe ":as => :time_zone" do
931
+ before do
932
+ @new_post.stub!(:time_zone)
933
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
934
+
935
+ semantic_form_for(@new_post) do |builder|
936
+ concat(builder.input(:time_zone))
937
+ end
938
+ end
939
+
940
+ it "should have a time_zone class on the wrapper" do
941
+ output_buffer.should have_tag('form li.time_zone')
942
+ end
943
+
944
+ it 'should have a post_title_input id on the wrapper' do
945
+ output_buffer.should have_tag('form li#post_time_zone_input')
946
+ end
947
+
948
+ it 'should generate a label for the input' do
949
+ output_buffer.should have_tag('form li label')
950
+ output_buffer.should have_tag('form li label[@for="post_time_zone"]')
951
+ output_buffer.should have_tag('form li label', /Time zone/)
952
+ end
953
+
954
+ it "should generate a select" do
955
+ output_buffer.should have_tag("form li select")
956
+ output_buffer.should have_tag("form li select#post_time_zone")
957
+ output_buffer.should have_tag("form li select[@name=\"post[time_zone]\"]")
958
+ end
959
+
960
+ it 'should use input_html to style inputs' do
961
+ semantic_form_for(@new_post) do |builder|
962
+ concat(builder.input(:time_zone, :input_html => { :class => 'myclass' }))
963
+ end
964
+ output_buffer.should have_tag("form li select.myclass")
965
+ end
966
+
967
+ describe 'when no object is given' do
968
+ before(:each) do
969
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
970
+ concat(builder.input(:time_zone, :as => :time_zone))
971
+ end
972
+ end
973
+
974
+ it 'should generate labels' do
975
+ output_buffer.should have_tag('form li label')
976
+ output_buffer.should have_tag('form li label[@for="project_time_zone"]')
977
+ output_buffer.should have_tag('form li label', /Time zone/)
978
+ end
979
+
980
+ it 'should generate select inputs' do
981
+ output_buffer.should have_tag("form li select")
982
+ output_buffer.should have_tag("form li select#project_time_zone")
983
+ output_buffer.should have_tag("form li select[@name=\"project[time_zone]\"]")
984
+ end
985
+ end
986
+ end
987
+
988
+ describe ":as => :country" do
989
+
990
+ before do
991
+ @new_post.stub!(:country)
992
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
993
+ end
994
+
995
+ describe "when country_select is not available as a helper from a plugin" do
996
+
997
+ it "should raise an error, sugesting the author installs a plugin" do
998
+ lambda {
999
+ semantic_form_for(@new_post) do |builder|
1000
+ concat(builder.input(:country, :as => :country))
1001
+ end
1002
+ }.should raise_error
1003
+ end
1004
+
1005
+ end
1006
+
1007
+ describe "when country_select is available as a helper (from a plugin)" do
1008
+
1009
+ before do
1010
+ semantic_form_for(@new_post) do |builder|
1011
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1012
+ concat(builder.input(:country, :as => :country))
1013
+ end
1014
+ end
1015
+
1016
+ it "should have a time_zone class on the wrapper" do
1017
+ output_buffer.should have_tag('form li.country')
1018
+ end
1019
+
1020
+ it 'should have a post_title_input id on the wrapper' do
1021
+ output_buffer.should have_tag('form li#post_country_input')
1022
+ end
1023
+
1024
+ it 'should generate a label for the input' do
1025
+ output_buffer.should have_tag('form li label')
1026
+ output_buffer.should have_tag('form li label[@for="post_country"]')
1027
+ output_buffer.should have_tag('form li label', /Country/)
1028
+ end
1029
+
1030
+ it "should generate a select" do
1031
+ output_buffer.should have_tag("form li select")
1032
+ end
1033
+
1034
+ end
1035
+
1036
+ describe ":priority_countries option" do
1037
+
1038
+ it "should be passed down to the country_select helper when provided" do
1039
+ priority_countries = ["Foo", "Bah"]
1040
+ semantic_form_for(@new_post) do |builder|
1041
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1042
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1043
+
1044
+ concat(builder.input(:country, :as => :country, :priority_countries => priority_countries))
1045
+ end
1046
+ end
1047
+
1048
+ it "should default to the @@priority_countries config when absent" do
1049
+ priority_countries = Formtastic::SemanticFormBuilder.priority_countries
1050
+ priority_countries.should_not be_empty
1051
+ priority_countries.should_not be_nil
1052
+
1053
+ semantic_form_for(@new_post) do |builder|
1054
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1055
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1056
+
1057
+ concat(builder.input(:country, :as => :country))
1058
+ end
1059
+ end
1060
+
1061
+ end
1062
+
1063
+ end
1064
+
1065
+ describe ':as => :radio' do
1066
+
1067
+ before do
1068
+ @new_post.stub!(:author).and_return(@bob)
1069
+ @new_post.stub!(:author_id).and_return(@bob.id)
1070
+ ::Post.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => ::Author, :macro => :belongs_to) }
1071
+ end
1072
+
1073
+ describe 'for belongs_to association' do
1074
+ before do
1075
+ semantic_form_for(@new_post) do |builder|
1076
+ concat(builder.input(:author, :as => :radio, :value_as_class => true))
1077
+ end
1078
+ end
1079
+
1080
+ it 'should have a radio class on the wrapper' do
1081
+ output_buffer.should have_tag('form li.radio')
1082
+ end
1083
+
1084
+ it 'should have a post_author_input id on the wrapper' do
1085
+ output_buffer.should have_tag('form li#post_author_input')
1086
+ end
1087
+
1088
+ it 'should generate a fieldset and legend containing label text for the input' do
1089
+ output_buffer.should have_tag('form li fieldset')
1090
+ output_buffer.should have_tag('form li fieldset legend')
1091
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1092
+ end
1093
+
1094
+ it 'should generate an ordered list with a list item for each choice' do
1095
+ output_buffer.should have_tag('form li fieldset ol')
1096
+ output_buffer.should have_tag('form li fieldset ol li', :count => ::Author.find(:all).size)
1097
+ end
1098
+
1099
+ it 'should have one option with a "checked" attribute' do
1100
+ output_buffer.should have_tag('form li input[@checked]', :count => 1)
1101
+ end
1102
+
1103
+ describe "each choice" do
1104
+
1105
+ it 'should contain a label for the radio input with a nested input and label text' do
1106
+ ::Author.find(:all).each do |author|
1107
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1108
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_id_#{author.id}']")
1109
+ end
1110
+ end
1111
+
1112
+ it 'should use values as li.class when value_as_class is true' do
1113
+ ::Author.find(:all).each do |author|
1114
+ output_buffer.should have_tag("form li fieldset ol li.#{author.id} label")
1115
+ end
1116
+ end
1117
+
1118
+ it "should have a radio input" do
1119
+ ::Author.find(:all).each do |author|
1120
+ output_buffer.should have_tag("form li fieldset ol li label input#post_author_id_#{author.id}")
1121
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1122
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1123
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='post[author_id]']")
1124
+ end
1125
+ end
1126
+
1127
+ it "should mark input as checked if it's the the existing choice" do
1128
+ @new_post.author_id.should == @bob.id
1129
+ @new_post.author.id.should == @bob.id
1130
+ @new_post.author.should == @bob
1131
+
1132
+ semantic_form_for(@new_post) do |builder|
1133
+ concat(builder.input(:author, :as => :radio))
1134
+ end
1135
+
1136
+ output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1137
+ end
1138
+ end
1139
+
1140
+ describe 'and no object is given' do
1141
+ before(:each) do
1142
+ output_buffer.replace ''
1143
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1144
+ concat(builder.input(:author_id, :as => :radio, :collection => ::Author.find(:all)))
1145
+ end
1146
+ end
1147
+
1148
+ it 'should generate a fieldset with legend' do
1149
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1150
+ end
1151
+
1152
+ it 'should generate an li tag for each item in the collection' do
1153
+ output_buffer.should have_tag('form li fieldset ol li', :count => ::Author.find(:all).size)
1154
+ end
1155
+
1156
+ it 'should generate labels for each item' do
1157
+ ::Author.find(:all).each do |author|
1158
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1159
+ output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1160
+ end
1161
+ end
1162
+
1163
+ it 'should generate inputs for each item' do
1164
+ ::Author.find(:all).each do |author|
1165
+ output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1166
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1167
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1168
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id]']")
1169
+ end
1170
+ end
1171
+ end
1172
+ end
1173
+ end
1174
+
1175
+ describe ':as => :select' do
1176
+
1177
+ before do
1178
+ @new_post.stub!(:author).and_return(@bob)
1179
+ @new_post.stub!(:author_id).and_return(@bob.id)
1180
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1181
+ end
1182
+
1183
+ describe 'for a belongs_to association' do
1184
+ before do
1185
+ semantic_form_for(@new_post) do |builder|
1186
+ concat(builder.input(:author, :as => :select))
1187
+ end
1188
+ end
1189
+
1190
+ it 'should have a select class on the wrapper' do
1191
+ output_buffer.should have_tag('form li.select')
1192
+ end
1193
+
1194
+ it 'should have a post_author_input id on the wrapper' do
1195
+ output_buffer.should have_tag('form li#post_author_input')
1196
+ end
1197
+
1198
+ it 'should have a label inside the wrapper' do
1199
+ output_buffer.should have_tag('form li label')
1200
+ output_buffer.should have_tag('form li label', /Author/)
1201
+ output_buffer.should have_tag("form li label[@for='post_author_id']")
1202
+ end
1203
+
1204
+ it 'should have a select inside the wrapper' do
1205
+ output_buffer.should have_tag('form li select')
1206
+ output_buffer.should have_tag('form li select#post_author_id')
1207
+ end
1208
+
1209
+ it 'should not create a multi-select' do
1210
+ output_buffer.should_not have_tag('form li select[@multiple]')
1211
+ end
1212
+
1213
+ it 'should create a select without size' do
1214
+ output_buffer.should_not have_tag('form li select[@size]')
1215
+ end
1216
+
1217
+ it 'should have a blank option' do
1218
+ output_buffer.should have_tag("form li select option[@value='']")
1219
+ end
1220
+
1221
+ it 'should have a select option for each Author' do
1222
+ output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size + 1)
1223
+ ::Author.find(:all).each do |author|
1224
+ output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1225
+ end
1226
+ end
1227
+
1228
+ it 'should have one option with a "selected" attribute' do
1229
+ output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1230
+ end
1231
+
1232
+ it 'should not singularize the association name' do
1233
+ @new_post.stub!(:author_status).and_return(@bob)
1234
+ @new_post.stub!(:author_status_id).and_return(@bob.id)
1235
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1236
+
1237
+ semantic_form_for(@new_post) do |builder|
1238
+ concat(builder.input(:author_status, :as => :select))
1239
+ end
1240
+
1241
+ output_buffer.should have_tag('form li select#post_author_status_id')
1242
+ end
1243
+ end
1244
+
1245
+ describe 'for a has_many association' do
1246
+ before do
1247
+ semantic_form_for(@fred) do |builder|
1248
+ concat(builder.input(:posts, :as => :select))
1249
+ end
1250
+ end
1251
+
1252
+ it 'should have a select class on the wrapper' do
1253
+ output_buffer.should have_tag('form li.select')
1254
+ end
1255
+
1256
+ it 'should have a post_author_input id on the wrapper' do
1257
+ output_buffer.should have_tag('form li#author_posts_input')
1258
+ end
1259
+
1260
+ it 'should have a label inside the wrapper' do
1261
+ output_buffer.should have_tag('form li label')
1262
+ output_buffer.should have_tag('form li label', /Post/)
1263
+ output_buffer.should have_tag("form li label[@for='author_post_ids']")
1264
+ end
1265
+
1266
+ it 'should have a select inside the wrapper' do
1267
+ output_buffer.should have_tag('form li select')
1268
+ output_buffer.should have_tag('form li select#author_post_ids')
1269
+ end
1270
+
1271
+ it 'should have a multi-select select' do
1272
+ output_buffer.should have_tag('form li select[@multiple="multiple"]')
1273
+ end
1274
+
1275
+ it 'should have a select option for each Post' do
1276
+ output_buffer.should have_tag('form li select option', :count => ::Post.find(:all).size)
1277
+ ::Post.find(:all).each do |post|
1278
+ output_buffer.should have_tag("form li select option[@value='#{post.id}']", /#{post.to_label}/)
1279
+ end
1280
+ end
1281
+
1282
+ it 'should not have a blank option' do
1283
+ output_buffer.should_not have_tag("form li select option[@value='']")
1284
+ end
1285
+
1286
+ it 'should have one option with a "selected" attribute' do
1287
+ output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1288
+ end
1289
+ end
1290
+
1291
+ describe 'for a has_and_belongs_to_many association' do
1292
+ before do
1293
+ semantic_form_for(@freds_post) do |builder|
1294
+ concat(builder.input(:authors, :as => :select))
1295
+ end
1296
+ end
1297
+
1298
+ it 'should have a select class on the wrapper' do
1299
+ output_buffer.should have_tag('form li.select')
1300
+ end
1301
+
1302
+ it 'should have a post_author_input id on the wrapper' do
1303
+ output_buffer.should have_tag('form li#post_authors_input')
1304
+ end
1305
+
1306
+ it 'should have a label inside the wrapper' do
1307
+ output_buffer.should have_tag('form li label')
1308
+ output_buffer.should have_tag('form li label', /Author/)
1309
+ output_buffer.should have_tag("form li label[@for='post_author_ids']")
1310
+ end
1311
+
1312
+ it 'should have a select inside the wrapper' do
1313
+ output_buffer.should have_tag('form li select')
1314
+ output_buffer.should have_tag('form li select#post_author_ids')
1315
+ end
1316
+
1317
+ it 'should have a multi-select select' do
1318
+ output_buffer.should have_tag('form li select[@multiple="multiple"]')
1319
+ end
1320
+
1321
+ it 'should have a select option for each Author' do
1322
+ output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size)
1323
+ ::Author.find(:all).each do |author|
1324
+ output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1325
+ end
1326
+ end
1327
+
1328
+ it 'should not have a blank option' do
1329
+ output_buffer.should_not have_tag("form li select option[@value='']")
1330
+ end
1331
+
1332
+ it 'should have one option with a "selected" attribute' do
1333
+ output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1334
+ end
1335
+ end
1336
+
1337
+ describe 'when :prompt => "choose something" is set' do
1338
+ before do
1339
+ @new_post.stub!(:author_id).and_return(nil)
1340
+ semantic_form_for(@new_post) do |builder|
1341
+ concat(builder.input(:author, :as => :select, :prompt => "choose author"))
1342
+ end
1343
+ end
1344
+
1345
+ it 'should have a select with prompt' do
1346
+ output_buffer.should have_tag("form li select option[@value='']", /choose author/)
1347
+ end
1348
+
1349
+ it 'should not have a blank select option' do
1350
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
1351
+ end
1352
+ end
1353
+
1354
+ describe 'when no object is given' do
1355
+ before(:each) do
1356
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1357
+ concat(builder.input(:author, :as => :select, :collection => ::Author.find(:all)))
1358
+ end
1359
+ end
1360
+
1361
+ it 'should generate label' do
1362
+ output_buffer.should have_tag('form li label', /Author/)
1363
+ output_buffer.should have_tag("form li label[@for='project_author']")
1364
+ end
1365
+
1366
+ it 'should generate select inputs' do
1367
+ output_buffer.should have_tag('form li select#project_author')
1368
+ output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size + 1)
1369
+ end
1370
+
1371
+ it 'should generate an option to each item' do
1372
+ ::Author.find(:all).each do |author|
1373
+ output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1374
+ end
1375
+ end
1376
+ end
1377
+ end
1378
+
1379
+ describe ':as => :check_boxes' do
1380
+
1381
+ describe 'for a has_many association' do
1382
+ before do
1383
+ semantic_form_for(@fred) do |builder|
1384
+ concat(builder.input(:posts, :as => :check_boxes, :value_as_class => true))
1385
+ end
1386
+ end
1387
+
1388
+ it 'should have a check_boxes class on the wrapper' do
1389
+ output_buffer.should have_tag('form li.check_boxes')
1390
+ end
1391
+
1392
+ it 'should have a author_posts_input id on the wrapper' do
1393
+ output_buffer.should have_tag('form li#author_posts_input')
1394
+ end
1395
+
1396
+ it 'should generate a fieldset and legend containing label text for the input' do
1397
+ output_buffer.should have_tag('form li fieldset')
1398
+ output_buffer.should have_tag('form li fieldset legend')
1399
+ output_buffer.should have_tag('form li fieldset legend', /Posts/)
1400
+ end
1401
+
1402
+ it 'should generate an ordered list with a list item for each choice' do
1403
+ output_buffer.should have_tag('form li fieldset ol')
1404
+ output_buffer.should have_tag('form li fieldset ol li', :count => ::Post.find(:all).size)
1405
+ end
1406
+
1407
+ it 'should have one option with a "checked" attribute' do
1408
+ output_buffer.should have_tag('form li input[@checked]', :count => 1)
1409
+ end
1410
+
1411
+ it 'should generate hidden inputs with default value blank' do
1412
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='hidden'][@value='']", :count => ::Post.find(:all).size)
1413
+ end
1414
+
1415
+ describe "each choice" do
1416
+
1417
+ it 'should contain a label for the radio input with a nested input and label text' do
1418
+ ::Post.find(:all).each do |post|
1419
+ output_buffer.should have_tag('form li fieldset ol li label', /#{post.to_label}/)
1420
+ output_buffer.should have_tag("form li fieldset ol li label[@for='author_post_ids_#{post.id}']")
1421
+ end
1422
+ end
1423
+
1424
+ it 'should use values as li.class when value_as_class is true' do
1425
+ ::Post.find(:all).each do |post|
1426
+ output_buffer.should have_tag("form li fieldset ol li.#{post.id} label")
1427
+ end
1428
+ end
1429
+
1430
+ it 'should have a checkbox input for each post' do
1431
+ ::Post.find(:all).each do |post|
1432
+ output_buffer.should have_tag("form li fieldset ol li label input#author_post_ids_#{post.id}")
1433
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='author[post_ids][]']", :count => 2)
1434
+ end
1435
+ end
1436
+
1437
+ it "should mark input as checked if it's the the existing choice" do
1438
+ ::Post.find(:all).include?(@fred.posts.first).should be_true
1439
+ output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1440
+ end
1441
+ end
1442
+
1443
+ describe 'and no object is given' do
1444
+ before(:each) do
1445
+ output_buffer.replace ''
1446
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1447
+ concat(builder.input(:author_id, :as => :check_boxes, :collection => ::Author.find(:all)))
1448
+ end
1449
+ end
1450
+
1451
+ it 'should generate a fieldset with legend' do
1452
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1453
+ end
1454
+
1455
+ it 'shold generate an li tag for each item in the collection' do
1456
+ output_buffer.should have_tag('form li fieldset ol li', :count => ::Author.find(:all).size)
1457
+ end
1458
+
1459
+ it 'should generate labels for each item' do
1460
+ ::Author.find(:all).each do |author|
1461
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1462
+ output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1463
+ end
1464
+ end
1465
+
1466
+ it 'should generate inputs for each item' do
1467
+ ::Author.find(:all).each do |author|
1468
+ output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1469
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='checkbox']")
1470
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1471
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id][]']")
1472
+ end
1473
+ end
1474
+ end
1475
+ end
1476
+ end
1477
+
1478
+ describe 'for collections' do
1479
+
1480
+ before do
1481
+ @new_post.stub!(:author).and_return(@bob)
1482
+ @new_post.stub!(:author_id).and_return(@bob.id)
1483
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1484
+ end
1485
+
1486
+ { :select => :option, :radio => :input, :check_boxes => :'input[@type="checkbox"]' }.each do |type, countable|
1487
+
1488
+ describe ":as => #{type.inspect}" do
1489
+
1490
+ describe 'when the :collection option is not provided' do
1491
+ it 'should perform a basic find on the association class' do
1492
+ ::Author.should_receive(:find)
1493
+
1494
+ semantic_form_for(@new_post) do |builder|
1495
+ concat(builder.input(:author, :as => type))
1496
+ end
1497
+ end
1498
+ end
1499
+
1500
+ describe 'when the :collection option is provided' do
1501
+
1502
+ before do
1503
+ @authors = ::Author.find(:all) * 2
1504
+ output_buffer.replace '' # clears the output_buffer from the before block, hax!
1505
+ end
1506
+
1507
+ it 'should not call find() on the parent class' do
1508
+ ::Author.should_not_receive(:find)
1509
+ semantic_form_for(@new_post) do |builder|
1510
+ concat(builder.input(:author, :as => type, :collection => @authors))
1511
+ end
1512
+ end
1513
+
1514
+ it 'should use the provided collection' do
1515
+ semantic_form_for(@new_post) do |builder|
1516
+ concat(builder.input(:author, :as => type, :collection => @authors))
1517
+ end
1518
+ output_buffer.should have_tag("form li.#{type} #{countable}", :count => @authors.size + (type == :select ? 1 : 0))
1519
+ end
1520
+
1521
+ describe 'and the :collection is an array of strings' do
1522
+ before do
1523
+ @new_post.stub!(:category_name).and_return('')
1524
+ @categories = [ 'General', 'Design', 'Development', 'Quasi-Serious Inventions' ]
1525
+ end
1526
+
1527
+ it "should use the string as the label text and value for each #{countable}" do
1528
+ semantic_form_for(@new_post) do |builder|
1529
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1530
+ end
1531
+
1532
+ @categories.each do |value|
1533
+ output_buffer.should have_tag("form li.#{type}", /#{value}/)
1534
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1535
+ end
1536
+ end
1537
+
1538
+ if type == :radio
1539
+ it 'should generate a sanitized label for attribute' do
1540
+ @bob.stub!(:category_name).and_return(@categories)
1541
+ semantic_form_for(@new_post) do |builder|
1542
+ builder.semantic_fields_for(@bob) do |bob_builder|
1543
+ concat(bob_builder.input(:category_name, :as => type, :collection => @categories))
1544
+ end
1545
+ end
1546
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_general']")
1547
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_design']")
1548
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_development']")
1549
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_quasiserious_inventions']")
1550
+ end
1551
+ end
1552
+ end
1553
+
1554
+ describe 'and the :collection is a hash of strings' do
1555
+ before do
1556
+ @new_post.stub!(:category_name).and_return('')
1557
+ @categories = { 'General' => 'gen', 'Design' => 'des','Development' => 'dev' }
1558
+ end
1559
+
1560
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
1561
+ semantic_form_for(@new_post) do |builder|
1562
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1563
+ end
1564
+
1565
+ @categories.each do |label, value|
1566
+ output_buffer.should have_tag("form li.#{type}", /#{label}/)
1567
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1568
+ end
1569
+ end
1570
+ end
1571
+
1572
+ describe 'and the :collection is an array of arrays' do
1573
+ before do
1574
+ @new_post.stub!(:category_name).and_return('')
1575
+ @categories = { 'General' => 'gen', 'Design' => 'des', 'Development' => 'dev' }.to_a
1576
+ end
1577
+
1578
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
1579
+ semantic_form_for(@new_post) do |builder|
1580
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1581
+ end
1582
+
1583
+ @categories.each do |text, value|
1584
+ label = type == :select ? :option : :label
1585
+ output_buffer.should have_tag("form li.#{type} #{label}", /#{text}/i)
1586
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1587
+ output_buffer.should have_tag("form li.#{type} #{countable}#post_category_name_#{value.to_s}") if type == :radio
1588
+ end
1589
+ end
1590
+ end
1591
+
1592
+ if type == :radio
1593
+ describe 'and the :collection is an array of arrays with boolean values' do
1594
+ before do
1595
+ @new_post.stub!(:category_name).and_return('')
1596
+ @choices = { 'Yeah' => true, 'Nah' => false }.to_a
1597
+ end
1598
+
1599
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
1600
+ semantic_form_for(@new_post) do |builder|
1601
+ concat(builder.input(:category_name, :as => type, :collection => @choices))
1602
+ end
1603
+
1604
+ output_buffer.should have_tag("form li.#{type} #{countable}#post_category_name_true")
1605
+ output_buffer.should have_tag("form li.#{type} #{countable}#post_category_name_false")
1606
+ end
1607
+ end
1608
+ end
1609
+
1610
+
1611
+ describe 'and the :collection is an array of symbols' do
1612
+ before do
1613
+ @new_post.stub!(:category_name).and_return('')
1614
+ @categories = [ :General, :Design, :Development ]
1615
+ end
1616
+
1617
+ it "should use the symbol as the label text and value for each #{countable}" do
1618
+ semantic_form_for(@new_post) do |builder|
1619
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1620
+ end
1621
+
1622
+ @categories.each do |value|
1623
+ label = type == :select ? :option : :label
1624
+ output_buffer.should have_tag("form li.#{type} #{label}", /#{value}/i)
1625
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1626
+ end
1627
+ end
1628
+ end
1629
+
1630
+ describe 'and the :collection is an OrderedHash of strings' do
1631
+ before do
1632
+ @new_post.stub!(:category_name).and_return('')
1633
+ @categories = ActiveSupport::OrderedHash.new('General' => 'gen', 'Design' => 'des','Development' => 'dev')
1634
+ end
1635
+
1636
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
1637
+ semantic_form_for(@new_post) do |builder|
1638
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1639
+ end
1640
+
1641
+ @categories.each do |label, value|
1642
+ output_buffer.should have_tag("form li.#{type}", /#{label}/)
1643
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1644
+ end
1645
+ end
1646
+
1647
+ end
1648
+
1649
+ describe 'when the :label_method option is provided' do
1650
+
1651
+ describe 'as a symbol' do
1652
+ before do
1653
+ semantic_form_for(@new_post) do |builder|
1654
+ concat(builder.input(:author, :as => type, :label_method => :login))
1655
+ end
1656
+ end
1657
+
1658
+ it 'should have options with text content from the specified method' do
1659
+ ::Author.find(:all).each do |author|
1660
+ output_buffer.should have_tag("form li.#{type}", /#{author.login}/)
1661
+ end
1662
+ end
1663
+ end
1664
+
1665
+ describe 'as a proc' do
1666
+ before do
1667
+ semantic_form_for(@new_post) do |builder|
1668
+ concat(builder.input(:author, :as => type, :label_method => Proc.new {|a| a.login.reverse }))
1669
+ end
1670
+ end
1671
+
1672
+ it 'should have options with the proc applied to each' do
1673
+ ::Author.find(:all).each do |author|
1674
+ output_buffer.should have_tag("form li.#{type}", /#{author.login.reverse}/)
1675
+ end
1676
+ end
1677
+ end
1678
+
1679
+ end
1680
+
1681
+ describe 'when the :label_method option is not provided' do
1682
+ Formtastic::SemanticFormBuilder.collection_label_methods.each do |label_method|
1683
+
1684
+ describe "when the collection objects respond to #{label_method}" do
1685
+ before do
1686
+ @fred.stub!(:respond_to?).and_return { |m| m.to_s == label_method }
1687
+ ::Author.find(:all).each { |a| a.stub!(label_method).and_return('The Label Text') }
1688
+
1689
+ semantic_form_for(@new_post) do |builder|
1690
+ concat(builder.input(:author, :as => type))
1691
+ end
1692
+ end
1693
+
1694
+ it "should render the options with #{label_method} as the label" do
1695
+ ::Author.find(:all).each do |author|
1696
+ output_buffer.should have_tag("form li.#{type}", /The Label Text/)
1697
+ end
1698
+ end
1699
+ end
1700
+
1701
+ end
1702
+ end
1703
+
1704
+ describe 'when the :value_method option is provided' do
1705
+
1706
+ describe 'as a symbol' do
1707
+ before do
1708
+ semantic_form_for(@new_post) do |builder|
1709
+ concat(builder.input(:author, :as => type, :value_method => :login))
1710
+ end
1711
+ end
1712
+
1713
+ it 'should have options with values from specified method' do
1714
+ ::Author.find(:all).each do |author|
1715
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{author.login}']")
1716
+ end
1717
+ end
1718
+ end
1719
+
1720
+ describe 'as a proc' do
1721
+ before do
1722
+ semantic_form_for(@new_post) do |builder|
1723
+ concat(builder.input(:author, :as => type, :value_method => Proc.new {|a| a.login.reverse }))
1724
+ end
1725
+ end
1726
+
1727
+ it 'should have options with the proc applied to each value' do
1728
+ ::Author.find(:all).each do |author|
1729
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{author.login.reverse}']")
1730
+ end
1731
+ end
1732
+ end
1733
+ end
1734
+
1735
+ end
1736
+ end
1737
+ end
1738
+
1739
+ describe 'for boolean attributes' do
1740
+
1741
+ { :select => :option, :radio => :input }.each do |type, countable|
1742
+ checked_or_selected = { :select => :selected, :radio => :checked }[type]
1743
+
1744
+ describe ":as => #{type.inspect}" do
1745
+
1746
+ before do
1747
+ @new_post.stub!(:allow_comments)
1748
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1749
+
1750
+ semantic_form_for(@new_post) do |builder|
1751
+ concat(builder.input(:allow_comments, :as => type))
1752
+ end
1753
+ end
1754
+
1755
+ it "should have a #{type} class on the wrapper" do
1756
+ output_buffer.should have_tag("form li.#{type}")
1757
+ end
1758
+
1759
+ it 'should have a post_allow_comments_input id on the wrapper' do
1760
+ output_buffer.should have_tag('form li#post_allow_comments_input')
1761
+ end
1762
+
1763
+ it 'should generate a fieldset containing a legend' do
1764
+ output_buffer.should have_tag("form li.#{type}", /Allow comments/)
1765
+ end
1766
+
1767
+ it "should generate two #{countable}" do
1768
+ output_buffer.should have_tag("form li.#{type} #{countable}", :count => (type == :select ? 3 : 2))
1769
+ output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="true"]})
1770
+ output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="false"]})
1771
+ end
1772
+
1773
+ describe 'when the locale sets the label text' do
1774
+ before do
1775
+ I18n.backend.store_translations 'en', :formtastic => {:yes => 'Absolutely!', :no => 'Never!'}
1776
+
1777
+ semantic_form_for(@new_post) do |builder|
1778
+ concat(builder.input(:allow_comments, :as => type))
1779
+ end
1780
+ end
1781
+
1782
+ after do
1783
+ I18n.backend.store_translations 'en', :formtastic => {:yes => nil, :no => nil}
1784
+ end
1785
+
1786
+ it 'should allow translation of the labels' do
1787
+ output_buffer.should have_tag("form li.#{type}", /Absolutely\!/)
1788
+ output_buffer.should have_tag("form li.#{type}", /Never\!/)
1789
+ end
1790
+ end
1791
+
1792
+ describe 'when the value is nil' do
1793
+ before do
1794
+ @new_post.stub!(:allow_comments).and_return(nil)
1795
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1796
+
1797
+ semantic_form_for(@new_post) do |builder|
1798
+ concat(builder.input(:allow_comments, :as => type))
1799
+ end
1800
+ end
1801
+
1802
+ it "should not mark either #{countable} as #{checked_or_selected}" do
1803
+ output_buffer.should_not have_tag(%{form li.#{type} input[@#{checked_or_selected}="#{checked_or_selected}"]})
1804
+ end
1805
+ end
1806
+
1807
+ describe 'when the value is true' do
1808
+ before do
1809
+ @new_post.stub!(:allow_comments).and_return(true)
1810
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1811
+ semantic_form_for(@new_post) do |builder|
1812
+ concat(builder.input(:allow_comments, :as => type))
1813
+ end
1814
+ end
1815
+
1816
+ it "should mark the true #{countable} as #{checked_or_selected}" do
1817
+ output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="true"][@#{checked_or_selected}="#{checked_or_selected}"]}, :count => 1)
1818
+ end
1819
+
1820
+ it "should not mark the false #{countable} as #{checked_or_selected}" do
1821
+ output_buffer.should_not have_tag(%{form li.#{type} #{countable}[@value="false"][@#{checked_or_selected}="#{checked_or_selected}"]})
1822
+ end
1823
+ end
1824
+
1825
+ describe 'when the value is false' do
1826
+ before do
1827
+ @new_post.stub!(:allow_comments).and_return(false)
1828
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1829
+ semantic_form_for(@new_post) do |builder|
1830
+ concat(builder.input(:allow_comments, :as => type))
1831
+ end
1832
+ end
1833
+
1834
+ it "should not mark the true #{countable} as #{checked_or_selected}" do
1835
+ output_buffer.should_not have_tag(%{form li.#{type} #{countable}[@value="true"][@#{checked_or_selected}="#{checked_or_selected}"]})
1836
+ end
1837
+
1838
+ it "should mark the false #{countable} as #{checked_or_selected}" do
1839
+ output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="false"][@#{checked_or_selected}="#{checked_or_selected}"]}, :count => 1)
1840
+ end
1841
+ end
1842
+
1843
+ describe 'when :true and :false options are provided' do
1844
+ before do
1845
+ @new_post.stub!(:allow_comments)
1846
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1847
+ semantic_form_for(@new_post) do |builder|
1848
+ concat(builder.input(:allow_comments, :as => type, :true => "Absolutely", :false => "No Way"))
1849
+ end
1850
+ end
1851
+
1852
+ it 'should use them as labels' do
1853
+ output_buffer.should have_tag("form li.#{type}", /Absolutely/)
1854
+ output_buffer.should have_tag("form li.#{type}", /No Way/)
1855
+ end
1856
+ end
1857
+ end
1858
+
1859
+ end
1860
+ end
1861
+ end
1862
+
1863
+ describe ':as => :date' do
1864
+
1865
+ before do
1866
+ @new_post.stub!(:publish_at)
1867
+ #@new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :date))
1868
+
1869
+ semantic_form_for(@new_post) do |builder|
1870
+ concat(builder.input(:publish_at, :as => :date))
1871
+ @builder = builder
1872
+ end
1873
+ end
1874
+
1875
+ it 'should have a date class on the wrapper li' do
1876
+ output_buffer.should have_tag('form li.date')
1877
+ end
1878
+
1879
+ it 'should have a fieldset inside the li wrapper' do
1880
+ output_buffer.should have_tag('form li.date fieldset')
1881
+ end
1882
+
1883
+ it 'should have a legend containing the label text inside the fieldset' do
1884
+ output_buffer.should have_tag('form li.date fieldset legend', /Publish at/)
1885
+ end
1886
+
1887
+ it 'should have an ordered list of three items inside the fieldset' do
1888
+ output_buffer.should have_tag('form li.date fieldset ol')
1889
+ output_buffer.should have_tag('form li.date fieldset ol li', :count => 3)
1890
+ end
1891
+
1892
+ it 'should have three labels for year, month and day' do
1893
+ output_buffer.should have_tag('form li.date fieldset ol li label', :count => 3)
1894
+ output_buffer.should have_tag('form li.date fieldset ol li label', /year/i)
1895
+ output_buffer.should have_tag('form li.date fieldset ol li label', /month/i)
1896
+ output_buffer.should have_tag('form li.date fieldset ol li label', /day/i)
1897
+ end
1898
+
1899
+ it 'should have three selects for year, month and day' do
1900
+ output_buffer.should have_tag('form li.date fieldset ol li select', :count => 3)
1901
+ end
1902
+ end
1903
+
1904
+ describe ':as => :datetime' do
1905
+
1906
+ before do
1907
+ @new_post.stub!(:publish_at)
1908
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :datetime))
1909
+
1910
+ semantic_form_for(@new_post) do |builder|
1911
+ concat(builder.input(:publish_at, :as => :datetime))
1912
+ end
1913
+ end
1914
+
1915
+ it 'should have a datetime class on the wrapper li' do
1916
+ output_buffer.should have_tag('form li.datetime')
1917
+ end
1918
+
1919
+ it 'should have a fieldset inside the li wrapper' do
1920
+ output_buffer.should have_tag('form li.datetime fieldset')
1921
+ end
1922
+
1923
+ it 'should have a legend containing the label text inside the fieldset' do
1924
+ output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
1925
+ end
1926
+
1927
+ it 'should have an ordered list of five items inside the fieldset' do
1928
+ output_buffer.should have_tag('form li.datetime fieldset ol')
1929
+ output_buffer.should have_tag('form li.datetime fieldset ol li', :count => 5)
1930
+ end
1931
+
1932
+ it 'should have five labels for year, month, day, hour and minute' do
1933
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
1934
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /year/i)
1935
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /month/i)
1936
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /day/i)
1937
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /hour/i)
1938
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /minute/i)
1939
+ end
1940
+
1941
+ it 'should have five selects for year, month, day, hour and minute' do
1942
+ output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
1943
+ end
1944
+
1945
+ it 'should generate a sanitized label and matching ids for attribute' do
1946
+ @bob.stub!(:publish_at)
1947
+ @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :datetime))
1948
+
1949
+ semantic_form_for(@new_post) do |builder|
1950
+ builder.semantic_fields_for(@bob, :index => 10) do |bob_builder|
1951
+ concat(bob_builder.input(:publish_at, :as => :datetime))
1952
+ end
1953
+ end
1954
+
1955
+ 1.upto(5) do |i|
1956
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_10_publish_at_#{i}i']")
1957
+ output_buffer.should have_tag("form li fieldset ol li #post_author_10_publish_at_#{i}i")
1958
+ end
1959
+ end
1960
+
1961
+ describe 'when :discard_input => true is set' do
1962
+ it 'should use default hidden value equals to 1 when attribute returns nil' do
1963
+ semantic_form_for(@new_post) do |builder|
1964
+ concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
1965
+ end
1966
+
1967
+ output_buffer.should have_tag("form li input[@type='hidden'][@value='1']")
1968
+ end
1969
+
1970
+ it 'should use default attribute value when it is not nil' do
1971
+ @new_post.stub!(:publish_at).and_return(Date.new(2007,12,27))
1972
+ semantic_form_for(@new_post) do |builder|
1973
+ concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
1974
+ end
1975
+
1976
+ output_buffer.should have_tag("form li input[@type='hidden'][@value='27']")
1977
+ end
1978
+ end
1979
+
1980
+ describe 'inputs order' do
1981
+ it 'should have a default' do
1982
+ semantic_form_for(@new_post) do |builder|
1983
+ self.should_receive(:select_year).once.ordered.and_return('')
1984
+ self.should_receive(:select_month).once.ordered.and_return('')
1985
+ self.should_receive(:select_day).once.ordered.and_return('')
1986
+ builder.input(:publish_at, :as => :datetime)
1987
+ end
1988
+ end
1989
+
1990
+ it 'should be specified with :order option' do
1991
+ I18n.backend.store_translations 'en', :date => { :order => [:month, :year, :day] }
1992
+ semantic_form_for(@new_post) do |builder|
1993
+ self.should_receive(:select_month).once.ordered.and_return('')
1994
+ self.should_receive(:select_year).once.ordered.and_return('')
1995
+ self.should_receive(:select_day).once.ordered.and_return('')
1996
+ builder.input(:publish_at, :as => :datetime)
1997
+ end
1998
+ end
1999
+
2000
+ it 'should be changed through I18n' do
2001
+ semantic_form_for(@new_post) do |builder|
2002
+ self.should_receive(:select_day).once.ordered.and_return('')
2003
+ self.should_receive(:select_month).once.ordered.and_return('')
2004
+ self.should_receive(:select_year).once.ordered.and_return('')
2005
+ builder.input(:publish_at, :as => :datetime, :order => [:day, :month, :year])
2006
+ end
2007
+ end
2008
+ end
2009
+
2010
+ describe 'when the locale changes the label text' do
2011
+ before do
2012
+ I18n.backend.store_translations 'en', :datetime => {:prompts => {
2013
+ :year => 'The Year', :month => 'The Month', :day => 'The Day',
2014
+ :hour => 'The Hour', :minute => 'The Minute'
2015
+ }}
2016
+ semantic_form_for(@new_post) do |builder|
2017
+ concat(builder.input(:publish_at, :as => :datetime))
2018
+ end
2019
+ end
2020
+
2021
+ after do
2022
+ I18n.backend.store_translations 'en', :formtastic => {
2023
+ :year => nil, :month => nil, :day => nil,
2024
+ :hour => nil, :minute => nil
2025
+ }
2026
+ end
2027
+
2028
+ it 'should have translated labels for year, month, day, hour and minute' do
2029
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Year/)
2030
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Month/)
2031
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Day/)
2032
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Hour/)
2033
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Minute/)
2034
+ end
2035
+ end
2036
+
2037
+ describe 'when no object is given' do
2038
+ before(:each) do
2039
+ output_buffer.replace ''
2040
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
2041
+ concat(builder.input(:publish_at, :as => :datetime))
2042
+ @builder = builder
2043
+ end
2044
+ end
2045
+
2046
+ it 'should have fieldset with legend' do
2047
+ output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
2048
+ end
2049
+
2050
+ it 'should have labels for each input' do
2051
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
2052
+ end
2053
+
2054
+ it 'should have selects for each inputs' do
2055
+ output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
2056
+ end
2057
+ end
2058
+ end
2059
+
2060
+ describe ':as => :time' do
2061
+ before do
2062
+ @new_post.stub!(:publish_at)
2063
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :time))
2064
+
2065
+ semantic_form_for(@new_post) do |builder|
2066
+ concat(builder.input(:publish_at, :as => :time))
2067
+ end
2068
+ end
2069
+
2070
+ it 'should have a time class on the wrapper li' do
2071
+ output_buffer.should have_tag('form li.time')
2072
+ end
2073
+
2074
+ it 'should have a fieldset inside the li wrapper' do
2075
+ output_buffer.should have_tag('form li.time fieldset')
2076
+ end
2077
+
2078
+ it 'should have a legend containing the label text inside the fieldset' do
2079
+ output_buffer.should have_tag('form li.time fieldset legend', /Publish at/)
2080
+ end
2081
+
2082
+ it 'should have an ordered list of two items inside the fieldset' do
2083
+ output_buffer.should have_tag('form li.time fieldset ol')
2084
+ output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
2085
+ end
2086
+
2087
+ it 'should have five labels for hour and minute' do
2088
+ output_buffer.should have_tag('form li.time fieldset ol li label', :count => 2)
2089
+ output_buffer.should have_tag('form li.time fieldset ol li label', /hour/i)
2090
+ output_buffer.should have_tag('form li.time fieldset ol li label', /minute/i)
2091
+ end
2092
+
2093
+ it 'should have two selects for hour and minute' do
2094
+ output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
2095
+ end
2096
+ end
2097
+
2098
+ describe ':as => :boolean' do
2099
+
2100
+ before do
2101
+ @new_post.stub!(:allow_comments)
2102
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
2103
+
2104
+ semantic_form_for(@new_post) do |builder|
2105
+ concat(builder.input(:allow_comments, :as => :boolean))
2106
+ end
2107
+ end
2108
+
2109
+ it 'should have a boolean class on the wrapper' do
2110
+ output_buffer.should have_tag('form li.boolean')
2111
+ end
2112
+
2113
+ it 'should have a post_allow_comments_input id on the wrapper' do
2114
+ output_buffer.should have_tag('form li#post_allow_comments_input')
2115
+ end
2116
+
2117
+ it 'should generate a label containing the input' do
2118
+ output_buffer.should have_tag('form li label', :count => 1)
2119
+ output_buffer.should have_tag('form li label[@for="post_allow_comments"]')
2120
+ output_buffer.should have_tag('form li label', /Allow comments/)
2121
+ output_buffer.should have_tag('form li label input[@type="checkbox"]')
2122
+ end
2123
+
2124
+ it 'should generate a checkbox input' do
2125
+ output_buffer.should have_tag('form li label input')
2126
+ output_buffer.should have_tag('form li label input#post_allow_comments')
2127
+ output_buffer.should have_tag('form li label input[@type="checkbox"]')
2128
+ output_buffer.should have_tag('form li label input[@name="post[allow_comments]"]')
2129
+ output_buffer.should have_tag('form li label input[@type="checkbox"][@value="1"]')
2130
+ end
2131
+
2132
+ it 'should allow checked and unchecked values to be sent' do
2133
+ semantic_form_for(@new_post) do |builder|
2134
+ concat(builder.input(:allow_comments, :as => :boolean, :checked_value => 'checked', :unchecked_value => 'unchecked'))
2135
+ end
2136
+
2137
+ output_buffer.should have_tag('form li label input[@type="checkbox"][@value="checked"]')
2138
+ output_buffer.should have_tag('form li label input[@type="hidden"][@value="unchecked"]')
2139
+ end
2140
+
2141
+ it 'should generate a label and a checkbox even if no object is given' do
2142
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
2143
+ concat(builder.input(:allow_comments, :as => :boolean))
2144
+ end
2145
+
2146
+ output_buffer.should have_tag('form li label[@for="project_allow_comments"]')
2147
+ output_buffer.should have_tag('form li label', /Allow comments/)
2148
+ output_buffer.should have_tag('form li label input[@type="checkbox"]')
2149
+
2150
+ output_buffer.should have_tag('form li label input#project_allow_comments')
2151
+ output_buffer.should have_tag('form li label input[@type="checkbox"]')
2152
+ output_buffer.should have_tag('form li label input[@name="project[allow_comments]"]')
2153
+ end
2154
+
2155
+ end
2156
+ end
2157
+