nofxx-formtastic 0.1.5

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