Back to Repositories

Testing Form Helper Implementation in Simple Form

This test suite validates the core form helper functionality in Simple Form, focusing on form builder instantiation, CSS class handling, and browser validation behaviors.

Test Coverage Overview

The test suite provides comprehensive coverage of SimpleForm’s form helper functionality.

  • Form builder instantiation and type verification
  • Default and custom CSS class handling
  • Browser validation configuration
  • Object name and persistence state class generation
  • Error handling procedures

Implementation Analysis

The testing approach uses ActionView::TestCase as the base framework, implementing systematic validation of form helper features.

Key patterns include:
  • Swap helper for configuration testing
  • Concat form helpers for DOM verification
  • CSS selector assertions for class presence
  • Form builder instance validation

Technical Details

Testing infrastructure includes:
  • Minitest framework integration
  • ActionView test case inheritance
  • Custom helper methods for form generation
  • CSS selector assertions
  • Configuration swapping utilities

Best Practices Demonstrated

The test suite exemplifies strong testing practices through isolated test cases, clear naming conventions, and comprehensive edge case coverage.

  • Isolated configuration testing
  • Consistent test naming patterns
  • Error proc validation
  • State-dependent behavior verification

heartcombo/simple_form

test/action_view_extensions/form_helper_test.rb

            
# frozen_string_literal: true
require 'test_helper'

class FormHelperTest < ActionView::TestCase

  test 'SimpleForm for yields an instance of FormBuilder' do
    simple_form_for :user do |f|
      assert f.instance_of?(SimpleForm::FormBuilder)
    end
  end

  test 'SimpleForm adds default class to form' do
    with_concat_form_for(:user)
    assert_select 'form.simple_form'
  end

  test 'SimpleForm allows overriding default form class' do
    swap SimpleForm, default_form_class: "my_custom_class" do
      with_concat_form_for :user, html: { class: "override_class" }
      assert_no_select 'form.my_custom_class'
      assert_select 'form.override_class'
    end
  end

  # Remove this test when SimpleForm.form_class is removed in 4.x
  test 'SimpleForm allows overriding default form class, but not form class' do
    SimpleForm.deprecator.silence do
      swap SimpleForm, form_class: "fixed_class", default_form_class: "my_custom_class" do
        with_concat_form_for :user, html: { class: "override_class" }
        assert_no_select 'form.my_custom_class'
        assert_select 'form.fixed_class.override_class'
      end
    end
  end

  test 'SimpleForm uses default browser validations by default' do
    with_concat_form_for(:user)
    assert_no_select 'form[novalidate]'
  end

  test 'SimpleForm does not use default browser validations if specified in the configuration options' do
    swap SimpleForm, browser_validations: false do
      with_concat_form_for(:user)
      assert_select 'form[novalidate="novalidate"]'
    end
  end

  test 'disabled browser validations overrides default configuration' do
    with_concat_form_for(:user, html: { novalidate: true })
    assert_select 'form[novalidate="novalidate"]'
  end

  test 'enabled browser validations overrides disabled configuration' do
    swap SimpleForm, browser_validations: false do
      with_concat_form_for(:user, html: { novalidate: false })
      assert_no_select 'form[novalidate]'
    end
  end

  test 'SimpleForm adds object name as css class to form when object is not present' do
    with_concat_form_for(:user, html: { novalidate: true })
    assert_select 'form.simple_form.user'
  end

  test 'SimpleForm adds :as option as css class to form when object is not present' do
    with_concat_form_for(:user, as: 'superuser')
    assert_select 'form.simple_form.superuser'
  end

  test 'SimpleForm adds object class name with new prefix as css class to form if record is not persisted' do
    @user.new_record!
    with_concat_form_for(@user)
    assert_select 'form.simple_form.new_user'
  end

  test 'SimpleForm adds :as option with new prefix as css class to form if record is not persisted' do
    @user.new_record!
    with_concat_form_for(@user, as: 'superuser')
    assert_select 'form.simple_form.new_superuser'
  end

  test 'SimpleForm adds edit class prefix as css class to form if record is persisted' do
    with_concat_form_for(@user)
    assert_select 'form.simple_form.edit_user'
  end

  test 'SimpleForm adds :as options with edit prefix as css class to form if record is persisted' do
    with_concat_form_for(@user, as: 'superuser')
    assert_select 'form.simple_form.edit_superuser'
  end

  test 'SimpleForm adds last object name as css class to form when there is array of objects' do
    with_concat_form_for([Company.new, @user])
    assert_select 'form.simple_form.edit_user'
  end

  test 'SimpleForm does not add object class to form if css_class is specified' do
    with_concat_form_for(:user, html: { class: nil })
    assert_no_select 'form.user'
  end

  test 'SimpleForm adds custom class to form if css_class is specified' do
    with_concat_form_for(:user, html: { class: 'my_class' })
    assert_select 'form.my_class'
  end

  test 'passes options to SimpleForm' do
    with_concat_form_for(:user, url: '/account', html: { id: 'my_form' })
    assert_select 'form#my_form'
    assert_select 'form[action="/account"]'
  end

  test 'form_for yields an instance of FormBuilder' do
    with_concat_form_for(:user) do |f|
      assert f.instance_of?(SimpleForm::FormBuilder)
    end
  end

  test 'fields_for with a hash like model yields an instance of FormBuilder' do
    with_concat_fields_for(:author, HashBackedAuthor.new) do |f|
      assert f.instance_of?(SimpleForm::FormBuilder)
      f.input :name
    end

    assert_select "input[name='author[name]'][value='hash backed author']"
  end

  test 'custom error proc is not destructive' do
    swap_field_error_proc do
      result = nil
      simple_form_for :user do |f|
        result = simple_fields_for 'address' do
          'hello'
        end
      end

      assert_equal 'hello', result
    end
  end

  test 'custom error proc survives an exception' do
    swap_field_error_proc do
      begin
        simple_form_for :user do |f|
          simple_fields_for 'address' do
            raise 'an exception'
          end
        end
      rescue StandardError
      end
    end
  end

  test 'SimpleForm for swaps default action view field_error_proc' do
    expected_error_proc = -> {}
    swap SimpleForm, field_error_proc: expected_error_proc do
      simple_form_for :user do |f|
        assert_equal expected_error_proc, ::ActionView::Base.field_error_proc
      end
    end
  end

  private

  def swap_field_error_proc(expected_error_proc = -> {})
    swap ActionView::Base, field_error_proc: expected_error_proc do
      yield

      assert_equal expected_error_proc, ActionView::Base.field_error_proc
    end
  end
end