spec/unit/form_builder_spec.rb in activeadmin-1.0.0.pre4 vs spec/unit/form_builder_spec.rb in activeadmin-1.0.0.pre5

- old
+ new

@@ -1,10 +1,9 @@ require 'rails_helper' require "rspec/mocks/standalone" -describe ActiveAdmin::FormBuilder do - +RSpec.describe ActiveAdmin::FormBuilder do # Setup an ActionView::Base object which can be used for # generating the form for. let(:helpers) do view = action_view def view.posts_path @@ -61,20 +60,28 @@ end context "it with custom settings" do let :body do build_form do |f| - f.inputs class: "custom_class" do + f.inputs class: "custom_class", name: 'custom_name', custom_attr: 'custom_attr' do f.input :title f.input :body end end end it "should generate a fieldset with a inputs and custom class" do - expect(body).to have_selector("fieldset.inputs.custom_class") + expect(body).to have_selector("fieldset.custom_class") end + + it "should generate a fieldset with a custom legend" do + expect(body).to have_css("legend", text: 'custom_name') + end + + it "should generate a fieldset with a custom attributes" do + expect(body).to have_selector("fieldset[custom_attr='custom_attr']") + end end end context "in general with actions" do let :body do @@ -275,10 +282,40 @@ end end end + context "with inputs component inside has_many" do + + def user + u = User.new + u.profile = Profile.new(bio: 'bio') + u + end + + let :body do + author = user() + build_form do |f| + f.form_builder.instance_eval do + @object.author = author + end + f.inputs name: 'Author', for: :author do |author| + author.has_many :profile, allow_destroy: true do |profile| + profile.inputs "inputs for profile #{profile.object.bio}" do + profile.input :bio + end + end + end + end + end + + it "should see the profile fields for an existing profile" do + expect(body).to have_selector("[id='post_author_attributes_profile_attributes_bio']", count: 1) + expect(body).to have_selector("textarea[name='post[author_attributes][profile_attributes][bio]']") + end + end + context "with a has_one relation on an author's profile" do let :body do author = user() build_form do |f| f.inputs do @@ -400,22 +437,22 @@ f.input :title f.input :body end f.inputs do f.input :author - f.input :published_at + f.input :created_at end end end it "should render four inputs" do expect(body).to have_selector("input[name='post[title]']", count: 1) expect(body).to have_selector("textarea[name='post[body]']", count: 1) expect(body).to have_selector("select[name='post[author_id]']", count: 1) - expect(body).to have_selector("select[name='post[published_at(1i)]']", count: 1) - expect(body).to have_selector("select[name='post[published_at(2i)]']", count: 1) - expect(body).to have_selector("select[name='post[published_at(3i)]']", count: 1) - expect(body).to have_selector("select[name='post[published_at(4i)]']", count: 1) + expect(body).to have_selector("select[name='post[created_at(1i)]']", count: 1) + expect(body).to have_selector("select[name='post[created_at(2i)]']", count: 1) + expect(body).to have_selector("select[name='post[created_at(3i)]']", count: 1) + expect(body).to have_selector("select[name='post[created_at(4i)]']", count: 1) end end context "with has many inputs" do describe "with simple block" do @@ -500,11 +537,10 @@ end it "should add a custom header" do expect(body).to have_selector("h3", text: "Post") end - end describe "without heading and new record link" do let :body do build_form({url: '/categories'}, Category.new) do |f| @@ -537,13 +573,12 @@ end end end it "should add a custom header" do - expect(body).to have_selector("h3", "Test heading") + expect(body).to have_selector("h3", text: "Test heading") end - end describe "with custom new record link" do let :body do build_form({url: '/categories'}, Category.new) do |f| @@ -555,55 +590,167 @@ end it "should add a custom new record link" do expect(body).to have_selector("a", text: "My Custom New Post") end - end describe "with allow destroy" do - context "with an existing post" do - let :body do - s = self - build_form({url: '/categories'}, Category.new) do |f| - s.instance_exec do - allow(f.object.posts.build).to receive(:new_record?).and_return(false) - end - f.has_many :posts, allow_destroy: true do |p| - p.input :title - end - end + shared_examples_for "has many with allow_destroy = true" do |child_num| + it "should render the nested form" do + expect(body).to have_selector("input[name='category[posts_attributes][#{child_num}][title]']") end it "should include a boolean field for _destroy" do - expect(body).to have_selector("input[name='category[posts_attributes][0][_destroy]']") + expect(body).to have_selector("input[name='category[posts_attributes][#{child_num}][_destroy]']") end it "should have a check box with 'Remove' as its label" do - expect(body).to have_selector("label[for=category_posts_attributes_0__destroy]", text: "Delete") + expect(body).to have_selector("label[for=category_posts_attributes_#{child_num}__destroy]", text: "Delete") end it "should wrap the destroy field in an li with class 'has_many_delete'" do expect(body).to have_selector(".has_many_container > fieldset > ol > li.has_many_delete > input", count: 1) end end - context "with a new post" do + shared_examples_for "has many with allow_destroy = false" do |child_num| + it "should render the nested form" do + expect(body).to have_selector("input[name='category[posts_attributes][#{child_num}][title]']") + end + + it "should not have a boolean field for _destroy" do + expect(body).not_to have_selector("input[name='category[posts_attributes][#{child_num}][_destroy]']") + end + + it "should not have a check box with 'Remove' as its label" do + expect(body).not_to have_selector("label[for=category_posts_attributes_#{child_num}__destroy]", text: "Remove") + end + end + + shared_examples_for "has many with allow_destroy as String, Symbol or Proc" do |allow_destroy_option| let :body do + s = self build_form({url: '/categories'}, Category.new) do |f| - f.object.posts.build - f.has_many :posts, allow_destroy: true do |p| + s.instance_exec do + allow(f.object.posts.build).to receive(:foo?).and_return(true) + allow(f.object.posts.build).to receive(:foo?).and_return(false) + + f.object.posts.each do |post| + allow(post).to receive(:new_record?).and_return(false) + end + end + f.has_many :posts, allow_destroy: allow_destroy_option do |p| p.input :title end end end - it "should not have a boolean field for _destroy" do - expect(body).not_to have_selector("input[name='category[posts_attributes][0][_destroy]']") + context 'for the child that responds with true' do + it_behaves_like "has many with allow_destroy = true", 0 end - it "should not have a check box with 'Remove' as its label" do - expect(body).not_to have_selector("label[for=category_posts_attributes_0__destroy]", text: "Remove") + context 'for the child that responds with false' do + it_behaves_like "has many with allow_destroy = false", 1 + end + end + + context "with an existing post" do + context "with allow_destroy = true" do + let :body do + s = self + build_form({url: '/categories'}, Category.new) do |f| + s.instance_exec do + allow(f.object.posts.build).to receive(:new_record?).and_return(false) + end + f.has_many :posts, allow_destroy: true do |p| + p.input :title + end + end + end + + it_behaves_like "has many with allow_destroy = true", 0 + end + + context "with allow_destroy = false" do + let :body do + s = self + build_form({url: '/categories'}, Category.new) do |f| + s.instance_exec do + allow(f.object.posts.build).to receive(:new_record?).and_return(false) + end + f.has_many :posts, allow_destroy: false do |p| + p.input :title + end + end + end + + it_behaves_like "has many with allow_destroy = false", 0 + end + + context "with allow_destroy = nil" do + let :body do + s = self + build_form({url: '/categories'}, Category.new) do |f| + s.instance_exec do + allow(f.object.posts.build).to receive(:new_record?).and_return(false) + end + f.has_many :posts, allow_destroy: nil do |p| + p.input :title + end + end + end + + it_behaves_like "has many with allow_destroy = false", 0 + end + + context "with allow_destroy as Symbol" do + it_behaves_like("has many with allow_destroy as String, Symbol or Proc", :foo?) + end + + context "with allow_destroy as String" do + it_behaves_like("has many with allow_destroy as String, Symbol or Proc", "foo?") + end + + context "with allow_destroy as proc" do + it_behaves_like("has many with allow_destroy as String, Symbol or Proc", + Proc.new { |child| child.foo? }) + end + + context "with allow_destroy as lambda" do + it_behaves_like("has many with allow_destroy as String, Symbol or Proc", + lambda { |child| child.foo? }) + end + + context "with allow_destroy as any other expression that evaluates to true" do + let :body do + s = self + build_form({url: '/categories'}, Category.new) do |f| + s.instance_exec do + allow(f.object.posts.build).to receive(:new_record?).and_return(false) + end + f.has_many :posts, allow_destroy: Object.new do |p| + p.input :title + end + end + end + + it_behaves_like "has many with allow_destroy = true", 0 + end + end + + context "with a new post" do + context "with allow_destroy = true" do + let :body do + build_form({url: '/categories'}, Category.new) do |f| + f.object.posts.build + f.has_many :posts, allow_destroy: true do |p| + p.input :title + end + end + end + + it_behaves_like "has many with allow_destroy = false", 0 end end end describe "sortable" do