lperichon-formtastic 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ describe 'Formtastic::SemanticFormHelper.builder' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ class MyCustomFormBuilder < Formtastic::SemanticFormBuilder
9
+ def awesome_input(method, options)
10
+ self.text_field(method)
11
+ end
12
+ end
13
+
14
+ before do
15
+ @output_buffer = ''
16
+ mock_everything
17
+ end
18
+
19
+ it 'is the Formtastic::SemanticFormBuilder by default' do
20
+ Formtastic::SemanticFormHelper.builder.should == Formtastic::SemanticFormBuilder
21
+ end
22
+
23
+ it 'can be configured to use your own custom form builder' do
24
+ # Set it to a custom builder class
25
+ Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
26
+ Formtastic::SemanticFormHelper.builder.should == MyCustomFormBuilder
27
+
28
+ # Reset it to the default
29
+ Formtastic::SemanticFormHelper.builder = Formtastic::SemanticFormBuilder
30
+ Formtastic::SemanticFormHelper.builder.should == Formtastic::SemanticFormBuilder
31
+ end
32
+
33
+ describe "when using a custom builder" do
34
+
35
+ before do
36
+ @new_post.stub!(:title)
37
+ Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
38
+ end
39
+
40
+ after do
41
+ Formtastic::SemanticFormHelper.builder = Formtastic::SemanticFormBuilder
42
+ end
43
+
44
+ describe "semantic_form_for" do
45
+
46
+ it "should yeild and instance of the custom builder" do
47
+ semantic_form_for(@new_post) do |builder|
48
+ builder.class.should == MyCustomFormBuilder
49
+ end
50
+ end
51
+
52
+ it "should allow me to call my custom input" do
53
+ semantic_form_for(@new_post) do |builder|
54
+ concat(builder.input(:title, :as => :awesome))
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ describe 'Rails field_error_proc' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ it "should not be overridden globally for all form builders" do
14
+ current_field_error_proc = ::ActionView::Base.field_error_proc
15
+
16
+ semantic_form_for(@new_post) do |builder|
17
+ ::ActionView::Base.field_error_proc.should_not == current_field_error_proc
18
+ end
19
+
20
+ ::ActionView::Base.field_error_proc.should == current_field_error_proc
21
+
22
+ form_for(@new_post) do |builder|
23
+ ::ActionView::Base.field_error_proc.should == current_field_error_proc
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,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
+