formtastic 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+