# encoding: UTF-8 require 'test_helper' class FormBuilderTest < ActionView::TestCase def with_custom_form_for(object, *args, &block) with_concat_custom_form_for(object) do |f| f.input(*args, &block) end end test 'nested simple fields should yield an instance of FormBuilder' do simple_form_for :user do |f| f.simple_fields_for :posts do |posts_form| assert posts_form.instance_of?(SimpleForm::FormBuilder) end end end test 'builder input is html safe' do simple_form_for @user do |f| assert f.input(:name).html_safe? end end test 'builder input should allow a block to configure input' do with_form_for @user, :name do text_field_tag :foo, :bar, :id => :cool end assert_no_select 'input.string' assert_select 'input#cool' end test 'builder should allow adding custom input mappings for default input types' do swap SimpleForm, :input_mappings => { /count$/ => :integer } do with_form_for @user, :post_count assert_no_select 'form input#user_post_count.string' assert_select 'form input#user_post_count.numeric.integer' end end test 'builder should allow to skip input_type class' do swap SimpleForm, :generate_additional_classes_for => [:label, :wrapper] do with_form_for @user, :post_count assert_no_select "form input#user_post_count.integer" assert_select "form input#user_post_count" end end test 'builder should allow to add additional classes only for wrapper' do swap SimpleForm, :generate_additional_classes_for => [:wrapper] do with_form_for @user, :post_count assert_no_select "form input#user_post_count.string" assert_no_select "form label#user_post_count.string" assert_select "form div.input.string" end end test 'builder should allow adding custom input mappings for integer input types' do swap SimpleForm, :input_mappings => { /lock_version/ => :hidden } do with_form_for @user, :lock_version assert_no_select 'form input#user_lock_version.integer' assert_select 'form input#user_lock_version.hidden' end end test 'builder uses the first matching custom input map when more than one matches' do swap SimpleForm, :input_mappings => { /count$/ => :integer, /^post_/ => :password } do with_form_for @user, :post_count assert_no_select 'form input#user_post_count.password' assert_select 'form input#user_post_count.numeric.integer' end end test 'builder uses the custom map only for matched attributes' do swap SimpleForm, :input_mappings => { /lock_version/ => :hidden } do with_form_for @user, :post_count assert_no_select 'form input#user_post_count.hidden' assert_select 'form input#user_post_count.string' end end # INPUT TYPES test 'builder should generate text fields for string columns' do with_form_for @user, :name assert_select 'form input#user_name.string' end test 'builder should generate text areas for text columns' do with_form_for @user, :description assert_select 'form textarea#user_description.text' end test 'builder should generate a checkbox for boolean columns' do with_form_for @user, :active assert_select 'form input[type=checkbox]#user_active.boolean' end test 'builder should use integer text field for integer columns' do with_form_for @user, :age assert_select 'form input#user_age.numeric.integer' end test 'builder should generate decimal text field for decimal columns' do with_form_for @user, :credit_limit assert_select 'form input#user_credit_limit.numeric.decimal' end test 'builder should generate password fields for columns that matches password' do with_form_for @user, :password assert_select 'form input#user_password.password' end test 'builder should generate country fields for columns that matches country' do with_form_for @user, :residence_country assert_select 'form select#user_residence_country.country' end test 'builder should generate time_zone fields for columns that matches time_zone' do with_form_for @user, :time_zone assert_select 'form select#user_time_zone.time_zone' end test 'builder should generate email fields for columns that matches email' do with_form_for @user, :email assert_select 'form input#user_email.string.email' end test 'builder should generate tel fields for columns that matches phone' do with_form_for @user, :phone_number assert_select 'form input#user_phone_number.string.tel' end test 'builder should generate url fields for columns that matches url' do with_form_for @user, :url assert_select 'form input#user_url.string.url' end test 'builder should generate date select for date columns' do with_form_for @user, :born_at assert_select 'form select#user_born_at_1i.date' end test 'builder should generate time select for time columns' do with_form_for @user, :delivery_time assert_select 'form select#user_delivery_time_4i.time' end test 'builder should generate datetime select for datetime columns' do with_form_for @user, :created_at assert_select 'form select#user_created_at_1i.datetime' end test 'builder should generate datetime select for timestamp columns' do with_form_for @user, :updated_at assert_select 'form select#user_updated_at_1i.datetime' end test 'builder should generate file for file columns' do @user.avatar = mock("file") @user.avatar.expects(:respond_to?).with(:mounted_as).returns(false) @user.avatar.expects(:respond_to?).with(:file?).returns(false) @user.avatar.expects(:respond_to?).with(:public_filename).returns(true) with_form_for @user, :avatar assert_select 'form input#user_avatar.file' end test 'builder should generate file for attributes that are real db columns but have file methods' do @user.home_picture = mock("file") @user.home_picture.expects(:respond_to?).with(:mounted_as).returns(true) with_form_for @user, :home_picture assert_select 'form input#user_home_picture.file' end test 'build should generate select if a collection is given' do with_form_for @user, :age, :collection => 1..60 assert_select 'form select#user_age.select' end test 'builder should allow overriding default input type for text' do with_form_for @user, :name, :as => :text assert_no_select 'form input#user_name' assert_select 'form textarea#user_name.text' with_form_for @user, :active, :as => :radio_buttons assert_no_select 'form input[type=checkbox]' assert_select 'form input.radio_buttons[type=radio]', :count => 2 with_form_for @user, :born_at, :as => :string assert_no_select 'form select' assert_select 'form input#user_born_at.string' end # COMMON OPTIONS test 'builder should add chosen form class' do swap SimpleForm, :form_class => :my_custom_class do with_form_for @user, :name assert_select 'form.my_custom_class' end end test 'builder should allow passing options to input' do with_form_for @user, :name, :input_html => { :class => 'my_input', :id => 'my_input' } assert_select 'form input#my_input.my_input.string' end test 'builder should not propagate input options to wrapper' do with_form_for @user, :name, :input_html => { :class => 'my_input', :id => 'my_input' } assert_no_select 'form div.input.my_input.string' assert_select 'form input#my_input.my_input.string' end test 'builder should not propagate input options to wrapper with custom wrapper' do swap_wrapper :default, self.custom_wrapper_with_wrapped_input do with_form_for @user, :name, :input_html => { :class => 'my_input' } assert_no_select 'form div.input.my_input' assert_select 'form input.my_input.string' end end test 'builder should not propagate label options to wrapper with custom wrapper' do swap_wrapper :default, self.custom_wrapper_with_wrapped_label do with_form_for @user, :name, :label_html => { :class => 'my_label' } assert_no_select 'form div.label.my_label' assert_select 'form label.my_label.string' end end test 'builder should generate a input with label' do with_form_for @user, :name assert_select 'form label.string[for=user_name]', /Name/ end test 'builder should be able to disable the label for a input' do with_form_for @user, :name, :label => false assert_no_select 'form label' end test 'builder should be able to disable the label for an input and return a html safe string' do with_form_for @user, :name, :label => false, :wrapper => custom_wrapper_with_wrapped_label_input assert_select 'form input#user_name' end test 'builder should use custom label' do with_form_for @user, :name, :label => 'Yay!' assert_select 'form label', /Yay!/ end test 'builder should pass options to label' do with_form_for @user, :name, :label_html => { :id => "cool" } assert_select 'form label#cool', /Name/ end test 'builder should not generate hints for a input' do with_form_for @user, :name assert_no_select 'span.hint' end test 'builder should be able to add a hint for a input' do with_form_for @user, :name, :hint => 'test' assert_select 'span.hint', 'test' end test 'builder should be able to disable a hint even if it exists in i18n' do store_translations(:en, :simple_form => { :hints => { :name => 'Hint test' } }) do SimpleForm::Inputs::Base.any_instance.expects(:hint).never with_form_for @user, :name, :hint => false assert_no_select 'span.hint' end end test 'builder should pass options to hint' do with_form_for @user, :name, :hint => 'test', :hint_html => { :id => "cool" } assert_select 'span.hint#cool', 'test' end test 'builder should generate errors for attribute without errors' do with_form_for @user, :credit_limit assert_no_select 'span.errors' end test 'builder should generate errors for attribute with errors' do with_form_for @user, :name assert_select 'span.error', "can't be blank" end test 'builder should be able to disable showing errors for a input' do with_form_for @user, :name, :error => false assert_no_select 'span.error' end test 'builder should pass options to errors' do with_form_for @user, :name, :error_html => { :id => "cool" } assert_select 'span.error#cool', "can't be blank" end test 'placeholder should not be generated when set to false' do store_translations(:en, :simple_form => { :placeholders => { :user => { :name => 'Name goes here' } } }) do with_form_for @user, :name, :placeholder => false assert_no_select 'input[placeholder]' end end # DEFAULT OPTIONS [:input, :input_field].each do |method| test "builder should receive a default argument and pass it to the inputs when calling '#{method}'" do with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f| f.send(method, :name) end assert_select 'input.default_class' end test "builder should receive a default argument and pass it to the inputs without changing the defaults when calling '#{method}'" do with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class', :id => 'default_id' } } do |f| concat(f.send(method, :name)) concat(f.send(method, :credit_limit)) end assert_select "input.string.default_class[name='user[name]']" assert_no_select "input.string[name='user[credit_limit]']" end test "builder should receive a default argument and pass it to the inputs and nested form when calling '#{method}'" do @user.company = Company.new(1, 'Empresa') with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f| concat(f.send(method, :name)) concat(f.simple_fields_for(:company) do |company_form| concat(company_form.send(method, :name)) end) end assert_select "input.string.default_class[name='user[name]']" assert_select "input.string.default_class[name='user[company_attributes][name]']" end end test "builder should receive a default argument and pass it to the inputs when calling 'input', respecting the specific options" do with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f| f.input :name, :input_html => { :id => 'specific_id' } end assert_select 'input.default_class#specific_id' end test "builder should receive a default argument and pass it to the inputs when calling 'input_field', respecting the specific options" do with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class' } } do |f| f.input_field :name, :id => 'specific_id' end assert_select 'input.default_class#specific_id' end test "builder should receive a default argument and pass it to the inputs when calling 'input', overwriting the defaults with specific options" do with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class', :id => 'default_id' } } do |f| f.input :name, :input_html => { :id => 'specific_id' } end assert_select 'input.default_class#specific_id' end test "builder should receive a default argument and pass it to the inputs when calling 'input_field', overwriting the defaults with specific options" do with_concat_form_for @user, :defaults => { :input_html => { :class => 'default_class', :id => 'default_id' } } do |f| f.input_field :name, :id => 'specific_id' end assert_select 'input.default_class#specific_id' end # WITHOUT OBJECT test 'builder should generate properly when object is not present' do with_form_for :project, :name assert_select 'form input.string#project_name' end test 'builder should generate password fields based on attribute name when object is not present' do with_form_for :project, :password_confirmation assert_select 'form input[type=password].password#project_password_confirmation' end test 'builder should generate text fields by default for all attributes when object is not present' do with_form_for :project, :created_at assert_select 'form input.string#project_created_at' with_form_for :project, :budget assert_select 'form input.string#project_budget' end test 'builder should allow overriding input type when object is not present' do with_form_for :project, :created_at, :as => :datetime assert_select 'form select.datetime#project_created_at_1i' with_form_for :project, :budget, :as => :decimal assert_select 'form input.decimal#project_budget' end # CUSTOM FORM BUILDER test 'custom builder should inherit mappings' do with_custom_form_for @user, :email assert_select 'form input[type=email]#user_email.custom' end test 'form with CustomMapTypeFormBuilder should use custom map type builder' do with_concat_custom_mapping_form_for(:user) do |user| assert user.instance_of?(CustomMapTypeFormBuilder) end end test 'form with CustomMapTypeFormBuilder should use custom mapping' do with_concat_custom_mapping_form_for(:user) do |user| assert_equal SimpleForm::Inputs::StringInput, user.class.mappings[:custom_type] end end test 'form without CustomMapTypeFormBuilder should not use custom mapping' do with_concat_form_for(:user) do |user| assert_nil user.class.mappings[:custom_type] end end end