spec/support/shared_examples.rb in formtastic-3.1.5 vs spec/support/shared_examples.rb in formtastic-4.0.0.rc1

- old
+ new

@@ -8,1306 +8,5 @@ after do ::I18n.backend.reload! end end - -# TODO: move this back to spec/helpers/action_helper_spec.rb in Formtastic 4.0 -RSpec.shared_examples 'Action Helper' do - include_context 'form builder' - - describe 'arguments and options' do - - it 'should require the first argument (the action method)' do - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action()) # no args passed in at all - end) - }.should raise_error(ArgumentError) - end - - describe ':as option' do - - describe 'when not provided' do - - it 'should default to a commit for commit' do - concat(semantic_form_for(:project, :url => 'http://test.host') do |builder| - concat(builder.action(:submit)) - end) - output_buffer.should have_tag('form li.action.input_action', :count => 1) - end - - it 'should default to a button for reset' do - concat(semantic_form_for(:project, :url => 'http://test.host') do |builder| - concat(builder.action(:reset)) - end) - output_buffer.should have_tag('form li.action.input_action', :count => 1) - end - - it 'should default to a link for cancel' do - concat(semantic_form_for(:project, :url => 'http://test.host') do |builder| - concat(builder.action(:cancel)) - end) - output_buffer.should have_tag('form li.action.link_action', :count => 1) - end - end - - it 'should call the corresponding action class with .to_html' do - [:input, :button, :link].each do |action_style| - semantic_form_for(:project, :url => "http://test.host") do |builder| - action_instance = double('Action instance') - action_class = "#{action_style.to_s}_action".classify - action_constant = "Formtastic::Actions::#{action_class}".constantize - - action_constant.should_receive(:new).and_return(action_instance) - action_instance.should_receive(:to_html).and_return("some HTML") - - concat(builder.action(:submit, :as => action_style)) - end - end - end - - end - - #describe ':label option' do - # - # describe 'when provided' do - # it 'should be passed down to the label tag' do - # concat(semantic_form_for(@new_post) do |builder| - # concat(builder.input(:title, :label => "Kustom")) - # end) - # output_buffer.should have_tag("form li label", /Kustom/) - # end - # - # it 'should not generate a label if false' do - # concat(semantic_form_for(@new_post) do |builder| - # concat(builder.input(:title, :label => false)) - # end) - # output_buffer.should_not have_tag("form li label") - # end - # - # it 'should be dupped if frozen' do - # concat(semantic_form_for(@new_post) do |builder| - # concat(builder.input(:title, :label => "Kustom".freeze)) - # end) - # output_buffer.should have_tag("form li label", /Kustom/) - # end - # end - # - # describe 'when not provided' do - # describe 'when localized label is provided' do - # describe 'and object is given' do - # describe 'and label_str_method not :humanize' do - # it 'should render a label with localized text and not apply the label_str_method' do - # with_config :label_str_method, :reverse do - # @localized_label_text = 'Localized title' - # @new_post.stub(:meta_description) - # ::I18n.backend.store_translations :en, - # :formtastic => { - # :labels => { - # :meta_description => @localized_label_text - # } - # } - # - # concat(semantic_form_for(@new_post) do |builder| - # concat(builder.input(:meta_description)) - # end) - # output_buffer.should have_tag('form li label', /Localized title/) - # end - # end - # end - # end - # end - # - # describe 'when localized label is NOT provided' do - # describe 'and object is not given' do - # it 'should default the humanized method name, passing it down to the label tag' do - # ::I18n.backend.store_translations :en, :formtastic => {} - # with_config :label_str_method, :humanize do - # concat(semantic_form_for(:project, :url => 'http://test.host') do |builder| - # concat(builder.input(:meta_description)) - # end) - # output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/) - # end - # end - # end - # - # describe 'and object is given' do - # it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do - # @new_post.stub(:meta_description) # a two word method name - # @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize) - # - # concat(semantic_form_for(@new_post) do |builder| - # concat(builder.input(:meta_description)) - # end) - # output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/) - # end - # end - # - # describe 'and object is given with label_str_method set to :capitalize' do - # it 'should capitalize method name, passing it down to the label tag' do - # with_config :label_str_method, :capitalize do - # @new_post.stub(:meta_description) - # - # concat(semantic_form_for(@new_post) do |builder| - # concat(builder.input(:meta_description)) - # end) - # output_buffer.should have_tag("form li label", /#{'meta_description'.capitalize}/) - # end - # end - # end - # end - # - # describe 'when localized label is provided' do - # before do - # @localized_label_text = 'Localized title' - # @default_localized_label_text = 'Default localized title' - # ::I18n.backend.store_translations :en, - # :formtastic => { - # :labels => { - # :title => @default_localized_label_text, - # :published => @default_localized_label_text, - # :post => { - # :title => @localized_label_text, - # :published => @default_localized_label_text - # } - # } - # } - # end - # - # it 'should render a label with localized label (I18n)' do - # with_config :i18n_lookups_by_default, false do - # concat(semantic_form_for(@new_post) do |builder| - # concat(builder.input(:title, :label => true)) - # concat(builder.input(:published, :as => :boolean, :label => true)) - # end) - # output_buffer.should have_tag('form li label', Regexp.new('^' + @localized_label_text)) - # end - # end - # - # it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do - # with_config :i18n_lookups_by_default, false do - # ::I18n.backend.store_translations :en, - # :formtastic => { - # :labels => { - # :post => { - # :title => nil, - # :published => nil - # } - # } - # } - # concat(semantic_form_for(@new_post) do |builder| - # concat(builder.input(:title, :label => true)) - # concat(builder.input(:published, :as => :boolean, :label => true)) - # end) - # output_buffer.should have_tag('form li label', Regexp.new('^' + @default_localized_label_text)) - # end - # end - # end - # end - # - #end - # - describe ':wrapper_html option' do - - describe 'when provided' do - it 'should be passed down to the li tag' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:submit, :wrapper_html => {:id => :another_id})) - end) - output_buffer.should have_tag("form li#another_id") - end - - it 'should append given classes to li default classes' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:submit, :wrapper_html => {:class => :another_class})) - end) - output_buffer.should have_tag("form li.action") - output_buffer.should have_tag("form li.input_action") - output_buffer.should have_tag("form li.another_class") - end - - it 'should allow classes to be an array' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:submit, :wrapper_html => {:class => [ :my_class, :another_class ]})) - end) - output_buffer.should have_tag("form li.action") - output_buffer.should have_tag("form li.input_action") - output_buffer.should have_tag("form li.my_class") - output_buffer.should have_tag("form li.another_class") - end - end - - describe 'when not provided' do - it 'should use default id and class' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:submit)) - end) - output_buffer.should have_tag("form li#post_submit_action") - output_buffer.should have_tag("form li.action") - output_buffer.should have_tag("form li.input_action") - end - end - - end - - end - - describe 'instantiating an action class' do - context 'when a class does not exist' do - it "should raise an error" do - lambda { - concat(semantic_form_for(@new_post) do |builder| - builder.action(:submit, :as => :non_existant) - end) - }.should raise_error(Formtastic::UnknownActionError) - end - end - - context 'when a customized top-level class does not exist' do - it 'should instantiate the Formtastic action' do - action = double('action', :to_html => 'some HTML') - Formtastic::Actions::ButtonAction.should_receive(:new).and_return(action) - concat(semantic_form_for(@new_post) do |builder| - builder.action(:commit, :as => :button) - end) - end - end - - describe 'when a top-level (custom) action class exists' do - it "should instantiate the top-level action instead of the Formtastic one" do - class ::ButtonAction < Formtastic::Actions::ButtonAction - end - - action = double('action', :to_html => 'some HTML') - Formtastic::Actions::ButtonAction.should_not_receive(:new) - ::ButtonAction.should_receive(:new).and_return(action) - - concat(semantic_form_for(@new_post) do |builder| - builder.action(:commit, :as => :button) - end) - end - end - - describe 'support for :as on each action' do - - it "should raise an error when the action does not support the :as" do - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:submit, :as => :link)) - end) - }.should raise_error(Formtastic::UnsupportedMethodForAction) - - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:cancel, :as => :input)) - end) - }.should raise_error(Formtastic::UnsupportedMethodForAction) - - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:cancel, :as => :button)) - end) - }.should raise_error(Formtastic::UnsupportedMethodForAction) - end - - it "should not raise an error when the action does not support the :as" do - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:cancel, :as => :link)) - end) - }.should_not raise_error - - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:submit, :as => :input)) - end) - }.should_not raise_error - - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:submit, :as => :button)) - end) - }.should_not raise_error - - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:reset, :as => :input)) - end) - }.should_not raise_error - - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.action(:reset, :as => :button)) - end) - }.should_not raise_error - end - - end - - end - -end - -# TODO: move this back to spec/helpers/input_helper_spec.rb in Formtastic 4.0 -RSpec.shared_examples 'Input Helper' do - include_context 'form builder' - - before do - @errors = double('errors') - @errors.stub(:[]).and_return([]) - @new_post.stub(:errors).and_return(@errors) - end - - describe 'arguments and options' do - - it 'should require the first argument (the method on form\'s object)' do - lambda { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input()) # no args passed in at all - end) - }.should raise_error(ArgumentError) - end - - describe ':required option' do - - describe 'when true' do - - it 'should set a "required" class' do - with_config :required_string, " required yo!" do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :required => true)) - end) - output_buffer.should_not have_tag('form li.optional') - output_buffer.should have_tag('form li.required') - end - end - - it 'should append the "required" string to the label' do - with_config :required_string, " required yo!" do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :required => true)) - end) - output_buffer.should have_tag('form li.required label', /required yo/) - end - end - end - - describe 'when false' do - - before do - @string = Formtastic::FormBuilder.optional_string = " optional yo!" # ensure there's something in the string - @new_post.class.should_not_receive(:reflect_on_all_validations) - end - - after do - Formtastic::FormBuilder.optional_string = '' - end - - it 'should set an "optional" class' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :required => false)) - end) - output_buffer.should_not have_tag('form li.required') - output_buffer.should have_tag('form li.optional') - end - - it 'should set and "optional" class also when there is presence validator' do - @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([ - active_model_presence_validator([:title]) - ]) - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :required => false)) - end) - output_buffer.should_not have_tag('form li.required') - output_buffer.should have_tag('form li.optional') - end - - it 'should append the "optional" string to the label' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :required => false)) - end) - output_buffer.should have_tag('form li.optional label', /#{@string}$/) - end - - end - - describe 'when not provided' do - - describe 'and an object was not given' do - - it 'should use the default value' do - Formtastic::FormBuilder.all_fields_required_by_default.should == true - Formtastic::FormBuilder.all_fields_required_by_default = false - - concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder| - concat(builder.input(:title)) - end) - output_buffer.should_not have_tag('form li.required') - output_buffer.should have_tag('form li.optional') - - Formtastic::FormBuilder.all_fields_required_by_default = true - end - - end - - describe 'and an object with :validators_on was given (ActiveModel, Active Resource)' do - before do - @new_post.stub(:class).and_return(::PostModel) - end - - after do - @new_post.stub(:class).and_return(::Post) - end - describe 'and validates_presence_of was called for the method' do - it 'should be required' do - - @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([ - active_model_presence_validator([:title]) - ]) - - @new_post.class.should_receive(:validators_on).with(:body).at_least(:once).and_return([ - active_model_presence_validator([:body], {:if => true}) - ]) - - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - concat(builder.input(:body)) - end) - output_buffer.should have_tag('form li.required') - output_buffer.should_not have_tag('form li.optional') - end - - it 'should be required when there is :on => :create option on create' do - with_config :required_string, " required yo!" do - @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([ - active_model_presence_validator([:title], {:on => :create}) - ]) - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should have_tag('form li.required') - output_buffer.should_not have_tag('form li.optional') - end - end - - it 'should be required when there is :create option in validation contexts array on create' do - with_config :required_string, " required yo!" do - @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([ - active_model_presence_validator([:title], {:on => [:create]}) - ]) - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should have_tag('form li.required') - output_buffer.should_not have_tag('form li.optional') - end - end - - it 'should be required when there is :on => :save option on create' do - with_config :required_string, " required yo!" do - @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([ - active_model_presence_validator([:title], {:on => :save}) - ]) - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should have_tag('form li.required') - output_buffer.should_not have_tag('form li.optional') - end - end - - it 'should be required when there is :save option in validation contexts array on create' do - with_config :required_string, " required yo!" do - @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([ - active_model_presence_validator([:title], {:on => [:save]}) - ]) - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should have_tag('form li.required') - output_buffer.should_not have_tag('form li.optional') - end - end - - it 'should be required when there is :on => :save option on update' do - with_config :required_string, " required yo!" do - @fred.class.should_receive(:validators_on).with(:login).at_least(:once).and_return([ - active_model_presence_validator([:login], {:on => :save}) - ]) - concat(semantic_form_for(@fred) do |builder| - concat(builder.input(:login)) - end) - output_buffer.should have_tag('form li.required') - output_buffer.should_not have_tag('form li.optional') - end - end - - it 'should be required when there is :save option in validation contexts array on update' do - with_config :required_string, " required yo!" do - @fred.class.should_receive(:validators_on).with(:login).at_least(:once).and_return([ - active_model_presence_validator([:login], {:on => [:save]}) - ]) - concat(semantic_form_for(@fred) do |builder| - concat(builder.input(:login)) - end) - output_buffer.should have_tag('form li.required') - output_buffer.should_not have_tag('form li.optional') - end - end - - it 'should not be required when there is :on => :create option on update' do - @fred.class.should_receive(:validators_on).with(:login).at_least(:once).and_return([ - active_model_presence_validator([:login], {:on => :create}) - ]) - concat(semantic_form_for(@fred) do |builder| - concat(builder.input(:login)) - end) - output_buffer.should_not have_tag('form li.required') - output_buffer.should have_tag('form li.optional') - end - - it 'should not be required when there is :create option in validation contexts array on update' do - @fred.class.should_receive(:validators_on).with(:login).at_least(:once).and_return([ - active_model_presence_validator([:login], {:on => [:create]}) - ]) - concat(semantic_form_for(@fred) do |builder| - concat(builder.input(:login)) - end) - output_buffer.should_not have_tag('form li.required') - output_buffer.should have_tag('form li.optional') - end - - it 'should not be required when there is :on => :update option on create' do - @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([ - active_model_presence_validator([:title], {:on => :update}) - ]) - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should_not have_tag('form li.required') - output_buffer.should have_tag('form li.optional') - end - - it 'should not be required when there is :update option in validation contexts array on create' do - @new_post.class.should_receive(:validators_on).with(:title).at_least(:once).and_return([ - active_model_presence_validator([:title], {:on => [:update]}) - ]) - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should_not have_tag('form li.required') - output_buffer.should have_tag('form li.optional') - end - - it 'should be not be required if the optional :if condition is not satisifed' do - presence_should_be_required(:required => false, :tag => :body, :options => { :if => false }) - end - - it 'should not be required if the optional :if proc evaluates to false' do - presence_should_be_required(:required => false, :tag => :body, :options => { :if => proc { |record| false } }) - end - - it 'should be required if the optional :if proc evaluates to true' do - presence_should_be_required(:required => true, :tag => :body, :options => { :if => proc { |record| true } }) - end - - it 'should not be required if the optional :unless proc evaluates to true' do - presence_should_be_required(:required => false, :tag => :body, :options => { :unless => proc { |record| true } }) - end - - it 'should be required if the optional :unless proc evaluates to false' do - presence_should_be_required(:required => true, :tag => :body, :options => { :unless => proc { |record| false } }) - end - - it 'should be required if the optional :if with a method string evaluates to true' do - @new_post.should_receive(:required_condition).and_return(true) - presence_should_be_required(:required => true, :tag => :body, :options => { :if => :required_condition }) - end - - it 'should be required if the optional :if with a method string evaluates to false' do - @new_post.should_receive(:required_condition).and_return(false) - presence_should_be_required(:required => false, :tag => :body, :options => { :if => :required_condition }) - end - - it 'should be required if the optional :unless with a method string evaluates to false' do - @new_post.should_receive(:required_condition).and_return(false) - presence_should_be_required(:required => true, :tag => :body, :options => { :unless => :required_condition }) - end - - it 'should not be required if the optional :unless with a method string evaluates to true' do - @new_post.should_receive(:required_condition).and_return(true) - presence_should_be_required(:required => false, :tag => :body, :options => { :unless => :required_condition }) - end - end - - describe 'and validates_inclusion_of was called for the method' do - it 'should be required' do - @new_post.class.should_receive(:validators_on).with(:published).at_least(:once).and_return([ - active_model_inclusion_validator([:published], {:in => [false, true]}) - ]) - should_be_required(:tag => :published, :required => true) - end - - it 'should not be required if allow_blank is true' do - @new_post.class.should_receive(:validators_on).with(:published).at_least(:once).and_return([ - active_model_inclusion_validator([:published], {:in => [false, true], :allow_blank => true}) - ]) - should_be_required(:tag => :published, :required => false) - end - end - - describe 'and validates_length_of was called for the method' do - it 'should be required if minimum is set' do - length_should_be_required(:tag => :title, :required => true, :options => {:minimum => 1}) - end - - it 'should be required if :within is set' do - length_should_be_required(:tag => :title, :required => true, :options => {:within => 1..5}) - end - - it 'should not be required if :within allows zero length' do - length_should_be_required(:tag => :title, :required => false, :options => {:within => 0..5}) - end - - it 'should not be required if only :minimum is zero' do - length_should_be_required(:tag => :title, :required => false, :options => {:minimum => 0}) - end - - it 'should not be required if only :minimum is not set' do - length_should_be_required(:tag => :title, :required => false, :options => {:maximum => 5}) - end - - it 'should not be required if allow_blank is true' do - length_should_be_required(:tag => :published, :required => false, :options => {:allow_blank => true}) - end - end - - def add_presence_validator(options) - @new_post.class.stub(:validators_on).with(options[:tag]).and_return([ - active_model_presence_validator([options[:tag]], options[:options]) - ]) - end - - def add_length_validator(options) - @new_post.class.should_receive(:validators_on).with(options[:tag]).at_least(:once) {[ - active_model_length_validator([options[:tag]], options[:options]) - ]} - end - - # TODO make a matcher for this? - def should_be_required(options) - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(options[:tag])) - end) - - if options[:required] - output_buffer.should_not have_tag('form li.optional') - output_buffer.should have_tag('form li.required') - else - output_buffer.should have_tag('form li.optional') - output_buffer.should_not have_tag('form li.required') - end - end - - def presence_should_be_required(options) - add_presence_validator(options) - should_be_required(options) - end - - def length_should_be_required(options) - add_length_validator(options) - should_be_required(options) - end - - # TODO JF reversed this during refactor, need to make sure - describe 'and there are no requirement validations on the method' do - before do - @new_post.class.should_receive(:validators_on).with(:title).and_return([]) - end - - it 'should not be required' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should_not have_tag('form li.required') - output_buffer.should have_tag('form li.optional') - end - end - - end - - describe 'and an object without :validators_on' do - - it 'should use the default value' do - Formtastic::FormBuilder.all_fields_required_by_default.should == true - Formtastic::FormBuilder.all_fields_required_by_default = false - - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should_not have_tag('form li.required') - output_buffer.should have_tag('form li.optional') - - Formtastic::FormBuilder.all_fields_required_by_default = true - end - - end - - end - - end - - describe ':as option' do - - describe 'when not provided' do - - it 'should default to a string for forms without objects unless column is password' do - concat(semantic_form_for(:project, :url => 'http://test.host') do |builder| - concat(builder.input(:anything)) - end) - output_buffer.should have_tag('form li.string') - end - - it 'should default to password for forms without objects if column is password' do - concat(semantic_form_for(:project, :url => 'http://test.host') do |builder| - concat(builder.input(:password)) - concat(builder.input(:password_confirmation)) - concat(builder.input(:confirm_password)) - end) - output_buffer.should have_tag('form li.password', :count => 3) - end - - it 'should default to a string for methods on objects that don\'t respond to "column_for_attribute"' do - @new_post.stub(:method_without_a_database_column) - @new_post.stub(:column_for_attribute).and_return(nil) - default_input_type(nil, :method_without_a_database_column).should == :string - end - - it 'should default to :password for methods that don\'t have a column in the database but "password" is in the method name' do - @new_post.stub(:password_method_without_a_database_column) - @new_post.stub(:column_for_attribute).and_return(nil) - default_input_type(nil, :password_method_without_a_database_column).should == :password - end - - it 'should default to :password for methods on objects that don\'t respond to "column_for_attribute" but "password" is in the method name' do - @new_post.stub(:password_method_without_a_database_column) - @new_post.stub(:column_for_attribute).and_return(nil) - default_input_type(nil, :password_method_without_a_database_column).should == :password - end - - it 'should default to :number for "integer" column with name ending in "_id"' do - @new_post.stub(:aws_instance_id) - @new_post.stub(:column_for_attribute).with(:aws_instance_id).and_return(double('column', :type => :integer)) - default_input_type(:integer, :aws_instance_id).should == :number - end - - it 'should default to :select for associations' do - @new_post.class.stub(:reflect_on_association).with(:user_id).and_return(double('ActiveRecord::Reflection::AssociationReflection')) - @new_post.class.stub(:reflect_on_association).with(:section_id).and_return(double('ActiveRecord::Reflection::AssociationReflection')) - default_input_type(:integer, :user_id).should == :select - default_input_type(:integer, :section_id).should == :select - end - - it 'should default to :select for enum' do - statuses = ActiveSupport::HashWithIndifferentAccess.new("active"=>0, "inactive"=>1) - @new_post.class.stub(:statuses) { statuses } - @new_post.stub(:defined_enums) { {"status" => statuses } } - - default_input_type(:integer, :status).should == :select - end - - it 'should default to :password for :string column types with "password" in the method name' do - default_input_type(:string, :password).should == :password - default_input_type(:string, :hashed_password).should == :password - default_input_type(:string, :password_hash).should == :password - end - - it 'should default to :text for :text column types' do - default_input_type(:text).should == :text - end - - it 'should default to :date_select for :date column types' do - default_input_type(:date).should == :date_select - end - - it 'should default to :datetime_select for :datetime and :timestamp column types' do - default_input_type(:datetime).should == :datetime_select - default_input_type(:timestamp).should == :datetime_select - end - - it 'should default to :time_select for :time column types' do - default_input_type(:time).should == :time_select - end - - it 'should default to :boolean for :boolean column types' do - default_input_type(:boolean).should == :boolean - end - - it 'should default to :string for :string column types' do - default_input_type(:string).should == :string - end - - it 'should default to :number for :integer, :float and :decimal column types' do - default_input_type(:integer).should == :number - default_input_type(:float).should == :number - default_input_type(:decimal).should == :number - end - - it 'should default to :country for :string columns named country' do - default_input_type(:string, :country).should == :country - end - - it 'should default to :email for :string columns matching email' do - default_input_type(:string, :email).should == :email - default_input_type(:string, :customer_email).should == :email - default_input_type(:string, :email_work).should == :email - end - - it 'should default to :url for :string columns named url or website' do - default_input_type(:string, :url).should == :url - default_input_type(:string, :website).should == :url - default_input_type(:string, :my_url).should == :url - default_input_type(:string, :hurl).should_not == :url - end - - it 'should default to :phone for :string columns named phone or fax' do - default_input_type(:string, :phone).should == :phone - default_input_type(:string, :fax).should == :phone - end - - it 'should default to :search for :string columns named search' do - default_input_type(:string, :search).should == :search - end - - it 'should default to :color for :string columns matching color' do - default_input_type(:string, :color).should == :color - default_input_type(:string, :user_color).should == :color - default_input_type(:string, :color_for_image).should == :color - end - - describe 'defaulting to file column' do - Formtastic::FormBuilder.file_methods.each do |method| - it "should default to :file for attributes that respond to ##{method}" do - column = double('column') - - Formtastic::FormBuilder.file_methods.each do |test| - ### TODO: Check if this is ok - column.stub(method).with(test).and_return(method == test) - end - - @new_post.should_receive(method).and_return(column) - - semantic_form_for(@new_post) do |builder| - builder.send(:default_input_type, method).should == :file - end - end - end - - end - end - - it 'should call the corresponding input class with .to_html' do - [:select, :time_zone, :radio, :date_select, :datetime_select, :time_select, :boolean, :check_boxes, :hidden, :string, :password, :number, :text, :file].each do |input_style| - @new_post.stub(:generic_column_name) - @new_post.stub(:column_for_attribute).and_return(double('column', :type => :string, :limit => 255)) - semantic_form_for(@new_post) do |builder| - input_instance = double('Input instance') - input_class = "#{input_style.to_s}_input".classify - input_constant = "Formtastic::Inputs::#{input_class}".constantize - - input_constant.should_receive(:new).and_return(input_instance) - input_instance.should_receive(:to_html).and_return("some HTML") - - concat(builder.input(:generic_column_name, :as => input_style)) - end - end - end - - end - - describe ':label option' do - - describe 'when provided' do - it 'should be passed down to the label tag' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :label => "Kustom")) - end) - output_buffer.should have_tag("form li label", /Kustom/) - end - - it 'should not generate a label if false' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :label => false)) - end) - output_buffer.should_not have_tag("form li label") - end - - it 'should be dupped if frozen' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :label => "Kustom".freeze)) - end) - output_buffer.should have_tag("form li label", /Kustom/) - end - end - - describe 'when not provided' do - describe 'when localized label is provided' do - describe 'and object is given' do - describe 'and label_str_method not :humanize' do - it 'should render a label with localized text and not apply the label_str_method' do - with_config :label_str_method, :reverse do - @localized_label_text = 'Localized title' - @new_post.stub(:meta_description) - ::I18n.backend.store_translations :en, - :formtastic => { - :labels => { - :meta_description => @localized_label_text - } - } - - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:meta_description)) - end) - output_buffer.should have_tag('form li label', /Localized title/) - end - end - end - end - end - - describe 'when localized label is NOT provided' do - describe 'and object is not given' do - it 'should default the humanized method name, passing it down to the label tag' do - ::I18n.backend.store_translations :en, :formtastic => {} - with_config :label_str_method, :humanize do - concat(semantic_form_for(:project, :url => 'http://test.host') do |builder| - concat(builder.input(:meta_description)) - end) - output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/) - end - end - end - - describe 'and object is given' do - it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do - @new_post.stub(:meta_description) # a two word method name - @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize) - - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:meta_description)) - end) - output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/) - end - end - - describe 'and object is given with label_str_method set to :capitalize' do - it 'should capitalize method name, passing it down to the label tag' do - with_config :label_str_method, :capitalize do - @new_post.stub(:meta_description) - - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:meta_description)) - end) - output_buffer.should have_tag("form li label", /#{'meta_description'.capitalize}/) - end - end - end - end - - describe 'when localized label is provided' do - before do - @localized_label_text = 'Localized title' - @default_localized_label_text = 'Default localized title' - ::I18n.backend.store_translations :en, - :formtastic => { - :labels => { - :title => @default_localized_label_text, - :published => @default_localized_label_text, - :post => { - :title => @localized_label_text, - :published => @default_localized_label_text - } - } - } - end - - it 'should render a label with localized label (I18n)' do - with_config :i18n_lookups_by_default, false do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :label => true)) - concat(builder.input(:published, :as => :boolean, :label => true)) - end) - output_buffer.should have_tag('form li label', Regexp.new('^' + @localized_label_text)) - end - end - - it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do - with_config :i18n_lookups_by_default, false do - ::I18n.backend.store_translations :en, - :formtastic => { - :labels => { - :post => { - :title => nil, - :published => nil - } - } - } - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :label => true)) - concat(builder.input(:published, :as => :boolean, :label => true)) - end) - output_buffer.should have_tag('form li label', Regexp.new('^' + @default_localized_label_text)) - end - end - end - end - - end - - describe ':hint option' do - - describe 'when provided' do - - after do - Formtastic::FormBuilder.default_hint_class = "inline-hints" - end - - it 'should be passed down to the paragraph tag' do - hint_text = "this is the title of the post" - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :hint => hint_text)) - end) - output_buffer.should have_tag("form li p.inline-hints", hint_text) - end - - it 'should have a custom hint class defaulted for all forms' do - hint_text = "this is the title of the post" - Formtastic::FormBuilder.default_hint_class = "custom-hint-class" - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :hint => hint_text)) - end) - output_buffer.should have_tag("form li p.custom-hint-class", hint_text) - end - end - - describe 'when not provided' do - describe 'when localized hint (I18n) is provided' do - before do - @localized_hint_text = "This is the localized hint." - @default_localized_hint_text = "This is the default localized hint." - ::I18n.backend.store_translations :en, - :formtastic => { - :hints => { - :title => @default_localized_hint_text, - } - } - end - - after do - ::I18n.backend.reload! - end - - describe 'when provided value (hint value) is set to TRUE' do - it 'should render a hint paragraph containing a localized hint (I18n)' do - with_config :i18n_lookups_by_default, false do - ::I18n.backend.store_translations :en, - :formtastic => { - :hints => { - :post => { - :title => @localized_hint_text - } - } - } - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :hint => true)) - end) - output_buffer.should have_tag('form li p.inline-hints', @localized_hint_text) - end - end - - it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do - with_config :i18n_lookups_by_default, false do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :hint => true)) - end) - output_buffer.should have_tag('form li p.inline-hints', @default_localized_hint_text) - end - end - end - - describe 'when provided value (label value) is set to FALSE' do - it 'should not render a hint paragraph' do - with_config :i18n_lookups_by_default, false do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :hint => false)) - end) - output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text) - end - end - end - end - - describe 'when localized hint (I18n) is a model with attribute hints' do - it "should see the provided hash as a blank entry" do - with_config :i18n_lookups_by_default, false do - ::I18n.backend.store_translations :en, - :formtastic => { - :hints => { - :title => { # movie title - :summary => @localized_hint_text # summary of movie - } - } - } - semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :hint => true)) - end - output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text) - end - end - end - - describe 'when localized hint (I18n) is not provided' do - it 'should not render a hint paragraph' do - with_config :i18n_lookups_by_default, false do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should_not have_tag('form li p.inline-hints') - end - end - end - end - - end - - describe ':wrapper_html option' do - - describe 'when provided' do - it 'should be passed down to the li tag' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :wrapper_html => {:id => :another_id})) - end) - output_buffer.should have_tag("form li#another_id") - end - - it 'should append given classes to li default classes' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :wrapper_html => {:class => :another_class}, :required => true)) - end) - output_buffer.should have_tag("form li.string") - output_buffer.should have_tag("form li.required") - output_buffer.should have_tag("form li.another_class") - end - - it 'should allow classes to be an array' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :wrapper_html => {:class => [ :my_class, :another_class ]})) - end) - output_buffer.should have_tag("form li.string") - output_buffer.should have_tag("form li.my_class") - output_buffer.should have_tag("form li.another_class") - end - - describe 'when nil' do - it 'should not put an id attribute on the div tag' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, :wrapper_html => {:id => nil})) - end) - output_buffer.should have_tag('form li:not([id])') - end - end - end - - describe 'when not provided' do - it 'should use default id and class' do - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title)) - end) - output_buffer.should have_tag("form li#post_title_input") - output_buffer.should have_tag("form li.string") - end - end - - end - - describe ':collection option' do - - it "should be required on polymorphic associations" do - @new_post.stub(:commentable) - @new_post.class.stub(:reflections).and_return({ - :commentable => double('macro_reflection', :options => { :polymorphic => true }, :macro => :belongs_to) - }) - @new_post.stub(:column_for_attribute).with(:commentable).and_return( - double('column', :type => :integer) - ) - @new_post.class.stub(:reflect_on_association).with(:commentable).and_return( - double('reflection', :macro => :belongs_to, :options => { :polymorphic => true }) - ) - expect { - concat(semantic_form_for(@new_post) do |builder| - concat(builder.inputs do - concat(builder.input :commentable) - end) - end) - }.to raise_error(Formtastic::PolymorphicInputWithoutCollectionError) - end - - end - - end - - describe 'options re-use' do - - it 'should retain :as option when re-using the same options hash' do - my_options = { :as => :string } - output = '' - - concat(semantic_form_for(@new_post) do |builder| - concat(builder.input(:title, my_options)) - concat(builder.input(:publish_at, my_options)) - end) - output_buffer.should have_tag 'li.string', :count => 2 - end - end - - describe 'instantiating an input class' do - context 'when a class does not exist' do - it "should raise an error" do - lambda { - concat(semantic_form_for(@new_post) do |builder| - builder.input(:title, :as => :non_existant) - end) - }.should raise_error(Formtastic::UnknownInputError) - end - end - - context 'when a customized top-level class does not exist' do - - it 'should instantiate the Formtastic input' do - input = double('input', :to_html => 'some HTML') - Formtastic::Inputs::StringInput.should_receive(:new).and_return(input) - concat(semantic_form_for(@new_post) do |builder| - builder.input(:title, :as => :string) - end) - end - - end - - describe 'when a top-level input class exists' do - it "should instantiate the top-level input instead of the Formtastic one" do - class ::StringInput < Formtastic::Inputs::StringInput - end - - input = double('input', :to_html => 'some HTML') - Formtastic::Inputs::StringInput.should_not_receive(:new) - ::StringInput.should_receive(:new).and_return(input) - - concat(semantic_form_for(@new_post) do |builder| - builder.input(:title, :as => :string) - end) - end - end - - - end -end