lperichon-formtastic 0.9.2

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,85 @@
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 render a paragraph with the first error when inline_errors config is :first' do
39
+ Formtastic::SemanticFormBuilder.inline_errors = :first
40
+ semantic_form_for(@new_post) do |builder|
41
+ builder.errors_on(:title).should have_tag('p.inline-errors', @title_errors.first)
42
+ end
43
+ end
44
+
45
+ it 'should return nil when inline_errors config is :none' do
46
+ Formtastic::SemanticFormBuilder.inline_errors = :none
47
+ semantic_form_for(@new_post) do |builder|
48
+ builder.errors_on(:title).should be_nil
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ describe 'when there are no errors (nil)' do
55
+ before do
56
+ @errors.stub!(:[]).with(:title).and_return(nil)
57
+ end
58
+
59
+ it 'should return nil when inline_errors config is :sentence, :list or :none' do
60
+ [:sentence, :list, :none].each do |config|
61
+ Formtastic::SemanticFormBuilder.inline_errors = config
62
+ semantic_form_for(@new_post) do |builder|
63
+ builder.errors_on(:title).should be_nil
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ describe 'when there are no errors (empty array)' do
70
+ before do
71
+ @errors.stub!(:[]).with(:title).and_return([])
72
+ end
73
+
74
+ it 'should return nil when inline_errors config is :sentence, :list or :none' do
75
+ [:sentence, :list, :none].each do |config|
76
+ Formtastic::SemanticFormBuilder.inline_errors = config
77
+ semantic_form_for(@new_post) do |builder|
78
+ builder.errors_on(:title).should be_nil
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ end
85
+
@@ -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,2209 @@
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
+ end
568
+
569
+ it 'should allow classes to be an array' do
570
+ semantic_form_for(@new_post) do |builder|
571
+ concat(builder.input(:title, :wrapper_html => {:class => [ :my_class, :another_class ]}))
572
+ end
573
+ output_buffer.should have_tag("form li.string")
574
+ output_buffer.should have_tag("form li.my_class")
575
+ output_buffer.should have_tag("form li.another_class")
576
+ end
577
+ end
578
+
579
+ describe 'when not provided' do
580
+ it 'should use default id and class' do
581
+ semantic_form_for(@new_post) do |builder|
582
+ concat(builder.input(:title))
583
+ end
584
+ output_buffer.should have_tag("form li#post_title_input")
585
+ output_buffer.should have_tag("form li.string")
586
+ end
587
+ end
588
+
589
+ end
590
+ end
591
+
592
+ describe ':as any type of input' do
593
+
594
+ it 'should create a list item for each input' do
595
+ semantic_form_for(@new_post) do |builder|
596
+ concat(builder.input(:title))
597
+ concat(builder.input(:body))
598
+ end
599
+ output_buffer.should have_tag('form li', :count => 2)
600
+ end
601
+
602
+ describe 'when there are errors on the object for this method' do
603
+ before do
604
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
605
+ @errors = mock('errors')
606
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
607
+ @new_post.stub!(:errors).and_return(@errors)
608
+ end
609
+
610
+ it 'should apply an errors class to the list item' do
611
+ semantic_form_for(@new_post) do |builder|
612
+ concat(builder.input(:title))
613
+ end
614
+ output_buffer.should have_tag('form li.error')
615
+ end
616
+
617
+ it 'should not wrap the input with the Rails default error wrapping' do
618
+ semantic_form_for(@new_post) do |builder|
619
+ concat(builder.input(:title))
620
+ end
621
+ output_buffer.should_not have_tag('div.fieldWithErrors')
622
+ end
623
+
624
+ it 'should render a paragraph for the errors' do
625
+ Formtastic::SemanticFormBuilder.inline_errors = :sentence
626
+ semantic_form_for(@new_post) do |builder|
627
+ concat(builder.input(:title))
628
+ end
629
+ output_buffer.should have_tag('form li.error p.inline-errors')
630
+ end
631
+
632
+ it 'should not display an error list' do
633
+ Formtastic::SemanticFormBuilder.inline_errors = :list
634
+ semantic_form_for(@new_post) do |builder|
635
+ concat(builder.input(:title))
636
+ end
637
+ output_buffer.should have_tag('form li.error ul.errors')
638
+ end
639
+ end
640
+
641
+ describe 'when there are no errors on the object for this method' do
642
+ before do
643
+ semantic_form_for(@new_post) do |builder|
644
+ concat(builder.input(:title))
645
+ end
646
+ end
647
+
648
+ it 'should not apply an errors class to the list item' do
649
+ output_buffer.should_not have_tag('form li.error')
650
+ end
651
+
652
+ it 'should not render a paragraph for the errors' do
653
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
654
+ end
655
+
656
+ it 'should not display an error list' do
657
+ output_buffer.should_not have_tag('form li.error ul.errors')
658
+ end
659
+ end
660
+
661
+ describe 'when no object is provided' do
662
+ before do
663
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
664
+ concat(builder.input(:title))
665
+ end
666
+ end
667
+
668
+ it 'should not apply an errors class to the list item' do
669
+ output_buffer.should_not have_tag('form li.error')
670
+ end
671
+
672
+ it 'should not render a paragraph for the errors' do
673
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
674
+ end
675
+
676
+ it 'should not display an error list' do
677
+ output_buffer.should_not have_tag('form li.error ul.errors')
678
+ end
679
+ end
680
+ end
681
+
682
+ # Test string_mappings: :string, :password and :numeric
683
+ string_mappings = Formtastic::SemanticFormBuilder::INPUT_MAPPINGS.slice(*Formtastic::SemanticFormBuilder::STRING_MAPPINGS)
684
+ string_mappings.each do |type, template_method|
685
+ describe ":as => #{type.inspect}" do
686
+
687
+ before do
688
+ @new_post.stub!(:title)
689
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => 50))
690
+
691
+ semantic_form_for(@new_post) do |builder|
692
+ concat(builder.input(:title, :as => type))
693
+ end
694
+ end
695
+
696
+ it "should have a #{type} class on the wrapper" do
697
+ output_buffer.should have_tag("form li.#{type}")
698
+ end
699
+
700
+ it 'should have a post_title_input id on the wrapper' do
701
+ output_buffer.should have_tag('form li#post_title_input')
702
+ end
703
+
704
+ it 'should generate a label for the input' do
705
+ output_buffer.should have_tag('form li label')
706
+ output_buffer.should have_tag('form li label[@for="post_title"]')
707
+ output_buffer.should have_tag('form li label', /Title/)
708
+ end
709
+
710
+ input_type = template_method.to_s.split('_').first
711
+
712
+ it "should generate a #{input_type} input" do
713
+ output_buffer.should have_tag("form li input")
714
+ output_buffer.should have_tag("form li input#post_title")
715
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
716
+ output_buffer.should have_tag("form li input[@name=\"post[title]\"]")
717
+ end
718
+
719
+ unless type == :numeric
720
+ it 'should have a maxlength matching the column limit' do
721
+ @new_post.column_for_attribute(:title).limit.should == 50
722
+ output_buffer.should have_tag("form li input[@maxlength='50']")
723
+ end
724
+
725
+ it 'should use default_text_field_size for columns longer than default_text_field_size' do
726
+ default_size = Formtastic::SemanticFormBuilder.default_text_field_size
727
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => default_size * 2))
728
+
729
+ semantic_form_for(@new_post) do |builder|
730
+ concat(builder.input(:title, :as => type))
731
+ end
732
+
733
+ output_buffer.should have_tag("form li input[@size='#{default_size}']")
734
+ end
735
+
736
+ it 'should use the column size for columns shorter than default_text_field_size' do
737
+ column_limit_shorted_than_default = 1
738
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => column_limit_shorted_than_default))
739
+
740
+ semantic_form_for(@new_post) do |builder|
741
+ concat(builder.input(:title, :as => type))
742
+ end
743
+
744
+ output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
745
+ end
746
+ end
747
+
748
+ it 'should use default_text_field_size for methods without database columns' do
749
+ default_size = Formtastic::SemanticFormBuilder.default_text_field_size
750
+ @new_post.stub!(:column_for_attribute).and_return(nil) # Return a nil column
751
+
752
+ semantic_form_for(@new_post) do |builder|
753
+ concat(builder.input(:title, :as => type))
754
+ end
755
+
756
+ output_buffer.should have_tag("form li input[@size='#{default_size}']")
757
+ end
758
+
759
+ it 'should use input_html to style inputs' do
760
+ semantic_form_for(@new_post) do |builder|
761
+ concat(builder.input(:title, :as => type, :input_html => { :class => 'myclass' }))
762
+ end
763
+ output_buffer.should have_tag("form li input.myclass")
764
+ end
765
+
766
+ it 'should consider input_html :id in labels' do
767
+ semantic_form_for(@new_post) do |builder|
768
+ concat(builder.input(:title, :as => type, :input_html => { :id => 'myid' }))
769
+ end
770
+ output_buffer.should have_tag('form li label[@for="myid"]')
771
+ end
772
+
773
+ it 'should generate input and labels even if no object is given' do
774
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
775
+ concat(builder.input(:title, :as => type))
776
+ end
777
+
778
+ output_buffer.should have_tag('form li label')
779
+ output_buffer.should have_tag('form li label[@for="project_title"]')
780
+ output_buffer.should have_tag('form li label', /Title/)
781
+
782
+ output_buffer.should have_tag("form li input")
783
+ output_buffer.should have_tag("form li input#project_title")
784
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
785
+ output_buffer.should have_tag("form li input[@name=\"project[title]\"]")
786
+ end
787
+
788
+ end
789
+ end
790
+
791
+ # Test other mappings that are not strings: :text and :file.
792
+ other_mappings = Formtastic::SemanticFormBuilder::INPUT_MAPPINGS.except(*Formtastic::SemanticFormBuilder::STRING_MAPPINGS)
793
+ other_mappings.each do |type, template_method|
794
+ describe ":as => #{type.inspect}" do
795
+
796
+ before do
797
+ @new_post.stub!(:body)
798
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type))
799
+
800
+ semantic_form_for(@new_post) do |builder|
801
+ concat(builder.input(:body, :as => type))
802
+ end
803
+ end
804
+
805
+ it "should have a #{type} class on the wrapper" do
806
+ output_buffer.should have_tag("form li.#{type}")
807
+ end
808
+
809
+ it 'should have a post_title_input id on the wrapper' do
810
+ output_buffer.should have_tag('form li#post_body_input')
811
+ end
812
+
813
+ it 'should generate a label for the input' do
814
+ output_buffer.should have_tag('form li label')
815
+ output_buffer.should have_tag('form li label[@for="post_body"]')
816
+ output_buffer.should have_tag('form li label', /Body/)
817
+ end
818
+
819
+ input_type = template_method.to_s.gsub(/_field|_/, '')
820
+
821
+ if template_method.to_s =~ /_field$/ # password_field
822
+
823
+ it "should generate a #{input_type} input" do
824
+ output_buffer.should have_tag("form li input")
825
+ output_buffer.should have_tag("form li input#post_body")
826
+ output_buffer.should have_tag("form li input[@name=\"post[body]\"]")
827
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
828
+ end
829
+
830
+ it 'should use input_html to style inputs' do
831
+ semantic_form_for(@new_post) do |builder|
832
+ concat(builder.input(:title, :as => type, :input_html => { :class => 'myclass' }))
833
+ end
834
+ output_buffer.should have_tag("form li input.myclass")
835
+ end
836
+
837
+ else # text_area
838
+
839
+ it "should generate a #{input_type} input" do
840
+ output_buffer.should have_tag("form li #{input_type}")
841
+ output_buffer.should have_tag("form li #{input_type}#post_body")
842
+ output_buffer.should have_tag("form li #{input_type}[@name=\"post[body]\"]")
843
+ end
844
+
845
+ it 'should use input_html to style inputs' do
846
+ semantic_form_for(@new_post) do |builder|
847
+ concat(builder.input(:title, :as => type, :input_html => { :class => 'myclass' }))
848
+ end
849
+ output_buffer.should have_tag("form li #{input_type}.myclass")
850
+ end
851
+
852
+ end
853
+
854
+ describe 'when no object is given' do
855
+ before(:each) do
856
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
857
+ concat(builder.input(:title, :as => type))
858
+ end
859
+ end
860
+
861
+ it 'should generate input' do
862
+ if template_method.to_s =~ /_field$/ # password_field
863
+ output_buffer.should have_tag("form li input")
864
+ output_buffer.should have_tag("form li input#project_title")
865
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
866
+ output_buffer.should have_tag("form li input[@name=\"project[title]\"]")
867
+ else
868
+ output_buffer.should have_tag("form li #{input_type}")
869
+ output_buffer.should have_tag("form li #{input_type}#project_title")
870
+ output_buffer.should have_tag("form li #{input_type}[@name=\"project[title]\"]")
871
+ end
872
+ end
873
+
874
+ it 'should generate labels' do
875
+ output_buffer.should have_tag('form li label')
876
+ output_buffer.should have_tag('form li label[@for="project_title"]')
877
+ output_buffer.should have_tag('form li label', /Title/)
878
+ end
879
+ end
880
+
881
+ end
882
+ end
883
+
884
+ describe ":as => :hidden" do
885
+ before do
886
+ @new_post.stub!(:secret)
887
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
888
+
889
+ semantic_form_for(@new_post) do |builder|
890
+ concat(builder.input(:secret, :as => :hidden))
891
+ end
892
+ end
893
+
894
+ it "should have a hidden class on the wrapper" do
895
+ output_buffer.should have_tag('form li.hidden')
896
+ end
897
+
898
+ it 'should have a post_hidden_input id on the wrapper' do
899
+ output_buffer.should have_tag('form li#post_secret_input')
900
+ end
901
+
902
+ it 'should not generate a label for the input' do
903
+ output_buffer.should_not have_tag('form li label')
904
+ end
905
+
906
+ it "should generate a input field" do
907
+ output_buffer.should have_tag("form li input#post_secret")
908
+ output_buffer.should have_tag("form li input[@type=\"hidden\"]")
909
+ output_buffer.should have_tag("form li input[@name=\"post[secret]\"]")
910
+ end
911
+
912
+ it "should not render inline errors" do
913
+ @errors = mock('errors')
914
+ @errors.stub!(:[]).with(:secret).and_return(["foo", "bah"])
915
+ @new_post.stub!(:errors).and_return(@errors)
916
+
917
+ semantic_form_for(@new_post) do |builder|
918
+ concat(builder.input(:secret, :as => :hidden))
919
+ end
920
+
921
+ output_buffer.should_not have_tag("form li p.inline-errors")
922
+ output_buffer.should_not have_tag("form li ul.errors")
923
+ end
924
+
925
+ end
926
+
927
+ describe ":as => :time_zone" do
928
+ before do
929
+ @new_post.stub!(:time_zone)
930
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
931
+
932
+ semantic_form_for(@new_post) do |builder|
933
+ concat(builder.input(:time_zone))
934
+ end
935
+ end
936
+
937
+ it "should have a time_zone class on the wrapper" do
938
+ output_buffer.should have_tag('form li.time_zone')
939
+ end
940
+
941
+ it 'should have a post_title_input id on the wrapper' do
942
+ output_buffer.should have_tag('form li#post_time_zone_input')
943
+ end
944
+
945
+ it 'should generate a label for the input' do
946
+ output_buffer.should have_tag('form li label')
947
+ output_buffer.should have_tag('form li label[@for="post_time_zone"]')
948
+ output_buffer.should have_tag('form li label', /Time zone/)
949
+ end
950
+
951
+ it "should generate a select" do
952
+ output_buffer.should have_tag("form li select")
953
+ output_buffer.should have_tag("form li select#post_time_zone")
954
+ output_buffer.should have_tag("form li select[@name=\"post[time_zone]\"]")
955
+ end
956
+
957
+ it 'should use input_html to style inputs' do
958
+ semantic_form_for(@new_post) do |builder|
959
+ concat(builder.input(:time_zone, :input_html => { :class => 'myclass' }))
960
+ end
961
+ output_buffer.should have_tag("form li select.myclass")
962
+ end
963
+
964
+ describe 'when no object is given' do
965
+ before(:each) do
966
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
967
+ concat(builder.input(:time_zone, :as => :time_zone))
968
+ end
969
+ end
970
+
971
+ it 'should generate labels' do
972
+ output_buffer.should have_tag('form li label')
973
+ output_buffer.should have_tag('form li label[@for="project_time_zone"]')
974
+ output_buffer.should have_tag('form li label', /Time zone/)
975
+ end
976
+
977
+ it 'should generate select inputs' do
978
+ output_buffer.should have_tag("form li select")
979
+ output_buffer.should have_tag("form li select#project_time_zone")
980
+ output_buffer.should have_tag("form li select[@name=\"project[time_zone]\"]")
981
+ end
982
+ end
983
+ end
984
+
985
+ describe ":as => :country" do
986
+
987
+ before do
988
+ @new_post.stub!(:country)
989
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
990
+ end
991
+
992
+ describe "when country_select is not available as a helper from a plugin" do
993
+
994
+ it "should raise an error, sugesting the author installs a plugin" do
995
+ lambda {
996
+ semantic_form_for(@new_post) do |builder|
997
+ concat(builder.input(:country, :as => :country))
998
+ end
999
+ }.should raise_error
1000
+ end
1001
+
1002
+ end
1003
+
1004
+ describe "when country_select is available as a helper (from a plugin)" do
1005
+
1006
+ before do
1007
+ semantic_form_for(@new_post) do |builder|
1008
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1009
+ concat(builder.input(:country, :as => :country))
1010
+ end
1011
+ end
1012
+
1013
+ it "should have a time_zone class on the wrapper" do
1014
+ output_buffer.should have_tag('form li.country')
1015
+ end
1016
+
1017
+ it 'should have a post_title_input id on the wrapper' do
1018
+ output_buffer.should have_tag('form li#post_country_input')
1019
+ end
1020
+
1021
+ it 'should generate a label for the input' do
1022
+ output_buffer.should have_tag('form li label')
1023
+ output_buffer.should have_tag('form li label[@for="post_country"]')
1024
+ output_buffer.should have_tag('form li label', /Country/)
1025
+ end
1026
+
1027
+ it "should generate a select" do
1028
+ output_buffer.should have_tag("form li select")
1029
+ end
1030
+
1031
+ end
1032
+
1033
+ describe ":priority_countries option" do
1034
+
1035
+ it "should be passed down to the country_select helper when provided" do
1036
+ priority_countries = ["Foo", "Bah"]
1037
+ semantic_form_for(@new_post) do |builder|
1038
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1039
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1040
+
1041
+ concat(builder.input(:country, :as => :country, :priority_countries => priority_countries))
1042
+ end
1043
+ end
1044
+
1045
+ it "should default to the @@priority_countries config when absent" do
1046
+ priority_countries = Formtastic::SemanticFormBuilder.priority_countries
1047
+ priority_countries.should_not be_empty
1048
+ priority_countries.should_not be_nil
1049
+
1050
+ semantic_form_for(@new_post) do |builder|
1051
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1052
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1053
+
1054
+ concat(builder.input(:country, :as => :country))
1055
+ end
1056
+ end
1057
+
1058
+ end
1059
+
1060
+ end
1061
+
1062
+ describe ':as => :radio' do
1063
+
1064
+ before do
1065
+ @new_post.stub!(:author).and_return(@bob)
1066
+ @new_post.stub!(:author_id).and_return(@bob.id)
1067
+ ::Post.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => ::Author, :macro => :belongs_to) }
1068
+ end
1069
+
1070
+ describe 'for belongs_to association' do
1071
+ before do
1072
+ semantic_form_for(@new_post) do |builder|
1073
+ concat(builder.input(:author, :as => :radio, :value_as_class => true))
1074
+ end
1075
+ end
1076
+
1077
+ it 'should have a radio class on the wrapper' do
1078
+ output_buffer.should have_tag('form li.radio')
1079
+ end
1080
+
1081
+ it 'should have a post_author_input id on the wrapper' do
1082
+ output_buffer.should have_tag('form li#post_author_input')
1083
+ end
1084
+
1085
+ it 'should generate a fieldset and legend containing label text for the input' do
1086
+ output_buffer.should have_tag('form li fieldset')
1087
+ output_buffer.should have_tag('form li fieldset legend')
1088
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1089
+ end
1090
+
1091
+ it 'should generate an ordered list with a list item for each choice' do
1092
+ output_buffer.should have_tag('form li fieldset ol')
1093
+ output_buffer.should have_tag('form li fieldset ol li', :count => ::Author.find(:all).size)
1094
+ end
1095
+
1096
+ it 'should have one option with a "checked" attribute' do
1097
+ output_buffer.should have_tag('form li input[@checked]', :count => 1)
1098
+ end
1099
+
1100
+ describe "each choice" do
1101
+
1102
+ it 'should contain a label for the radio input with a nested input and label text' do
1103
+ ::Author.find(:all).each do |author|
1104
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1105
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_id_#{author.id}']")
1106
+ end
1107
+ end
1108
+
1109
+ it 'should use values as li.class when value_as_class is true' do
1110
+ ::Author.find(:all).each do |author|
1111
+ output_buffer.should have_tag("form li fieldset ol li.#{author.id} label")
1112
+ end
1113
+ end
1114
+
1115
+ it "should have a radio input" do
1116
+ ::Author.find(:all).each do |author|
1117
+ output_buffer.should have_tag("form li fieldset ol li label input#post_author_id_#{author.id}")
1118
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1119
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1120
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='post[author_id]']")
1121
+ end
1122
+ end
1123
+
1124
+ it "should mark input as checked if it's the the existing choice" do
1125
+ @new_post.author_id.should == @bob.id
1126
+ @new_post.author.id.should == @bob.id
1127
+ @new_post.author.should == @bob
1128
+
1129
+ semantic_form_for(@new_post) do |builder|
1130
+ concat(builder.input(:author, :as => :radio))
1131
+ end
1132
+
1133
+ output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1134
+ end
1135
+ end
1136
+
1137
+ describe 'and no object is given' do
1138
+ before(:each) do
1139
+ output_buffer.replace ''
1140
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1141
+ concat(builder.input(:author_id, :as => :radio, :collection => ::Author.find(:all)))
1142
+ end
1143
+ end
1144
+
1145
+ it 'should generate a fieldset with legend' do
1146
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1147
+ end
1148
+
1149
+ it 'should generate an li tag for each item in the collection' do
1150
+ output_buffer.should have_tag('form li fieldset ol li', :count => ::Author.find(:all).size)
1151
+ end
1152
+
1153
+ it 'should generate labels for each item' do
1154
+ ::Author.find(:all).each do |author|
1155
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1156
+ output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1157
+ end
1158
+ end
1159
+
1160
+ it 'should generate inputs for each item' do
1161
+ ::Author.find(:all).each do |author|
1162
+ output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1163
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1164
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1165
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id]']")
1166
+ end
1167
+ end
1168
+ end
1169
+ end
1170
+ end
1171
+
1172
+ describe ':as => :select' do
1173
+
1174
+ before do
1175
+ @new_post.stub!(:author).and_return(@bob)
1176
+ @new_post.stub!(:author_id).and_return(@bob.id)
1177
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1178
+ end
1179
+
1180
+ describe 'for a belongs_to association' do
1181
+ before do
1182
+ semantic_form_for(@new_post) do |builder|
1183
+ concat(builder.input(:author, :as => :select))
1184
+ end
1185
+ end
1186
+
1187
+ it 'should have a select class on the wrapper' do
1188
+ output_buffer.should have_tag('form li.select')
1189
+ end
1190
+
1191
+ it 'should have a post_author_input id on the wrapper' do
1192
+ output_buffer.should have_tag('form li#post_author_input')
1193
+ end
1194
+
1195
+ it 'should have a label inside the wrapper' do
1196
+ output_buffer.should have_tag('form li label')
1197
+ output_buffer.should have_tag('form li label', /Author/)
1198
+ output_buffer.should have_tag("form li label[@for='post_author_id']")
1199
+ end
1200
+
1201
+ it 'should have a select inside the wrapper' do
1202
+ output_buffer.should have_tag('form li select')
1203
+ output_buffer.should have_tag('form li select#post_author_id')
1204
+ end
1205
+
1206
+ it 'should not create a multi-select' do
1207
+ output_buffer.should_not have_tag('form li select[@multiple]')
1208
+ end
1209
+
1210
+ it 'should create a select without size' do
1211
+ output_buffer.should_not have_tag('form li select[@size]')
1212
+ end
1213
+
1214
+ it 'should have a blank option' do
1215
+ output_buffer.should have_tag("form li select option[@value='']")
1216
+ end
1217
+
1218
+ it 'should have a select option for each Author' do
1219
+ output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size + 1)
1220
+ ::Author.find(:all).each do |author|
1221
+ output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1222
+ end
1223
+ end
1224
+
1225
+ it 'should have one option with a "selected" attribute' do
1226
+ output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1227
+ end
1228
+
1229
+ it 'should not singularize the association name' do
1230
+ @new_post.stub!(:author_status).and_return(@bob)
1231
+ @new_post.stub!(:author_status_id).and_return(@bob.id)
1232
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1233
+
1234
+ semantic_form_for(@new_post) do |builder|
1235
+ concat(builder.input(:author_status, :as => :select))
1236
+ end
1237
+
1238
+ output_buffer.should have_tag('form li select#post_author_status_id')
1239
+ end
1240
+ end
1241
+
1242
+ describe 'for a has_many association' do
1243
+ before do
1244
+ semantic_form_for(@fred) do |builder|
1245
+ concat(builder.input(:posts, :as => :select))
1246
+ end
1247
+ end
1248
+
1249
+ it 'should have a select class on the wrapper' do
1250
+ output_buffer.should have_tag('form li.select')
1251
+ end
1252
+
1253
+ it 'should have a post_author_input id on the wrapper' do
1254
+ output_buffer.should have_tag('form li#author_posts_input')
1255
+ end
1256
+
1257
+ it 'should have a label inside the wrapper' do
1258
+ output_buffer.should have_tag('form li label')
1259
+ output_buffer.should have_tag('form li label', /Post/)
1260
+ output_buffer.should have_tag("form li label[@for='author_post_ids']")
1261
+ end
1262
+
1263
+ it 'should have a select inside the wrapper' do
1264
+ output_buffer.should have_tag('form li select')
1265
+ output_buffer.should have_tag('form li select#author_post_ids')
1266
+ end
1267
+
1268
+ it 'should have a multi-select select' do
1269
+ output_buffer.should have_tag('form li select[@multiple="multiple"]')
1270
+ end
1271
+
1272
+ it 'should have a select option for each Post' do
1273
+ output_buffer.should have_tag('form li select option', :count => ::Post.find(:all).size)
1274
+ ::Post.find(:all).each do |post|
1275
+ output_buffer.should have_tag("form li select option[@value='#{post.id}']", /#{post.to_label}/)
1276
+ end
1277
+ end
1278
+
1279
+ it 'should not have a blank option' do
1280
+ output_buffer.should_not have_tag("form li select option[@value='']")
1281
+ end
1282
+
1283
+ it 'should have one option with a "selected" attribute' do
1284
+ output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1285
+ end
1286
+ end
1287
+
1288
+ describe 'for a has_and_belongs_to_many association' do
1289
+ before do
1290
+ semantic_form_for(@freds_post) do |builder|
1291
+ concat(builder.input(:authors, :as => :select))
1292
+ end
1293
+ end
1294
+
1295
+ it 'should have a select class on the wrapper' do
1296
+ output_buffer.should have_tag('form li.select')
1297
+ end
1298
+
1299
+ it 'should have a post_author_input id on the wrapper' do
1300
+ output_buffer.should have_tag('form li#post_authors_input')
1301
+ end
1302
+
1303
+ it 'should have a label inside the wrapper' do
1304
+ output_buffer.should have_tag('form li label')
1305
+ output_buffer.should have_tag('form li label', /Author/)
1306
+ output_buffer.should have_tag("form li label[@for='post_author_ids']")
1307
+ end
1308
+
1309
+ it 'should have a select inside the wrapper' do
1310
+ output_buffer.should have_tag('form li select')
1311
+ output_buffer.should have_tag('form li select#post_author_ids')
1312
+ end
1313
+
1314
+ it 'should have a multi-select select' do
1315
+ output_buffer.should have_tag('form li select[@multiple="multiple"]')
1316
+ end
1317
+
1318
+ it 'should have a select option for each Author' do
1319
+ output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size)
1320
+ ::Author.find(:all).each do |author|
1321
+ output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1322
+ end
1323
+ end
1324
+
1325
+ it 'should not have a blank option' do
1326
+ output_buffer.should_not have_tag("form li select option[@value='']")
1327
+ end
1328
+
1329
+ it 'should have one option with a "selected" attribute' do
1330
+ output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1331
+ end
1332
+ end
1333
+
1334
+ describe 'when :prompt => "choose something" is set' do
1335
+ before do
1336
+ @new_post.stub!(:author_id).and_return(nil)
1337
+ semantic_form_for(@new_post) do |builder|
1338
+ concat(builder.input(:author, :as => :select, :prompt => "choose author"))
1339
+ end
1340
+ end
1341
+
1342
+ it 'should have a select with prompt' do
1343
+ output_buffer.should have_tag("form li select option[@value='']", /choose author/)
1344
+ end
1345
+
1346
+ it 'should not have a blank select option' do
1347
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
1348
+ end
1349
+ end
1350
+
1351
+ describe 'when no object is given' do
1352
+ before(:each) do
1353
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1354
+ concat(builder.input(:author, :as => :select, :collection => ::Author.find(:all)))
1355
+ end
1356
+ end
1357
+
1358
+ it 'should generate label' do
1359
+ output_buffer.should have_tag('form li label', /Author/)
1360
+ output_buffer.should have_tag("form li label[@for='project_author']")
1361
+ end
1362
+
1363
+ it 'should generate select inputs' do
1364
+ output_buffer.should have_tag('form li select#project_author')
1365
+ output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size + 1)
1366
+ end
1367
+
1368
+ it 'should generate an option to each item' do
1369
+ ::Author.find(:all).each do |author|
1370
+ output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1371
+ end
1372
+ end
1373
+ end
1374
+
1375
+ describe 'when :selected is set' do
1376
+ before do
1377
+ @new_post.stub!(:author_id).and_return(nil)
1378
+ semantic_form_for(@new_post) do |builder|
1379
+ concat(builder.input(:author, :as => :select, :selected => @bob.id ))
1380
+ end
1381
+ end
1382
+
1383
+ it 'should have a selected item' do
1384
+ output_buffer.should have_tag("form li select option[@selected='selected']")
1385
+ end
1386
+
1387
+ it 'bob should be selected' do
1388
+ output_buffer.should have_tag("form li select option[@selected='selected']", /bob/i)
1389
+ output_buffer.should have_tag("form li select option[@selected='selected'][@value='42']")
1390
+ end
1391
+
1392
+ end
1393
+
1394
+ end
1395
+
1396
+ describe ':as => :check_boxes' do
1397
+
1398
+ describe 'for a has_many association' do
1399
+ before do
1400
+ semantic_form_for(@fred) do |builder|
1401
+ concat(builder.input(:posts, :as => :check_boxes, :value_as_class => true))
1402
+ end
1403
+ end
1404
+
1405
+ it 'should have a check_boxes class on the wrapper' do
1406
+ output_buffer.should have_tag('form li.check_boxes')
1407
+ end
1408
+
1409
+ it 'should have a author_posts_input id on the wrapper' do
1410
+ output_buffer.should have_tag('form li#author_posts_input')
1411
+ end
1412
+
1413
+ it 'should generate a fieldset and legend containing label text for the input' do
1414
+ output_buffer.should have_tag('form li fieldset')
1415
+ output_buffer.should have_tag('form li fieldset legend')
1416
+ output_buffer.should have_tag('form li fieldset legend', /Posts/)
1417
+ end
1418
+
1419
+ it 'should generate an ordered list with a list item for each choice' do
1420
+ output_buffer.should have_tag('form li fieldset ol')
1421
+ output_buffer.should have_tag('form li fieldset ol li', :count => ::Post.find(:all).size)
1422
+ end
1423
+
1424
+ it 'should have one option with a "checked" attribute' do
1425
+ output_buffer.should have_tag('form li input[@checked]', :count => 1)
1426
+ end
1427
+
1428
+ it 'should generate hidden inputs with default value blank' do
1429
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='hidden'][@value='']", :count => ::Post.find(:all).size)
1430
+ end
1431
+
1432
+ describe "each choice" do
1433
+
1434
+ it 'should contain a label for the radio input with a nested input and label text' do
1435
+ ::Post.find(:all).each do |post|
1436
+ output_buffer.should have_tag('form li fieldset ol li label', /#{post.to_label}/)
1437
+ output_buffer.should have_tag("form li fieldset ol li label[@for='author_post_ids_#{post.id}']")
1438
+ end
1439
+ end
1440
+
1441
+ it 'should use values as li.class when value_as_class is true' do
1442
+ ::Post.find(:all).each do |post|
1443
+ output_buffer.should have_tag("form li fieldset ol li.#{post.id} label")
1444
+ end
1445
+ end
1446
+
1447
+ it 'should have a checkbox input for each post' do
1448
+ ::Post.find(:all).each do |post|
1449
+ output_buffer.should have_tag("form li fieldset ol li label input#author_post_ids_#{post.id}")
1450
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='author[post_ids][]']", :count => 2)
1451
+ end
1452
+ end
1453
+
1454
+ it "should mark input as checked if it's the the existing choice" do
1455
+ ::Post.find(:all).include?(@fred.posts.first).should be_true
1456
+ output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1457
+ end
1458
+ end
1459
+
1460
+ describe 'and no object is given' do
1461
+ before(:each) do
1462
+ output_buffer.replace ''
1463
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1464
+ concat(builder.input(:author_id, :as => :check_boxes, :collection => ::Author.find(:all)))
1465
+ end
1466
+ end
1467
+
1468
+ it 'should generate a fieldset with legend' do
1469
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1470
+ end
1471
+
1472
+ it 'shold generate an li tag for each item in the collection' do
1473
+ output_buffer.should have_tag('form li fieldset ol li', :count => ::Author.find(:all).size)
1474
+ end
1475
+
1476
+ it 'should generate labels for each item' do
1477
+ ::Author.find(:all).each do |author|
1478
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1479
+ output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1480
+ end
1481
+ end
1482
+
1483
+ it 'should generate inputs for each item' do
1484
+ ::Author.find(:all).each do |author|
1485
+ output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1486
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='checkbox']")
1487
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1488
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id][]']")
1489
+ end
1490
+ end
1491
+ end
1492
+ end
1493
+ end
1494
+
1495
+ describe 'for collections' do
1496
+
1497
+ before do
1498
+ @new_post.stub!(:author).and_return(@bob)
1499
+ @new_post.stub!(:author_id).and_return(@bob.id)
1500
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1501
+ end
1502
+
1503
+ { :select => :option, :radio => :input, :check_boxes => :'input[@type="checkbox"]' }.each do |type, countable|
1504
+
1505
+ describe ":as => #{type.inspect}" do
1506
+
1507
+ describe 'when the :collection option is not provided' do
1508
+ it 'should perform a basic find on the association class' do
1509
+ ::Author.should_receive(:find)
1510
+
1511
+ semantic_form_for(@new_post) do |builder|
1512
+ concat(builder.input(:author, :as => type))
1513
+ end
1514
+ end
1515
+ end
1516
+
1517
+ describe 'when the :collection option is provided' do
1518
+
1519
+ before do
1520
+ @authors = ::Author.find(:all) * 2
1521
+ output_buffer.replace '' # clears the output_buffer from the before block, hax!
1522
+ end
1523
+
1524
+ it 'should not call find() on the parent class' do
1525
+ ::Author.should_not_receive(:find)
1526
+ semantic_form_for(@new_post) do |builder|
1527
+ concat(builder.input(:author, :as => type, :collection => @authors))
1528
+ end
1529
+ end
1530
+
1531
+ it 'should use the provided collection' do
1532
+ semantic_form_for(@new_post) do |builder|
1533
+ concat(builder.input(:author, :as => type, :collection => @authors))
1534
+ end
1535
+ output_buffer.should have_tag("form li.#{type} #{countable}", :count => @authors.size + (type == :select ? 1 : 0))
1536
+ end
1537
+
1538
+ describe 'and the :collection is an array of strings' do
1539
+ before do
1540
+ @new_post.stub!(:category_name).and_return('')
1541
+ @categories = [ 'General', 'Design', 'Development', 'Quasi-Serious Inventions' ]
1542
+ end
1543
+
1544
+ it "should use the string as the label text and value for each #{countable}" do
1545
+ semantic_form_for(@new_post) do |builder|
1546
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1547
+ end
1548
+
1549
+ @categories.each do |value|
1550
+ output_buffer.should have_tag("form li.#{type}", /#{value}/)
1551
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1552
+ end
1553
+ end
1554
+
1555
+ if type == :radio
1556
+ it 'should generate a sanitized label for attribute' do
1557
+ @bob.stub!(:category_name).and_return(@categories)
1558
+ semantic_form_for(@new_post) do |builder|
1559
+ builder.semantic_fields_for(@bob) do |bob_builder|
1560
+ concat(bob_builder.input(:category_name, :as => type, :collection => @categories))
1561
+ end
1562
+ end
1563
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_general']")
1564
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_design']")
1565
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_development']")
1566
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_quasiserious_inventions']")
1567
+ end
1568
+ end
1569
+ end
1570
+
1571
+ describe 'and the :collection is a hash of strings' do
1572
+ before do
1573
+ @new_post.stub!(:category_name).and_return('')
1574
+ @categories = { 'General' => 'gen', 'Design' => 'des','Development' => 'dev' }
1575
+ end
1576
+
1577
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
1578
+ semantic_form_for(@new_post) do |builder|
1579
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1580
+ end
1581
+
1582
+ @categories.each do |label, value|
1583
+ output_buffer.should have_tag("form li.#{type}", /#{label}/)
1584
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1585
+ end
1586
+ end
1587
+ end
1588
+
1589
+ describe 'and the :collection is an array of arrays' do
1590
+ before do
1591
+ @new_post.stub!(:category_name).and_return('')
1592
+ @categories = { 'General' => 'gen', 'Design' => 'des', 'Development' => 'dev' }.to_a
1593
+ end
1594
+
1595
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
1596
+ semantic_form_for(@new_post) do |builder|
1597
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1598
+ end
1599
+
1600
+ @categories.each do |text, value|
1601
+ label = type == :select ? :option : :label
1602
+ output_buffer.should have_tag("form li.#{type} #{label}", /#{text}/i)
1603
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1604
+ output_buffer.should have_tag("form li.#{type} #{countable}#post_category_name_#{value.to_s}") if type == :radio
1605
+ end
1606
+ end
1607
+ end
1608
+
1609
+ if type == :radio
1610
+ describe 'and the :collection is an array of arrays with boolean values' do
1611
+ before do
1612
+ @new_post.stub!(:category_name).and_return('')
1613
+ @choices = { 'Yeah' => true, 'Nah' => false }.to_a
1614
+ end
1615
+
1616
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
1617
+ semantic_form_for(@new_post) do |builder|
1618
+ concat(builder.input(:category_name, :as => type, :collection => @choices))
1619
+ end
1620
+
1621
+ output_buffer.should have_tag("form li.#{type} #{countable}#post_category_name_true")
1622
+ output_buffer.should have_tag("form li.#{type} #{countable}#post_category_name_false")
1623
+ end
1624
+ end
1625
+ end
1626
+
1627
+
1628
+ describe 'and the :collection is an array of symbols' do
1629
+ before do
1630
+ @new_post.stub!(:category_name).and_return('')
1631
+ @categories = [ :General, :Design, :Development ]
1632
+ end
1633
+
1634
+ it "should use the symbol as the label text and value for each #{countable}" do
1635
+ semantic_form_for(@new_post) do |builder|
1636
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1637
+ end
1638
+
1639
+ @categories.each do |value|
1640
+ label = type == :select ? :option : :label
1641
+ output_buffer.should have_tag("form li.#{type} #{label}", /#{value}/i)
1642
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1643
+ end
1644
+ end
1645
+ end
1646
+
1647
+ describe 'and the :collection is an OrderedHash of strings' do
1648
+ before do
1649
+ @new_post.stub!(:category_name).and_return('')
1650
+ @categories = ActiveSupport::OrderedHash.new('General' => 'gen', 'Design' => 'des','Development' => 'dev')
1651
+ end
1652
+
1653
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
1654
+ semantic_form_for(@new_post) do |builder|
1655
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1656
+ end
1657
+
1658
+ @categories.each do |label, value|
1659
+ output_buffer.should have_tag("form li.#{type}", /#{label}/)
1660
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1661
+ end
1662
+ end
1663
+
1664
+ end
1665
+
1666
+ describe 'when the :label_method option is provided' do
1667
+
1668
+ describe 'as a symbol' do
1669
+ before do
1670
+ semantic_form_for(@new_post) do |builder|
1671
+ concat(builder.input(:author, :as => type, :label_method => :login))
1672
+ end
1673
+ end
1674
+
1675
+ it 'should have options with text content from the specified method' do
1676
+ ::Author.find(:all).each do |author|
1677
+ output_buffer.should have_tag("form li.#{type}", /#{author.login}/)
1678
+ end
1679
+ end
1680
+ end
1681
+
1682
+ describe 'as a proc' do
1683
+ before do
1684
+ semantic_form_for(@new_post) do |builder|
1685
+ concat(builder.input(:author, :as => type, :label_method => Proc.new {|a| a.login.reverse }))
1686
+ end
1687
+ end
1688
+
1689
+ it 'should have options with the proc applied to each' do
1690
+ ::Author.find(:all).each do |author|
1691
+ output_buffer.should have_tag("form li.#{type}", /#{author.login.reverse}/)
1692
+ end
1693
+ end
1694
+ end
1695
+
1696
+ end
1697
+
1698
+ describe 'when the :label_method option is not provided' do
1699
+ Formtastic::SemanticFormBuilder.collection_label_methods.each do |label_method|
1700
+
1701
+ describe "when the collection objects respond to #{label_method}" do
1702
+ before do
1703
+ @fred.stub!(:respond_to?).and_return { |m| m.to_s == label_method }
1704
+ ::Author.find(:all).each { |a| a.stub!(label_method).and_return('The Label Text') }
1705
+
1706
+ semantic_form_for(@new_post) do |builder|
1707
+ concat(builder.input(:author, :as => type))
1708
+ end
1709
+ end
1710
+
1711
+ it "should render the options with #{label_method} as the label" do
1712
+ ::Author.find(:all).each do |author|
1713
+ output_buffer.should have_tag("form li.#{type}", /The Label Text/)
1714
+ end
1715
+ end
1716
+ end
1717
+
1718
+ end
1719
+ end
1720
+
1721
+ describe 'when the :value_method option is provided' do
1722
+
1723
+ describe 'as a symbol' do
1724
+ before do
1725
+ semantic_form_for(@new_post) do |builder|
1726
+ concat(builder.input(:author, :as => type, :value_method => :login))
1727
+ end
1728
+ end
1729
+
1730
+ it 'should have options with values from specified method' do
1731
+ ::Author.find(:all).each do |author|
1732
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{author.login}']")
1733
+ end
1734
+ end
1735
+ end
1736
+
1737
+ describe 'as a proc' do
1738
+ before do
1739
+ semantic_form_for(@new_post) do |builder|
1740
+ concat(builder.input(:author, :as => type, :value_method => Proc.new {|a| a.login.reverse }))
1741
+ end
1742
+ end
1743
+
1744
+ it 'should have options with the proc applied to each value' do
1745
+ ::Author.find(:all).each do |author|
1746
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{author.login.reverse}']")
1747
+ end
1748
+ end
1749
+ end
1750
+ end
1751
+
1752
+ end
1753
+ end
1754
+ end
1755
+
1756
+ describe 'for boolean attributes' do
1757
+
1758
+ { :select => :option, :radio => :input }.each do |type, countable|
1759
+ checked_or_selected = { :select => :selected, :radio => :checked }[type]
1760
+
1761
+ describe ":as => #{type.inspect}" do
1762
+
1763
+ before do
1764
+ @new_post.stub!(:allow_comments)
1765
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1766
+
1767
+ semantic_form_for(@new_post) do |builder|
1768
+ concat(builder.input(:allow_comments, :as => type))
1769
+ end
1770
+ end
1771
+
1772
+ it "should have a #{type} class on the wrapper" do
1773
+ output_buffer.should have_tag("form li.#{type}")
1774
+ end
1775
+
1776
+ it 'should have a post_allow_comments_input id on the wrapper' do
1777
+ output_buffer.should have_tag('form li#post_allow_comments_input')
1778
+ end
1779
+
1780
+ it 'should generate a fieldset containing a legend' do
1781
+ output_buffer.should have_tag("form li.#{type}", /Allow comments/)
1782
+ end
1783
+
1784
+ it "should generate two #{countable}" do
1785
+ output_buffer.should have_tag("form li.#{type} #{countable}", :count => (type == :select ? 3 : 2))
1786
+ output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="true"]})
1787
+ output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="false"]})
1788
+ end
1789
+
1790
+ describe 'when the locale sets the label text' do
1791
+ before do
1792
+ I18n.backend.store_translations 'en', :formtastic => {:yes => 'Absolutely!', :no => 'Never!'}
1793
+
1794
+ semantic_form_for(@new_post) do |builder|
1795
+ concat(builder.input(:allow_comments, :as => type))
1796
+ end
1797
+ end
1798
+
1799
+ after do
1800
+ I18n.backend.store_translations 'en', :formtastic => {:yes => nil, :no => nil}
1801
+ end
1802
+
1803
+ it 'should allow translation of the labels' do
1804
+ output_buffer.should have_tag("form li.#{type}", /Absolutely\!/)
1805
+ output_buffer.should have_tag("form li.#{type}", /Never\!/)
1806
+ end
1807
+ end
1808
+
1809
+ describe 'when the value is nil' do
1810
+ before do
1811
+ @new_post.stub!(:allow_comments).and_return(nil)
1812
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1813
+
1814
+ semantic_form_for(@new_post) do |builder|
1815
+ concat(builder.input(:allow_comments, :as => type))
1816
+ end
1817
+ end
1818
+
1819
+ it "should not mark either #{countable} as #{checked_or_selected}" do
1820
+ output_buffer.should_not have_tag(%{form li.#{type} input[@#{checked_or_selected}="#{checked_or_selected}"]})
1821
+ end
1822
+ end
1823
+
1824
+ describe 'when the value is true' do
1825
+ before do
1826
+ @new_post.stub!(:allow_comments).and_return(true)
1827
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1828
+ semantic_form_for(@new_post) do |builder|
1829
+ concat(builder.input(:allow_comments, :as => type))
1830
+ end
1831
+ end
1832
+
1833
+ it "should mark the true #{countable} as #{checked_or_selected}" do
1834
+ output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="true"][@#{checked_or_selected}="#{checked_or_selected}"]}, :count => 1)
1835
+ end
1836
+
1837
+ it "should not mark the false #{countable} as #{checked_or_selected}" do
1838
+ output_buffer.should_not have_tag(%{form li.#{type} #{countable}[@value="false"][@#{checked_or_selected}="#{checked_or_selected}"]})
1839
+ end
1840
+ end
1841
+
1842
+ describe 'when the value is false' do
1843
+ before do
1844
+ @new_post.stub!(:allow_comments).and_return(false)
1845
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1846
+ semantic_form_for(@new_post) do |builder|
1847
+ concat(builder.input(:allow_comments, :as => type))
1848
+ end
1849
+ end
1850
+
1851
+ it "should not mark the true #{countable} as #{checked_or_selected}" do
1852
+ output_buffer.should_not have_tag(%{form li.#{type} #{countable}[@value="true"][@#{checked_or_selected}="#{checked_or_selected}"]})
1853
+ end
1854
+
1855
+ it "should mark the false #{countable} as #{checked_or_selected}" do
1856
+ output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="false"][@#{checked_or_selected}="#{checked_or_selected}"]}, :count => 1)
1857
+ end
1858
+ end
1859
+
1860
+ describe 'when :true and :false options are provided' do
1861
+ before do
1862
+ @new_post.stub!(:allow_comments)
1863
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1864
+ semantic_form_for(@new_post) do |builder|
1865
+ concat(builder.input(:allow_comments, :as => type, :true => "Absolutely", :false => "No Way"))
1866
+ end
1867
+ end
1868
+
1869
+ it 'should use them as labels' do
1870
+ output_buffer.should have_tag("form li.#{type}", /Absolutely/)
1871
+ output_buffer.should have_tag("form li.#{type}", /No Way/)
1872
+ end
1873
+ end
1874
+
1875
+ describe 'when the :selected option is excluded' do
1876
+
1877
+ before do
1878
+ @output_buffer = ''
1879
+ @new_post.stub!(:allow_comments)
1880
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1881
+ semantic_form_for(@new_post) do |builder|
1882
+ concat(builder.input(:allow_comments, :as => type))
1883
+ end
1884
+ end
1885
+
1886
+ it 'should not pre-select either value' do
1887
+ output_buffer.should_not have_tag("form li.#{type} #{countable}[@#{checked_or_selected}]")
1888
+ end
1889
+
1890
+ end
1891
+
1892
+ describe 'when the :selected option is provided' do
1893
+
1894
+ before do
1895
+ @output_buffer = ''
1896
+ @new_post.stub!(:allow_comments)
1897
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
1898
+ semantic_form_for(@new_post) do |builder|
1899
+ concat(builder.input(:allow_comments, :as => type, :selected => true))
1900
+ end
1901
+ end
1902
+
1903
+ it 'should pre-select the value' do
1904
+ output_buffer.should have_tag("form li.#{type} #{countable}[@#{checked_or_selected}]")
1905
+ end
1906
+
1907
+ end
1908
+
1909
+ end
1910
+
1911
+ end
1912
+ end
1913
+ end
1914
+
1915
+ describe ':as => :date' do
1916
+
1917
+ before do
1918
+ @new_post.stub!(:publish_at)
1919
+ #@new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :date))
1920
+
1921
+ semantic_form_for(@new_post) do |builder|
1922
+ concat(builder.input(:publish_at, :as => :date))
1923
+ @builder = builder
1924
+ end
1925
+ end
1926
+
1927
+ it 'should have a date class on the wrapper li' do
1928
+ output_buffer.should have_tag('form li.date')
1929
+ end
1930
+
1931
+ it 'should have a fieldset inside the li wrapper' do
1932
+ output_buffer.should have_tag('form li.date fieldset')
1933
+ end
1934
+
1935
+ it 'should have a legend containing the label text inside the fieldset' do
1936
+ output_buffer.should have_tag('form li.date fieldset legend', /Publish at/)
1937
+ end
1938
+
1939
+ it 'should have an ordered list of three items inside the fieldset' do
1940
+ output_buffer.should have_tag('form li.date fieldset ol')
1941
+ output_buffer.should have_tag('form li.date fieldset ol li', :count => 3)
1942
+ end
1943
+
1944
+ it 'should have three labels for year, month and day' do
1945
+ output_buffer.should have_tag('form li.date fieldset ol li label', :count => 3)
1946
+ output_buffer.should have_tag('form li.date fieldset ol li label', /year/i)
1947
+ output_buffer.should have_tag('form li.date fieldset ol li label', /month/i)
1948
+ output_buffer.should have_tag('form li.date fieldset ol li label', /day/i)
1949
+ end
1950
+
1951
+ it 'should have three selects for year, month and day' do
1952
+ output_buffer.should have_tag('form li.date fieldset ol li select', :count => 3)
1953
+ end
1954
+ end
1955
+
1956
+ describe ':as => :datetime' do
1957
+
1958
+ before do
1959
+ @new_post.stub!(:publish_at)
1960
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :datetime))
1961
+
1962
+ semantic_form_for(@new_post) do |builder|
1963
+ concat(builder.input(:publish_at, :as => :datetime))
1964
+ end
1965
+ end
1966
+
1967
+ it 'should have a datetime class on the wrapper li' do
1968
+ output_buffer.should have_tag('form li.datetime')
1969
+ end
1970
+
1971
+ it 'should have a fieldset inside the li wrapper' do
1972
+ output_buffer.should have_tag('form li.datetime fieldset')
1973
+ end
1974
+
1975
+ it 'should have a legend containing the label text inside the fieldset' do
1976
+ output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
1977
+ end
1978
+
1979
+ it 'should have an ordered list of five items inside the fieldset' do
1980
+ output_buffer.should have_tag('form li.datetime fieldset ol')
1981
+ output_buffer.should have_tag('form li.datetime fieldset ol li', :count => 5)
1982
+ end
1983
+
1984
+ it 'should have five labels for year, month, day, hour and minute' do
1985
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
1986
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /year/i)
1987
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /month/i)
1988
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /day/i)
1989
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /hour/i)
1990
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /minute/i)
1991
+ end
1992
+
1993
+ it 'should have five selects for year, month, day, hour and minute' do
1994
+ output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
1995
+ end
1996
+
1997
+ it 'should generate a sanitized label and matching ids for attribute' do
1998
+ @bob.stub!(:publish_at)
1999
+ @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :datetime))
2000
+
2001
+ semantic_form_for(@new_post) do |builder|
2002
+ builder.semantic_fields_for(@bob, :index => 10) do |bob_builder|
2003
+ concat(bob_builder.input(:publish_at, :as => :datetime))
2004
+ end
2005
+ end
2006
+
2007
+ 1.upto(5) do |i|
2008
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_10_publish_at_#{i}i']")
2009
+ output_buffer.should have_tag("form li fieldset ol li #post_author_10_publish_at_#{i}i")
2010
+ end
2011
+ end
2012
+
2013
+ describe 'when :discard_input => true is set' do
2014
+ it 'should use default hidden value equals to 1 when attribute returns nil' do
2015
+ semantic_form_for(@new_post) do |builder|
2016
+ concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
2017
+ end
2018
+
2019
+ output_buffer.should have_tag("form li input[@type='hidden'][@value='1']")
2020
+ end
2021
+
2022
+ it 'should use default attribute value when it is not nil' do
2023
+ @new_post.stub!(:publish_at).and_return(Date.new(2007,12,27))
2024
+ semantic_form_for(@new_post) do |builder|
2025
+ concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
2026
+ end
2027
+
2028
+ output_buffer.should have_tag("form li input[@type='hidden'][@value='27']")
2029
+ end
2030
+ end
2031
+
2032
+ describe 'inputs order' do
2033
+ it 'should have a default' do
2034
+ semantic_form_for(@new_post) do |builder|
2035
+ self.should_receive(:select_year).once.ordered.and_return('')
2036
+ self.should_receive(:select_month).once.ordered.and_return('')
2037
+ self.should_receive(:select_day).once.ordered.and_return('')
2038
+ builder.input(:publish_at, :as => :datetime)
2039
+ end
2040
+ end
2041
+
2042
+ it 'should be specified with :order option' do
2043
+ I18n.backend.store_translations 'en', :date => { :order => [:month, :year, :day] }
2044
+ semantic_form_for(@new_post) do |builder|
2045
+ self.should_receive(:select_month).once.ordered.and_return('')
2046
+ self.should_receive(:select_year).once.ordered.and_return('')
2047
+ self.should_receive(:select_day).once.ordered.and_return('')
2048
+ builder.input(:publish_at, :as => :datetime)
2049
+ end
2050
+ end
2051
+
2052
+ it 'should be changed through I18n' do
2053
+ semantic_form_for(@new_post) do |builder|
2054
+ self.should_receive(:select_day).once.ordered.and_return('')
2055
+ self.should_receive(:select_month).once.ordered.and_return('')
2056
+ self.should_receive(:select_year).once.ordered.and_return('')
2057
+ builder.input(:publish_at, :as => :datetime, :order => [:day, :month, :year])
2058
+ end
2059
+ end
2060
+ end
2061
+
2062
+ describe 'when the locale changes the label text' do
2063
+ before do
2064
+ I18n.backend.store_translations 'en', :datetime => {:prompts => {
2065
+ :year => 'The Year', :month => 'The Month', :day => 'The Day',
2066
+ :hour => 'The Hour', :minute => 'The Minute'
2067
+ }}
2068
+ semantic_form_for(@new_post) do |builder|
2069
+ concat(builder.input(:publish_at, :as => :datetime))
2070
+ end
2071
+ end
2072
+
2073
+ after do
2074
+ I18n.backend.store_translations 'en', :formtastic => {
2075
+ :year => nil, :month => nil, :day => nil,
2076
+ :hour => nil, :minute => nil
2077
+ }
2078
+ end
2079
+
2080
+ it 'should have translated labels for year, month, day, hour and minute' do
2081
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Year/)
2082
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Month/)
2083
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Day/)
2084
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Hour/)
2085
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Minute/)
2086
+ end
2087
+ end
2088
+
2089
+ describe 'when no object is given' do
2090
+ before(:each) do
2091
+ output_buffer.replace ''
2092
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
2093
+ concat(builder.input(:publish_at, :as => :datetime))
2094
+ @builder = builder
2095
+ end
2096
+ end
2097
+
2098
+ it 'should have fieldset with legend' do
2099
+ output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
2100
+ end
2101
+
2102
+ it 'should have labels for each input' do
2103
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
2104
+ end
2105
+
2106
+ it 'should have selects for each inputs' do
2107
+ output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
2108
+ end
2109
+ end
2110
+ end
2111
+
2112
+ describe ':as => :time' do
2113
+ before do
2114
+ @new_post.stub!(:publish_at)
2115
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :time))
2116
+
2117
+ semantic_form_for(@new_post) do |builder|
2118
+ concat(builder.input(:publish_at, :as => :time))
2119
+ end
2120
+ end
2121
+
2122
+ it 'should have a time class on the wrapper li' do
2123
+ output_buffer.should have_tag('form li.time')
2124
+ end
2125
+
2126
+ it 'should have a fieldset inside the li wrapper' do
2127
+ output_buffer.should have_tag('form li.time fieldset')
2128
+ end
2129
+
2130
+ it 'should have a legend containing the label text inside the fieldset' do
2131
+ output_buffer.should have_tag('form li.time fieldset legend', /Publish at/)
2132
+ end
2133
+
2134
+ it 'should have an ordered list of two items inside the fieldset' do
2135
+ output_buffer.should have_tag('form li.time fieldset ol')
2136
+ output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
2137
+ end
2138
+
2139
+ it 'should have five labels for hour and minute' do
2140
+ output_buffer.should have_tag('form li.time fieldset ol li label', :count => 2)
2141
+ output_buffer.should have_tag('form li.time fieldset ol li label', /hour/i)
2142
+ output_buffer.should have_tag('form li.time fieldset ol li label', /minute/i)
2143
+ end
2144
+
2145
+ it 'should have two selects for hour and minute' do
2146
+ output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
2147
+ end
2148
+ end
2149
+
2150
+ describe ':as => :boolean' do
2151
+
2152
+ before do
2153
+ @new_post.stub!(:allow_comments)
2154
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
2155
+
2156
+ semantic_form_for(@new_post) do |builder|
2157
+ concat(builder.input(:allow_comments, :as => :boolean))
2158
+ end
2159
+ end
2160
+
2161
+ it 'should have a boolean class on the wrapper' do
2162
+ output_buffer.should have_tag('form li.boolean')
2163
+ end
2164
+
2165
+ it 'should have a post_allow_comments_input id on the wrapper' do
2166
+ output_buffer.should have_tag('form li#post_allow_comments_input')
2167
+ end
2168
+
2169
+ it 'should generate a label containing the input' do
2170
+ output_buffer.should have_tag('form li label', :count => 1)
2171
+ output_buffer.should have_tag('form li label[@for="post_allow_comments"]')
2172
+ output_buffer.should have_tag('form li label', /Allow comments/)
2173
+ output_buffer.should have_tag('form li label input[@type="checkbox"]')
2174
+ end
2175
+
2176
+ it 'should generate a checkbox input' do
2177
+ output_buffer.should have_tag('form li label input')
2178
+ output_buffer.should have_tag('form li label input#post_allow_comments')
2179
+ output_buffer.should have_tag('form li label input[@type="checkbox"]')
2180
+ output_buffer.should have_tag('form li label input[@name="post[allow_comments]"]')
2181
+ output_buffer.should have_tag('form li label input[@type="checkbox"][@value="1"]')
2182
+ end
2183
+
2184
+ it 'should allow checked and unchecked values to be sent' do
2185
+ semantic_form_for(@new_post) do |builder|
2186
+ concat(builder.input(:allow_comments, :as => :boolean, :checked_value => 'checked', :unchecked_value => 'unchecked'))
2187
+ end
2188
+
2189
+ output_buffer.should have_tag('form li label input[@type="checkbox"][@value="checked"]')
2190
+ output_buffer.should have_tag('form li label input[@type="hidden"][@value="unchecked"]')
2191
+ end
2192
+
2193
+ it 'should generate a label and a checkbox even if no object is given' do
2194
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
2195
+ concat(builder.input(:allow_comments, :as => :boolean))
2196
+ end
2197
+
2198
+ output_buffer.should have_tag('form li label[@for="project_allow_comments"]')
2199
+ output_buffer.should have_tag('form li label', /Allow comments/)
2200
+ output_buffer.should have_tag('form li label input[@type="checkbox"]')
2201
+
2202
+ output_buffer.should have_tag('form li label input#project_allow_comments')
2203
+ output_buffer.should have_tag('form li label input[@type="checkbox"]')
2204
+ output_buffer.should have_tag('form li label input[@name="project[allow_comments]"]')
2205
+ end
2206
+
2207
+ end
2208
+ end
2209
+