Back to Repositories

Validating Required Field Handling in SimpleForm

This test suite examines the required field validation functionality in SimpleForm, focusing on how form inputs handle required attributes and validation rules. It verifies the interaction between SimpleForm’s required field handling and ActiveModel::Validations, including browser validation behavior and conditional validation scenarios.

Test Coverage Overview

The test suite provides comprehensive coverage of SimpleForm’s required field validation mechanisms.

Key areas tested include:
  • ActiveModel::Validations integration
  • Required attribute overriding
  • Browser validation behavior
  • Conditional validation scenarios (:if/:unless)
  • Lifecycle-specific validations (create/update/save)

Implementation Analysis

The testing approach uses ActionView::TestCase as the foundation, implementing systematic validation checks through form builder interactions. The tests utilize SimpleForm’s configuration swapping capability to verify behavior under different settings, particularly focusing on browser_validations and required_by_default options.

Technical patterns include:
  • Form builder wrapper customization
  • DOM assertion validations
  • Configuration state management

Technical Details

Testing tools and configuration:
  • ActionView::TestCase framework
  • SimpleForm configuration swapping
  • Custom wrapper definitions
  • CSS selector assertions
  • Model state manipulation methods

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through thorough coverage and organized structure.

Notable practices include:
  • Isolated test cases for each validation scenario
  • Clear test naming conventions
  • Comprehensive edge case coverage
  • Configuration state management
  • Systematic validation of HTML attributes and CSS classes

heartcombo/simple_form

test/inputs/required_test.rb

            
# frozen_string_literal: true
require 'test_helper'

class RequiredTest < ActionView::TestCase
  # REQUIRED AND PRESENCE VALIDATION
  test 'builder input obtains required from ActiveModel::Validations when it is included' do
    with_form_for @validating_user, :name
    assert_select 'input.required[required]#validating_user_name'
    with_form_for @validating_user, :status
    assert_select 'input.optional#validating_user_status'
  end

  test 'builder input allows overriding required when ActiveModel::Validations is included' do
    with_form_for @validating_user, :name, required: false
    assert_select 'input.optional#validating_user_name'
    with_form_for @validating_user, :status, required: true
    assert_select 'input.required[required]#validating_user_status'
  end

  test 'builder input is required by default when ActiveModel::Validations is not included' do
    with_form_for @user, :name
    assert_select 'input.required[required]#user_name'
  end

  test 'builder input does not be required by default when ActiveModel::Validations is not included if option is set to false' do
    swap SimpleForm, required_by_default: false do
      with_form_for @user, :name
      assert_select 'input.optional#user_name'
      assert_no_select 'input[required]'
    end
  end

  test 'when not using browser validations, input does not generate required html attribute' do
    swap SimpleForm, browser_validations: false do
      with_input_for @user, :name, :string
      assert_select 'input[type=text].required'
      assert_no_select 'input[type=text][required]'
    end
  end

  test 'when not using browser validations, when required option is set to false, input does not generate required html attribute' do
    swap SimpleForm, browser_validations: false do
      with_input_for @user, :name, :string, required: false
      assert_no_select 'input[type=text].required'
      assert_no_select 'input[type=text][required]'
    end
  end

  test 'when not using browser validations, when required option is set to true, input generates required html attribute' do
    swap SimpleForm, browser_validations: false do
      with_input_for @user, :name, :string, required: true
      assert_select 'input[type=text].required'
      assert_select 'input[type=text][required]'
    end
  end

  test 'when not using browser validations, when required option is true in the wrapper, input does not generate required html attribute' do
    swap SimpleForm, browser_validations: false do
      swap_wrapper :default, self.custom_wrapper_with_required_input do
        with_concat_form_for(@user) do |f|
          concat f.input :name
        end
        assert_select 'input[type=text].required'
        assert_no_select 'input[type=text][required]'
      end
    end
  end

  test 'builder input allows disabling required when ActiveModel::Validations is not included' do
    with_form_for @user, :name, required: false
    assert_no_select 'input.required'
    assert_no_select 'input[required]'
    assert_select 'input.optional#user_name'
  end

  test 'when not the required component the input does not have the required attribute but has the required class' do
    swap_wrapper do
      with_input_for @user, :name, :string
      assert_select 'input[type=text].required'
      assert_no_select 'input[type=text][required]'
    end
  end

  # VALIDATORS :if :unless
  test 'builder input does not be required when ActiveModel::Validations is included and if option is present' do
    with_form_for @validating_user, :age
    assert_no_select 'input.required'
    assert_no_select 'input[required]'
    assert_select 'input.optional#validating_user_age'
  end

  test 'builder input does not be required when ActiveModel::Validations is included and unless option is present' do
    with_form_for @validating_user, :amount
    assert_no_select 'input.required'
    assert_no_select 'input[required]'
    assert_select 'input.optional#validating_user_amount'
  end

  # VALIDATORS :on
  test 'builder input is required when validation is on create and is not persisted' do
    @validating_user.new_record!
    with_form_for @validating_user, :action
    assert_select 'input.required'
    assert_select 'input[required]'
    assert_select 'input.required[required]#validating_user_action'
  end

  test 'builder input does not be required when validation is on create and is persisted' do
    with_form_for @validating_user, :action
    assert_no_select 'input.required'
    assert_no_select 'input[required]'
    assert_select 'input.optional#validating_user_action'
  end

  test 'builder input is required when validation is on save' do
    with_form_for @validating_user, :credit_limit
    assert_select 'input.required'
    assert_select 'input[required]'
    assert_select 'input.required[required]#validating_user_credit_limit'

    @validating_user.new_record!
    with_form_for @validating_user, :credit_limit
    assert_select 'input.required'
    assert_select 'input[required]'
    assert_select 'input.required[required]#validating_user_credit_limit'
  end

  test 'builder input is required when validation is on update and is persisted' do
    with_form_for @validating_user, :phone_number
    assert_select 'input.required'
    assert_select 'input[required]'
    assert_select 'input.required[required]#validating_user_phone_number'
  end

  test 'builder input does not be required when validation is on update and is not persisted' do
    @validating_user.new_record!
    with_form_for @validating_user, :phone_number
    assert_no_select 'input.required'
    assert_no_select 'input[required]'
    assert_select 'input.optional#validating_user_phone_number'
  end

  test 'builder input does not generate required html attribute when option is set to false when it is set to true in wrapper' do
    swap SimpleForm, browser_validations: true do
      swap_wrapper :default, self.custom_wrapper_with_required_input do
        with_concat_form_for(@user) do |f|
          concat f.input :name, required: false
        end
        assert_no_select 'input[type=text][required]'
      end
    end
  end
end