tmayad-formtastic 0.9.7
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.
- data/MIT-LICENSE +20 -0
- data/README.textile +517 -0
- data/Rakefile +101 -0
- data/generators/form/USAGE +16 -0
- data/generators/form/form_generator.rb +120 -0
- data/generators/form/templates/view__form.html.erb +5 -0
- data/generators/form/templates/view__form.html.haml +4 -0
- data/generators/formtastic/formtastic_generator.rb +24 -0
- data/generators/formtastic/templates/formtastic.css +138 -0
- data/generators/formtastic/templates/formtastic.rb +54 -0
- data/generators/formtastic/templates/formtastic_changes.css +10 -0
- data/generators/formtastic_stylesheets/formtastic_stylesheets_generator.rb +16 -0
- data/lib/formtastic.rb +1643 -0
- data/lib/formtastic/i18n.rb +32 -0
- data/lib/locale/en.yml +8 -0
- data/rails/init.rb +3 -0
- data/spec/buttons_spec.rb +149 -0
- data/spec/commit_button_spec.rb +344 -0
- data/spec/custom_builder_spec.rb +62 -0
- data/spec/custom_macros.rb +561 -0
- data/spec/defaults_spec.rb +20 -0
- data/spec/error_proc_spec.rb +27 -0
- data/spec/errors_spec.rb +85 -0
- data/spec/form_helper_spec.rb +120 -0
- data/spec/i18n_spec.rb +131 -0
- data/spec/include_blank_spec.rb +70 -0
- data/spec/input_spec.rb +608 -0
- data/spec/inputs/boolean_input_spec.rb +93 -0
- data/spec/inputs/check_boxes_input_spec.rb +162 -0
- data/spec/inputs/country_input_spec.rb +80 -0
- data/spec/inputs/date_input_spec.rb +45 -0
- data/spec/inputs/datetime_input_spec.rb +155 -0
- data/spec/inputs/file_input_spec.rb +33 -0
- data/spec/inputs/hidden_input_spec.rb +52 -0
- data/spec/inputs/numeric_input_spec.rb +44 -0
- data/spec/inputs/password_input_spec.rb +46 -0
- data/spec/inputs/radio_input_spec.rb +149 -0
- data/spec/inputs/select_input_spec.rb +459 -0
- data/spec/inputs/string_input_spec.rb +47 -0
- data/spec/inputs/text_input_spec.rb +33 -0
- data/spec/inputs/time_input_spec.rb +44 -0
- data/spec/inputs/time_zone_input_spec.rb +102 -0
- data/spec/inputs_spec.rb +395 -0
- data/spec/label_spec.rb +48 -0
- data/spec/semantic_fields_for_spec.rb +44 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +212 -0
- metadata +169 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
describe 'file input' do
|
5
|
+
|
6
|
+
include FormtasticSpecHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@output_buffer = ''
|
10
|
+
mock_everything
|
11
|
+
|
12
|
+
semantic_form_for(@new_post) do |builder|
|
13
|
+
concat(builder.input(:body, :as => :file))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it_should_have_input_wrapper_with_class("file")
|
18
|
+
it_should_have_input_wrapper_with_id("post_body_input")
|
19
|
+
it_should_have_label_with_text(/Body/)
|
20
|
+
it_should_have_label_for("post_body")
|
21
|
+
it_should_have_input_with_id("post_body")
|
22
|
+
it_should_have_input_with_name("post[body]")
|
23
|
+
it_should_apply_error_logic_for_input_type(:file)
|
24
|
+
|
25
|
+
it 'should use input_html to style inputs' do
|
26
|
+
semantic_form_for(@new_post) do |builder|
|
27
|
+
concat(builder.input(:title, :as => :file, :input_html => { :class => 'myclass' }))
|
28
|
+
end
|
29
|
+
output_buffer.should have_tag("form li input.myclass")
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
describe 'hidden input' do
|
5
|
+
|
6
|
+
include FormtasticSpecHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@output_buffer = ''
|
10
|
+
mock_everything
|
11
|
+
|
12
|
+
semantic_form_for(@new_post) do |builder|
|
13
|
+
concat(builder.input(:secret, :as => :hidden))
|
14
|
+
concat(builder.input(:author_id, :as => :hidden, :value => 99))
|
15
|
+
concat(builder.input(:published, :as => :hidden, :input_html => {:value => true}))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it_should_have_input_wrapper_with_class("hidden")
|
20
|
+
it_should_have_input_wrapper_with_id("post_secret_input")
|
21
|
+
it_should_not_have_a_label
|
22
|
+
|
23
|
+
it "should generate a input field" do
|
24
|
+
output_buffer.should have_tag("form li input#post_secret")
|
25
|
+
output_buffer.should have_tag("form li input#post_secret[@type=\"hidden\"]")
|
26
|
+
output_buffer.should have_tag("form li input#post_secret[@name=\"post[secret]\"]")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should pass any explicitly specified value - using :value" do
|
30
|
+
output_buffer.should have_tag("form li input#post_author_id[@type=\"hidden\"][@value=\"99\"]")
|
31
|
+
end
|
32
|
+
|
33
|
+
# Handle Formtastic :input_html options for consistency.
|
34
|
+
it "should pass any explicitly specified value - using :input_html options" do
|
35
|
+
output_buffer.should have_tag("form li input#post_published[@type=\"hidden\"][@value=\"true\"]")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not render inline errors" do
|
39
|
+
@errors = mock('errors')
|
40
|
+
@errors.stub!(:[]).with(:secret).and_return(["foo", "bah"])
|
41
|
+
@new_post.stub!(:errors).and_return(@errors)
|
42
|
+
|
43
|
+
semantic_form_for(@new_post) do |builder|
|
44
|
+
concat(builder.input(:secret, :as => :hidden))
|
45
|
+
end
|
46
|
+
|
47
|
+
output_buffer.should_not have_tag("form li p.inline-errors")
|
48
|
+
output_buffer.should_not have_tag("form li ul.errors")
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
describe 'numeric input' do
|
5
|
+
|
6
|
+
include FormtasticSpecHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@output_buffer = ''
|
10
|
+
mock_everything
|
11
|
+
|
12
|
+
semantic_form_for(@new_post) do |builder|
|
13
|
+
concat(builder.input(:title, :as => :numeric))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it_should_have_input_wrapper_with_class(:numeric)
|
18
|
+
it_should_have_input_wrapper_with_id("post_title_input")
|
19
|
+
it_should_have_label_with_text(/Title/)
|
20
|
+
it_should_have_label_for("post_title")
|
21
|
+
it_should_have_input_with_id("post_title")
|
22
|
+
it_should_have_input_with_type(:text)
|
23
|
+
it_should_have_input_with_name("post[title]")
|
24
|
+
it_should_use_default_text_field_size_when_method_has_no_database_column(:string)
|
25
|
+
it_should_apply_custom_input_attributes_when_input_html_provided(:string)
|
26
|
+
it_should_apply_custom_for_to_label_when_input_html_id_provided(:string)
|
27
|
+
it_should_apply_error_logic_for_input_type(:numeric)
|
28
|
+
|
29
|
+
describe "when no object is provided" do
|
30
|
+
before do
|
31
|
+
semantic_form_for(:project, :url => 'http://test.host/') do |builder|
|
32
|
+
concat(builder.input(:title, :as => :numeric))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it_should_have_label_with_text(/Title/)
|
37
|
+
it_should_have_label_for("project_title")
|
38
|
+
it_should_have_input_with_id("project_title")
|
39
|
+
it_should_have_input_with_type(:text)
|
40
|
+
it_should_have_input_with_name("project[title]")
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
describe 'password input' do
|
5
|
+
|
6
|
+
include FormtasticSpecHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@output_buffer = ''
|
10
|
+
mock_everything
|
11
|
+
|
12
|
+
semantic_form_for(@new_post) do |builder|
|
13
|
+
concat(builder.input(:title, :as => :password))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it_should_have_input_wrapper_with_class(:password)
|
18
|
+
it_should_have_input_wrapper_with_id("post_title_input")
|
19
|
+
it_should_have_label_with_text(/Title/)
|
20
|
+
it_should_have_label_for("post_title")
|
21
|
+
it_should_have_input_with_id("post_title")
|
22
|
+
it_should_have_input_with_type(:password)
|
23
|
+
it_should_have_input_with_name("post[title]")
|
24
|
+
it_should_have_maxlength_matching_column_limit
|
25
|
+
it_should_use_default_text_field_size_for_columns_longer_than_default_text_field_size(:string)
|
26
|
+
it_should_use_column_size_for_columns_shorter_than_default_text_field_size(:string)
|
27
|
+
it_should_use_default_text_field_size_when_method_has_no_database_column(:string)
|
28
|
+
it_should_apply_custom_input_attributes_when_input_html_provided(:string)
|
29
|
+
it_should_apply_custom_for_to_label_when_input_html_id_provided(:string)
|
30
|
+
it_should_apply_error_logic_for_input_type(:password)
|
31
|
+
|
32
|
+
describe "when no object is provided" do
|
33
|
+
before do
|
34
|
+
semantic_form_for(:project, :url => 'http://test.host/') do |builder|
|
35
|
+
concat(builder.input(:title, :as => :password))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it_should_have_label_with_text(/Title/)
|
40
|
+
it_should_have_label_for("project_title")
|
41
|
+
it_should_have_input_with_id("project_title")
|
42
|
+
it_should_have_input_with_type(:password)
|
43
|
+
it_should_have_input_with_name("project[title]")
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
describe 'radio input' do
|
5
|
+
|
6
|
+
include FormtasticSpecHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@output_buffer = ''
|
10
|
+
mock_everything
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'for belongs_to association' do
|
14
|
+
before do
|
15
|
+
semantic_form_for(@new_post) do |builder|
|
16
|
+
concat(builder.input(:author, :as => :radio, :value_as_class => true))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it_should_have_input_wrapper_with_class("radio")
|
21
|
+
it_should_have_input_wrapper_with_id("post_author_input")
|
22
|
+
it_should_have_a_nested_fieldset
|
23
|
+
it_should_apply_error_logic_for_input_type(:radio)
|
24
|
+
it_should_use_the_collection_when_provided(:radio, 'input')
|
25
|
+
|
26
|
+
|
27
|
+
it 'should generate a legend - classified as a label - containing label text for the input' do
|
28
|
+
output_buffer.should have_tag('form li fieldset legend.label')
|
29
|
+
output_buffer.should have_tag('form li fieldset legend.label', /Author/)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should generate an ordered list with a list item for each choice' do
|
33
|
+
output_buffer.should have_tag('form li fieldset ol')
|
34
|
+
output_buffer.should have_tag('form li fieldset ol li', :count => ::Author.find(:all).size)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should have one option with a "checked" attribute' do
|
38
|
+
output_buffer.should have_tag('form li input[@checked]', :count => 1)
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "each choice" do
|
42
|
+
|
43
|
+
it 'should contain a label for the radio input with a nested input and label text' do
|
44
|
+
::Author.find(:all).each do |author|
|
45
|
+
output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
|
46
|
+
output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_id_#{author.id}']")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should use values as li.class when value_as_class is true' do
|
51
|
+
::Author.find(:all).each do |author|
|
52
|
+
output_buffer.should have_tag("form li fieldset ol li.author_#{author.id} label")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should have a radio input" do
|
57
|
+
::Author.find(:all).each do |author|
|
58
|
+
output_buffer.should have_tag("form li fieldset ol li label input#post_author_id_#{author.id}")
|
59
|
+
output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
|
60
|
+
output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
|
61
|
+
output_buffer.should have_tag("form li fieldset ol li label input[@name='post[author_id]']")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should mark input as checked if it's the the existing choice" do
|
66
|
+
@new_post.author_id.should == @bob.id
|
67
|
+
@new_post.author.id.should == @bob.id
|
68
|
+
@new_post.author.should == @bob
|
69
|
+
|
70
|
+
semantic_form_for(@new_post) do |builder|
|
71
|
+
concat(builder.input(:author, :as => :radio))
|
72
|
+
end
|
73
|
+
|
74
|
+
output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'and no object is given' do
|
79
|
+
before(:each) do
|
80
|
+
output_buffer.replace ''
|
81
|
+
semantic_form_for(:project, :url => 'http://test.host') do |builder|
|
82
|
+
concat(builder.input(:author_id, :as => :radio, :collection => ::Author.find(:all)))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should generate a fieldset with legend' do
|
87
|
+
output_buffer.should have_tag('form li fieldset legend', /Author/)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should generate an li tag for each item in the collection' do
|
91
|
+
output_buffer.should have_tag('form li fieldset ol li', :count => ::Author.find(:all).size)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should generate labels for each item' do
|
95
|
+
::Author.find(:all).each do |author|
|
96
|
+
output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
|
97
|
+
output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should generate inputs for each item' do
|
102
|
+
::Author.find(:all).each do |author|
|
103
|
+
output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
|
104
|
+
output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
|
105
|
+
output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
|
106
|
+
output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id]']")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe 'when :selected is set' do
|
113
|
+
before do
|
114
|
+
@output_buffer = ''
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "no selected items" do
|
118
|
+
before do
|
119
|
+
@new_post.stub!(:author_ids).and_return(nil)
|
120
|
+
|
121
|
+
semantic_form_for(@new_post) do |builder|
|
122
|
+
concat(builder.input(:authors, :as => :radio, :selected => nil))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should not have any selected item(s)' do
|
127
|
+
output_buffer.should_not have_tag("form li fieldset ol li label input[@checked='checked']")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "single selected item" do
|
132
|
+
before do
|
133
|
+
@new_post.stub!(:author_ids).and_return(nil)
|
134
|
+
|
135
|
+
semantic_form_for(@new_post) do |builder|
|
136
|
+
concat(builder.input(:authors, :as => :radio, :selected => @fred.id))
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should have one item selected; the specified one" do
|
141
|
+
output_buffer.should have_tag("form li fieldset ol li label input[@type='radio'][@checked='checked']", :count => 1)
|
142
|
+
output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_ids_#{@fred.id}']", /fred/i)
|
143
|
+
output_buffer.should have_tag("form li fieldset ol li label input[@type='radio'][@checked='checked'][@value='#{@fred.id}']")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
@@ -0,0 +1,459 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
describe 'select input' do
|
5
|
+
|
6
|
+
include FormtasticSpecHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@output_buffer = ''
|
10
|
+
mock_everything
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'explicit values' do
|
14
|
+
describe 'using an array of values' do
|
15
|
+
before do
|
16
|
+
@array_with_values = ["Title A", "Title B", "Title C"]
|
17
|
+
@array_with_keys_and_values = [["Title D", 1], ["Title E", 2], ["Title F", 3]]
|
18
|
+
semantic_form_for(@new_post) do |builder|
|
19
|
+
concat(builder.input(:title, :as => :select, :collection => @array_with_values))
|
20
|
+
concat(builder.input(:title, :as => :select, :collection => @array_with_keys_and_values))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should have a option for each key and/or value' do
|
25
|
+
@array_with_values.each do |v|
|
26
|
+
output_buffer.should have_tag("form li select option[@value='#{v}']", /^#{v}$/)
|
27
|
+
end
|
28
|
+
@array_with_keys_and_values.each do |v|
|
29
|
+
output_buffer.should have_tag("form li select option[@value='#{v.second}']", /^#{v.first}$/)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'using a range' do
|
35
|
+
before do
|
36
|
+
@range_with_values = 1..5
|
37
|
+
semantic_form_for(@new_post) do |builder|
|
38
|
+
concat(builder.input(:title, :as => :select, :collection => @range_with_values))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should have an option for each value' do
|
43
|
+
@range_with_values.each do |v|
|
44
|
+
output_buffer.should have_tag("form li select option[@value='#{v}']", /^#{v}$/)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'for a belongs_to association' do
|
51
|
+
before do
|
52
|
+
semantic_form_for(@new_post) do |builder|
|
53
|
+
concat(builder.input(:author, :as => :select))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it_should_have_input_wrapper_with_class("select")
|
58
|
+
it_should_have_input_wrapper_with_id("post_author_input")
|
59
|
+
it_should_have_label_with_text(/Author/)
|
60
|
+
it_should_have_label_for('post_author_id')
|
61
|
+
it_should_apply_error_logic_for_input_type(:select)
|
62
|
+
it_should_call_find_on_association_class_when_no_collection_is_provided(:select)
|
63
|
+
it_should_use_the_collection_when_provided(:select, 'option')
|
64
|
+
|
65
|
+
it 'should have a select inside the wrapper' do
|
66
|
+
output_buffer.should have_tag('form li select')
|
67
|
+
output_buffer.should have_tag('form li select#post_author_id')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should have a valid name' do
|
71
|
+
output_buffer.should have_tag("form li select[@name='post[author_id]']")
|
72
|
+
output_buffer.should_not have_tag("form li select[@name='post[author_id][]']")
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should not create a multi-select' do
|
76
|
+
output_buffer.should_not have_tag('form li select[@multiple]')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should create a select without size' do
|
80
|
+
output_buffer.should_not have_tag('form li select[@size]')
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should have a blank option' do
|
84
|
+
output_buffer.should have_tag("form li select option[@value='']")
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should have a select option for each Author' do
|
88
|
+
output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size + 1)
|
89
|
+
::Author.find(:all).each do |author|
|
90
|
+
output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should have one option with a "selected" attribute' do
|
95
|
+
output_buffer.should have_tag('form li select option[@selected]', :count => 1)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should not singularize the association name' do
|
99
|
+
@new_post.stub!(:author_status).and_return(@bob)
|
100
|
+
@new_post.stub!(:author_status_id).and_return(@bob.id)
|
101
|
+
@new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
|
102
|
+
|
103
|
+
semantic_form_for(@new_post) do |builder|
|
104
|
+
concat(builder.input(:author_status, :as => :select))
|
105
|
+
end
|
106
|
+
|
107
|
+
output_buffer.should have_tag('form li select#post_author_status_id')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "for a belongs_to association with :group_by => :author" do
|
112
|
+
it "should call author.posts" do
|
113
|
+
[@freds_post].each { |post| post.stub!(:to_label).and_return("Post - #{post.id}") }
|
114
|
+
@fred.should_receive(:posts)
|
115
|
+
|
116
|
+
semantic_form_for(@new_post) do |builder|
|
117
|
+
concat(builder.input(:main_post, :as => :select, :group_by => :author ) )
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe 'for a belongs_to association with :group_by => :continent' do
|
123
|
+
before do
|
124
|
+
@authors = [@bob, @fred, @fred, @fred]
|
125
|
+
::Author.stub!(:find).and_return(@authors)
|
126
|
+
@continent_names = %w(Europe Africa)
|
127
|
+
@continents = (0..1).map { |i| c = ::Continent.new; c.stub!(:id).and_return(100 - i);c }
|
128
|
+
@authors[0..1].each_with_index { |author, i| author.stub!(:continent).and_return(@continents[i]) }
|
129
|
+
::Continent.stub!(:reflect_on_all_associations).and_return {|macro| mock('reflection', :klass => Author) if macro == :has_many}
|
130
|
+
::Continent.stub!(:reflect_on_association).and_return {|column_name| mock('reflection', :klass => Author) if column_name == :authors}
|
131
|
+
::Author.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => Continent, :macro => :belongs_to) if column_name == :continent }
|
132
|
+
|
133
|
+
|
134
|
+
@continents.each_with_index do |continent, i|
|
135
|
+
continent.stub!(:to_label).and_return(@continent_names[i])
|
136
|
+
continent.stub!(:authors).and_return([@authors[i]])
|
137
|
+
end
|
138
|
+
|
139
|
+
semantic_form_for(@new_post) do |builder|
|
140
|
+
concat(builder.input(:author, :as => :select, :group_by => :continent ) )
|
141
|
+
concat(builder.input(:author, :as => :select, :group_by => :continent, :group_label_method => :id ) )
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it_should_have_input_wrapper_with_class("select")
|
146
|
+
it_should_have_input_wrapper_with_id("post_author_input")
|
147
|
+
it_should_have_label_with_text(/Author/)
|
148
|
+
it_should_have_label_for('post_author_id')
|
149
|
+
|
150
|
+
# TODO, need to find a way to repeat some of the specs and logic from the belongs_to specs without grouping
|
151
|
+
|
152
|
+
0.upto(1) do |i|
|
153
|
+
it 'should have all option groups and the right values' do
|
154
|
+
output_buffer.should have_tag("form li select optgroup[@label='#{@continent_names[i]}']", @authors[i].to_label)
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should have custom group labels' do
|
158
|
+
output_buffer.should have_tag("form li select optgroup[@label='#{@continents[i].id}']", @authors[i].to_label)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should have no duplicate groups' do
|
163
|
+
output_buffer.should have_tag('form li select optgroup', :count => 4)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should sort the groups on the label method' do
|
167
|
+
output_buffer.should have_tag("form li select optgroup[@label='Africa']")
|
168
|
+
output_buffer.should have_tag("form li select optgroup[@label='99']")
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should call find with :include for more optimized queries' do
|
172
|
+
Author.should_receive(:find).with(:all, :include => :continent)
|
173
|
+
|
174
|
+
semantic_form_for(@new_post) do |builder|
|
175
|
+
concat(builder.input(:author, :as => :select, :group_by => :continent ) )
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe 'for a has_many association' do
|
181
|
+
before do
|
182
|
+
semantic_form_for(@fred) do |builder|
|
183
|
+
concat(builder.input(:posts, :as => :select))
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
it_should_have_input_wrapper_with_class("select")
|
188
|
+
it_should_have_input_wrapper_with_id("author_posts_input")
|
189
|
+
it_should_have_label_with_text(/Post/)
|
190
|
+
it_should_have_label_for('author_post_ids')
|
191
|
+
it_should_apply_error_logic_for_input_type(:select)
|
192
|
+
it_should_call_find_on_association_class_when_no_collection_is_provided(:select)
|
193
|
+
it_should_use_the_collection_when_provided(:select, 'option')
|
194
|
+
|
195
|
+
it 'should have a select inside the wrapper' do
|
196
|
+
output_buffer.should have_tag('form li select')
|
197
|
+
output_buffer.should have_tag('form li select#author_post_ids')
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'should have a multi-select select' do
|
201
|
+
output_buffer.should have_tag('form li select[@multiple="multiple"]')
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'should have a select option for each Post' do
|
205
|
+
output_buffer.should have_tag('form li select option', :count => ::Post.find(:all).size)
|
206
|
+
::Post.find(:all).each do |post|
|
207
|
+
output_buffer.should have_tag("form li select option[@value='#{post.id}']", /#{post.to_label}/)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should not have a blank option' do
|
212
|
+
output_buffer.should_not have_tag("form li select option[@value='']")
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'should have one option with a "selected" attribute' do
|
216
|
+
output_buffer.should have_tag('form li select option[@selected]', :count => 1)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe 'for a has_and_belongs_to_many association' do
|
221
|
+
before do
|
222
|
+
semantic_form_for(@freds_post) do |builder|
|
223
|
+
concat(builder.input(:authors, :as => :select))
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
it_should_have_input_wrapper_with_class("select")
|
228
|
+
it_should_have_input_wrapper_with_id("post_authors_input")
|
229
|
+
it_should_have_label_with_text(/Author/)
|
230
|
+
it_should_have_label_for('post_author_ids')
|
231
|
+
it_should_apply_error_logic_for_input_type(:select)
|
232
|
+
it_should_call_find_on_association_class_when_no_collection_is_provided(:select)
|
233
|
+
it_should_use_the_collection_when_provided(:select, 'option')
|
234
|
+
|
235
|
+
it 'should have a select inside the wrapper' do
|
236
|
+
output_buffer.should have_tag('form li select')
|
237
|
+
output_buffer.should have_tag('form li select#post_author_ids')
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should have a multi-select select' do
|
241
|
+
output_buffer.should have_tag('form li select[@multiple="multiple"]')
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should have a select option for each Author' do
|
245
|
+
output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size)
|
246
|
+
::Author.find(:all).each do |author|
|
247
|
+
output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should not have a blank option' do
|
252
|
+
output_buffer.should_not have_tag("form li select option[@value='']")
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'should have one option with a "selected" attribute' do
|
256
|
+
output_buffer.should have_tag('form li select option[@selected]', :count => 1)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe 'when :prompt => "choose something" is set' do
|
261
|
+
before do
|
262
|
+
@new_post.stub!(:author_id).and_return(nil)
|
263
|
+
semantic_form_for(@new_post) do |builder|
|
264
|
+
concat(builder.input(:author, :as => :select, :prompt => "choose author"))
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'should have a select with prompt' do
|
269
|
+
output_buffer.should have_tag("form li select option[@value='']", /choose author/)
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'should not have a blank select option' do
|
273
|
+
output_buffer.should_not have_tag("form li select option[@value='']", "")
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
describe 'when no object is given' do
|
278
|
+
before(:each) do
|
279
|
+
semantic_form_for(:project, :url => 'http://test.host') do |builder|
|
280
|
+
concat(builder.input(:author, :as => :select, :collection => ::Author.find(:all)))
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'should generate label' do
|
285
|
+
output_buffer.should have_tag('form li label', /Author/)
|
286
|
+
output_buffer.should have_tag("form li label[@for='project_author']")
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'should generate select inputs' do
|
290
|
+
output_buffer.should have_tag('form li select#project_author')
|
291
|
+
output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size + 1)
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'should generate an option to each item' do
|
295
|
+
::Author.find(:all).each do |author|
|
296
|
+
output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
describe 'when :selected is set' do
|
302
|
+
before do
|
303
|
+
@output_buffer = ''
|
304
|
+
end
|
305
|
+
|
306
|
+
describe "no selected items" do
|
307
|
+
before do
|
308
|
+
@new_post.stub!(:author_id).and_return(nil)
|
309
|
+
semantic_form_for(@new_post) do |builder|
|
310
|
+
concat(builder.input(:author, :as => :select, :selected => nil))
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'should not have any selected item(s)' do
|
315
|
+
output_buffer.should_not have_tag("form li select option[@selected='selected']")
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
describe "single selected item" do
|
320
|
+
before do
|
321
|
+
@new_post.stub!(:author_id).and_return(nil)
|
322
|
+
semantic_form_for(@new_post) do |builder|
|
323
|
+
concat(builder.input(:author, :as => :select, :selected => @bob.id))
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'should have a selected item; the specified one' do
|
328
|
+
output_buffer.should have_tag("form li select option[@selected='selected']", :count => 1)
|
329
|
+
output_buffer.should have_tag("form li select option[@selected='selected']", /bob/i)
|
330
|
+
output_buffer.should have_tag("form li select option[@selected='selected'][@value='#{@bob.id}']")
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
describe "multiple selected items" do
|
335
|
+
|
336
|
+
describe "when :multiple => false" do
|
337
|
+
before do
|
338
|
+
@new_post.stub!(:author_ids).and_return(nil)
|
339
|
+
|
340
|
+
semantic_form_for(@new_post) do |builder|
|
341
|
+
concat(builder.input(:authors, :as => :select, :selected => [@bob.id, @fred.id], :multiple => false))
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
it "should only select the first value" do
|
346
|
+
output_buffer.should have_tag("form li select option[@selected='selected']", :count => 1)
|
347
|
+
# FIXME: Not supported by Nokogiri.
|
348
|
+
# output_buffer.should have_tag("form li select:not([@multiple]) option[@selected='selected']", /bob/i)
|
349
|
+
# output_buffer.should have_tag("form li select:not([@multiple]) option[@selected='selected'][@value='#{@bob.id}']")
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
describe "when :multiple => true" do
|
354
|
+
before do
|
355
|
+
@new_post.stub!(:author_ids).and_return(nil)
|
356
|
+
|
357
|
+
semantic_form_for(@new_post) do |builder|
|
358
|
+
concat(builder.input(:authors, :as => :select, :selected => [@bob.id, @fred.id]))
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should have multiple items selected; the specified ones" do
|
363
|
+
output_buffer.should have_tag("form li select option[@selected='selected']", :count => 2)
|
364
|
+
output_buffer.should have_tag("form li select[@multiple] option[@selected='selected']", /bob/i)
|
365
|
+
output_buffer.should have_tag("form li select[@multiple] option[@selected='selected'][@value='#{@bob.id}']")
|
366
|
+
output_buffer.should have_tag("form li select[@multiple] option[@selected='selected']", /fred/i)
|
367
|
+
output_buffer.should have_tag("form li select[@multiple] option[@selected='selected'][@value='#{@fred.id}']")
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
end
|
374
|
+
|
375
|
+
describe 'boolean select' do
|
376
|
+
describe 'default formtastic locale' do
|
377
|
+
before do
|
378
|
+
# Note: Works, but something like Formtastic.root.join(...) would probably be "safer".
|
379
|
+
::I18n.load_path = [File.join(File.dirname(__FILE__), *%w[.. .. lib locale en.yml])]
|
380
|
+
::I18n.backend.send(:init_translations)
|
381
|
+
|
382
|
+
semantic_form_for(@new_post) do |builder|
|
383
|
+
concat(builder.input(:published, :as => :select))
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
after do
|
388
|
+
::I18n.backend.store_translations :en, {}
|
389
|
+
end
|
390
|
+
|
391
|
+
it 'should render a select with at least options: true/false' do
|
392
|
+
output_buffer.should have_tag("form li select option[@value='true']", /^Yes$/)
|
393
|
+
output_buffer.should have_tag("form li select option[@value='false']", /^No$/)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
describe 'custom locale' do
|
398
|
+
before do
|
399
|
+
@boolean_select_labels = {:yes => 'Yep', :no => 'Nope'}
|
400
|
+
::I18n.backend.store_translations :en, :formtastic => @boolean_select_labels
|
401
|
+
|
402
|
+
semantic_form_for(@new_post) do |builder|
|
403
|
+
concat(builder.input(:published, :as => :select))
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
after do
|
408
|
+
::I18n.backend.store_translations :en, {}
|
409
|
+
end
|
410
|
+
|
411
|
+
it 'should render a select with at least options: true/false' do
|
412
|
+
output_buffer.should have_tag("form li select option[@value='true']", /#{@boolean_select_labels[:yes]}/)
|
413
|
+
output_buffer.should have_tag("form li select option[@value='false']", /#{@boolean_select_labels[:no]}/)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
describe "enums" do
|
419
|
+
describe ":collection is set" do
|
420
|
+
before do
|
421
|
+
@output_buffer = ''
|
422
|
+
@some_meta_descriptions = ["One", "Two", "Three"]
|
423
|
+
@new_post.stub!(:meta_description).any_number_of_times
|
424
|
+
end
|
425
|
+
|
426
|
+
describe ":as is not set" do
|
427
|
+
before do
|
428
|
+
semantic_form_for(@new_post) do |builder|
|
429
|
+
concat(builder.input(:meta_description, :collection => @some_meta_descriptions))
|
430
|
+
end
|
431
|
+
semantic_form_for(:project, :url => 'http://test.host') do |builder|
|
432
|
+
concat(builder.input(:meta_description, :collection => @some_meta_descriptions))
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
it "should render a select field" do
|
437
|
+
output_buffer.should have_tag("form li select", :count => 2)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
describe ":as is set" do
|
442
|
+
before do
|
443
|
+
# Should not be a case, but just checking :as got highest priority in setting input type.
|
444
|
+
semantic_form_for(@new_post) do |builder|
|
445
|
+
concat(builder.input(:meta_description, :as => :string, :collection => @some_meta_descriptions))
|
446
|
+
end
|
447
|
+
semantic_form_for(:project, :url => 'http://test.host') do |builder|
|
448
|
+
concat(builder.input(:meta_description, :as => :string, :collection => @some_meta_descriptions))
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
it "should render a text field" do
|
453
|
+
output_buffer.should have_tag("form li input[@type='text']", :count => 2)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
end
|