ShadowBelmolve-formtastic 0.1.6 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
- module JustinFrench
2
- module Formtastic
3
- class SemanticFormBuilder < ::Formtastic::SemanticFormBuilder
1
+ module JustinFrench #:nodoc:
2
+ module Formtastic #:nodoc:
3
+ class SemanticFormBuilder < ::Formtastic::SemanticFormBuilder #:nodoc:
4
4
  def initialize(*args)
5
5
  ::ActiveSupport::Deprecation.warn("JustinFrench::Formtastic::SemanticFormBuilder is deprecated. User Formtastic::SemanticFormBuilder instead", caller)
6
6
  super
@@ -62,7 +62,7 @@ describe 'Formtastic' do
62
62
  @fred.stub!(:login).and_return('fred_smith')
63
63
  @fred.stub!(:id).and_return(37)
64
64
  @fred.stub!(:new_record?).and_return(false)
65
- @fred.stub!(:errors).and_return(mock('errors', :on => nil))
65
+ @fred.stub!(:errors).and_return(mock('errors', :[] => nil))
66
66
 
67
67
  @bob = mock('user')
68
68
  @bob.stub!(:class).and_return(Author)
@@ -72,20 +72,20 @@ describe 'Formtastic' do
72
72
  @bob.stub!(:posts).and_return([])
73
73
  @bob.stub!(:post_ids).and_return([])
74
74
  @bob.stub!(:new_record?).and_return(false)
75
- @bob.stub!(:errors).and_return(mock('errors', :on => nil))
75
+ @bob.stub!(:errors).and_return(mock('errors', :[] => nil))
76
76
 
77
77
  Author.stub!(:find).and_return([@fred, @bob])
78
78
  Author.stub!(:human_attribute_name).and_return { |column_name| column_name.humanize }
79
79
  Author.stub!(:human_name).and_return('Author')
80
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 }
81
+ Author.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => Post, :macro => :has_many) if column_name == :posts }
82
82
 
83
83
  # Sometimes we need a mock @post object and some Authors for belongs_to
84
84
  @new_post = mock('post')
85
85
  @new_post.stub!(:class).and_return(Post)
86
86
  @new_post.stub!(:id).and_return(nil)
87
87
  @new_post.stub!(:new_record?).and_return(true)
88
- @new_post.stub!(:errors).and_return(mock('errors', :on => nil))
88
+ @new_post.stub!(:errors).and_return(mock('errors', :[] => nil))
89
89
  @new_post.stub!(:author).and_return(nil)
90
90
 
91
91
  @freds_post = mock('post')
@@ -97,7 +97,7 @@ describe 'Formtastic' do
97
97
  @freds_post.stub!(:authors).and_return([@fred])
98
98
  @freds_post.stub!(:author_ids).and_return([@fred.id])
99
99
  @freds_post.stub!(:new_record?).and_return(false)
100
- @freds_post.stub!(:errors).and_return(mock('errors', :on => nil))
100
+ @freds_post.stub!(:errors).and_return(mock('errors', :[] => nil))
101
101
  @fred.stub!(:posts).and_return([@freds_post])
102
102
  @fred.stub!(:post_ids).and_return([@freds_post.id])
103
103
 
@@ -106,10 +106,10 @@ describe 'Formtastic' do
106
106
  Post.stub!(:reflect_on_all_validations).and_return([])
107
107
  Post.stub!(:reflect_on_association).and_return do |column_name|
108
108
  case column_name
109
- when :author
110
- mock('reflection', :klass => Author, :macro => :belongs_to)
109
+ when :author, :author_status
110
+ mock('reflection', :options => {}, :klass => Author, :macro => :belongs_to)
111
111
  when :authors
112
- mock('reflection', :klass => Author, :macro => :has_and_belongs_to_many)
112
+ mock('reflection', :options => {}, :klass => Author, :macro => :has_and_belongs_to_many)
113
113
  end
114
114
  end
115
115
  Post.stub!(:find).and_return([@freds_post])
@@ -234,6 +234,10 @@ describe 'Formtastic' do
234
234
  @new_post.stub!(:body)
235
235
  @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
236
236
  end
237
+
238
+ after do
239
+ Formtastic::SemanticFormHelper.builder = Formtastic::SemanticFormBuilder
240
+ end
237
241
 
238
242
  it "can be overridden" do
239
243
 
@@ -286,6 +290,103 @@ describe 'Formtastic' do
286
290
  end
287
291
  end
288
292
 
293
+ describe '#label' do
294
+ it 'should humanize the given attribute' do
295
+ semantic_form_for(@new_post) do |builder|
296
+ builder.label(:login).should have_tag('label', :with => /Login/)
297
+ end
298
+ end
299
+
300
+ it 'should be printed as span' do
301
+ semantic_form_for(@new_post) do |builder|
302
+ builder.label(:login, nil, { :required => true, :as_span => true }).should have_tag('span.label abbr')
303
+ end
304
+ end
305
+
306
+ describe 'when required is given' do
307
+ it 'should append a required note' do
308
+ semantic_form_for(@new_post) do |builder|
309
+ builder.label(:login, nil, :required => true).should have_tag('label abbr')
310
+ end
311
+ end
312
+
313
+ it 'should allow require option to be given as second argument' do
314
+ semantic_form_for(@new_post) do |builder|
315
+ builder.label(:login, :required => true).should have_tag('label abbr')
316
+ end
317
+ end
318
+ end
319
+
320
+ describe 'when label is given' do
321
+ it 'should allow the text to be given as label option' do
322
+ semantic_form_for(@new_post) do |builder|
323
+ builder.label(:login, :required => true, :label => 'My label').should have_tag('label', :with => /My label/)
324
+ end
325
+ end
326
+
327
+ it 'should return nil if label is false' do
328
+ semantic_form_for(@new_post) do |builder|
329
+ builder.label(:login, :label => false).should be_blank
330
+ end
331
+ end
332
+ end
333
+ end
334
+
335
+ describe '#errors_on' do
336
+ before(:each) do
337
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
338
+ @errors = mock('errors')
339
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
340
+ @errors.stub!(:[]).with(:body).and_return(nil)
341
+ @new_post.stub!(:errors).and_return(@errors)
342
+ end
343
+
344
+ describe 'and the errors will be displayed as a sentence' do
345
+ it 'should render a paragraph with the errors joined into a sentence' do
346
+ Formtastic::SemanticFormBuilder.inline_errors = :sentence
347
+ semantic_form_for(@new_post) do |builder|
348
+ builder.errors_on(:title).should have_tag('p.inline-errors', @title_errors.to_sentence)
349
+ end
350
+ end
351
+ end
352
+
353
+ describe 'and the errors will be displayed as a list' do
354
+ it 'should render an unordered list with the class errors' do
355
+ Formtastic::SemanticFormBuilder.inline_errors = :list
356
+ semantic_form_for(@new_post) do |builder|
357
+ builder.errors_on(:title).should have_tag('ul.errors')
358
+ end
359
+ end
360
+
361
+ it 'should include a list element for each of the errors within the unordered list' do
362
+ Formtastic::SemanticFormBuilder.inline_errors = :list
363
+ semantic_form_for(@new_post) do |builder|
364
+ @title_errors.each do |error|
365
+ builder.errors_on(:title).should have_tag('ul.errors li', error)
366
+ end
367
+ end
368
+ end
369
+ end
370
+
371
+ describe 'but the errors will not be shown' do
372
+ it 'should return nil' do
373
+ Formtastic::SemanticFormBuilder.inline_errors = :none
374
+ semantic_form_for(@new_post) do |builder|
375
+ builder.errors_on(:title).should be_nil
376
+ end
377
+ end
378
+ end
379
+
380
+ describe 'and no error is found on the method' do
381
+ it 'should return nil' do
382
+ Formtastic::SemanticFormBuilder.inline_errors = :sentence
383
+ semantic_form_for(@new_post) do |builder|
384
+ builder.errors_on(:body).should be_nil
385
+ end
386
+ end
387
+ end
388
+ end
389
+
289
390
  describe '#input' do
290
391
 
291
392
  before do
@@ -472,13 +573,22 @@ describe 'Formtastic' do
472
573
 
473
574
  describe 'when not provided' do
474
575
 
475
- it 'should default to a string for forms without objects' do
576
+ it 'should default to a string for forms without objects unless column is password' do
476
577
  semantic_form_for(:project, :url => 'http://test.host') do |builder|
477
578
  concat(builder.input(:anything))
478
579
  end
479
580
  output_buffer.should have_tag('form li.string')
480
581
  end
481
582
 
583
+ it 'should default to password for forms without objects if column is password' do
584
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
585
+ concat(builder.input(:password))
586
+ concat(builder.input(:password_confirmation))
587
+ concat(builder.input(:confirm_password))
588
+ end
589
+ output_buffer.should have_tag('form li.password', :count => 3)
590
+ end
591
+
482
592
  it 'should default to a string for methods on objects that don\'t respond to "column_for_attribute"' do
483
593
  @new_post.stub!(:method_without_a_database_column)
484
594
  @new_post.stub!(:column_for_attribute).and_return(nil)
@@ -538,6 +648,10 @@ describe 'Formtastic' do
538
648
  default_input_type(:float).should == :numeric
539
649
  default_input_type(:decimal).should == :numeric
540
650
  end
651
+
652
+ it 'should default to :country for :string columns named country' do
653
+ default_input_type(:string, :country).should == :country
654
+ end
541
655
 
542
656
  describe 'defaulting to file column' do
543
657
  Formtastic::SemanticFormBuilder.file_methods.each do |method|
@@ -561,7 +675,7 @@ describe 'Formtastic' do
561
675
  end
562
676
 
563
677
  it 'should call the corresponding input method' do
564
- [:select, :time_zone, :radio, :date, :datetime, :time, :boolean].each do |input_style|
678
+ [:select, :time_zone, :radio, :date, :datetime, :time, :boolean, :check_boxes, :hidden].each do |input_style|
565
679
  @new_post.stub!(:generic_column_name)
566
680
  @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
567
681
  semantic_form_for(@new_post) do |builder|
@@ -583,9 +697,8 @@ describe 'Formtastic' do
583
697
  end
584
698
 
585
699
  describe ':label option' do
586
-
700
+
587
701
  describe 'when provided' do
588
-
589
702
  it 'should be passed down to the label tag' do
590
703
  semantic_form_for(@new_post) do |builder|
591
704
  concat(builder.input(:title, :label => "Kustom"))
@@ -593,35 +706,89 @@ describe 'Formtastic' do
593
706
  output_buffer.should have_tag("form li label", /Kustom/)
594
707
  end
595
708
 
709
+ it 'should not generate a label if false' do
710
+ semantic_form_for(@new_post) do |builder|
711
+ concat(builder.input(:title, :label => false))
712
+ end
713
+ output_buffer.should_not have_tag("form li label")
714
+ end
715
+
716
+ it 'should be dupped if frozen' do
717
+ semantic_form_for(@new_post) do |builder|
718
+ concat(builder.input(:title, :label => "Kustom".freeze))
719
+ end
720
+ output_buffer.should have_tag("form li label", /Kustom/)
721
+ end
596
722
  end
597
723
 
598
724
  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))
725
+ describe 'when localized label is NOT provided' do
726
+ describe 'and object is not given' do
727
+ it 'should default the humanized method name, passing it down to the label tag' do
728
+ Formtastic::SemanticFormBuilder.label_str_method = :humanize
729
+
730
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
731
+ concat(builder.input(:meta_description))
732
+ end
733
+
734
+ output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
735
+ end
736
+ end
737
+
738
+ describe 'and object is given' do
739
+ it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
740
+ @new_post.stub!(:meta_description) # a two word method name
741
+ @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
742
+
743
+ semantic_form_for(@new_post) do |builder|
744
+ concat(builder.input(:meta_description))
745
+ end
746
+
747
+ output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
605
748
  end
606
-
607
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
608
749
  end
609
750
  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
-
751
+
752
+ describe 'when localized label is provided' do
753
+ before do
754
+ @localized_label_text = 'Localized title'
755
+ @default_localized_label_text = 'Default localized title'
756
+ ::I18n.backend.store_translations :en,
757
+ :formtastic => {
758
+ :labels => {
759
+ :title => @default_localized_label_text,
760
+ :post => {
761
+ :title => @localized_label_text
762
+ }
763
+ }
764
+ }
765
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
766
+ end
767
+
768
+ it 'should render a label with localized label (I18n)' do
616
769
  semantic_form_for(@new_post) do |builder|
617
- concat(builder.input(:meta_description))
770
+ concat(builder.input(:title, :label => true))
618
771
  end
619
-
620
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
772
+ output_buffer.should have_tag('form li label', @localized_label_text)
773
+ end
774
+
775
+ it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
776
+ ::I18n.backend.store_translations :en,
777
+ :formtastic => {
778
+ :labels => {
779
+ :post => {
780
+ :title => nil
781
+ }
782
+ }
783
+ }
784
+ semantic_form_for(@new_post) do |builder|
785
+ concat(builder.input(:title, :label => true))
786
+ end
787
+ output_buffer.should have_tag('form li label', @default_localized_label_text)
621
788
  end
622
789
  end
623
790
  end
624
-
791
+
625
792
  end
626
793
 
627
794
  describe ':hint option' do
@@ -637,12 +804,104 @@ describe 'Formtastic' do
637
804
  end
638
805
 
639
806
  describe 'when not provided' do
640
- it 'should not render a hint paragraph' do
641
- hint_text = "this is the title of the post"
807
+ describe 'when localized hint (I18n) is provided' do
808
+ before do
809
+ @localized_hint_text = "This is the localized hint."
810
+ @default_localized_hint_text = "This is the default localized hint."
811
+ ::I18n.backend.store_translations :en,
812
+ :formtastic => {
813
+ :hints => {
814
+ :title => @default_localized_hint_text,
815
+ :post => {
816
+ :title => @localized_hint_text
817
+ }
818
+ }
819
+ }
820
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
821
+ end
822
+
823
+ describe 'when provided value (hint value) is set to TRUE' do
824
+ it 'should render a hint paragraph containing a localized hint (I18n)' do
825
+ semantic_form_for(@new_post) do |builder|
826
+ concat(builder.input(:title, :hint => true))
827
+ end
828
+ output_buffer.should have_tag('form li p.inline-hints', @localized_hint_text)
829
+ end
830
+
831
+ it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do
832
+ ::I18n.backend.store_translations :en,
833
+ :formtastic => {
834
+ :hints => {
835
+ :post => {
836
+ :title => nil
837
+ }
838
+ }
839
+ }
840
+ semantic_form_for(@new_post) do |builder|
841
+ concat(builder.input(:title, :hint => true))
842
+ end
843
+ output_buffer.should have_tag('form li p.inline-hints', @default_localized_hint_text)
844
+ end
845
+ end
846
+
847
+ describe 'when provided value (label value) is set to FALSE' do
848
+ it 'should not render a hint paragraph' do
849
+ semantic_form_for(@new_post) do |builder|
850
+ concat(builder.input(:title, :hint => false))
851
+ end
852
+ output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text)
853
+ end
854
+ end
855
+ end
856
+
857
+ describe 'when localized hint (I18n) is not provided' do
858
+ it 'should not render a hint paragraph' do
859
+ semantic_form_for(@new_post) do |builder|
860
+ concat(builder.input(:title))
861
+ end
862
+ output_buffer.should_not have_tag('form li p.inline-hints')
863
+ end
864
+ end
865
+ end
866
+
867
+ end
868
+
869
+ describe ':wrapper_html option' do
870
+
871
+ describe 'when provided' do
872
+ it 'should be passed down to the li tag' do
873
+ semantic_form_for(@new_post) do |builder|
874
+ concat(builder.input(:title, :wrapper_html => {:id => :another_id}))
875
+ end
876
+ output_buffer.should have_tag("form li#another_id")
877
+ end
878
+
879
+ it 'should append given classes to li default classes' do
880
+ semantic_form_for(@new_post) do |builder|
881
+ concat(builder.input(:title, :wrapper_html => {:class => :another_class}, :required => true))
882
+ end
883
+ output_buffer.should have_tag("form li.string")
884
+ output_buffer.should have_tag("form li.required")
885
+ output_buffer.should have_tag("form li.another_class")
886
+ end
887
+
888
+ it 'should allow classes to be an array' do
889
+ semantic_form_for(@new_post) do |builder|
890
+ concat(builder.input(:title, :wrapper_html => {:class => [ :my_class, :another_class ]}))
891
+ end
892
+ output_buffer.should have_tag("form li.string")
893
+ output_buffer.should have_tag("form li.my_class")
894
+ output_buffer.should have_tag("form li.another_class")
895
+ end
896
+ end
897
+
898
+ describe 'when not provided' do
899
+ it 'should use default id and class' do
642
900
  semantic_form_for(@new_post) do |builder|
643
901
  concat(builder.input(:title))
644
902
  end
645
- output_buffer.should_not have_tag("form li p.inline-hints")
903
+ output_buffer.should have_tag("form li#post_title_input")
904
+ output_buffer.should have_tag("form li.string")
646
905
  end
647
906
  end
648
907
 
@@ -660,11 +919,10 @@ describe 'Formtastic' do
660
919
  end
661
920
 
662
921
  describe 'when there are errors on the object for this method' do
663
-
664
922
  before do
665
923
  @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
666
924
  @errors = mock('errors')
667
- @errors.stub!(:on).with('title').and_return(@title_errors)
925
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
668
926
  @new_post.stub!(:errors).and_return(@errors)
669
927
  end
670
928
 
@@ -682,65 +940,24 @@ describe 'Formtastic' do
682
940
  output_buffer.should_not have_tag('div.fieldWithErrors')
683
941
  end
684
942
 
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
943
+ it 'should render a paragraph for the errors' do
944
+ Formtastic::SemanticFormBuilder.inline_errors = :sentence
945
+ semantic_form_for(@new_post) do |builder|
946
+ concat(builder.input(:title))
717
947
  end
718
-
948
+ output_buffer.should have_tag('form li.error p.inline-errors')
719
949
  end
720
950
 
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')
951
+ it 'should not display an error list' do
952
+ Formtastic::SemanticFormBuilder.inline_errors = :list
953
+ semantic_form_for(@new_post) do |builder|
954
+ concat(builder.input(:title))
736
955
  end
737
-
956
+ output_buffer.should have_tag('form li.error ul.errors')
738
957
  end
739
-
740
958
  end
741
959
 
742
960
  describe 'when there are no errors on the object for this method' do
743
-
744
961
  before do
745
962
  semantic_form_for(@new_post) do |builder|
746
963
  concat(builder.input(:title))
@@ -758,11 +975,9 @@ describe 'Formtastic' do
758
975
  it 'should not display an error list' do
759
976
  output_buffer.should_not have_tag('form li.error ul.errors')
760
977
  end
761
-
762
978
  end
763
979
 
764
980
  describe 'when no object is provided' do
765
-
766
981
  before do
767
982
  semantic_form_for(:project, :url => 'http://test.host') do |builder|
768
983
  concat(builder.input(:title))
@@ -780,7 +995,6 @@ describe 'Formtastic' do
780
995
  it 'should not display an error list' do
781
996
  output_buffer.should_not have_tag('form li.error ul.errors')
782
997
  end
783
-
784
998
  end
785
999
  end
786
1000
 
@@ -821,31 +1035,33 @@ describe 'Formtastic' do
821
1035
  output_buffer.should have_tag("form li input[@name=\"post[title]\"]")
822
1036
  end
823
1037
 
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
1038
+ unless type == :numeric
1039
+ it 'should have a maxlength matching the column limit' do
1040
+ @new_post.column_for_attribute(:title).limit.should == 50
1041
+ output_buffer.should have_tag("form li input[@maxlength='50']")
1042
+ end
828
1043
 
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))
1044
+ it 'should use default_text_field_size for columns longer than default_text_field_size' do
1045
+ default_size = Formtastic::SemanticFormBuilder.default_text_field_size
1046
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => default_size * 2))
832
1047
 
833
- semantic_form_for(@new_post) do |builder|
834
- concat(builder.input(:title, :as => type))
1048
+ semantic_form_for(@new_post) do |builder|
1049
+ concat(builder.input(:title, :as => type))
1050
+ end
1051
+
1052
+ output_buffer.should have_tag("form li input[@size='#{default_size}']")
835
1053
  end
836
1054
 
837
- output_buffer.should have_tag("form li input[@size='#{default_size}']")
838
- end
1055
+ it 'should use the column size for columns shorter than default_text_field_size' do
1056
+ column_limit_shorted_than_default = 1
1057
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => column_limit_shorted_than_default))
839
1058
 
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))
1059
+ semantic_form_for(@new_post) do |builder|
1060
+ concat(builder.input(:title, :as => type))
1061
+ end
843
1062
 
844
- semantic_form_for(@new_post) do |builder|
845
- concat(builder.input(:title, :as => type))
1063
+ output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
846
1064
  end
847
-
848
- output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
849
1065
  end
850
1066
 
851
1067
  it 'should use default_text_field_size for methods without database columns' do
@@ -866,6 +1082,13 @@ describe 'Formtastic' do
866
1082
  output_buffer.should have_tag("form li input.myclass")
867
1083
  end
868
1084
 
1085
+ it 'should consider input_html :id in labels' do
1086
+ semantic_form_for(@new_post) do |builder|
1087
+ concat(builder.input(:title, :as => type, :input_html => { :id => 'myid' }))
1088
+ end
1089
+ output_buffer.should have_tag('form li label[@for="myid"]')
1090
+ end
1091
+
869
1092
  it 'should generate input and labels even if no object is given' do
870
1093
  semantic_form_for(:project, :url => 'http://test.host/') do |builder|
871
1094
  concat(builder.input(:title, :as => type))
@@ -947,139 +1170,206 @@ describe 'Formtastic' do
947
1170
 
948
1171
  end
949
1172
 
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))
1173
+ describe 'when no object is given' do
1174
+ before(:each) do
1175
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
1176
+ concat(builder.input(:title, :as => type))
1177
+ end
953
1178
  end
954
1179
 
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/)
1180
+ it 'should generate input' do
1181
+ if template_method.to_s =~ /_field$/ # password_field
1182
+ output_buffer.should have_tag("form li input")
1183
+ output_buffer.should have_tag("form li input#project_title")
1184
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
1185
+ output_buffer.should have_tag("form li input[@name=\"project[title]\"]")
1186
+ else
1187
+ output_buffer.should have_tag("form li #{input_type}")
1188
+ output_buffer.should have_tag("form li #{input_type}#project_title")
1189
+ output_buffer.should have_tag("form li #{input_type}[@name=\"project[title]\"]")
1190
+ end
1191
+ end
958
1192
 
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]\"]")
1193
+ it 'should generate labels' do
1194
+ output_buffer.should have_tag('form li label')
1195
+ output_buffer.should have_tag('form li label[@for="project_title"')
1196
+ output_buffer.should have_tag('form li label', /Title/)
968
1197
  end
969
1198
  end
970
1199
 
971
1200
  end
972
1201
  end
973
1202
 
1203
+ describe ":as => :hidden" do
1204
+ before do
1205
+ @new_post.stub!(:hidden)
1206
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
974
1207
 
975
- describe ':as => :radio' do
1208
+ semantic_form_for(@new_post) do |builder|
1209
+ concat(builder.input(:hidden, :as => :hidden))
1210
+ end
1211
+ end
976
1212
 
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))
1213
+ it "should have a hidden class on the wrapper" do
1214
+ output_buffer.should have_tag('form li.hidden')
981
1215
  end
982
1216
 
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
1217
+ it 'should have a post_hidden_input id on the wrapper' do
1218
+ output_buffer.should have_tag('form li#post_hidden_input')
1219
+ end
989
1220
 
990
- it 'should have a radio class on the wrapper' do
991
- output_buffer.should have_tag('form li.radio')
992
- end
1221
+ it 'should not generate a label for the input' do
1222
+ output_buffer.should_not have_tag('form li label')
1223
+ end
993
1224
 
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
1225
+ it "should generate a input field" do
1226
+ output_buffer.should have_tag("form li input#post_hidden")
1227
+ output_buffer.should have_tag("form li input[@type=\"hidden\"]")
1228
+ output_buffer.should have_tag("form li input[@name=\"post[hidden]\"]")
1229
+ end
1230
+ end
997
1231
 
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
1232
+ describe ":as => :time_zone" do
1233
+ before do
1234
+ @new_post.stub!(:time_zone)
1235
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
1003
1236
 
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)
1237
+ semantic_form_for(@new_post) do |builder|
1238
+ concat(builder.input(:time_zone))
1007
1239
  end
1240
+ end
1008
1241
 
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
1242
+ it "should have a time_zone class on the wrapper" do
1243
+ output_buffer.should have_tag('form li.time_zone')
1244
+ end
1012
1245
 
1013
- describe "each choice" do
1246
+ it 'should have a post_title_input id on the wrapper' do
1247
+ output_buffer.should have_tag('form li#post_time_zone_input')
1248
+ end
1014
1249
 
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
1250
+ it 'should generate a label for the input' do
1251
+ output_buffer.should have_tag('form li label')
1252
+ output_buffer.should have_tag('form li label[@for="post_time_zone"')
1253
+ output_buffer.should have_tag('form li label', /Time zone/)
1254
+ end
1023
1255
 
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
1256
+ it "should generate a select" do
1257
+ output_buffer.should have_tag("form li select")
1258
+ output_buffer.should have_tag("form li select#post_time_zone")
1259
+ output_buffer.should have_tag("form li select[@name=\"post[time_zone]\"]")
1260
+ end
1029
1261
 
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
1262
+ it 'should use input_html to style inputs' do
1263
+ semantic_form_for(@new_post) do |builder|
1264
+ concat(builder.input(:time_zone, :input_html => { :class => 'myclass' }))
1265
+ end
1266
+ output_buffer.should have_tag("form li select.myclass")
1267
+ end
1268
+
1269
+ describe 'when no object is given' do
1270
+ before(:each) do
1271
+ semantic_form_for(:project, :url => 'http://test.host/') do |builder|
1272
+ concat(builder.input(:time_zone, :as => :time_zone))
1037
1273
  end
1274
+ end
1038
1275
 
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
1276
+ it 'should generate labels' do
1277
+ output_buffer.should have_tag('form li label')
1278
+ output_buffer.should have_tag('form li label[@for="project_time_zone"')
1279
+ output_buffer.should have_tag('form li label', /Time zone/)
1280
+ end
1043
1281
 
1282
+ it 'should generate select inputs' do
1283
+ output_buffer.should have_tag("form li select")
1284
+ output_buffer.should have_tag("form li select#project_time_zone")
1285
+ output_buffer.should have_tag("form li select[@name=\"project[time_zone]\"]")
1286
+ end
1287
+ end
1288
+ end
1289
+
1290
+ describe ":as => :country" do
1291
+
1292
+ before do
1293
+ @new_post.stub!(:country)
1294
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
1295
+ end
1296
+
1297
+ describe "when country_select is not available as a helper from a plugin" do
1298
+
1299
+ it "should raise an error, sugesting the author installs a plugin" do
1300
+ lambda {
1044
1301
  semantic_form_for(@new_post) do |builder|
1045
- concat(builder.input(:author, :as => :radio))
1302
+ concat(builder.input(:country, :as => :country))
1046
1303
  end
1047
-
1048
- output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1049
- end
1304
+ }.should raise_error
1050
1305
  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)))
1306
+
1307
+ end
1308
+
1309
+ describe "when country_select is available as a helper (from a plugin)" do
1310
+
1311
+ before do
1312
+ semantic_form_for(@new_post) do |builder|
1313
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1314
+ concat(builder.input(:country, :as => :country))
1057
1315
  end
1316
+ end
1317
+
1318
+ it "should have a time_zone class on the wrapper" do
1319
+ output_buffer.should have_tag('form li.country')
1320
+ end
1058
1321
 
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)
1322
+ it 'should have a post_title_input id on the wrapper' do
1323
+ output_buffer.should have_tag('form li#post_country_input')
1324
+ end
1061
1325
 
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}']")
1326
+ it 'should generate a label for the input' do
1327
+ output_buffer.should have_tag('form li label')
1328
+ output_buffer.should have_tag('form li label[@for="post_country"')
1329
+ output_buffer.should have_tag('form li label', /Country/)
1330
+ end
1065
1331
 
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]']")
1332
+ it "should generate a select" do
1333
+ output_buffer.should have_tag("form li select")
1334
+ end
1335
+
1336
+ end
1337
+
1338
+ describe ":priority_countries option" do
1339
+
1340
+ it "should be passed down to the country_select helper when provided" do
1341
+ priority_countries = ["Foo", "Bah"]
1342
+ semantic_form_for(@new_post) do |builder|
1343
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1344
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1345
+
1346
+ concat(builder.input(:country, :as => :country, :priority_countries => priority_countries))
1347
+ end
1348
+ end
1349
+
1350
+ it "should default to the @@priority_countries config when absent" do
1351
+ priority_countries = Formtastic::SemanticFormBuilder.priority_countries
1352
+ priority_countries.should_not be_empty
1353
+ priority_countries.should_not be_nil
1354
+
1355
+ semantic_form_for(@new_post) do |builder|
1356
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1357
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1358
+
1359
+ concat(builder.input(:country, :as => :country))
1070
1360
  end
1071
1361
  end
1072
-
1362
+
1073
1363
  end
1074
-
1364
+
1075
1365
  end
1076
-
1077
- describe ':as => :check_boxes' do
1366
+
1367
+ describe ':as => :radio' do
1078
1368
 
1079
1369
  before do
1080
1370
  @new_post.stub!(:author).and_return(@bob)
1081
1371
  @new_post.stub!(:author_id).and_return(@bob.id)
1082
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1372
+ Post.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => Author, :macro => :belongs_to) }
1083
1373
  end
1084
1374
 
1085
1375
  describe 'for belongs_to association' do
@@ -1093,7 +1383,7 @@ describe 'Formtastic' do
1093
1383
  output_buffer.should have_tag('form li.radio')
1094
1384
  end
1095
1385
 
1096
- it 'should have a post_author_id_input id on the wrapper' do
1386
+ it 'should have a post_author_input id on the wrapper' do
1097
1387
  output_buffer.should have_tag('form li#post_author_input')
1098
1388
  end
1099
1389
 
@@ -1108,7 +1398,7 @@ describe 'Formtastic' do
1108
1398
  output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1109
1399
  end
1110
1400
 
1111
- it 'should have one option with a "selected" attribute' do
1401
+ it 'should have one option with a "checked" attribute' do
1112
1402
  output_buffer.should have_tag('form li input[@checked]', :count => 1)
1113
1403
  end
1114
1404
 
@@ -1116,10 +1406,8 @@ describe 'Formtastic' do
1116
1406
 
1117
1407
  it 'should contain a label for the radio input with a nested input and label text' do
1118
1408
  Author.find(:all).each do |author|
1119
- output_buffer.should have_tag('form li fieldset ol li label')
1120
1409
  output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1121
1410
  output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_id_#{author.id}']")
1122
- output_buffer.should have_tag("form li fieldset ol li label input")
1123
1411
  end
1124
1412
  end
1125
1413
 
@@ -1151,29 +1439,39 @@ describe 'Formtastic' do
1151
1439
  end
1152
1440
  end
1153
1441
 
1154
- it 'should generate a fieldset, legend, labels and inputs even if no object is given' do
1155
- output_buffer.replace ''
1442
+ describe 'and no object is given' do
1443
+ before(:each) do
1444
+ output_buffer.replace ''
1445
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1446
+ concat(builder.input(:author_id, :as => :radio, :collection => Author.find(:all)))
1447
+ end
1448
+ end
1156
1449
 
1157
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
1158
- concat(builder.input(:author_id, :as => :radio, :collection => Author.find(:all)))
1450
+ it 'should generate a fieldset with legend' do
1451
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1159
1452
  end
1160
1453
 
1161
- output_buffer.should have_tag('form li fieldset legend', /Author/)
1162
- output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1454
+ it 'shold generate an li tag for each item in the collection' do
1455
+ output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1456
+ end
1163
1457
 
1164
- Author.find(:all).each do |author|
1165
- output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1166
- output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1458
+ it 'should generate labels for each item' do
1459
+ Author.find(:all).each do |author|
1460
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1461
+ output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1462
+ end
1463
+ end
1167
1464
 
1168
- output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1169
- output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1170
- output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1171
- output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id]']")
1465
+ it 'should generate inputs for each item' do
1466
+ Author.find(:all).each do |author|
1467
+ output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1468
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1469
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1470
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id]']")
1471
+ end
1172
1472
  end
1173
1473
  end
1174
-
1175
1474
  end
1176
-
1177
1475
  end
1178
1476
 
1179
1477
  describe ':as => :select' do
@@ -1217,9 +1515,13 @@ describe 'Formtastic' do
1217
1515
  it 'should create a select without size' do
1218
1516
  output_buffer.should_not have_tag('form li select[@size]')
1219
1517
  end
1220
-
1518
+
1519
+ it 'should have a blank option' do
1520
+ output_buffer.should have_tag("form li select option[@value='']")
1521
+ end
1522
+
1221
1523
  it 'should have a select option for each Author' do
1222
- output_buffer.should have_tag('form li select option', :count => Author.find(:all).size)
1524
+ output_buffer.should have_tag('form li select option', :count => Author.find(:all).size + 1)
1223
1525
  Author.find(:all).each do |author|
1224
1526
  output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1225
1527
  end
@@ -1228,6 +1530,18 @@ describe 'Formtastic' do
1228
1530
  it 'should have one option with a "selected" attribute' do
1229
1531
  output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1230
1532
  end
1533
+
1534
+ it 'should not singularize the association name' do
1535
+ @new_post.stub!(:author_status).and_return(@bob)
1536
+ @new_post.stub!(:author_status_id).and_return(@bob.id)
1537
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1538
+
1539
+ semantic_form_for(@new_post) do |builder|
1540
+ concat(builder.input(:author_status, :as => :select))
1541
+ end
1542
+
1543
+ output_buffer.should have_tag('form li select#post_author_status_id')
1544
+ end
1231
1545
  end
1232
1546
 
1233
1547
  describe 'for a has_many association' do
@@ -1247,7 +1561,7 @@ describe 'Formtastic' do
1247
1561
 
1248
1562
  it 'should have a label inside the wrapper' do
1249
1563
  output_buffer.should have_tag('form li label')
1250
- output_buffer.should have_tag('form li label', /Posts/)
1564
+ output_buffer.should have_tag('form li label', /Post/)
1251
1565
  output_buffer.should have_tag("form li label[@for='author_post_ids']")
1252
1566
  end
1253
1567
 
@@ -1266,6 +1580,10 @@ describe 'Formtastic' do
1266
1580
  output_buffer.should have_tag("form li select option[@value='#{post.id}']", /#{post.to_label}/)
1267
1581
  end
1268
1582
  end
1583
+
1584
+ it 'should not have a blank option' do
1585
+ output_buffer.should_not have_tag("form li select option[@value='']")
1586
+ end
1269
1587
 
1270
1588
  it 'should have one option with a "selected" attribute' do
1271
1589
  output_buffer.should have_tag('form li select option[@selected]', :count => 1)
@@ -1289,7 +1607,7 @@ describe 'Formtastic' do
1289
1607
 
1290
1608
  it 'should have a label inside the wrapper' do
1291
1609
  output_buffer.should have_tag('form li label')
1292
- output_buffer.should have_tag('form li label', /Authors/)
1610
+ output_buffer.should have_tag('form li label', /Author/)
1293
1611
  output_buffer.should have_tag("form li label[@for='post_author_ids']")
1294
1612
  end
1295
1613
 
@@ -1308,42 +1626,179 @@ describe 'Formtastic' do
1308
1626
  output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1309
1627
  end
1310
1628
  end
1629
+
1630
+ it 'should not have a blank option' do
1631
+ output_buffer.should_not have_tag("form li select option[@value='']")
1632
+ end
1311
1633
 
1312
1634
  it 'should have one option with a "selected" attribute' do
1313
1635
  output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1314
1636
  end
1315
1637
  end
1316
-
1317
- describe 'when :include_blank => true, :prompt => "choose something" is set' do
1638
+
1639
+ describe 'when :include_blank is not set' do
1640
+ before do
1641
+ @new_post.stub!(:author_id).and_return(nil)
1642
+ semantic_form_for(@new_post) do |builder|
1643
+ concat(builder.input(:author, :as => :select))
1644
+ end
1645
+ end
1646
+
1647
+ it 'should have a blank option by default' do
1648
+ output_buffer.should have_tag("form li select option[@value='']", "")
1649
+ end
1650
+ end
1651
+
1652
+ describe 'when :include_blank is set to false' do
1318
1653
  before do
1319
1654
  @new_post.stub!(:author_id).and_return(nil)
1320
1655
  semantic_form_for(@new_post) do |builder|
1321
- concat(builder.input(:author, :as => :select, :include_blank => true, :prompt => "choose author"))
1656
+ concat(builder.input(:author, :as => :select, :include_blank => false))
1322
1657
  end
1323
1658
  end
1659
+
1660
+ it 'should not have a blank option' do
1661
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
1662
+ end
1663
+ end
1324
1664
 
1325
- it 'should have a blank select option' do
1326
- output_buffer.should have_tag("form li select option[@value='']", //)
1665
+ describe 'when :prompt => "choose something" is set' do
1666
+ before do
1667
+ @new_post.stub!(:author_id).and_return(nil)
1668
+ semantic_form_for(@new_post) do |builder|
1669
+ concat(builder.input(:author, :as => :select, :prompt => "choose author"))
1670
+ end
1327
1671
  end
1328
1672
 
1329
1673
  it 'should have a select with prompt' do
1330
1674
  output_buffer.should have_tag("form li select option[@value='']", /choose author/)
1331
1675
  end
1676
+
1677
+ it 'should not have a blank select option' do
1678
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
1679
+ end
1332
1680
  end
1333
1681
 
1334
- it 'should generate label, select and options even if object is not given' do
1335
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
1336
- concat(builder.input(:author, :as => :select, :collection => Author.find(:all)))
1682
+ describe 'when no object is given' do
1683
+ before(:each) do
1684
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1685
+ concat(builder.input(:author, :as => :select, :collection => Author.find(:all)))
1686
+ end
1687
+ end
1688
+
1689
+ it 'should generate label' do
1690
+ output_buffer.should have_tag('form li label', /Author/)
1691
+ output_buffer.should have_tag("form li label[@for='project_author']")
1692
+ end
1693
+
1694
+ it 'should generate select inputs' do
1695
+ output_buffer.should have_tag('form li select#project_author')
1696
+ output_buffer.should have_tag('form li select option', :count => Author.find(:all).size + 1)
1697
+ end
1698
+
1699
+ it 'should generate an option to each item' do
1700
+ Author.find(:all).each do |author|
1701
+ output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1702
+ end
1703
+ end
1704
+ end
1705
+ end
1706
+
1707
+ describe ':as => :check_boxes' do
1708
+
1709
+ describe 'for a has_many association' do
1710
+ before do
1711
+ semantic_form_for(@fred) do |builder|
1712
+ concat(builder.input(:posts, :as => :check_boxes, :value_as_class => true))
1713
+ end
1714
+ end
1715
+
1716
+ it 'should have a check_boxes class on the wrapper' do
1717
+ output_buffer.should have_tag('form li.check_boxes')
1718
+ end
1719
+
1720
+ it 'should have a author_posts_input id on the wrapper' do
1721
+ output_buffer.should have_tag('form li#author_posts_input')
1722
+ end
1723
+
1724
+ it 'should generate a fieldset and legend containing label text for the input' do
1725
+ output_buffer.should have_tag('form li fieldset')
1726
+ output_buffer.should have_tag('form li fieldset legend')
1727
+ output_buffer.should have_tag('form li fieldset legend', /Posts/)
1728
+ end
1729
+
1730
+ it 'should generate an ordered list with a list item for each choice' do
1731
+ output_buffer.should have_tag('form li fieldset ol')
1732
+ output_buffer.should have_tag('form li fieldset ol li', :count => Post.find(:all).size)
1733
+ end
1734
+
1735
+ it 'should have one option with a "checked" attribute' do
1736
+ output_buffer.should have_tag('form li input[@checked]', :count => 1)
1737
+ end
1738
+
1739
+ it 'should generate hidden inputs with default value blank' do
1740
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='hidden'][@value='']", :count => Post.find(:all).size)
1741
+ end
1742
+
1743
+ describe "each choice" do
1744
+
1745
+ it 'should contain a label for the radio input with a nested input and label text' do
1746
+ Post.find(:all).each do |post|
1747
+ output_buffer.should have_tag('form li fieldset ol li label', /#{post.to_label}/)
1748
+ output_buffer.should have_tag("form li fieldset ol li label[@for='author_post_ids_#{post.id}']")
1749
+ end
1750
+ end
1751
+
1752
+ it 'should use values as li.class when value_as_class is true' do
1753
+ Post.find(:all).each do |post|
1754
+ output_buffer.should have_tag("form li fieldset ol li.#{post.id} label")
1755
+ end
1756
+ end
1757
+
1758
+ it 'should have a checkbox input for each post' do
1759
+ Post.find(:all).each do |post|
1760
+ output_buffer.should have_tag("form li fieldset ol li label input#author_post_ids_#{post.id}")
1761
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='author[post_ids][]']", :count => 2)
1762
+ end
1763
+ end
1764
+
1765
+ it "should mark input as checked if it's the the existing choice" do
1766
+ Post.find(:all).include?(@fred.posts.first).should be_true
1767
+ output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1768
+ end
1337
1769
  end
1338
1770
 
1339
- output_buffer.should have_tag('form li label', /Author/)
1340
- output_buffer.should have_tag("form li label[@for='project_author']")
1771
+ describe 'and no object is given' do
1772
+ before(:each) do
1773
+ output_buffer.replace ''
1774
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
1775
+ concat(builder.input(:author_id, :as => :check_boxes, :collection => Author.find(:all)))
1776
+ end
1777
+ end
1778
+
1779
+ it 'should generate a fieldset with legend' do
1780
+ output_buffer.should have_tag('form li fieldset legend', /Author/)
1781
+ end
1341
1782
 
1342
- output_buffer.should have_tag('form li select#project_author')
1343
- output_buffer.should have_tag('form li select option', :count => Author.find(:all).size)
1783
+ it 'shold generate an li tag for each item in the collection' do
1784
+ output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1785
+ end
1786
+
1787
+ it 'should generate labels for each item' do
1788
+ Author.find(:all).each do |author|
1789
+ output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1790
+ output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1791
+ end
1792
+ end
1344
1793
 
1345
- Author.find(:all).each do |author|
1346
- output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1794
+ it 'should generate inputs for each item' do
1795
+ Author.find(:all).each do |author|
1796
+ output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1797
+ output_buffer.should have_tag("form li fieldset ol li label input[@type='checkbox']")
1798
+ output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1799
+ output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id][]']")
1800
+ end
1801
+ end
1347
1802
  end
1348
1803
  end
1349
1804
  end
@@ -1356,7 +1811,7 @@ describe 'Formtastic' do
1356
1811
  @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1357
1812
  end
1358
1813
 
1359
- { :select => :option, :radio => :input }.each do |type, countable|
1814
+ { :select => :option, :radio => :input, :check_boxes => :'input[@type="checkbox"]' }.each do |type, countable|
1360
1815
 
1361
1816
  describe ":as => #{type.inspect}" do
1362
1817
  describe 'when the :collection option is not provided' do
@@ -1397,7 +1852,7 @@ describe 'Formtastic' do
1397
1852
  semantic_form_for(@new_post) do |builder|
1398
1853
  concat(builder.input(:author, :as => type, :collection => @authors))
1399
1854
  end
1400
- output_buffer.should have_tag("form li.#{type} #{countable}", :count => @authors.size)
1855
+ output_buffer.should have_tag("form li.#{type} #{countable}", :count => @authors.size + (type == :select ? 1 : 0))
1401
1856
  end
1402
1857
 
1403
1858
  describe 'and the :collection is an array of strings' do
@@ -1411,9 +1866,9 @@ describe 'Formtastic' do
1411
1866
  concat(builder.input(:category_name, :as => type, :collection => @categories))
1412
1867
  end
1413
1868
 
1414
- @categories.each do |item|
1415
- output_buffer.should have_tag("form li.#{type}", /#{item}/)
1416
- output_buffer.should have_tag("form li.#{type} #{countable}[@value=#{item}]")
1869
+ @categories.each do |value|
1870
+ output_buffer.should have_tag("form li.#{type}", /#{value}/)
1871
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1417
1872
  end
1418
1873
  end
1419
1874
 
@@ -1446,7 +1901,7 @@ describe 'Formtastic' do
1446
1901
 
1447
1902
  @categories.each do |label, value|
1448
1903
  output_buffer.should have_tag("form li.#{type}", /#{label}/)
1449
- output_buffer.should have_tag("form li.#{type} #{countable}[@value=#{value}]")
1904
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1450
1905
  end
1451
1906
  end
1452
1907
  end
@@ -1459,12 +1914,13 @@ describe 'Formtastic' do
1459
1914
 
1460
1915
  it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
1461
1916
  semantic_form_for(@new_post) do |builder|
1462
- concat(builder.input(:category_name, :as => :radio, :collection => @categories))
1917
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1463
1918
  end
1464
1919
 
1465
- @categories.each do |label, value|
1466
- output_buffer.should have_tag('form li fieldset ol li label', /#{label}/i)
1467
- output_buffer.should have_tag('form li fieldset ol li label input[@value='+value+']')
1920
+ @categories.each do |text, value|
1921
+ label = type == :select ? :option : :label
1922
+ output_buffer.should have_tag("form li.#{type} #{label}", /#{text}/i)
1923
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1468
1924
  end
1469
1925
  end
1470
1926
  end
@@ -1477,12 +1933,13 @@ describe 'Formtastic' do
1477
1933
 
1478
1934
  it "should use the symbol as the label text and value for each #{countable}" do
1479
1935
  semantic_form_for(@new_post) do |builder|
1480
- concat(builder.input(:category_name, :as => :radio, :collection => @categories))
1936
+ concat(builder.input(:category_name, :as => type, :collection => @categories))
1481
1937
  end
1482
1938
 
1483
1939
  @categories.each do |value|
1484
- output_buffer.should have_tag('form li fieldset ol li label', /#{value}/i)
1485
- output_buffer.should have_tag('form li fieldset ol li label input[@value='+value.to_s+']')
1940
+ label = type == :select ? :option : :label
1941
+ output_buffer.should have_tag("form li.#{type} #{label}", /#{value}/i)
1942
+ output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1486
1943
  end
1487
1944
  end
1488
1945
  end
@@ -1539,8 +1996,15 @@ describe 'Formtastic' do
1539
1996
  end
1540
1997
 
1541
1998
  end
1999
+ end
2000
+ end
2001
+
2002
+ describe 'for boolean attributes' do
2003
+
2004
+ { :select => :option, :radio => :input }.each do |type, countable|
2005
+ checked_or_selected = { :select => :selected, :radio => :checked }[type]
1542
2006
 
1543
- describe 'when attribute is a boolean' do
2007
+ describe ":as => #{type.inspect}" do
1544
2008
 
1545
2009
  before do
1546
2010
  @new_post.stub!(:allow_comments)
@@ -1564,7 +2028,7 @@ describe 'Formtastic' do
1564
2028
  end
1565
2029
 
1566
2030
  it "should generate two #{countable}" do
1567
- output_buffer.should have_tag("form li.#{type} #{countable}", :count => 2)
2031
+ output_buffer.should have_tag("form li.#{type} #{countable}", :count => (type == :select ? 3 : 2))
1568
2032
  output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="true"]})
1569
2033
  output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="false"]})
1570
2034
  end
@@ -1588,8 +2052,6 @@ describe 'Formtastic' do
1588
2052
  end
1589
2053
  end
1590
2054
 
1591
- checked_or_selected = { :select => :selected, :radio => :checked }[type]
1592
-
1593
2055
  describe 'when the value is nil' do
1594
2056
  before do
1595
2057
  @new_post.stub!(:allow_comments).and_return(nil)
@@ -1656,6 +2118,7 @@ describe 'Formtastic' do
1656
2118
  end
1657
2119
  end
1658
2120
  end
2121
+
1659
2122
  end
1660
2123
  end
1661
2124
  end
@@ -1758,24 +2221,21 @@ describe 'Formtastic' do
1758
2221
  end
1759
2222
 
1760
2223
  describe 'when :discard_input => true is set' do
1761
-
1762
2224
  it 'should use default hidden value equals to 1 when attribute returns nil' do
1763
- pending
1764
2225
  semantic_form_for(@new_post) do |builder|
1765
2226
  concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
1766
2227
  end
1767
2228
 
1768
- output_buffer.should have_tag("form li fieldset ol input[@type='hidden'][@value='1']")
2229
+ output_buffer.should have_tag("form li input[@type='hidden'][@value='1']")
1769
2230
  end
1770
2231
 
1771
2232
  it 'should use default attribute value when it is not nil' do
1772
- pending
1773
2233
  @new_post.stub!(:publish_at).and_return(Date.new(2007,12,27))
1774
2234
  semantic_form_for(@new_post) do |builder|
1775
2235
  concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
1776
2236
  end
1777
2237
 
1778
- output_buffer.should have_tag("form li fieldset ol input[@type='hidden'][@value='27']")
2238
+ output_buffer.should have_tag("form li input[@type='hidden'][@value='27']")
1779
2239
  end
1780
2240
  end
1781
2241
 
@@ -1848,16 +2308,25 @@ describe 'Formtastic' do
1848
2308
  end
1849
2309
  end
1850
2310
 
1851
- it 'should have fieldset, legend, label and selects even if object is not given' do
1852
- output_buffer.replace ''
2311
+ describe 'when no object is given' do
2312
+ before(:each) do
2313
+ output_buffer.replace ''
2314
+ semantic_form_for(:project, :url => 'http://test.host') do |@builder|
2315
+ concat(@builder.input(:publish_at, :as => :datetime))
2316
+ end
2317
+ end
1853
2318
 
1854
- semantic_form_for(:project, :url => 'http://test.host') do |@builder|
1855
- concat(@builder.input(:publish_at, :as => :datetime))
2319
+ it 'should have fieldset with legend' do
2320
+ output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
1856
2321
  end
1857
2322
 
1858
- output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
1859
- output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
1860
- output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
2323
+ it 'should have labels for each input' do
2324
+ output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
2325
+ end
2326
+
2327
+ it 'should have selects for each inputs' do
2328
+ output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
2329
+ end
1861
2330
  end
1862
2331
  end
1863
2332
 
@@ -1885,19 +2354,18 @@ describe 'Formtastic' do
1885
2354
 
1886
2355
  it 'should have an ordered list of two items inside the fieldset' do
1887
2356
  output_buffer.should have_tag('form li.time fieldset ol')
1888
- # output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
2357
+ output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
1889
2358
  end
1890
2359
 
1891
2360
  it 'should have five labels for hour and minute' do
1892
- pending
1893
2361
  output_buffer.should have_tag('form li.time fieldset ol li label', :count => 2)
1894
2362
  output_buffer.should have_tag('form li.time fieldset ol li label', /hour/i)
1895
2363
  output_buffer.should have_tag('form li.time fieldset ol li label', /minute/i)
1896
2364
  end
1897
2365
 
1898
- it 'should have five selects for hour and minute' do
1899
- pending
1900
- output_buffer.should have_tag('form li.time fieldset ol li select', :count => 2)
2366
+ it 'should have two selects for hour and minute' do
2367
+ #output_buffer.should have_tag('form li.time fieldset ol li select', :count => 2)
2368
+ output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
1901
2369
  end
1902
2370
  end
1903
2371
 
@@ -1976,7 +2444,6 @@ describe 'Formtastic' do
1976
2444
  end
1977
2445
  end
1978
2446
 
1979
-
1980
2447
  describe '#inputs' do
1981
2448
 
1982
2449
  describe 'with a block' do
@@ -2130,8 +2597,8 @@ describe 'Formtastic' do
2130
2597
  describe 'without a block' do
2131
2598
 
2132
2599
  before do
2133
- Post.stub!(:reflections).and_return({:author => mock('reflection', :macro => :belongs_to),
2134
- :comments => mock('reflection', :macro => :has_many) })
2600
+ Post.stub!(:reflections).and_return({:author => mock('reflection', :options => {}, :macro => :belongs_to),
2601
+ :comments => mock('reflection', :options => {}, :macro => :has_many) })
2135
2602
  Post.stub!(:content_columns).and_return([mock('column', :name => 'title'), mock('column', :name => 'body'), mock('column', :name => 'created_at')])
2136
2603
  Author.stub!(:find).and_return([@fred, @bob])
2137
2604
 
@@ -2436,7 +2903,41 @@ describe 'Formtastic' do
2436
2903
  output_buffer.should have_tag('li.commit input#my_id')
2437
2904
  output_buffer.should have_tag('li.commit input.my_class')
2438
2905
  end
2906
+
2907
+ end
2439
2908
 
2909
+ describe 'when the first option is a string and the second is a hash' do
2910
+
2911
+ before do
2912
+ @new_post.stub!(:new_record?).and_return(false)
2913
+ semantic_form_for(@new_post) do |builder|
2914
+ concat(builder.commit_button("a string", :button_html => { :class => "pretty"}))
2915
+ end
2916
+ end
2917
+
2918
+ it "should render the string as the value of the button" do
2919
+ output_buffer.should have_tag('li input[@value="a string"]')
2920
+ end
2921
+
2922
+ it "should deal with the options hash" do
2923
+ output_buffer.should have_tag('li input.pretty')
2924
+ end
2925
+
2926
+ end
2927
+
2928
+ describe 'when the first option is a hash' do
2929
+
2930
+ before do
2931
+ @new_post.stub!(:new_record?).and_return(false)
2932
+ semantic_form_for(@new_post) do |builder|
2933
+ concat(builder.commit_button(:button_html => { :class => "pretty"}))
2934
+ end
2935
+ end
2936
+
2937
+ it "should deal with the options hash" do
2938
+ output_buffer.should have_tag('li input.pretty')
2939
+ end
2940
+
2440
2941
  end
2441
2942
 
2442
2943
  describe 'when used on an existing record' do
@@ -2549,7 +3050,7 @@ describe 'Formtastic' do
2549
3050
  end
2550
3051
  end
2551
3052
 
2552
- 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>")
3053
+ 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>")
2553
3054
  end
2554
3055
 
2555
3056
  it "should have a show method" do