speedo-formstrap 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +117 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +192 -0
  7. data/Rakefile +49 -0
  8. data/VERSION +1 -0
  9. data/formtastic-bootstrap.gemspec +56 -0
  10. data/lib/action_view/helpers/text_field_date_helper.rb +166 -0
  11. data/lib/formtastic-bootstrap.rb +7 -0
  12. data/lib/formtastic-bootstrap/actions.rb +4 -0
  13. data/lib/formtastic-bootstrap/actions/base.rb +18 -0
  14. data/lib/formtastic-bootstrap/actions/button_action.rb +7 -0
  15. data/lib/formtastic-bootstrap/actions/input_action.rb +7 -0
  16. data/lib/formtastic-bootstrap/actions/link_action.rb +7 -0
  17. data/lib/formtastic-bootstrap/engine.rb +4 -0
  18. data/lib/formtastic-bootstrap/form_builder.rb +40 -0
  19. data/lib/formtastic-bootstrap/helpers.rb +21 -0
  20. data/lib/formtastic-bootstrap/helpers/action_helper.rb +12 -0
  21. data/lib/formtastic-bootstrap/helpers/actions_helper.rb +23 -0
  22. data/lib/formtastic-bootstrap/helpers/buttons_helper.rb +56 -0
  23. data/lib/formtastic-bootstrap/helpers/fieldset_wrapper.rb +42 -0
  24. data/lib/formtastic-bootstrap/helpers/input_helper.rb +12 -0
  25. data/lib/formtastic-bootstrap/helpers/inputs_helper.rb +36 -0
  26. data/lib/formtastic-bootstrap/inputs.rb +29 -0
  27. data/lib/formtastic-bootstrap/inputs/base.rb +23 -0
  28. data/lib/formtastic-bootstrap/inputs/base/choices.rb +38 -0
  29. data/lib/formtastic-bootstrap/inputs/base/errors.rb +48 -0
  30. data/lib/formtastic-bootstrap/inputs/base/hints.rb +27 -0
  31. data/lib/formtastic-bootstrap/inputs/base/html.rb +21 -0
  32. data/lib/formtastic-bootstrap/inputs/base/labelling.rb +28 -0
  33. data/lib/formtastic-bootstrap/inputs/base/numeric.rb +18 -0
  34. data/lib/formtastic-bootstrap/inputs/base/stringish.rb +18 -0
  35. data/lib/formtastic-bootstrap/inputs/base/timeish.rb +28 -0
  36. data/lib/formtastic-bootstrap/inputs/base/wrapping.rb +74 -0
  37. data/lib/formtastic-bootstrap/inputs/boolean_input.rb +29 -0
  38. data/lib/formtastic-bootstrap/inputs/check_boxes_input.rb +36 -0
  39. data/lib/formtastic-bootstrap/inputs/date_input.rb +16 -0
  40. data/lib/formtastic-bootstrap/inputs/datetime_input.rb +19 -0
  41. data/lib/formtastic-bootstrap/inputs/email_input.rb +15 -0
  42. data/lib/formtastic-bootstrap/inputs/file_input.rb +14 -0
  43. data/lib/formtastic-bootstrap/inputs/hidden_input.rb +14 -0
  44. data/lib/formtastic-bootstrap/inputs/number_input.rb +15 -0
  45. data/lib/formtastic-bootstrap/inputs/password_input.rb +15 -0
  46. data/lib/formtastic-bootstrap/inputs/phone_input.rb +15 -0
  47. data/lib/formtastic-bootstrap/inputs/radio_input.rb +33 -0
  48. data/lib/formtastic-bootstrap/inputs/range_input.rb +15 -0
  49. data/lib/formtastic-bootstrap/inputs/search_input.rb +15 -0
  50. data/lib/formtastic-bootstrap/inputs/select_input.rb +14 -0
  51. data/lib/formtastic-bootstrap/inputs/string_input.rb +15 -0
  52. data/lib/formtastic-bootstrap/inputs/text_input.rb +14 -0
  53. data/lib/formtastic-bootstrap/inputs/time_input.rb +16 -0
  54. data/lib/formtastic-bootstrap/inputs/time_zone_input.rb +14 -0
  55. data/lib/formtastic-bootstrap/inputs/url_input.rb +14 -0
  56. data/spec/actions/button_action_spec.rb +68 -0
  57. data/spec/actions/generic_action_spec.rb +486 -0
  58. data/spec/actions/input_action_spec.rb +64 -0
  59. data/spec/actions/link_action_spec.rb +93 -0
  60. data/spec/builder/semantic_fields_for_spec.rb +130 -0
  61. data/spec/helpers/action_helper_spec.rb +365 -0
  62. data/spec/helpers/actions_helper_spec.rb +143 -0
  63. data/spec/helpers/buttons_helper_spec.rb +159 -0
  64. data/spec/helpers/input_helper_spec.rb +956 -0
  65. data/spec/helpers/inputs_helper_spec.rb +591 -0
  66. data/spec/inputs/boolean_input_spec.rb +221 -0
  67. data/spec/inputs/check_boxes_input_spec.rb +467 -0
  68. data/spec/inputs/date_input_spec.rb +213 -0
  69. data/spec/inputs/datetime_input_spec.rb +101 -0
  70. data/spec/inputs/email_input_spec.rb +87 -0
  71. data/spec/inputs/file_input_spec.rb +91 -0
  72. data/spec/inputs/hidden_input_spec.rb +150 -0
  73. data/spec/inputs/number_input_spec.rb +817 -0
  74. data/spec/inputs/password_input_spec.rb +101 -0
  75. data/spec/inputs/phone_input_spec.rb +87 -0
  76. data/spec/inputs/radio_input_spec.rb +268 -0
  77. data/spec/inputs/range_input_spec.rb +507 -0
  78. data/spec/inputs/search_input_spec.rb +86 -0
  79. data/spec/inputs/select_input_spec.rb +613 -0
  80. data/spec/inputs/string_input_spec.rb +227 -0
  81. data/spec/inputs/text_input_spec.rb +190 -0
  82. data/spec/inputs/time_input_spec.rb +206 -0
  83. data/spec/inputs/time_zone_input_spec.rb +120 -0
  84. data/spec/inputs/url_input_spec.rb +87 -0
  85. data/spec/spec_helper.rb +24 -0
  86. data/spec/support/custom_macros.rb +575 -0
  87. data/spec/support/depracation.rb +6 -0
  88. data/spec/support/formtastic_spec_helper.rb +398 -0
  89. metadata +216 -0
@@ -0,0 +1,120 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'time_zone input' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ Formtastic::Helpers::FormHelper.builder = FormtasticBootstrap::FormBuilder
12
+
13
+ concat(semantic_form_for(@new_post) do |builder|
14
+ concat(builder.input(:time_zone))
15
+ end)
16
+ end
17
+
18
+ it_should_have_input_wrapper_with_class("time_zone-wrapper")
19
+ it_should_have_input_wrapper_with_class("control-group")
20
+ it_should_have_input_wrapper_with_id("post_time_zone_input")
21
+ it_should_apply_error_logic_for_input_type(:time_zone)
22
+
23
+ it 'should generate a label for the input' do
24
+ output_buffer.should have_tag('form div label.control-label')
25
+ output_buffer.should have_tag('form div label.control-label[@for="post_time_zone"]')
26
+ output_buffer.should have_tag('form div label.control-label', /Time zone/)
27
+ end
28
+
29
+ it "should generate a select" do
30
+ output_buffer.should have_tag("form div select")
31
+ output_buffer.should have_tag("form div select#post_time_zone")
32
+ output_buffer.should have_tag("form div select[@name=\"post[time_zone]\"]")
33
+ end
34
+
35
+ it 'should use input_html to style inputs' do
36
+ concat(semantic_form_for(@new_post) do |builder|
37
+ concat(builder.input(:time_zone, :input_html => { :class => 'myclass' }))
38
+ end)
39
+ output_buffer.should have_tag("form div select.myclass")
40
+ end
41
+
42
+ describe "when namespace is provided" do
43
+
44
+ before do
45
+ @output_buffer = ''
46
+ mock_everything
47
+ Formtastic::Helpers::FormHelper.builder = FormtasticBootstrap::FormBuilder
48
+
49
+ concat(semantic_form_for(@new_post, :namespace => 'context2') do |builder|
50
+ concat(builder.input(:time_zone))
51
+ end)
52
+ end
53
+
54
+ it_should_have_input_wrapper_with_id("context2_post_time_zone_input")
55
+ it_should_have_select_with_id("context2_post_time_zone")
56
+ it_should_have_label_for("context2_post_time_zone")
57
+
58
+ end
59
+
60
+ describe "when index is provided" do
61
+
62
+ before do
63
+ @output_buffer = ''
64
+ mock_everything
65
+ Formtastic::Helpers::FormHelper.builder = FormtasticBootstrap::FormBuilder
66
+
67
+ concat(semantic_form_for(@new_post) do |builder|
68
+ concat(builder.fields_for(:author, :index => 3) do |author|
69
+ concat(author.input(:name, :as => :time_zone))
70
+ end)
71
+ end)
72
+ end
73
+
74
+ it 'should index the id of the wrapper' do
75
+ output_buffer.should have_tag("div#post_author_attributes_3_name_input")
76
+ end
77
+
78
+ it 'should index the id of the select tag' do
79
+ output_buffer.should have_tag("select#post_author_attributes_3_name")
80
+ end
81
+
82
+ it 'should index the name of the select tag' do
83
+ output_buffer.should have_tag("select[@name='post[author_attributes][3][name]']")
84
+ end
85
+
86
+ end
87
+
88
+
89
+ describe 'when no object is given' do
90
+ before(:each) do
91
+ concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder|
92
+ concat(builder.input(:time_zone, :as => :time_zone))
93
+ end)
94
+ end
95
+
96
+ it 'should generate labels' do
97
+ output_buffer.should have_tag('form div label.control-label')
98
+ output_buffer.should have_tag('form div label.control-label[@for="project_time_zone"]')
99
+ output_buffer.should have_tag('form div label.control-label', /Time zone/)
100
+ end
101
+
102
+ it 'should generate select inputs' do
103
+ output_buffer.should have_tag("form div select")
104
+ output_buffer.should have_tag("form div select#project_time_zone")
105
+ output_buffer.should have_tag("form div select[@name=\"project[time_zone]\"]")
106
+ end
107
+ end
108
+
109
+ context "when required" do
110
+ it "should add the required attribute to the input's html options" do
111
+ with_config :use_required_attribute, true do
112
+ concat(semantic_form_for(@new_post) do |builder|
113
+ concat(builder.input(:title, :as => :time_zone, :required => true))
114
+ end)
115
+ output_buffer.should have_tag("select[@required]")
116
+ end
117
+ end
118
+ end
119
+
120
+ end
@@ -0,0 +1,87 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'url input' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ Formtastic::Helpers::FormHelper.builder = FormtasticBootstrap::FormBuilder
12
+ end
13
+
14
+ describe "when object is provided" do
15
+ before do
16
+ concat(semantic_form_for(@new_post) do |builder|
17
+ concat(builder.input(:url))
18
+ end)
19
+ end
20
+
21
+ it_should_have_input_wrapper_with_class('url-wrapper')
22
+ it_should_have_input_wrapper_with_class("control-group")
23
+ it_should_have_input_wrapper_with_class(:stringish)
24
+ it_should_have_input_class_in_the_right_place
25
+ it_should_have_input_wrapper_with_id("post_url_input")
26
+ it_should_have_label_with_text(/Url/)
27
+ it_should_have_label_for("post_url")
28
+ it_should_have_input_with_id("post_url")
29
+ it_should_have_input_with_type(:url)
30
+ it_should_have_input_with_name("post[url]")
31
+
32
+ end
33
+
34
+ describe "when namespace is provided" do
35
+
36
+ before do
37
+ concat(semantic_form_for(@new_post, :namespace => "context2") do |builder|
38
+ concat(builder.input(:url))
39
+ end)
40
+ end
41
+
42
+ it_should_have_input_wrapper_with_id("context2_post_url_input")
43
+ it_should_have_label_and_input_with_id("context2_post_url")
44
+
45
+ end
46
+
47
+ describe "when index is provided" do
48
+
49
+ before do
50
+ @output_buffer = ''
51
+ mock_everything
52
+
53
+ concat(semantic_form_for(@new_post) do |builder|
54
+ concat(builder.fields_for(:author, :index => 3) do |author|
55
+ concat(author.input(:name, :as => :url))
56
+ end)
57
+ end)
58
+ end
59
+
60
+ it 'should index the id of the wrapper' do
61
+ output_buffer.should have_tag("div#post_author_attributes_3_name_input")
62
+ end
63
+
64
+ it 'should index the id of the select tag' do
65
+ output_buffer.should have_tag("input#post_author_attributes_3_name")
66
+ end
67
+
68
+ it 'should index the name of the select tag' do
69
+ output_buffer.should have_tag("input[@name='post[author_attributes][3][name]']")
70
+ end
71
+
72
+ end
73
+
74
+
75
+ describe "when required" do
76
+ it "should add the required attribute to the input's html options" do
77
+ with_config :use_required_attribute, true do
78
+ concat(semantic_form_for(@new_post) do |builder|
79
+ concat(builder.input(:title, :as => :url, :required => true))
80
+ end)
81
+ output_buffer.should have_tag("input[@required]")
82
+ end
83
+ end
84
+ end
85
+
86
+ end
87
+
@@ -0,0 +1,24 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'rspec_tag_matchers'
5
+ require 'rubygems'
6
+ require 'bundler'
7
+ Bundler.setup
8
+
9
+ require 'active_support'
10
+ require 'action_pack'
11
+ require 'action_view'
12
+ require 'action_controller'
13
+ require 'action_dispatch'
14
+
15
+ require 'speedo-formstrap'
16
+
17
+ # Requires supporting files with custom matchers and macros, etc,
18
+ # in ./support/ and its subdirectories.
19
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
20
+
21
+ RSpec.configure do |config|
22
+ config.include RspecTagMatchers
23
+ config.include CustomMacros
24
+ end
@@ -0,0 +1,575 @@
1
+ # encoding: utf-8
2
+
3
+ module CustomMacros
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def it_should_have_input_wrapper_with_class(class_name)
12
+ it "should have input wrapper with class '#{class_name}'" do
13
+ output_buffer.should have_tag("form div.#{class_name}")
14
+ end
15
+ end
16
+
17
+ # This is one of the things we move for Bootstrap. In vanilla Formtastic
18
+ # it's located on the outer wrapper. We move it to the inner wrapper.
19
+ def it_should_have_input_class_in_the_right_place
20
+ it "should have 'input' class in the right place" do
21
+ output_buffer.should have_tag("form div.control-group div.controls")
22
+ output_buffer.should_not have_tag("form div.control-group.input")
23
+ end
24
+ end
25
+
26
+ def it_should_have_input_wrapper_with_id(id_string)
27
+ it "should have input wrapper with id '#{id_string}'" do
28
+ output_buffer.should have_tag("form div##{id_string}")
29
+ end
30
+ end
31
+
32
+ def it_should_not_have_a_label
33
+ it "should not have a label" do
34
+ output_buffer.should_not have_tag("form div.control-group label.control-label")
35
+ end
36
+ end
37
+
38
+ def it_should_have_a_nested_fieldset
39
+ it "should have a nested_fieldset" do
40
+ output_buffer.should have_tag("form li fieldset")
41
+ end
42
+ end
43
+
44
+ def it_should_have_a_nested_fieldset_with_class(klass)
45
+ it "should have a nested_fieldset with class #{klass}" do
46
+ output_buffer.should have_tag("form li fieldset.#{klass}")
47
+ end
48
+ end
49
+
50
+ def it_should_have_a_nested_div
51
+ it "should have a nested div" do
52
+ output_buffer.should have_tag("form div.control-group div")
53
+ end
54
+ end
55
+
56
+ def it_should_have_a_nested_div_with_class(klass)
57
+ it "should have a nested div with class #{klass}" do
58
+ output_buffer.should have_tag("form div.control-group div.#{klass}")
59
+ end
60
+ end
61
+
62
+ def it_should_have_a_nested_ordered_list_with_class(klass)
63
+ it "should have a nested fieldset with class #{klass}" do
64
+ output_buffer.should have_tag("form li ol.#{klass}")
65
+ end
66
+ end
67
+
68
+ def it_should_have_a_nested_unordered_list_with_class(klass)
69
+ it "should have a nested unordered list with class #{klass}" do
70
+ output_buffer.should have_tag("form div.control-group div ul.#{klass}")
71
+ end
72
+ end
73
+
74
+ def it_should_have_label_with_text(string_or_regex)
75
+ it "should have a label with text '#{string_or_regex}'" do
76
+ output_buffer.should have_tag("form div.control-group label.control-label", string_or_regex)
77
+ end
78
+ end
79
+
80
+ def it_should_have_label_for(element_id)
81
+ it "should have a label for ##{element_id}" do
82
+ # output_buffer.should have_tag("form div label.label[@for='#{element_id}']")
83
+ output_buffer.should have_tag("form div.control-group label[@for='#{element_id}']")
84
+ end
85
+ end
86
+
87
+ def it_should_have_an_inline_label_for(element_id)
88
+ it "should have a label for ##{element_id}" do
89
+ output_buffer.should have_tag("form div.controls label[@for='#{element_id}']")
90
+ end
91
+ end
92
+
93
+ def it_should_have_input_with_id(element_id)
94
+ it "should have an input with id '#{element_id}'" do
95
+ # output_buffer.should have_tag("form div.control-group div.controls input##{element_id}")
96
+ output_buffer.should have_tag("form div.control-group div.controls input[@id=\"#{element_id}\"]")
97
+ end
98
+ end
99
+
100
+ def it_should_have_select_with_id(element_id)
101
+ it "should have a select box with id '#{element_id}'" do
102
+ output_buffer.should have_tag("form div.control-group div.controls select##{element_id}")
103
+ end
104
+ end
105
+
106
+ def it_should_have_input_with_type(input_type)
107
+ it "should have a #{input_type} input" do
108
+ output_buffer.should have_tag("form div.control-group div.controls input[@type=\"#{input_type}\"]")
109
+ end
110
+ end
111
+
112
+ def it_should_have_input_with_name(name)
113
+ it "should have an input named #{name}" do
114
+ output_buffer.should have_tag("form div.control-group div.controls input[@name=\"#{name}\"]")
115
+ end
116
+ end
117
+
118
+ def it_should_have_select_with_name(name)
119
+ it "should have an input named #{name}" do
120
+ output_buffer.should have_tag("form div.control-group div.controls select[@name=\"#{name}\"]")
121
+ end
122
+ end
123
+
124
+ def it_should_have_textarea_with_name(name)
125
+ it "should have an input named #{name}" do
126
+ output_buffer.should have_tag("form div.control-group div.controls textarea[@name=\"#{name}\"]")
127
+ end
128
+ end
129
+
130
+ def it_should_have_textarea_with_id(element_id)
131
+ it "should have an input with id '#{element_id}'" do
132
+ output_buffer.should have_tag("form div.control-group div.controls textarea##{element_id}")
133
+ end
134
+ end
135
+
136
+ def it_should_have_label_and_input_with_id(element_id)
137
+ it "should have an input with id '#{element_id}'" do
138
+ output_buffer.should have_tag("form div.control-group div.controls input##{element_id}")
139
+ output_buffer.should have_tag("form div.control-group label.control-label[@for='#{element_id}']")
140
+ end
141
+ end
142
+
143
+ def it_should_use_default_text_field_size_when_not_nil(as)
144
+ it 'should use default_text_field_size when not nil' do
145
+ with_config :default_text_field_size, 30 do
146
+ concat(semantic_form_for(@new_post) do |builder|
147
+ concat(builder.input(:title, :as => as))
148
+ end)
149
+ output_buffer.should have_tag("form div.control-group div.controls input[@size='#{FormtasticBootstrap::FormBuilder.default_text_field_size}']")
150
+ end
151
+ end
152
+ end
153
+
154
+ def it_should_not_use_default_text_field_size_when_nil(as)
155
+ it 'should not use default_text_field_size when nil' do
156
+ with_config :default_text_field_size, nil do
157
+ concat(semantic_form_for(@new_post) do |builder|
158
+ concat(builder.input(:title, :as => as))
159
+ end)
160
+ output_buffer.should have_tag("form div.control-group div.controls input")
161
+ output_buffer.should_not have_tag("form div.control-group div.controls input[@size]")
162
+ end
163
+ end
164
+ end
165
+
166
+ def it_should_apply_custom_input_attributes_when_input_html_provided(as)
167
+ it 'it should apply custom input attributes when input_html provided' do
168
+ concat(semantic_form_for(@new_post) do |builder|
169
+ concat(builder.input(:title, :as => as, :input_html => { :class => 'myclass' }))
170
+ end)
171
+ output_buffer.should have_tag("form div.control-group div.controls input.myclass")
172
+ end
173
+ end
174
+
175
+ def it_should_apply_custom_for_to_label_when_input_html_id_provided(as)
176
+ it 'it should apply custom for to label when input_html :id provided' do
177
+ concat(semantic_form_for(@new_post) do |builder|
178
+ concat(builder.input(:title, :as => as, :input_html => { :id => 'myid' }))
179
+ end)
180
+ output_buffer.should have_tag('form div.control-group label.control-label[@for="myid"]')
181
+ end
182
+ end
183
+
184
+ def it_should_have_maxlength_matching_column_limit
185
+ it 'should have a maxlength matching column limit' do
186
+ @new_post.column_for_attribute(:title).limit.should == 50
187
+ output_buffer.should have_tag("form div.control-group div.controls input[@maxlength='50']")
188
+ end
189
+ end
190
+
191
+ def it_should_use_column_size_for_columns_shorter_than_default_text_field_size(as)
192
+ it 'should use the column size for columns shorter than default_text_field_size' do
193
+ column_limit_shorted_than_default = 1
194
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => as, :limit => column_limit_shorted_than_default))
195
+
196
+ concat(semantic_form_for(@new_post) do |builder|
197
+ concat(builder.input(:title, :as => as))
198
+ end)
199
+
200
+ output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
201
+ end
202
+ end
203
+
204
+ def it_should_apply_error_logic_for_input_type(type, inline_or_block = :inline)
205
+ describe 'when there are errors on the object for this method' do
206
+
207
+ before(:each) do
208
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
209
+ @errors = mock('errors')
210
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
211
+ Formtastic::FormBuilder.file_metadata_suffixes.each do |suffix|
212
+ @errors.stub!(:[]).with("title_#{suffix}".to_sym).and_return(nil)
213
+ end
214
+ @new_post.stub!(:errors).and_return(@errors)
215
+
216
+ @orig_inline_errors = FormtasticBootstrap::FormBuilder.inline_errors
217
+ @orig_inline_error_class = FormtasticBootstrap::FormBuilder.default_inline_error_class
218
+ @orig_error_list_class = FormtasticBootstrap::FormBuilder.default_error_list_class
219
+ end
220
+
221
+ after(:each) do
222
+ FormtasticBootstrap::FormBuilder.inline_errors = @orig_inline_errors
223
+ FormtasticBootstrap::FormBuilder.default_inline_error_class = @orig_inline_error_class
224
+ FormtasticBootstrap::FormBuilder.default_error_list_class = @orig_error_list_class
225
+ end
226
+
227
+ it 'should apply an errors class to the list item' do
228
+ concat(semantic_form_for(@new_post) do |builder|
229
+ concat(builder.input(:title, :as => type))
230
+ end)
231
+ output_buffer.should have_tag('form div.error')
232
+ end
233
+
234
+ it 'should not wrap the input with the Rails default error wrapping' do
235
+ concat(semantic_form_for(@new_post) do |builder|
236
+ concat(builder.input(:title, :as => type))
237
+ end)
238
+ output_buffer.should_not have_tag('div.fieldWithErrors')
239
+ end
240
+
241
+ it 'should render a paragraph for the errors' do
242
+ FormtasticBootstrap::FormBuilder.inline_errors = :sentence
243
+ concat(semantic_form_for(@new_post) do |builder|
244
+ concat(builder.input(:title, :as => type))
245
+ end)
246
+ # output_buffer.should have_tag('form div.error p.inline-errors')
247
+ if inline_or_block == :inline
248
+ output_buffer.should have_tag('form div.error span.help-inline')
249
+ else
250
+ output_buffer.should have_tag('form div.error span.help-block')
251
+ end
252
+ end
253
+
254
+ it 'should not display an error list' do
255
+ FormtasticBootstrap::FormBuilder.inline_errors = :list
256
+ concat(semantic_form_for(@new_post) do |builder|
257
+ concat(builder.input(:title, :as => type))
258
+ end)
259
+ output_buffer.should have_tag('form div.error ul.errors')
260
+ end
261
+ end
262
+
263
+ describe 'when there are no errors on the object for this method' do
264
+ before do
265
+ @form = semantic_form_for(@new_post) do |builder|
266
+ concat(builder.input(:title, :as => type))
267
+ end
268
+ end
269
+
270
+ it 'should not apply an errors class to the list item' do
271
+ output_buffer.should_not have_tag('form div.error')
272
+ end
273
+
274
+ it 'should not render a paragraph for the errors' do
275
+ # output_buffer.should_not have_tag('form div.error p.inline-errors')
276
+ output_buffer.should_not have_tag('form div.error span.help-inline')
277
+ end
278
+
279
+ it 'should not display an error list' do
280
+ output_buffer.should_not have_tag('form div.error ul.errors')
281
+ end
282
+ end
283
+
284
+ describe 'when no object is provided' do
285
+ before do
286
+ concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
287
+ concat(builder.input(:title, :as => type))
288
+ end)
289
+ end
290
+
291
+ it 'should not apply an errors class to the list item' do
292
+ output_buffer.should_not have_tag('form div.error')
293
+ end
294
+
295
+ it 'should not render a paragraph for the errors' do
296
+ # output_buffer.should_not have_tag('form div.error p.inline-errors')
297
+ output_buffer.should_not have_tag('form div.error span.help-inline')
298
+ end
299
+
300
+ it 'should not display an error list' do
301
+ output_buffer.should_not have_tag('form div.error ul.errors')
302
+ end
303
+ end
304
+ end
305
+
306
+ def it_should_call_find_on_association_class_when_no_collection_is_provided(as)
307
+ it "should call find on the association class when no collection is provided" do
308
+ ::Author.should_receive(:where)
309
+ concat(semantic_form_for(@new_post) do |builder|
310
+ concat(builder.input(:author, :as => as))
311
+ end)
312
+ end
313
+ end
314
+
315
+ def it_should_use_the_collection_when_provided(as, countable)
316
+ describe 'when the :collection option is provided' do
317
+
318
+ before do
319
+ @authors = ::Author.all * 2
320
+ output_buffer.replace ''
321
+ end
322
+
323
+ it 'should use the provided collection' do
324
+ concat(semantic_form_for(@new_post) do |builder|
325
+ concat(builder.input(:author, :as => as, :collection => @authors))
326
+ end)
327
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}", :count => @authors.size + (as == :select ? 1 : 0))
328
+ end
329
+
330
+ describe 'and the :collection is an array of strings' do
331
+ before do
332
+ @categories = [ 'General', 'Design', 'Development', 'Quasi-Serious Inventions' ]
333
+ end
334
+
335
+ it "should use the string as the label text and value for each #{countable}" do
336
+ concat(semantic_form_for(@new_post) do |builder|
337
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
338
+ end)
339
+
340
+ @categories.each do |value|
341
+ output_buffer.should have_tag("form div.#{as}-wrapper", /#{value}/)
342
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}[@value='#{value}']")
343
+ end
344
+ end
345
+
346
+ if as == :radio
347
+ it 'should generate a sanitized label for attribute' do
348
+ @bob.stub!(:category_name).and_return(@categories)
349
+ concat(semantic_form_for(@new_post) do |builder|
350
+ fields = builder.semantic_fields_for(@bob) do |bob_builder|
351
+ concat(bob_builder.input(:category_name, :as => as, :collection => @categories))
352
+ end
353
+ concat(fields)
354
+ end)
355
+ output_buffer.should have_tag("form div div label.radio[@for='post_author_category_name_general']")
356
+ output_buffer.should have_tag("form div div label.radio[@for='post_author_category_name_design']")
357
+ output_buffer.should have_tag("form div div label.radio[@for='post_author_category_name_development']")
358
+ output_buffer.should have_tag("form div div label.radio[@for='post_author_category_name_quasi-serious_inventions']")
359
+ end
360
+ end
361
+ end
362
+
363
+ describe 'and the :collection is a hash of strings' do
364
+ before do
365
+ @categories = { 'General' => 'gen', 'Design' => 'des','Development' => 'dev' }
366
+ end
367
+
368
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
369
+ concat(semantic_form_for(@new_post) do |builder|
370
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
371
+ end)
372
+
373
+ @categories.each do |label, value|
374
+ output_buffer.should have_tag("form div.#{as}-wrapper", /#{label}/)
375
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}[@value='#{value}']")
376
+ end
377
+ end
378
+ end
379
+
380
+ describe 'and the :collection is an array of arrays' do
381
+ before do
382
+ @categories = { 'General' => 'gen', 'Design' => 'des', 'Development' => 'dev' }.to_a
383
+ end
384
+
385
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
386
+ concat(semantic_form_for(@new_post) do |builder|
387
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
388
+ end)
389
+
390
+ @categories.each do |text, value|
391
+ label = as == :select ? :option : :label
392
+ output_buffer.should have_tag("form div.#{as}-wrapper #{label}", /#{text}/i)
393
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}[@value='#{value.to_s}']")
394
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}#post_category_name_#{value.to_s}") if as == :radio
395
+ end
396
+ end
397
+ end
398
+
399
+ if as == :radio
400
+ describe 'and the :collection is an array of arrays with boolean values' do
401
+ before do
402
+ @choices = { 'Yeah' => true, 'Nah' => false }.to_a
403
+ end
404
+
405
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
406
+ concat(semantic_form_for(@new_post) do |builder|
407
+ concat(builder.input(:category_name, :as => as, :collection => @choices))
408
+ end)
409
+
410
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}#post_category_name_true")
411
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}#post_category_name_false")
412
+ end
413
+ end
414
+ end
415
+
416
+ describe 'and the :collection is an array of symbols' do
417
+ before do
418
+ @categories = [ :General, :Design, :Development ]
419
+ end
420
+
421
+ it "should use the symbol as the label text and value for each #{countable}" do
422
+ concat(semantic_form_for(@new_post) do |builder|
423
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
424
+ end)
425
+
426
+ @categories.each do |value|
427
+ label = as == :select ? :option : :label
428
+ output_buffer.should have_tag("form div.#{as}-wrapper #{label}", /#{value}/i)
429
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}[@value='#{value.to_s}']")
430
+ end
431
+ end
432
+ end
433
+
434
+ describe 'and the :collection is an OrderedHash of strings' do
435
+ before do
436
+ @categories = ActiveSupport::OrderedHash.new('General' => 'gen', 'Design' => 'des','Development' => 'dev')
437
+ end
438
+
439
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
440
+ concat(semantic_form_for(@new_post) do |builder|
441
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
442
+ end)
443
+
444
+ @categories.each do |label, value|
445
+ output_buffer.should have_tag("form div.#{as}-wrapper", /#{label}/)
446
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}[@value='#{value}']")
447
+ end
448
+ end
449
+
450
+ end
451
+
452
+ describe 'when the :member_label option is provided' do
453
+
454
+ describe 'as a symbol' do
455
+ before do
456
+ concat(semantic_form_for(@new_post) do |builder|
457
+ concat(builder.input(:author, :as => as, :member_label => :login))
458
+ end)
459
+ end
460
+
461
+ it 'should have options with text content from the specified method' do
462
+ ::Author.all.each do |author|
463
+ output_buffer.should have_tag("form div.#{as}-wrapper", /#{author.login}/)
464
+ end
465
+ end
466
+ end
467
+
468
+ describe 'as a proc' do
469
+ before do
470
+ concat(semantic_form_for(@new_post) do |builder|
471
+ concat(builder.input(:author, :as => as, :member_label => Proc.new {|a| a.login.reverse }))
472
+ end)
473
+ end
474
+
475
+ it 'should have options with the proc applied to each' do
476
+ ::Author.all.each do |author|
477
+ output_buffer.should have_tag("form div.#{as}-wrapper", /#{author.login.reverse}/)
478
+ end
479
+ end
480
+ end
481
+
482
+ describe 'as a method object' do
483
+ before do
484
+ def reverse_login(a)
485
+ a.login.reverse
486
+ end
487
+ concat(semantic_form_for(@new_post) do |builder|
488
+ concat(builder.input(:author, :as => as, :member_label => method(:reverse_login)))
489
+ end)
490
+ end
491
+
492
+ it 'should have options with the proc applied to each' do
493
+ ::Author.all.each do |author|
494
+ output_buffer.should have_tag("form div.#{as}-wrapper", /#{author.login.reverse}/)
495
+ end
496
+ end
497
+ end
498
+ end
499
+
500
+ describe 'when the :member_label option is not provided' do
501
+ Formtastic::FormBuilder.collection_label_methods.each do |label_method|
502
+
503
+ describe "when the collection objects respond to #{label_method}" do
504
+ before do
505
+ @fred.stub!(:respond_to?).and_return { |m| m.to_s == label_method || m.to_s == 'id' }
506
+ ::Author.all.each { |a| a.stub!(label_method).and_return('The Label Text') }
507
+
508
+ concat(semantic_form_for(@new_post) do |builder|
509
+ concat(builder.input(:author, :as => as))
510
+ end)
511
+ end
512
+
513
+ it "should render the options with #{label_method} as the label" do
514
+ ::Author.all.each do |author|
515
+ output_buffer.should have_tag("form div.#{as}-wrapper", /The Label Text/)
516
+ end
517
+ end
518
+ end
519
+
520
+ end
521
+ end
522
+
523
+ describe 'when the :member_value option is provided' do
524
+
525
+ describe 'as a symbol' do
526
+ before do
527
+ concat(semantic_form_for(@new_post) do |builder|
528
+ concat(builder.input(:author, :as => as, :member_value => :login))
529
+ end)
530
+ end
531
+
532
+ it 'should have options with values from specified method' do
533
+ ::Author.all.each do |author|
534
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}[@value='#{author.login}']")
535
+ end
536
+ end
537
+ end
538
+
539
+ describe 'as a proc' do
540
+ before do
541
+ concat(semantic_form_for(@new_post) do |builder|
542
+ concat(builder.input(:author, :as => as, :member_value => Proc.new {|a| a.login.reverse }))
543
+ end)
544
+ end
545
+
546
+ it 'should have options with the proc applied to each value' do
547
+ ::Author.all.each do |author|
548
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}[@value='#{author.login.reverse}']")
549
+ end
550
+ end
551
+ end
552
+
553
+ describe 'as a method object' do
554
+ before do
555
+ def reverse_login(a)
556
+ a.login.reverse
557
+ end
558
+ concat(semantic_form_for(@new_post) do |builder|
559
+ concat(builder.input(:author, :as => as, :member_value => method(:reverse_login)))
560
+ end)
561
+ end
562
+
563
+ it 'should have options with the proc applied to each value' do
564
+ ::Author.all.each do |author|
565
+ output_buffer.should have_tag("form div.#{as}-wrapper #{countable}[@value='#{author.login.reverse}']")
566
+ end
567
+ end
568
+ end
569
+ end
570
+
571
+ end
572
+ end
573
+
574
+ end
575
+ end