require "spec_helper" [FreeForm::Builder, FreeForm::SimpleBuilder, defined?(FreeForm::FormtasticBuilder) ? FreeForm::FormtasticBuilder : nil].compact.each do |builder| describe builder do let!(:milestone_form_class) do klass = Class.new(FreeForm::Form) do form_input_key :milestone form_models :milestone allow_destroy_on_save property :name, :on => :milestone end # This wrapper just avoids CONST warnings v, $VERBOSE = $VERBOSE, nil Module.const_set("MilestoneForm", klass) $VERBOSE = v klass end let!(:task_form_class) do klass = Class.new(FreeForm::Form) do form_input_key :task form_models :task allow_destroy_on_save property :name, :on => :task has_many :milestones, :class => Module::MilestoneForm, :default_initializer => :milestone_initializer def milestone_initializer {:milestone => Milestone.new} end end # This wrapper just avoids CONST warnings v, $VERBOSE = $VERBOSE, nil Module.const_set("TaskForm", klass) $VERBOSE = v klass end let(:form_class) do klass = Class.new(FreeForm::Form) do form_input_key :project form_models :project allow_destroy_on_save property :name, :on => :project has_many :tasks, :class => Module::TaskForm, :default_initializer => :task_initializer def task_initializer {:task => Task.new} end end # This wrapper just avoids CONST warnings v, $VERBOSE = $VERBOSE, nil Module.const_set("ViewForm", klass) $VERBOSE = v klass end let(:form) { form_class.new(:project => Project.new) } let(:template) do template = ActionView::Base.new template.output_buffer = "" template end context "with no options", :no_options => true do subject do builder.new(:item, form, template, {}, proc {}) end describe '#link_to_add', :link_to_add => true do it "behaves similar to a Rails link_to" do subject.link_to_add("Add", :tasks).should eq('Add') subject.link_to_add("Add", :tasks, :class => "foo", :href => "url").should eq('Add') subject.link_to_add(:tasks) { "Add" }.should eq('Add') end it 'raises ArgumentError when missing association is provided' do expect { subject.link_to_add('Add', :bugs) }.to raise_error(ArgumentError) end it 'raises ArgumentError when accepts_nested_attributes_for is missing' do expect { subject.link_to_add('Add', :not_nested_tasks) }.to raise_error(ArgumentError) end end describe '#link_to_remove', :link_to_remove => true do it "behaves similar to a Rails link_to" do subject.link_to_remove("Remove").should eq('Remove') subject.link_to_remove("Remove", :class => "foo", :href => "url").should eq('Remove') subject.link_to_remove { "Remove" }.should eq('Remove') end it 'has data-association attribute' do form.build_task subject.fields_for(:tasks, :builder => builder) do |tf| tf.link_to_remove 'Remove' end.should match 'Remove' end context 'when there is more than one nested level' do it 'properly detects association name' do task = form.build_task task.build_milestone subject.fields_for(:tasks, :builder => builder) do |tf| tf.fields_for(:milestones, :builder => builder) do |mf| mf.link_to_remove 'Remove' end end.should match 'Remove' end end end describe '#fields_for' do it "wraps nested fields each in a div with class" do 2.times { form.build_task } fields = if subject.is_a?(FreeForm::SimpleBuilder) subject.simple_fields_for(:tasks) { "Task" } else subject.fields_for(:tasks) { "Task" } end fields.should == '
Task
Task
' end end it "wraps nested fields marked for destruction with an additional class, and hides them" do task = form.build_task task.mark_for_destruction fields = subject.fields_for(:tasks) { 'Task' } fields.should eq('') end it "puts blueprint into data-blueprint attribute" do task = form.build_task task.mark_for_destruction subject.fields_for(:tasks) { 'Task' } subject.link_to_add('Add', :tasks) output = template.send(:after_freeform_callbacks) expected = ERB::Util.html_escape '
Task
' output.should match(/div.+data-blueprint="#{expected}"/) end it "adds parent association name to the blueprint div id" do task = form.build_task task.build_milestone subject.fields_for(:tasks, :builder => builder) do |tf| tf.fields_for(:milestones, :builder => builder) { 'Milestone' } tf.link_to_add('Add', :milestones) end output = template.send(:after_freeform_callbacks) output.should match(/div.+id="tasks_milestones_fields_blueprint"/) end it "doesn't render wrapper div" do task = form.build_task fields = subject.fields_for(:tasks, :wrapper => false) { 'Task' } fields.should eq('Task') subject.link_to_add 'Add', :tasks output = template.send(:after_freeform_callbacks) output.should match(/div.+data-blueprint="Task"/) end it "doesn't render wrapper div when collection is passed" do task = form.build_task fields = subject.fields_for(:tasks, form.tasks, :wrapper => false) { 'Task' } fields.should eq('Task') subject.link_to_add 'Add', :tasks output = template.send(:after_freeform_callbacks) output.should match(/div.+data-blueprint="Task"/) end it "doesn't render wrapper with nested_wrapper option" do task = form.build_task fields = subject.fields_for(:tasks, :nested_wrapper => false) { 'Task' } fields.should eq('Task') subject.link_to_add 'Add', :tasks output = template.send(:after_freeform_callbacks) output.should match(/div.+data-blueprint="Task"/) end end context "with options", :with_options => true do subject { builder.new(:item, form, template, {}, proc {}) } context "when model_object given" do it "should use it instead of new generated" do subject.fields_for(:tasks) {|f| f.object.name } subject.link_to_add("Add", :tasks, :model_object => Task.new(:name => 'for check')) output = template.send(:after_freeform_callbacks) expected = ERB::Util.html_escape '
for check
' output.should match(/div.+data-blueprint="#{expected}"/) end end end end end