merb-helpers 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. data/LICENSE +20 -0
  2. data/README +180 -0
  3. data/Rakefile +77 -0
  4. data/TODO +5 -0
  5. data/lib/merb-helpers.rb +38 -0
  6. data/lib/merb-helpers/core_ext.rb +57 -0
  7. data/lib/merb-helpers/core_ext/numeric.rb +388 -0
  8. data/lib/merb-helpers/date_time_formatting.rb +127 -0
  9. data/lib/merb-helpers/date_time_helpers.rb +190 -0
  10. data/lib/merb-helpers/form/builder.rb +410 -0
  11. data/lib/merb-helpers/form/helpers.rb +448 -0
  12. data/lib/merb-helpers/form_helpers.rb +24 -0
  13. data/lib/merb-helpers/tag_helpers.rb +61 -0
  14. data/lib/merb-helpers/text_helpers.rb +61 -0
  15. data/lib/merb-helpers/time_dsl.rb +59 -0
  16. data/spec/core_ext_spec.rb +19 -0
  17. data/spec/fixture/app/controllers/application.rb +4 -0
  18. data/spec/fixture/app/controllers/bound_check_box.rb +2 -0
  19. data/spec/fixture/app/controllers/bound_file_field.rb +2 -0
  20. data/spec/fixture/app/controllers/bound_hidden_field.rb +2 -0
  21. data/spec/fixture/app/controllers/bound_option_tag.rb +2 -0
  22. data/spec/fixture/app/controllers/bound_password_field.rb +2 -0
  23. data/spec/fixture/app/controllers/bound_radio_button.rb +2 -0
  24. data/spec/fixture/app/controllers/bound_radio_group.rb +2 -0
  25. data/spec/fixture/app/controllers/bound_select.rb +2 -0
  26. data/spec/fixture/app/controllers/bound_text_area.rb +2 -0
  27. data/spec/fixture/app/controllers/bound_text_field.rb +2 -0
  28. data/spec/fixture/app/controllers/button.rb +2 -0
  29. data/spec/fixture/app/controllers/check_box.rb +2 -0
  30. data/spec/fixture/app/controllers/custom_builder.rb +2 -0
  31. data/spec/fixture/app/controllers/delete_button.rb +2 -0
  32. data/spec/fixture/app/controllers/exceptions.rb +25 -0
  33. data/spec/fixture/app/controllers/field_set.rb +2 -0
  34. data/spec/fixture/app/controllers/fields_for.rb +3 -0
  35. data/spec/fixture/app/controllers/file_field.rb +2 -0
  36. data/spec/fixture/app/controllers/foo.rb +23 -0
  37. data/spec/fixture/app/controllers/form.rb +2 -0
  38. data/spec/fixture/app/controllers/form_for.rb +2 -0
  39. data/spec/fixture/app/controllers/hidden_field.rb +2 -0
  40. data/spec/fixture/app/controllers/label.rb +3 -0
  41. data/spec/fixture/app/controllers/numeric_ext.rb +3 -0
  42. data/spec/fixture/app/controllers/option_tag.rb +2 -0
  43. data/spec/fixture/app/controllers/password_field.rb +2 -0
  44. data/spec/fixture/app/controllers/radio_button.rb +2 -0
  45. data/spec/fixture/app/controllers/radio_group.rb +2 -0
  46. data/spec/fixture/app/controllers/select.rb +2 -0
  47. data/spec/fixture/app/controllers/specs_controller.rb +11 -0
  48. data/spec/fixture/app/controllers/submit.rb +2 -0
  49. data/spec/fixture/app/controllers/tag_helper.rb +21 -0
  50. data/spec/fixture/app/controllers/text_area.rb +2 -0
  51. data/spec/fixture/app/controllers/text_field.rb +3 -0
  52. data/spec/fixture/app/helpers/global_helpers.rb +8 -0
  53. data/spec/fixture/app/models/fake_dm_model.rb +25 -0
  54. data/spec/fixture/app/models/first_generic_fake_model.rb +57 -0
  55. data/spec/fixture/app/models/second_generic_fake_model.rb +18 -0
  56. data/spec/fixture/app/models/third_generic_fake_model.rb +3 -0
  57. data/spec/fixture/app/views/bound_check_box_specs/basic.html.erb +4 -0
  58. data/spec/fixture/app/views/bound_check_box_specs/checked.html.erb +4 -0
  59. data/spec/fixture/app/views/bound_check_box_specs/errors.html.erb +4 -0
  60. data/spec/fixture/app/views/bound_check_box_specs/label.html.erb +3 -0
  61. data/spec/fixture/app/views/bound_check_box_specs/on_and_off.html.erb +3 -0
  62. data/spec/fixture/app/views/bound_check_box_specs/raise_value_error.html.erb +3 -0
  63. data/spec/fixture/app/views/bound_file_field_specs/additional_attributes.html.erb +3 -0
  64. data/spec/fixture/app/views/bound_file_field_specs/takes_string.html.erb +3 -0
  65. data/spec/fixture/app/views/bound_file_field_specs/with_label.html.erb +3 -0
  66. data/spec/fixture/app/views/bound_hidden_field_specs/basic.html.erb +3 -0
  67. data/spec/fixture/app/views/bound_hidden_field_specs/errors.html.erb +3 -0
  68. data/spec/fixture/app/views/bound_hidden_field_specs/hidden_error.html.erb +3 -0
  69. data/spec/fixture/app/views/bound_hidden_field_specs/label.html.erb +3 -0
  70. data/spec/fixture/app/views/bound_option_tag_specs/grouped.html.erb +3 -0
  71. data/spec/fixture/app/views/bound_option_tag_specs/nested.html.erb +3 -0
  72. data/spec/fixture/app/views/bound_option_tag_specs/text_and_value.html.erb +4 -0
  73. data/spec/fixture/app/views/bound_password_field_specs/attributes.html.erb +3 -0
  74. data/spec/fixture/app/views/bound_password_field_specs/basic.html.erb +3 -0
  75. data/spec/fixture/app/views/bound_password_field_specs/label.html.erb +3 -0
  76. data/spec/fixture/app/views/bound_radio_button_specs/basic.html.erb +3 -0
  77. data/spec/fixture/app/views/bound_radio_group_specs/basic.html.erb +3 -0
  78. data/spec/fixture/app/views/bound_radio_group_specs/hashes.html.erb +3 -0
  79. data/spec/fixture/app/views/bound_radio_group_specs/mixed.html.erb +4 -0
  80. data/spec/fixture/app/views/bound_radio_group_specs/override_id.html.erb +3 -0
  81. data/spec/fixture/app/views/bound_select_specs/basic.html.erb +3 -0
  82. data/spec/fixture/app/views/bound_select_specs/blank.html.erb +3 -0
  83. data/spec/fixture/app/views/bound_select_specs/multiple.html.erb +3 -0
  84. data/spec/fixture/app/views/bound_select_specs/prompt.html.erb +3 -0
  85. data/spec/fixture/app/views/bound_select_specs/with_options.html.erb +3 -0
  86. data/spec/fixture/app/views/bound_select_specs/with_options_with_blank.html.erb +3 -0
  87. data/spec/fixture/app/views/bound_text_area_specs/basic.html.erb +3 -0
  88. data/spec/fixture/app/views/bound_text_field_specs/basic.html.erb +3 -0
  89. data/spec/fixture/app/views/button_specs/button_with_label.html.erb +1 -0
  90. data/spec/fixture/app/views/button_specs/button_with_values.html.erb +1 -0
  91. data/spec/fixture/app/views/button_specs/disabled_button.html.erb +1 -0
  92. data/spec/fixture/app/views/check_box_specs/basic.html.erb +1 -0
  93. data/spec/fixture/app/views/check_box_specs/boolean.html.erb +1 -0
  94. data/spec/fixture/app/views/check_box_specs/disabled.html.erb +1 -0
  95. data/spec/fixture/app/views/check_box_specs/label.html.erb +1 -0
  96. data/spec/fixture/app/views/check_box_specs/on_off_is_boolean.html.erb +1 -0
  97. data/spec/fixture/app/views/check_box_specs/raise_unless_both_on_and_off.html.erb +2 -0
  98. data/spec/fixture/app/views/check_box_specs/raises_error_if_not_boolean.html.erb +1 -0
  99. data/spec/fixture/app/views/check_box_specs/raises_error_if_on_off_and_boolean_false.html.erb +1 -0
  100. data/spec/fixture/app/views/check_box_specs/simple.html.erb +1 -0
  101. data/spec/fixture/app/views/check_box_specs/to_string.html.erb +8 -0
  102. data/spec/fixture/app/views/check_box_specs/unchecked.html.erb +2 -0
  103. data/spec/fixture/app/views/custom_builder_specs/everything.html.erb +10 -0
  104. data/spec/fixture/app/views/delete_button_specs/delete_with_explicit_url.html.erb +1 -0
  105. data/spec/fixture/app/views/delete_button_specs/delete_with_extra_params.html.erb +1 -0
  106. data/spec/fixture/app/views/delete_button_specs/delete_with_label.html.erb +1 -0
  107. data/spec/fixture/app/views/delete_button_specs/simple_delete.html.erb +1 -0
  108. data/spec/fixture/app/views/exeptions/client_error.html.erb +37 -0
  109. data/spec/fixture/app/views/exeptions/internal_server_error.html.erb +216 -0
  110. data/spec/fixture/app/views/exeptions/not_acceptable.html.erb +38 -0
  111. data/spec/fixture/app/views/exeptions/not_found.html.erb +40 -0
  112. data/spec/fixture/app/views/fields_for_specs/basic.html.erb +3 -0
  113. data/spec/fixture/app/views/fields_for_specs/midstream.html.erb +7 -0
  114. data/spec/fixture/app/views/fields_for_specs/nil.html.erb +3 -0
  115. data/spec/fixture/app/views/fieldset_specs/legend.html.erb +3 -0
  116. data/spec/fixture/app/views/file_field_specs/disabled.html.erb +1 -0
  117. data/spec/fixture/app/views/file_field_specs/makes_multipart.html.erb +3 -0
  118. data/spec/fixture/app/views/file_field_specs/with_label.html.erb +1 -0
  119. data/spec/fixture/app/views/file_field_specs/with_values.html.erb +1 -0
  120. data/spec/fixture/app/views/foo/bar.html.erb +0 -0
  121. data/spec/fixture/app/views/form_for_specs/basic.html.erb +3 -0
  122. data/spec/fixture/app/views/form_specs/create_a_form.html.erb +3 -0
  123. data/spec/fixture/app/views/form_specs/create_a_multipart_form.html.erb +3 -0
  124. data/spec/fixture/app/views/form_specs/fake_delete_if_set.html.erb +3 -0
  125. data/spec/fixture/app/views/form_specs/fake_put_if_set.html.erb +3 -0
  126. data/spec/fixture/app/views/form_specs/get_if_set.html.erb +3 -0
  127. data/spec/fixture/app/views/form_specs/post_by_default.html.erb +3 -0
  128. data/spec/fixture/app/views/form_specs/resourceful_form.html.erb +3 -0
  129. data/spec/fixture/app/views/hidden_field_specs/basic.html.erb +1 -0
  130. data/spec/fixture/app/views/hidden_field_specs/disabled.html.erb +1 -0
  131. data/spec/fixture/app/views/hidden_field_specs/label.html.erb +1 -0
  132. data/spec/fixture/app/views/label_specs/basic.html.erb +1 -0
  133. data/spec/fixture/app/views/layout/application.html.erb +11 -0
  134. data/spec/fixture/app/views/numeric_ext_specs/minutes_to_hours.html.erb +1 -0
  135. data/spec/fixture/app/views/numeric_ext_specs/to_concurrency_default.html.erb +1 -0
  136. data/spec/fixture/app/views/numeric_ext_specs/two_digits.html.erb +1 -0
  137. data/spec/fixture/app/views/option_tag_specs/array.html.erb +1 -0
  138. data/spec/fixture/app/views/option_tag_specs/clean.html.erb +1 -0
  139. data/spec/fixture/app/views/option_tag_specs/collection.html.erb +1 -0
  140. data/spec/fixture/app/views/option_tag_specs/multiple_selects.html.erb +1 -0
  141. data/spec/fixture/app/views/option_tag_specs/no_extra_attributes.html.erb +1 -0
  142. data/spec/fixture/app/views/option_tag_specs/optgroups.html.erb +1 -0
  143. data/spec/fixture/app/views/option_tag_specs/selected.html.erb +1 -0
  144. data/spec/fixture/app/views/option_tag_specs/with_blank.html.erb +1 -0
  145. data/spec/fixture/app/views/option_tag_specs/with_prompt.html.erb +1 -0
  146. data/spec/fixture/app/views/password_field_specs/basic.html.erb +1 -0
  147. data/spec/fixture/app/views/password_field_specs/disabled.html.erb +1 -0
  148. data/spec/fixture/app/views/radio_button_specs/basic.html.erb +1 -0
  149. data/spec/fixture/app/views/radio_button_specs/disabled.html.erb +1 -0
  150. data/spec/fixture/app/views/radio_button_specs/label.html.erb +1 -0
  151. data/spec/fixture/app/views/radio_group_specs/attributes.html.erb +1 -0
  152. data/spec/fixture/app/views/radio_group_specs/basic.html.erb +1 -0
  153. data/spec/fixture/app/views/radio_group_specs/hash.html.erb +1 -0
  154. data/spec/fixture/app/views/radio_group_specs/specific_attributes.html.erb +1 -0
  155. data/spec/fixture/app/views/select_specs/blank.html.erb +1 -0
  156. data/spec/fixture/app/views/select_specs/multiple.html.erb +1 -0
  157. data/spec/fixture/app/views/submit_specs/disabled_submit.html.erb +1 -0
  158. data/spec/fixture/app/views/submit_specs/submit_with_label.html.erb +1 -0
  159. data/spec/fixture/app/views/submit_specs/submit_with_values.html.erb +1 -0
  160. data/spec/fixture/app/views/tag_helper/nested_tags.html.erb +5 -0
  161. data/spec/fixture/app/views/tag_helper/tag_with_attributes.html.erb +1 -0
  162. data/spec/fixture/app/views/tag_helper/tag_with_content.html.erb +1 -0
  163. data/spec/fixture/app/views/tag_helper/tag_with_content_in_the_block.html.erb +3 -0
  164. data/spec/fixture/app/views/text_area_specs/basic.html.erb +1 -0
  165. data/spec/fixture/app/views/text_area_specs/disabled.html.erb +1 -0
  166. data/spec/fixture/app/views/text_area_specs/label.html.erb +1 -0
  167. data/spec/fixture/app/views/text_area_specs/nil.html.erb +1 -0
  168. data/spec/fixture/app/views/text_field_specs/basic.html.erb +1 -0
  169. data/spec/fixture/app/views/text_field_specs/class.html.erb +1 -0
  170. data/spec/fixture/app/views/text_field_specs/disabled.html.erb +1 -0
  171. data/spec/fixture/app/views/text_field_specs/label.html.erb +1 -0
  172. data/spec/fixture/config/environments/development.rb +6 -0
  173. data/spec/fixture/config/environments/production.rb +5 -0
  174. data/spec/fixture/config/environments/test.rb +6 -0
  175. data/spec/fixture/config/init.rb +46 -0
  176. data/spec/fixture/config/rack.rb +11 -0
  177. data/spec/fixture/config/router.rb +36 -0
  178. data/spec/fixture/log/merb.main.pid +1 -0
  179. data/spec/fixture/log/merb_test.log +624 -0
  180. data/spec/fixture/public/images/merb.jpg +0 -0
  181. data/spec/fixture/public/merb.fcgi +4 -0
  182. data/spec/fixture/public/stylesheets/master.css +119 -0
  183. data/spec/merb_helpers_config_spec.rb +82 -0
  184. data/spec/merb_helpers_date_time_spec.rb +257 -0
  185. data/spec/merb_helpers_form_spec.rb +1266 -0
  186. data/spec/merb_helpers_tag_helper_spec.rb +46 -0
  187. data/spec/merb_helpers_text_spec.rb +67 -0
  188. data/spec/numeric_extlib_spec.rb +135 -0
  189. data/spec/ordinalize_spec.rb +51 -0
  190. data/spec/spec_helper.rb +149 -0
  191. data/spec/time_dsl_spec.rb +43 -0
  192. metadata +303 -0
@@ -0,0 +1,1266 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ # Quick rundown of how these specs work
4
+ # please read before hacking on this plugin
5
+ #
6
+ # helpers must be tested through then entire stack
7
+ # what that means is that each spec must
8
+ # send a request to a controller and render a template
9
+ #
10
+ # Start by creating a spec controller subclassing SpecController
11
+ # which itself is a subclass of Merb::Controller
12
+ # specs_controller.rb (available at spec/fixture/app/controllers/specs_controller.rb)
13
+ # defines SpecController.
14
+ # Create a new controller in the spec/fixture/app/controllers/ if you are adding a new helper
15
+ #
16
+ # To test your helper, start by initializing a controller
17
+ #
18
+ # @controller = CustomHelperSpecs.new(Merb::Request.new({}))
19
+ #
20
+ # Note that we are sending a real request to the controller, feel free to use the request as needed
21
+ #
22
+ # You might need to access real objects in your views
23
+ # you can do that by setting them up in the controller
24
+ #
25
+ # @obj = FakeModel.new # FaKeModel is defined in spec/fixture/models/first_generic_fake_model.rb check it out!
26
+ # @controller.instance_variable_set(:@obj, @obj)
27
+ #
28
+ # To test a helper, you need to render a view:
29
+ #
30
+ # result = @controller.render :view_name
31
+ #
32
+ # Of course, you need to create a view:
33
+ # spec/fixture/app/views/custom_helper_specs/view_name.html.erb
34
+ # in the view, call the helper you want to test
35
+ #
36
+ # You can now test the helper in the view:
37
+ # result.should match_tag(:form, :method => "post")
38
+ #
39
+
40
+
41
+ Merb::Plugins.config[:helpers] = {
42
+ :default_builder => Merb::Helpers::Form::Builder::FormWithErrors
43
+ }
44
+
45
+ Merb::Router.append do
46
+ resources :obj
47
+ end
48
+
49
+
50
+ describe "error_messages_for" do
51
+
52
+ before :each do
53
+ @c = Application.new({})
54
+ @dm_obj = Object.new
55
+ @sq_obj = Object.new
56
+ @dm_errors = [["foo", "bar"],["baz","bat"]]
57
+ @sq_errors = Object.new
58
+ @sq_errors.stub!(:full_messages).and_return(["foo", "baz"])
59
+ @dm_obj.stub!(:errors).and_return(@dm_errors)
60
+ @dm_obj.stub!(:new_record?).and_return(false)
61
+ @sq_obj.stub!(:errors).and_return(@sq_errors)
62
+ @sq_obj.stub!(:new_record?).and_return(false)
63
+ end
64
+
65
+ it "should build default error messages for AR-like models" do
66
+ errs = @c.error_messages_for(@dm_obj)
67
+ errs.should include("<h2>Form submission failed because of 2 problems</h2>")
68
+ errs.should include("<li>foo bar</li>")
69
+ errs.should include("<li>baz bat</li>")
70
+ end
71
+
72
+ it "should build default error messages for Sequel-like models" do
73
+ errs = @c.error_messages_for(@sq_obj)
74
+ errs.should include("<h2>Form submission failed because of 2 problems</h2>")
75
+ errs.should include("<li>foo</li>")
76
+ errs.should include("<li>baz</li>")
77
+ end
78
+
79
+ # it "should build default error messages for symbol" do
80
+ # errs = error_messages_for(:obj)
81
+ # errs.should include("<h2>Form submittal failed because of 2 problems</h2>")
82
+ # errs.should include("<li>foo bar</li>")
83
+ # errs.should include("<li>baz bat</li>")
84
+ # end
85
+
86
+ it "should accept a custom HTML class" do
87
+ errs = @c.error_messages_for(@dm_obj, :error_class => "foo")
88
+ errs.should include("<div class='foo'>")
89
+ end
90
+
91
+ it "should accept a custom header block" do
92
+ errs = @c.error_messages_for(@dm_obj, :header => "<h3>Failure: %s issue%s</h3>")
93
+ errs.should include("<h3>Failure: 2 issues</h3>")
94
+ end
95
+
96
+ # it "should put the error messages inside a form if :before is false" do
97
+ # ret = @c.form_for @dm_obj do
98
+ # _buffer << error_messages
99
+ # end
100
+ # ret.should =~ /\A\s*<form.*<div class='error'>/
101
+ # end
102
+
103
+ end
104
+
105
+ describe "form" do
106
+
107
+ before :each do
108
+ @c = FormSpecs.new(Merb::Request.new({}))
109
+ end
110
+
111
+ describe "when _default_builder is Merb::Helpers::Form::Builder::ResourcefulFormWithErrors" do
112
+
113
+ before(:each) do
114
+ @obj = FakeModel2.new
115
+ @c.instance_variable_set(:@obj, @obj)
116
+ end
117
+
118
+ it "should not explode when #form is called" do
119
+ r = @c.render :resourceful_form
120
+ pending
121
+ #r.should =~ /action="fake_model2\/#{@obj.id}"/
122
+ end
123
+ end
124
+
125
+
126
+ it "should use the post method by default" do
127
+ ret = @c.render(:post_by_default)
128
+ ret.should match_tag(:form, :method => "post")
129
+ ret.should include("CONTENT")
130
+ end
131
+
132
+ it "should use the get method if set" do
133
+ ret = @c.render(:get_if_set)
134
+ ret.should match_tag(:form, :method => "get")
135
+ end
136
+
137
+ it "should fake out the put method if set" do
138
+ ret = @c.render(:fake_put_if_set)
139
+ ret.should match_tag(:form, :method => "post")
140
+ ret.should match_tag(:input, :type => "hidden", :name => "_method", :value => "put")
141
+ end
142
+
143
+ it "should fake out the delete method if set" do
144
+ ret = @c.render(:fake_delete_if_set)
145
+ ret.should match_tag(:form, :method => "post")
146
+ ret.should match_tag(:input, :type => "hidden", :name => "_method", :value => "delete")
147
+ end
148
+
149
+ # TODO: Why is this required?
150
+ # ---------------------------
151
+ #
152
+ # it "should silently set method to post if an unsupported method is used" do
153
+ # form_tag :method => :dodgy do
154
+ # _buffer << "CONTENT"
155
+ # end
156
+ # _buffer.should match_tag(:form, :method => "post")
157
+ # _buffer.should_not match_tag(:input, :type => "hidden", :name => "_method", :value => "dodgy")
158
+ # end
159
+
160
+ it "should take create a form" do
161
+ ret = @c.render(:create_a_form)
162
+ ret.should match_tag(:form, :action => "foo", :method => "post")
163
+ ret.should include("Hello")
164
+ end
165
+
166
+ it "should set a form to be multipart" do
167
+ ret = @c.render(:create_a_multipart_form)
168
+ ret.should match_tag( :form, :action => "foo", :method => "post", :enctype => "multipart/form-data")
169
+ ret.should include("CONTENT")
170
+ end
171
+ end
172
+
173
+
174
+ describe "form_for" do
175
+
176
+ before :each do
177
+ @c = FormForSpecs.new(Merb::Request.new({}))
178
+ @c.instance_variable_set(:@obj, FakeModel.new)
179
+ end
180
+
181
+ it "should wrap the contents in a form tag" do
182
+ form = @c.render :basic
183
+ form.should match_tag(:form, :method => "post")
184
+ form.should match_tag(:input, :type => "hidden", :value => "put", :name => "_method")
185
+ end
186
+
187
+ it "should set the method to post be default" do
188
+ new_fake_model = FakeModel2.new
189
+ @c.instance_variable_set(:@obj, new_fake_model)
190
+ form = @c.render :basic
191
+ form.should match_tag(:form, :method => "post")
192
+ form.should_not match_tag(:input, :type => "hidden", :name => "_method")
193
+ end
194
+
195
+ it "should support PUT if the object passed in is not a new_record? via a hidden field" do
196
+ form = @c.render :basic
197
+ form.should match_tag(:form, :method => "post")
198
+ form.should match_tag(:input, :type => "hidden", :value => "put", :name => "_method")
199
+ end
200
+
201
+ end
202
+
203
+
204
+ describe "fields_for" do
205
+
206
+ before :each do
207
+ @c = FieldsForSpecs.new(Merb::Request.new({}))
208
+ @c.instance_variable_set(:@obj, FakeModel.new)
209
+ end
210
+
211
+
212
+ it "should dump the contents in the context of the object" do
213
+ r = @c.render :basic
214
+ r.should match_tag(:input, :type => "text", :value => "foowee")
215
+ end
216
+
217
+ it "should be able to modify the context midstream" do
218
+ @c.instance_variable_set(:@obj2, FakeModel2.new)
219
+ r = @c.render :midstream
220
+ r.should match_tag(:input, :type => "text", :value => "foowee")
221
+ r.should match_tag(:input, :name => "fake_model2[foo]", :type => "text", :value => "foowee2")
222
+ end
223
+
224
+ it "should handle an explicit nil attribute" do
225
+ r = @c.render :nil
226
+ r.should match_tag(:input, :name => "fake_model[foo]", :value => "foowee", :type => "text")
227
+ end
228
+
229
+ it "should pass context back to the old object after exiting block" do
230
+ @c.instance_variable_set(:@obj2, FakeModel2.new)
231
+ r = @c.render :midstream
232
+ r.should match_tag(:input, :id => "fake_model_foo", :name => "fake_model[foo]", :type => "text", :extra => "true")
233
+ end
234
+ end
235
+
236
+ describe "text_field" do
237
+
238
+ before :each do
239
+ @c = TextFieldSpecs.new(Merb::Request.new({}))
240
+ end
241
+
242
+ it "should return a basic text field based on the values passed in" do
243
+ r = @c.render :basic
244
+ r.should match_tag( :input, :type => "text", :name => "foo", :value => "bar")
245
+ end
246
+
247
+ it "should provide an additional label tag if the :label option is passed in" do
248
+ r = @c.render :basic
249
+ r.should match(/<label>LABEL<\/label>/)
250
+ end
251
+
252
+ it "should update an existing :class with a new class" do
253
+ r = @c.render :class
254
+ r.should == "<input type=\"text\" class=\"awesome foobar text\"/>"
255
+ end
256
+
257
+ it "should be disabled if :disabled => true is passed in" do
258
+ r = @c.render :disabled
259
+ r.should match_tag(:input, :type => "text", :disabled => "disabled")
260
+ end
261
+
262
+ it "should provide an additional label tag if the :label option is passed in as a hash" do
263
+ r = @c.render :label
264
+ r.should match(/<label class="cool">LABEL<\/label>/)
265
+ end
266
+
267
+ end
268
+
269
+ describe "bound_text_field" do
270
+
271
+ before :each do
272
+ @c = BoundTextFieldSpecs.new(Merb::Request.new({}))
273
+ @c.instance_variable_set(:@obj, FakeModel.new)
274
+ end
275
+
276
+ it "should take a string object and return a useful text control" do
277
+ r = @c.render :basic
278
+ r.should match_tag(:input, :type => "text", :name => "fake_model[foo]", :value => "foowee")
279
+ end
280
+
281
+ it "should take additional attributes and use them" do
282
+ r = @c.render :basic
283
+ r.should match_tag(:input, :type => "text", :name => "fake_model[foo]", :value => "foowee", :bar => "7")
284
+ end
285
+
286
+ it "should provide an additional label tag if the :label option is passed in" do
287
+ form = @c.render :basic
288
+ form.should match(/<label.*>LABEL<\/label><input/)
289
+ res = form.scan(/<[^>]*>/)
290
+ res[2].should_not match_tag(:input, :label => "LABEL")
291
+ end
292
+
293
+ it "should not errorify the field for a new object" do
294
+ r = @c.render :basic
295
+ r.should_not match_tag(:input, :type => "text", :name => "fake_model[foo]", :class => "error")
296
+ end
297
+
298
+ it "should errorify a field for a model with errors" do
299
+ model = mock("model")
300
+ model.stub!(:new_record?).and_return(true)
301
+ model.stub!(:class).and_return("MyClass")
302
+ model.stub!(:foo).and_return("FOO")
303
+ errors = mock("errors")
304
+ errors.should_receive(:on).with(:foo).and_return(true)
305
+
306
+ model.stub!(:errors).and_return(errors)
307
+ @c.instance_variable_set(:@obj, model)
308
+ r = @c.render :basic
309
+ r.should match_tag(:input, :class => "error text")
310
+ end
311
+ end
312
+
313
+ describe "bound_radio_button" do
314
+
315
+ before :each do
316
+ @c = BoundRadioButtonSpecs.new(Merb::Request.new({}))
317
+ @c.instance_variable_set(:@obj, FakeModel.new)
318
+ end
319
+
320
+ it "should take a string object and return a useful text control" do
321
+ r = @c.render :basic
322
+ r.should match_tag(:input, :type => "radio", :name => "fake_model[foo]", :value => "foowee")
323
+ end
324
+
325
+ it "should take additional attributes and use them" do
326
+ r = @c.render :basic
327
+ r.should match_tag(:input, :type => "radio", :name => "fake_model[foo]", :value => "foowee", :bar => "7")
328
+ end
329
+
330
+ it "should provide an additional label tag if the :label option is passed in" do
331
+ form = @c.render :basic
332
+ form.should match(/<input.*><label.*>LABEL<\/label>/)
333
+ res = form.scan(/<[^>]*>/)
334
+ res[2].should_not match_tag(:input, :label => "LABEL")
335
+ end
336
+
337
+ it "should not errorify the field for a new object" do
338
+ r = @c.render :basic
339
+ r.should_not match_tag(:input, :type => "radio", :name => "fake_model[foo]", :class => "error")
340
+ end
341
+
342
+ it "should errorify a field for a model with errors" do
343
+ model = mock("model")
344
+ model.stub!(:new_record?).and_return(true)
345
+ model.stub!(:class).and_return("MyClass")
346
+ model.stub!(:foo).and_return("FOO")
347
+ errors = mock("errors")
348
+ errors.should_receive(:on).with(:foo).and_return(true)
349
+
350
+ model.stub!(:errors).and_return(errors)
351
+ @c.instance_variable_set(:@obj, model)
352
+ r = @c.render :basic
353
+ r.should match_tag(:input, :class => "error radio")
354
+ end
355
+ end
356
+
357
+ describe "password_field" do
358
+
359
+ before :each do
360
+ @c = PasswordFieldSpecs.new(Merb::Request.new({}))
361
+ end
362
+
363
+ it "should return a basic password field, but omit the value" do
364
+ r = @c.render :basic
365
+ r.should match_tag(:input, :type => "password", :name => "foo")
366
+ end
367
+
368
+ it "should provide an additional label tag if the :label option is passed in" do
369
+ r = @c.render :basic
370
+ r.should match(/<label.*>LABEL<\/label>/)
371
+ end
372
+
373
+ it "should be disabled if :disabled => true is passed in" do
374
+ r = @c.render :disabled
375
+ r.should match_tag(:input, :type => "password", :disabled => "disabled")
376
+ end
377
+ end
378
+
379
+ describe "bound_password_field" do
380
+
381
+ before :each do
382
+ @c = BoundPasswordFieldSpecs.new(Merb::Request.new({}))
383
+ @obj = FakeModel.new
384
+ @c.instance_variable_set(:@obj, @obj)
385
+ end
386
+
387
+ it "should take a string object and return a useful password control, but omit the value" do
388
+ r = @c.render :basic
389
+ r.should match_tag(:input, :type => "password", :name => "fake_model[foo]")
390
+ end
391
+
392
+ it "should take additional attributes and use them" do
393
+ r = @c.render :basic
394
+ r.should match_tag(:input, :type => "password", :name => "fake_model[foo]", :bar => "7", :value => @obj.foo)
395
+ end
396
+
397
+ it "should provide an additional label tag if the :label option is passed in" do
398
+ r = @c.render :basic
399
+ r.should match(/<label.*>LABEL<\/label><input/)
400
+ res = r.scan(/<[^>]*>/)
401
+ res[2].should_not match_tag(:input, :label => "LABEL")
402
+ end
403
+
404
+ it "should not errorify the field for a new object" do
405
+ r = @c.render :basic
406
+ r.should_not match_tag(:input, :class => "error")
407
+ end
408
+
409
+ it "should errorify a field for a model with errors" do
410
+ model = mock("model")
411
+ model.stub!(:new_record?).and_return(true)
412
+ model.stub!(:class).and_return("MyClass")
413
+ model.stub!(:foo).and_return("FOO")
414
+ errors = mock("errors")
415
+ errors.should_receive(:on).with(:foo).and_return(true)
416
+
417
+ model.stub!(:errors).and_return(errors)
418
+
419
+ @c.instance_variable_set(:@obj, model)
420
+ r = @c.render :basic
421
+ r.should match_tag(:input, :class => "error password")
422
+ end
423
+
424
+ end
425
+
426
+ describe "check_box" do
427
+
428
+ before :each do
429
+ @c = CheckBoxSpecs.new(Merb::Request.new({}))
430
+ end
431
+
432
+ it "should return a basic checkbox based on the values passed in" do
433
+ r = @c.render :basic
434
+ r.should match_tag(:input, :class => "checkbox", :name => "foo", :checked => "checked")
435
+ end
436
+
437
+ it "should provide an additional label tag if the :label option is passed in" do
438
+ result = @c.render :label
439
+ result.should match(/<input.*><label>LABEL<\/label>/)
440
+ res = result.scan(/<[^>]*>/)
441
+ res[0].should_not match_tag(:input, :label => "LABEL")
442
+ end
443
+
444
+ it 'should remove the checked="checked" attribute if :checked is false or nil' do
445
+ r = @c.render :unchecked
446
+ r.should_not include('checked="')
447
+ end
448
+
449
+ it 'should have the checked="checked" attribute if :checked => true is passed in' do
450
+ r = @c.render :basic
451
+ r.should include('checked="checked"')
452
+ end
453
+
454
+ it "should not be boolean by default" do
455
+ r = @c.render :basic
456
+ r.should match_tag(:input, :type => "checkbox", :name => "foo")
457
+ end
458
+
459
+ it "should add a hidden input if boolean" do
460
+ r = @c.render :boolean
461
+ r.should have_tag(:input, :type => "checkbox", :value => "1")
462
+ r.should have_tag(:input, :type => "hidden", :value => "0")
463
+ r.should match(/<input.*?type="hidden"[^>]*>[^<]*<input.*?type="checkbox"[^>]*>/)
464
+
465
+ end
466
+
467
+ it "should not allow a :value param if boolean" do
468
+ lambda { @c.render :raises_error_if_not_boolean }.
469
+ should raise_error(ArgumentError, /can't be used with a boolean checkbox/)
470
+ end
471
+
472
+ it "should not allow :boolean => false if :on and :off are specified" do
473
+ lambda { @c.render :raises_error_if_on_off_and_boolean_false }.
474
+ should raise_error(ArgumentError, /cannot be used/)
475
+ end
476
+
477
+ it "should be boolean if :on and :off are specified" do
478
+ html = @c.render :on_off_is_boolean
479
+ html.should have_tag(:input, :type => "checkbox", :value => "YES", :name => "foo")
480
+ html.should have_tag(:input, :type => "hidden", :value => "NO", :name => "foo")
481
+ end
482
+
483
+ it "should have both :on and :off specified or neither" do
484
+ lambda { @c.render :raise_unless_both_on_and_off }.should raise_error(ArgumentError, /must be specified/)
485
+ lambda { @c.render :raise_unless_both_on_and_off }.should raise_error(ArgumentError, /must be specified/)
486
+ end
487
+
488
+ it "should convert :value to a string on a non-boolean checkbox" do
489
+ r = @c.render :to_string
490
+ r.should match_tag(:input, :value => "")
491
+ r.should match_tag(:input, :value => "false")
492
+ r.should match_tag(:input, :value => "0")
493
+ r.should match_tag(:input, :value => "0")
494
+ r.should match_tag(:input, :value => "1")
495
+ r.should match_tag(:input, :value => "1")
496
+ r.should match_tag(:input, :value => "true")
497
+ end
498
+
499
+ it "should be disabled if :disabled => true is passed in" do
500
+ r = @c.render :disabled
501
+ r.should match_tag(:input, :type => "checkbox", :disabled => "disabled")
502
+ end
503
+
504
+ it "should be possible to call with just check_box" do
505
+ r = @c.render :simple
506
+ r.should match_tag(:input, :type => "checkbox", :class => "checkbox")
507
+ end
508
+ end
509
+
510
+ describe "bound_check_box" do
511
+
512
+ before :each do
513
+ @c = BoundCheckBoxSpecs.new(Merb::Request.new({}))
514
+ @c.instance_variable_set(:@obj, FakeModel.new)
515
+ end
516
+
517
+ it "should take a string and return a useful checkbox control" do
518
+ r = @c.render :basic
519
+ r.should match_tag(:input, :type =>"checkbox", :name => "fake_model[baz]", :class => "checkbox", :value => "1", :checked => "checked", :id => "fake_model_baz")
520
+ r.should match_tag(:input, :type =>"checkbox", :name => "fake_model[bat]", :class => "checkbox", :value => "0")
521
+ end
522
+
523
+ it "should raise an error if you try to use :value" do
524
+ lambda { @c.render(:raise_value_error) }.should raise_error(ArgumentError, /:value can't be used with a bound_check_box/)
525
+ end
526
+
527
+ it "should support models from datamapper" do
528
+ @c.instance_variable_set(:@obj, FakeDMModel.new)
529
+ r = @c.render :basic
530
+ r.should match_tag(:input,
531
+ :type =>"checkbox",
532
+ :name => "fake_dm_model[baz]",
533
+ :class => "checkbox",
534
+ :value => "1",
535
+ :checked => "checked",
536
+ :id => "fake_dm_model_baz")
537
+ r.should match_tag(:input, :type =>"checkbox", :name => "fake_dm_model[bat]", :class => "checkbox", :value => "0")
538
+ end
539
+
540
+ it "should allow a user to set the :off value" do
541
+ r = @c.render :on_and_off
542
+ r.should match_tag(:input, :type =>"checkbox", :name => "fake_model[bat]", :class => "checkbox", :value => "off")
543
+ end
544
+
545
+ it "should render controls with errors if their attribute contains an error" do
546
+ r = @c.render :errors
547
+ r.should match_tag(:input, :type =>"checkbox", :name => "fake_model[bazbad]", :class => "error checkbox", :value => "1", :checked => "checked")
548
+ r.should match_tag(:input, :type =>"checkbox", :name => "fake_model[batbad]", :class => "error checkbox", :value => "0")
549
+ end
550
+
551
+ it "should provide an additional label tag if the :label option is passed in" do
552
+ form = @c.render :label
553
+ form.should match( /<input.*><label.*>LABEL<\/label>/ )
554
+ res = form.scan(/<[^>]*>/)
555
+ res[0].should_not match_tag(:input, :label => "LABEL")
556
+ end
557
+
558
+ it "should not errorify the field for a new object" do
559
+ r = @c.render :basic
560
+ r.should_not match_tag(:input, :type => "checkbox", :class => "error checkbox")
561
+ end
562
+
563
+ it "should errorify a field for a model with errors" do
564
+ model = mock("model")
565
+ model.stub!(:new_record?).and_return(true)
566
+ model.stub!(:class).and_return("MyClass")
567
+ model.stub!(:baz).and_return("BAZ")
568
+ model.stub!(:bat).and_return("BAT")
569
+ errors = mock("errors")
570
+ errors.should_receive(:on).with(:baz).and_return(true)
571
+ errors.should_receive(:on).with(:bat).and_return(true)
572
+
573
+ model.stub!(:errors).and_return(errors)
574
+
575
+ @c.instance_variable_set(:@obj, model)
576
+ r = @c.render :basic
577
+ r.should match_tag(:input, :type => "checkbox", :class => "error checkbox")
578
+ end
579
+
580
+ it "should be boolean" do
581
+ r = @c.render :basic
582
+ r.should have_tag(:input, :type => "checkbox", :value => "1")
583
+ r.should have_tag(:input, :type => "hidden", :value => "0")
584
+ end
585
+
586
+ it "should be checked if the value of the model's attribute is equal to the value of :on" do
587
+ r = @c.render :checked
588
+ r.should match_tag(:input, :type =>"checkbox", :value => "foowee", :checked => "checked")
589
+ r.should match_tag(:input, :type =>"checkbox", :value => "YES", :checked => "checked")
590
+
591
+ end
592
+ end
593
+
594
+ describe "hidden_field" do
595
+
596
+ before :each do
597
+ @c = HiddenFieldSpecs.new(Merb::Request.new({}))
598
+ end
599
+
600
+ it "should return a basic checkbox based on the values passed in" do
601
+ r = @c.render :basic
602
+ r.should match_tag(:input, :type => "hidden", :name => "foo", :value => "bar")
603
+ end
604
+
605
+ it "should not render a label if the :label option is passed in" do
606
+ res = @c.render :label
607
+ res.should_not match(/<label>LABEL/)
608
+ res.should_not match_tag(:input, :label=> "LABEL")
609
+ end
610
+
611
+ it "should be disabled if :disabled => true is passed in" do
612
+ r = @c.render :disabled
613
+ r.should match_tag(:input, :type => "hidden", :disabled => "disabled")
614
+ end
615
+ end
616
+
617
+ describe "bound_hidden_field" do
618
+
619
+ before :each do
620
+ @c = BoundHiddenFieldSpecs.new(Merb::Request.new({}))
621
+ @c.instance_variable_set(:@obj, FakeModel.new)
622
+ end
623
+
624
+ it "should take a string and return a hidden field control" do
625
+ r = @c.render :basic
626
+ r.should match_tag(:input, :type =>"hidden", :name => "fake_model[foo]", :value => "foowee")
627
+ end
628
+
629
+ it "should render controls with errors if their attribute contains an error" do
630
+ r = @c.render :errors
631
+ r.should match_tag(:input, :type =>"hidden", :name => "fake_model[foobad]", :value => "foowee", :class => "error hidden")
632
+ end
633
+
634
+ it "should not render a label if the :label option is passed in" do
635
+ r = @c.render :label
636
+ r.should_not match(/<label>LABEL/)
637
+ r.should_not match_tag(:input, :label=> "LABEL")
638
+ end
639
+
640
+ it "should not errorify the field for a new object" do
641
+ r = @c.render :basic
642
+ r.should_not match_tag(:input, :type => "hidden", :class => "error")
643
+ end
644
+
645
+ it "should not errorify a field for a model with errors" do
646
+ model = mock("model")
647
+ model.stub!(:new_record?).and_return(true)
648
+ model.stub!(:class).and_return("MyClass")
649
+ model.stub!(:foo).and_return("FOO")
650
+ errors = mock("errors")
651
+ errors.should_receive(:on).with(:foo).and_return(true)
652
+
653
+ model.stub!(:errors).and_return(errors)
654
+
655
+ Merb::Router.append do
656
+ resources :models
657
+ end
658
+
659
+ @c.instance_variable_set(:@model, model)
660
+ r = @c.render :hidden_error
661
+ r.should match_tag(:input, :type => "hidden", :name => "my_class[foo]", :class => "error hidden")
662
+ end
663
+
664
+ end
665
+
666
+ describe "radio_button" do
667
+
668
+ before :each do
669
+ @c = RadioButtonSpecs.new(Merb::Request.new({}))
670
+ end
671
+
672
+ it "should should return a basic radio button based on the values passed in" do
673
+ r = @c.render :basic
674
+ r.should match_tag(:input, :type => "radio", :name => "foo", :value => "bar", :id => "baz")
675
+ end
676
+
677
+ it "should provide an additional label tag if the :label option is passed in" do
678
+ result = @c.render :label
679
+ # result.should match(/<label.*>LABEL<\/label><input/)
680
+ # res = result.scan(/<[^>]*>/)
681
+ # res[2].should_not match_tag(:input, :label => "LABEL")
682
+ result.should match(/<input.*><label.*>LABEL<\/label>/)
683
+ res = result.scan(/<[^>]*>/)
684
+ res[0].should_not match_tag(:input, :label => "LABEL")
685
+ end
686
+
687
+ it "should be disabled if :disabled => true is passed in" do
688
+ r = @c.render :disabled
689
+ r.should match_tag(:input, :type => "radio", :disabled => "disabled")
690
+ end
691
+ end
692
+
693
+ describe "radio_group" do
694
+
695
+ before :each do
696
+ @c = RadioGroupSpecs.new(Merb::Request.new({}))
697
+ end
698
+
699
+ it "should return a group of radio buttons" do
700
+ radio = @c.render :basic
701
+ radio = radio.scan(/<[^>]*>/)
702
+ radio[0].should match_tag(:input, :type => "radio", :value => "foowee")
703
+ radio[3].should match_tag(:input, :type => "radio", :value => "baree")
704
+ end
705
+
706
+ it "should provide an additional label tag for each option in array-based options" do
707
+ radio = @c.render :basic
708
+ radio.scan( /<input.*?><label.*?>(foowee|baree)<\/label>/ ).size.should == 2
709
+ radio = radio.scan(/<[^>]*>/)
710
+ radio[0].should_not match_tag(:input, :label => "LABEL")
711
+ radio[3].should_not match_tag(:input, :label => "LABEL")
712
+ end
713
+
714
+ it "should accept array of hashes as options" do
715
+ radio = @c.render :hash
716
+ radio.scan( /<input.*?><label.*?>(Five|Bar)<\/label>/ ).size.should == 2
717
+ radio = radio.scan(/<[^>]*>/)
718
+ radio.size.should == 6
719
+ radio[0].should match_tag(:input, :value => 5)
720
+ radio[1].should match_tag(:label)
721
+ radio[2].should match_tag('/label')
722
+ radio[3].should match_tag(:input, :value => 'bar', :id => 'bar_id')
723
+ radio[4].should match_tag(:label, :for => 'bar_id')
724
+ radio[5].should match_tag('/label')
725
+ end
726
+
727
+ it "should apply attributes to each element" do
728
+ radio = @c.render :attributes
729
+ radio = radio.scan(/<[^>]*>/)
730
+ radio[0].should match_tag(:input, :type => "radio", :value => "foowee", :class => "CLASS radio")
731
+ radio[3].should match_tag(:input, :type => "radio", :value => "baree", :class => "CLASS radio")
732
+ end
733
+
734
+ it "should override universal attributes with specific ones" do
735
+ radio = @c.render :specific_attributes
736
+ radio = radio.scan(/<[^>]*>/)
737
+ radio[0].should match_tag(:input, :type => "radio", :value => "foowee", :class => "CLASS radio")
738
+ radio[3].should match_tag(:input, :type => "radio", :value => "baree", :class => "BAREE radio")
739
+ end
740
+ end
741
+
742
+
743
+ describe "bound_radio_group" do
744
+
745
+ before do
746
+ @c = BoundRadioGroupSpecs.new(Merb::Request.new({}))
747
+ @c.instance_variable_set(:@obj, FakeModel.new)
748
+ end
749
+
750
+ it "should return a group of radio buttons" do
751
+ r = @c.render :basic
752
+ radio = r.scan(/<[^>]*>/)
753
+ radio[2].should match_tag(:input, :type => "radio", :name => "fake_model[foo]", :value => "foowee", :checked => "checked")
754
+ radio[5].should match_tag(:input, :type => "radio", :name => "fake_model[foo]", :value => "baree")
755
+ radio[6].should not_match_tag(:checked => "checked")
756
+ end
757
+
758
+ it "should provide an additional label tag for each option in array-based options" do
759
+ r = @c.render :basic
760
+ r.scan( /<input.*?><label.*?>(foowee|baree)<\/label>/ ).size.should == 2
761
+ radio = r.scan(/<[^>]*>/)[2..-2]
762
+ radio[0].should_not match_tag(:input, :label => "LABEL")
763
+ radio[3].should_not match_tag(:input, :label => "LABEL")
764
+ end
765
+
766
+ it "should accept array of hashes as options" do
767
+ r = @c.render :hashes
768
+ r.scan( /<input.*?><label.*?>(Five|Bar)<\/label>/ ).size.should == 2
769
+ radio = r.scan(/<[^>]*>/)[2..-2]
770
+ radio.size.should == 6
771
+ radio[0].should match_tag(:input, :value => 5)
772
+ radio[1].should match_tag(:label)
773
+ radio[2].should match_tag('/label')
774
+ radio[3].should match_tag(:input, :value => 'bar', :id => 'bar_id')
775
+ radio[4].should match_tag(:label, :for => 'bar_id')
776
+ radio[5].should match_tag('/label')
777
+ end
778
+
779
+ it "should provide autogenerated id for inputs" do
780
+ r = @c.render :mixed
781
+ radio = r.scan(/<[^>]*>/)[2..-2]
782
+ pp radio
783
+ radio[0].should match_tag(:input, :id => 'fake_model_foo_bar')
784
+ radio[1].should match_tag(:label, :for => 'fake_model_foo_bar')
785
+ radio[3].should match_tag(:input, :id => 'fake_model_foo_bar')
786
+ radio[4].should match_tag(:label, :for => 'fake_model_foo_bar')
787
+ end
788
+
789
+ it "should override autogenerated id for inputs with hash-given id" do
790
+ r = @c.render :override_id
791
+ radio = r.scan(/<[^>]*>/)[2..-2]
792
+ radio[0].should match_tag(:input, :id => 'bar_id')
793
+ radio[1].should match_tag(:label, :for => 'bar_id')
794
+ end
795
+ end
796
+
797
+
798
+ describe "text_area" do
799
+
800
+ before do
801
+ @c = TextAreaSpecs.new(Merb::Request.new({}))
802
+ end
803
+
804
+ it "should should return a basic text area based on the values passed in" do
805
+ r = @c.render :basic
806
+ r.should match_tag(:textarea, :name => "foo")
807
+ end
808
+
809
+ it "should handle a nil content" do
810
+ r = @c.render :nil
811
+ r.should == "<textarea name=\"foo\"></textarea>"
812
+ end
813
+
814
+
815
+ # TODO: Why is this required?
816
+ # ---------------------------
817
+ #
818
+ # it "should handle a nil attributes hash" do
819
+ # text_area("CONTENT", nil).should == "<textarea>CONTENT</textarea>"
820
+ # end
821
+
822
+ it "should render a label when the label is passed in" do
823
+ result = @c.render :label
824
+ result.should match(/<label.*>LABEL<\/label><textarea/)
825
+ res = result.scan(/<[^>]*>/)
826
+ res[1].should_not match_tag(:textarea, :label => "LABEL")
827
+ end
828
+
829
+ it "should be disabled if :disabled => true is passed in" do
830
+ r = @c.render :disabled
831
+ r.should match_tag(:textarea, :disabled => "disabled")
832
+ end
833
+ end
834
+
835
+ describe "bound_text_area" do
836
+
837
+ before do
838
+ @c = BoundTextAreaSpecs.new(Merb::Request.new({}))
839
+ @obj = FakeModel.new
840
+ @c.instance_variable_set(:@obj, @obj)
841
+ end
842
+
843
+ it "should provide :id attribute" do
844
+ r = @c.render :basic
845
+ r.should match_tag(:textarea, :id => 'fake_model_foo', :name => "fake_model[foo]")
846
+ r.should =~ />\s*#{@obj.foo}\s*</
847
+ end
848
+ end
849
+
850
+ describe "select" do
851
+
852
+ before do
853
+ @c = SelectSpecs.new(Merb::Request.new({}))
854
+ end
855
+
856
+ it "should provide a blank option if you :include_blank" do
857
+ r = @c.render :blank
858
+ r.should =~ /<option.*>\s*<\/option>/
859
+ end
860
+
861
+ it "should render the select tag with suffix '[]' to name when :multiple => true" do
862
+ r = @c.render :multiple
863
+ r.should match_tag( :select, :name => "foo[]" )
864
+ end
865
+ end
866
+
867
+ describe "bound_select" do
868
+
869
+ before do
870
+ @c = BoundSelectSpecs.new(Merb::Request.new({}))
871
+ @c.instance_variable_set(:@obj, FakeModel.new)
872
+ end
873
+
874
+ it "should render the select tag with the correct id and name" do
875
+ r = @c.render :basic
876
+ r.should match_tag( :select, :id => "fake_model_foo", :name => "fake_model[foo]" )
877
+ end
878
+
879
+ it "should render the select tag with suffix '[]' to name when :multiple => true" do
880
+ r = @c.render :multiple
881
+ r.should match_tag( :select, :id => "fake_model_foo", :name => "fake_model[foo][]" )
882
+ end
883
+
884
+ it "should include a blank option" do
885
+ r = @c.render :blank
886
+ r.should match_tag(:option, :value => '')
887
+ r.should =~ /<option.*>\s*<\/option>/
888
+ end
889
+
890
+ it "should render a prompt option without a value" do
891
+ r = @c.render :prompt
892
+ r.should match_tag(:option, :value => '')
893
+ r.should =~ /<option.*>Choose<\/option>/
894
+ end
895
+
896
+ it "should render a select tag with options" do
897
+ r = @c.render :with_options
898
+ r.should match_tag( :select, :class => "class1 class2", :title=> "This is the title" )
899
+ r.should =~ /<select.*>\s*<\/select>/
900
+ end
901
+
902
+ it "should render a select tag with options and a blank option" do
903
+ r = @c.render :with_options_with_blank
904
+ r.should match_tag( :select, :title => "TITLE" )
905
+ r.should match_tag( :option, :value => '' )
906
+ r.should =~ /<option.*>\s*<\/option>/
907
+ end
908
+
909
+ # Not sure how this makes any sense
910
+ # ---------------------------------
911
+ #
912
+ # it "should render the text as the value if no text_method is specified" do
913
+ # form_for @obj do
914
+ # content = select( :foo, :collection => [FakeModel] )
915
+ # content.should match_tag( :option, :value => "FakeModel" )
916
+ # end
917
+ # end
918
+
919
+ end
920
+
921
+ describe "bound option tags" do
922
+
923
+ before do
924
+ @c = BoundOptionTagSpecs.new(Merb::Request.new({}))
925
+ @c.instance_variable_set(:@obj, FakeModel.new)
926
+ end
927
+
928
+
929
+ it "should use text_method and value_method for tag generation" do
930
+ r = @c.render :text_and_value
931
+ r.should match_tag( :option, :content => "foowee", :value => "7" )
932
+ r.should match_tag( :option, :content => "foowee2", :value => "barbar" )
933
+
934
+ # content = options_from_collection_for_select( [FakeModel.new, FakeModel2.new], :text_method => 'foo', :value_method => 'bar' )
935
+ # content.should match_tag( :option, :content => "foowee", :value => "7" )
936
+ # content.should match_tag( :option, :content => "foowee2", :value => "barbar" )
937
+ end
938
+
939
+ it "should render a hash of arrays as a grouped select box" do
940
+ model1 = FakeModel.new ; model1.make = "Ford" ; model1.model = "Mustang" ; model1.vin = '1'
941
+ model2 = FakeModel.new ; model2.make = "Ford" ; model2.model = "Falcon" ; model2.vin = '2'
942
+ model3 = FakeModel.new ; model3.make = "Holden" ; model3.model = "Commodore" ; model3.vin = '3'
943
+ @c.instance_variable_set(:@model1, model1)
944
+ @c.instance_variable_set(:@model2, model2)
945
+ @c.instance_variable_set(:@model3, model3)
946
+ @c.instance_variable_set(:@collection, [model1, model2, model3].inject({}) {|s,e| (s[e.make] ||= []) << e; s })
947
+ r = @c.render :grouped
948
+ # Blank actually defaults to ""
949
+ r.should =~ /<optgroup label=\"Ford\"><option/
950
+ r.should match_tag( :optgroup, :label => "Ford" )
951
+ r.should match_tag( :option, :selected => "selected", :value => "1", :content => "Mustang" )
952
+ r.should match_tag( :option, :value => "2", :content => "Falcon" )
953
+ r.should match_tag( :optgroup, :label => "Holden" )
954
+ r.should match_tag( :option, :value => "3", :content => "Commodore" )
955
+
956
+ # collection = [@model1, @model2, @model3].inject({}) {|s,e| (s[e.make] ||= []) << e; s }
957
+ # content = options_from_collection_for_select(collection, :text_method => 'model', :value_method => 'vin', :selected => '1')
958
+ end
959
+
960
+ it "should render a collection of nested value/content arrays" do
961
+ r = @c.render :nested
962
+ r.should match_tag(:select, :id => "fake_model_foo", :name => "fake_model[foo]")
963
+ r.should match_tag(:option, :value => "small", :content => "Small")
964
+ r.should match_tag(:option, :value => "medium", :content => "Medium")
965
+ r.should match_tag(:option, :value => "large", :content => "Large")
966
+ end
967
+
968
+ # Is this really worth the extra speed hit? I'm thinking not
969
+ # ----------------------------------------------------------
970
+ #
971
+ # it "should humanize and titlize keys in the label for the option group" do
972
+ # collection = { :some_snake_case_key => [FakeModel.new] }
973
+ # form_for @obj do
974
+ # content = select( :foo, :collection => collection )
975
+ # content.should match_tag( :optgroup, :label => "Some Snake Case Key" )
976
+ # end
977
+ # end
978
+
979
+ end
980
+
981
+ require "hpricot"
982
+
983
+ describe "option tags" do
984
+
985
+ before do
986
+ @c = OptionTagSpecs.new(Merb::Request.new({}))
987
+ @c.instance_variable_set(:@collection, [['rabbit','Rabbit'],['horse','Horse'],['bird','Bird']])
988
+ end
989
+
990
+ it "should provide an option tag for each item in the collection" do
991
+ r = @c.render :collection
992
+ doc = Hpricot( r )
993
+ (doc/"option").size.should == 3
994
+ end
995
+
996
+ it "should provide a blank option" do
997
+ r = @c.render :with_blank
998
+ r.should match_tag( :option, :value => '' )
999
+ end
1000
+
1001
+ it "should render the prompt option at the top" do
1002
+ r = @c.render :with_prompt
1003
+ #ontent = select( :collection => [["foo", "Foo"]], :prompt => 'Choose' )
1004
+ r.should match(/<option[^>]*>Choose<\/option>[^<]*<option[^>]*>Foo<\/option>/)
1005
+ end
1006
+
1007
+ it "should provide selected options by value" do
1008
+ r = @c.render :selected
1009
+ r.should match_tag( :option, :value => 'rabbit', :selected => 'selected', :content => 'Rabbit' )
1010
+ r.should_not match_tag( :option, :value => 'chicken', :selected => nil, :content => 'Chicken' )
1011
+ end
1012
+
1013
+ it "should handle arrays for selected when :multiple is true" do
1014
+ r = @c.render :multiple_selects
1015
+ r.should match_tag( :option, :value => 'minutes', :selected => 'selected', :content => 'Time' )
1016
+ r.should match_tag( :option, :value => 'dollars', :selected => 'selected', :content => 'Money' )
1017
+ end
1018
+
1019
+ it "should render a hash of options as optgroup" do
1020
+ r = @c.render :optgroups
1021
+ r.should match_tag( :optgroup, :label => 'Fruit' )
1022
+ r.should match_tag( :optgroup, :label => 'Vegetables' )
1023
+ r.should match_tag( :option, :value => 'banana', :selected => 'selected', :content => 'Banana' )
1024
+ end
1025
+
1026
+ it "should accept an array of strings in :collection as the content/value of each option" do
1027
+ r = @c.render :array
1028
+ r.should match_tag(:option, :content => "one", :value => "one")
1029
+ r.should match_tag(:option, :content => "two", :value => "two")
1030
+ end
1031
+
1032
+ it "should only pass :selected and :value attrs to <option> tags" do
1033
+ r = @c.render :no_extra_attributes
1034
+ r = r.slice(/<option[^>]*>[^<]*<\/option>/)
1035
+ r.should match_tag(:option, :value => "rabbit", :content => "Rabbit")
1036
+ r.should_not match_tag(:option, :id => "my_id", :name => "my_name", :class => "classy")
1037
+ end
1038
+
1039
+ it "should not pollute the <select> attributes with <option> attributes" do
1040
+ r = @c.render :clean
1041
+ r = r.slice(/<select[^>]*>/)
1042
+ r.should_not match_tag(:select, :value => "banana", :selected => "selected")
1043
+ end
1044
+ end
1045
+
1046
+ describe "fieldset" do
1047
+
1048
+ before :each do
1049
+ @c = FieldsetSpecs.new(Merb::Request.new({}))
1050
+ end
1051
+
1052
+ it "should provide legend option" do
1053
+ r = @c.render :legend
1054
+ # res = fieldset :legend => 'TEST' do
1055
+ # _buffer << "CONTENT"
1056
+ # end
1057
+ r.should include("CONTENT")
1058
+ r.should match_tag(:fieldset, {})
1059
+ r.should match_tag(:legend, :content => 'TEST')
1060
+ end
1061
+
1062
+ end
1063
+
1064
+ describe "label" do
1065
+
1066
+ before :each do
1067
+ @c = LabelSpecs.new(Merb::Request.new({}))
1068
+ end
1069
+
1070
+ it "should render a label tag" do
1071
+ r = @c.render :basic
1072
+ #r = label("First Name", :id => "user_first_name")
1073
+ r.should match_tag(:label, :for => "user_first_name", :content => "First Name")
1074
+ end
1075
+ end
1076
+
1077
+ describe "file_field" do
1078
+
1079
+ before :each do
1080
+ @c = FileFieldSpecs.new(Merb::Request.new({}))
1081
+ end
1082
+
1083
+ it "should return a basic file field based on the values passed in" do
1084
+ r = @c.render :with_values
1085
+ #file_field(:name => "foo", :value => "bar")
1086
+ r.should match_tag( :input, :type => "file", :name => "foo", :value => "bar")
1087
+ end
1088
+
1089
+ it "should wrap the field in a label if the :label option is passed to the file" do
1090
+ r = @c.render :with_label
1091
+ r.should match(/<label>LABEL<\/label><input type="file" class="file"\s*\/>/)
1092
+ end
1093
+
1094
+ it "should be disabled if :disabled => true is passed in" do
1095
+ r = @c.render :disabled
1096
+ r.should match_tag(:input, :type => "file", :disabled => "disabled")
1097
+ end
1098
+
1099
+ it "should make the surrounding form multipart" do
1100
+ r = @c.render :makes_multipart
1101
+ r.should match_tag(:form, :enctype => "multipart/form-data")
1102
+ end
1103
+ end
1104
+
1105
+ describe "bound_file_field" do
1106
+
1107
+ before :each do
1108
+ @c = BoundFileFieldSpecs.new(Merb::Request.new({}))
1109
+ @c.instance_variable_set(:@obj, FakeModel.new)
1110
+ end
1111
+
1112
+ it "should take a string object and return a useful file control" do
1113
+ r = @c.render :takes_string
1114
+ r.should match_tag(:input, :type => "file", :name => "fake_model[foo]", :value => "foowee")
1115
+ end
1116
+
1117
+ it "should take additional attributes and use them" do
1118
+ r = @c.render :additional_attributes
1119
+ r.should match_tag(:input, :type => "file", :name => "fake_model[foo]", :value => "foowee", :bar => "7")
1120
+ end
1121
+
1122
+ it "should wrap the file_field in a label if the :label option is passed in" do
1123
+ r = @c.render :with_label
1124
+ # form = form_for @obj do
1125
+ # _buffer << text_field(:foo, :label => "LABEL")
1126
+ # end
1127
+ r.should match(/<label.*>LABEL<\/label><input/)
1128
+ res = r.scan(/<[^>]*>/)
1129
+ res[2].should_not match_tag(:input, :label => "LABEL")
1130
+ end
1131
+ end
1132
+
1133
+ describe "submit" do
1134
+
1135
+ before :each do
1136
+ @c = SubmitSpecs.new(Merb::Request.new({}))
1137
+ end
1138
+
1139
+ it "should return a basic submit input based on the values passed in" do
1140
+ r = @c.render :submit_with_values
1141
+ r.should match_tag(:input, :type => "submit", :name => "foo", :value => "Done")
1142
+ end
1143
+
1144
+ it "should provide an additional label tag if the :label option is passed in" do
1145
+ r = @c.render :submit_with_label
1146
+ r.should match(/<input.*type="submit"/)
1147
+ r.should match(/<input.*name="submit"/)
1148
+ r.should match(/<input.*value="Done"/)
1149
+ r.should match(/<label.*>LABEL<\/label>/)
1150
+ end
1151
+
1152
+ it "should be disabled if :disabled => true is passed in" do
1153
+ r = @c.render :disabled_submit
1154
+ r.should match_tag(:input, :type => "submit", :value => "Done", :disabled => "disabled")
1155
+ end
1156
+ end
1157
+
1158
+ describe "button" do
1159
+
1160
+ before :each do
1161
+ @c = ButtonSpecs.new(Merb::Request.new({}))
1162
+ end
1163
+
1164
+ it "should return a button based on the values passed in" do
1165
+ r = @c.render :button_with_values
1166
+ r.should match_tag(:button, :type => "button", :name => "foo", :value => "bar", :content => "Click Me")
1167
+ end
1168
+
1169
+ it "should provide an additional label tag if the :label option is passed in" do
1170
+ r = @c.render :button_with_label
1171
+ r.should match(/<button.*value="foo"/)
1172
+ r.should match(/<label.*>LABEL<\/label>/)
1173
+ end
1174
+
1175
+ it "should be disabled if :disabled => true is passed in" do
1176
+ r = @c.render :disabled_button
1177
+ r.should match_tag(:button, :disabled => "true")
1178
+ end
1179
+ end
1180
+
1181
+
1182
+ class MyBuilder < Merb::Helpers::Form::Builder::Base
1183
+
1184
+ def update_bound_controls(method, attrs, type)
1185
+ super
1186
+ attrs[:bound] = type
1187
+ end
1188
+
1189
+ def update_unbound_controls(attrs, type)
1190
+ super
1191
+ attrs[:unbound] = type
1192
+ end
1193
+
1194
+ end
1195
+
1196
+ describe "custom builder" do
1197
+
1198
+ before :each do
1199
+ @c = CustomBuilderSpecs.new(Merb::Request.new({}))
1200
+ @c.instance_variable_set(:@obj, FakeModel.new)
1201
+ end
1202
+
1203
+ it "should let you override update_bound_controls" do
1204
+ r = @c.render :everything
1205
+ r.should =~ / bound="file"/
1206
+ r.should =~ / bound="text"/
1207
+ r.should =~ / bound="hidden"/
1208
+ r.should =~ / bound="password"/
1209
+ r.should =~ / bound="radio"/
1210
+ r.should =~ / bound="text_area"/
1211
+ end
1212
+
1213
+ it "should let you override update_unbound_controls" do
1214
+ r = @c.render :everything
1215
+ r.should match_tag(:button, :unbound => "button")
1216
+ r.should match_tag(:input, :unbound => "submit")
1217
+ r.should match_tag(:textarea, :unbound => "text_area")
1218
+ end
1219
+ end
1220
+
1221
+
1222
+ describe 'delete_button' do
1223
+
1224
+ before :each do
1225
+ @controller = DeleteButtonSpecs.new(Merb::Request.new({}))
1226
+ @controller.instance_variable_set(:@obj, FakeModel.new)
1227
+ end
1228
+
1229
+ it "should have a default submit button text" do
1230
+ result = @controller.render :simple_delete # <%= delete_button @obj %>
1231
+ result.should match(/<input type=\"submit\">Delete<\/input>/)
1232
+ end
1233
+
1234
+ it 'should return a button inside of a form for the object' do
1235
+ result = @controller.render :simple_delete # <%= delete_button @obj %>
1236
+ result.should match_tag(:form, :action => "/fake_models/fake_model", :method => "post")
1237
+ result.should match_tag(:input, :type => "hidden", :value => "DELETE", :name => "_method")
1238
+ end
1239
+
1240
+ it 'should allow you to modify the label' do
1241
+ result = @controller.render :delete_with_label # <%= delete_button(@obj, "Delete moi!") %>
1242
+ result.should match(/<input type=\"submit\">Delete moi!<\/input>/)
1243
+ end
1244
+
1245
+ it "should allow you to pass some extra params like a class" do
1246
+ result = @controller.render :delete_with_extra_params
1247
+ result.should match(/<input type=\"submit\" class=\"custom-class\">Delete<\/input>/)
1248
+ end
1249
+
1250
+ it "should allow to pass an explicit url as a string" do
1251
+ result = @controller.render :delete_with_explicit_url # <%= delete_button('/test/custom_url') %>
1252
+ result.should match_tag(:form, :action => "/test/custom_url", :method => "post")
1253
+ end
1254
+
1255
+ end
1256
+
1257
+ # describe "control_value" do
1258
+ #
1259
+ #
1260
+ # it 'should escape [&"<>]' do
1261
+ # @obj.vin = '&"<>'
1262
+ # f = form_for :obj do
1263
+ # control_value(:vin).should == '&amp;&quot;&lt;&gt;'
1264
+ # end
1265
+ # end
1266
+ # end