Back to Repositories

Testing Collection Radio Button Components in Simple Form

This test suite validates the collection radio buttons input functionality in SimpleForm, focusing on HTML generation, internationalization support, and various configuration options. It ensures proper rendering and behavior of radio button groups with different styles and customization options.

Test Coverage Overview

The test suite provides comprehensive coverage of radio button input generation and behavior.

Key areas tested include:
  • Default boolean radio button generation
  • Internal label handling and translations
  • Collection rendering with various data structures
  • Custom HTML attributes and styling options
  • Nested and inline display styles

Implementation Analysis

The testing approach uses ActionView::TestCase for thorough validation of HTML output.

Key implementation patterns include:
  • Dynamic collection handling with various data types
  • I18n integration for label translations
  • Flexible wrapper and styling configurations
  • Support for nested and inline display modes

Technical Details

Testing infrastructure includes:
  • Minitest framework integration
  • ActionView test helpers
  • SimpleForm configuration swapping
  • HTML assertion methods
  • I18n translation helpers

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices:

  • Comprehensive edge case coverage
  • Isolation of individual features
  • Clear test naming conventions
  • Thorough HTML structure validation
  • Configuration flexibility testing

heartcombo/simple_form

test/inputs/collection_radio_buttons_input_test.rb

            
# frozen_string_literal: true
# encoding: UTF-8
require 'test_helper'

class CollectionRadioButtonsInputTest < ActionView::TestCase
  test 'input generates boolean radio buttons by default for radio types' do
    with_input_for @user, :active, :radio_buttons
    assert_select 'input[type=radio][value=true].radio_buttons#user_active_true'
    assert_select 'input[type=radio][value=false].radio_buttons#user_active_false'
  end

  test 'input as radio generates internal labels by default' do
    with_input_for @user, :active, :radio_buttons
    assert_select 'label[for=user_active_true]', 'Yes'
    assert_select 'label[for=user_active_false]', 'No'
  end

  test 'input as radio generates internal labels with accurate `for` values with nested boolean style' do
    swap SimpleForm, boolean_style: :nested do
      with_input_for @user, :active, :radio_buttons
      assert_select 'label[for=user_active_true]', 'Yes'
      assert_select 'label[for=user_active_false]', 'No'
    end
  end

  test 'nested label does not duplicate input id' do
    swap SimpleForm, boolean_style: :nested do
      with_input_for @user, :active, :radio_buttons, id: 'nested_id'
      assert_select 'input#user_active_true'
      assert_no_select 'label#user_active_true'
    end
  end

  test 'input as radio uses i18n to translate internal labels' do
    store_translations(:en, simple_form: { yes: 'Sim', no: 'Não' }) do
      with_input_for @user, :active, :radio_buttons
      assert_select 'label[for=user_active_true]', 'Sim'
      assert_select 'label[for=user_active_false]', 'Não'
    end
  end

  test 'input radio does not include for attribute by default' do
    with_input_for @user, :gender, :radio_buttons, collection: %i[male female]
    assert_select 'label'
    assert_no_select 'label[for=user_gender]'
  end

  test 'input radio includes for attribute when giving as html option' do
    with_input_for @user, :gender, :radio_buttons, collection: %i[male female], label_html: { for: 'gender' }
    assert_select 'label[for=gender]'
  end

  test 'input marks the checked value when using boolean and radios' do
    @user.active = false
    with_input_for @user, :active, :radio_buttons
    assert_no_select 'input[type=radio][value=true][checked]'
    assert_select 'input[type=radio][value=false][checked]'
  end

  test 'input allows overriding collection for radio types' do
    with_input_for @user, :name, :radio_buttons, collection: %w[Jose Carlos]
    assert_select 'input[type=radio][value=Jose]'
    assert_select 'input[type=radio][value=Carlos]'
    assert_select 'label.collection_radio_buttons[for=user_name_jose]', 'Jose'
    assert_select 'label.collection_radio_buttons[for=user_name_carlos]', 'Carlos'
  end

  test 'input does automatic collection translation for radio types using defaults key' do
    store_translations(:en, simple_form: { options: { defaults: {
      gender: { male: 'Male', female: 'Female' }
    } } } ) do
      with_input_for @user, :gender, :radio_buttons, collection: %i[male female]
      assert_select 'input[type=radio][value=male]'
      assert_select 'input[type=radio][value=female]'
      assert_select 'label.collection_radio_buttons[for=user_gender_male]', 'Male'
      assert_select 'label.collection_radio_buttons[for=user_gender_female]', 'Female'
    end
  end

  test 'input does automatic collection translation for radio types using specific object key' do
    store_translations(:en, simple_form: { options: { user: {
      gender: { male: 'Male', female: 'Female' }
    } } } ) do
      with_input_for @user, :gender, :radio_buttons, collection: %i[male female]
      assert_select 'input[type=radio][value=male]'
      assert_select 'input[type=radio][value=female]'
      assert_select 'label.collection_radio_buttons[for=user_gender_male]', 'Male'
      assert_select 'label.collection_radio_buttons[for=user_gender_female]', 'Female'
    end
  end

  test 'input does automatic collection translation and preserve html markup' do
    swap SimpleForm, boolean_style: :nested do
      store_translations(:en, simple_form: { options: { user: {
        gender: { male_html: '<strong>Male</strong>', female_html: '<strong>Female</strong>' }
      } } } ) do
        with_input_for @user, :gender, :radio_buttons, collection: %i[male female]
        assert_select 'input[type=radio][value=male]'
        assert_select 'input[type=radio][value=female]'
        assert_select 'label[for=user_gender_male] strong', 'Male'
        assert_select 'label[for=user_gender_female] strong', 'Female'
      end
    end
  end

  test 'input does automatic collection translation with keys prefixed with _html and a string value' do
    swap SimpleForm, boolean_style: :nested do
      store_translations(:en, simple_form: { options: { user: {
        gender: { male_html: 'Male', female_html: 'Female' }
      } } } ) do
        with_input_for @user, :gender, :radio_buttons, collection: %i[male female]
        assert_select 'input[type=radio][value=male]'
        assert_select 'input[type=radio][value=female]'
        assert_select 'label[for=user_gender_male]', 'Male'
        assert_select 'label[for=user_gender_female]', 'Female'
      end
    end
  end

  test 'input marks the current radio value by default' do
    @user.name = "Carlos"
    with_input_for @user, :name, :radio_buttons, collection: %w[Jose Carlos]
    assert_select 'input[type=radio][value=Carlos][checked=checked]'
  end

  test 'input accepts html options as the last element of collection' do
    with_input_for @user, :name, :radio_buttons, collection: [['Jose', 'jose', class: 'foo']]
    assert_select 'input.foo[type=radio][value=jose]'
  end

  test 'input allows using a collection with text/value arrays' do
    with_input_for @user, :name, :radio_buttons, collection: [%w[Jose jose], %w[Carlos carlos]]
    assert_select 'input[type=radio][value=jose]'
    assert_select 'input[type=radio][value=carlos]'
    assert_select 'label.collection_radio_buttons', 'Jose'
    assert_select 'label.collection_radio_buttons', 'Carlos'
  end

  test 'input allows using a collection with a Proc' do
    with_input_for @user, :name, :radio_buttons, collection: proc { %w[Jose Carlos] }
    assert_select 'label.collection_radio_buttons', 'Jose'
    assert_select 'label.collection_radio_buttons', 'Carlos'
  end

  test 'input allows overriding only label method for collections' do
    with_input_for @user, :name, :radio_buttons,
                          collection: %w[Jose Carlos],
                          label_method: :upcase
    assert_select 'label.collection_radio_buttons', 'JOSE'
    assert_select 'label.collection_radio_buttons', 'CARLOS'
  end

  test 'input allows overriding only value method for collections' do
    with_input_for @user, :name, :radio_buttons,
                          collection: %w[Jose Carlos],
                          value_method: :upcase
    assert_select 'input[type=radio][value=JOSE]'
    assert_select 'input[type=radio][value=CARLOS]'
  end

  test 'input allows overriding label and value method for collections' do
    with_input_for @user, :name, :radio_buttons,
                          collection: %w[Jose Carlos],
                          label_method: :upcase,
                          value_method: :downcase
    assert_select 'input[type=radio][value=jose]'
    assert_select 'input[type=radio][value=carlos]'
    assert_select 'label.collection_radio_buttons', 'JOSE'
    assert_select 'label.collection_radio_buttons', 'CARLOS'
  end

  test 'input allows overriding label and value method using a lambda for collections' do
    with_input_for @user, :name, :radio_buttons,
                          collection: %w[Jose Carlos],
                          label_method: ->(i) { i.upcase },
                          value_method: ->(i) { i.downcase }
    assert_select 'input[type=radio][value=jose]'
    assert_select 'input[type=radio][value=carlos]'
    assert_select 'label.collection_radio_buttons', 'JOSE'
    assert_select 'label.collection_radio_buttons', 'CARLOS'
  end

  test 'collection input with radio type generates required html attribute' do
    with_input_for @user, :name, :radio_buttons, collection: %w[Jose Carlos]
    assert_select 'input[type=radio].required'
    assert_select 'input[type=radio][required]'
  end

  test 'input radio does not wrap the collection by default' do
    with_input_for @user, :active, :radio_buttons

    assert_select 'form input[type=radio]', count: 2
    assert_no_select 'form ul'
  end

  test 'input radio wraps the collection in the configured collection wrapper tag' do
    swap SimpleForm, collection_wrapper_tag: :ul do
      with_input_for @user, :active, :radio_buttons

      assert_select 'form ul input[type=radio]', count: 2
    end
  end

  test 'input radio does not wrap the collection when configured with falsy values' do
    swap SimpleForm, collection_wrapper_tag: false do
      with_input_for @user, :active, :radio_buttons

      assert_select 'form input[type=radio]', count: 2
      assert_no_select 'form ul'
    end
  end

  test 'input radio allows overriding the collection wrapper tag at input level' do
    swap SimpleForm, collection_wrapper_tag: :ul do
      with_input_for @user, :active, :radio_buttons, collection_wrapper_tag: :section

      assert_select 'form section input[type=radio]', count: 2
      assert_no_select 'form ul'
    end
  end

  test 'input radio allows disabling the collection wrapper tag at input level' do
    swap SimpleForm, collection_wrapper_tag: :ul do
      with_input_for @user, :active, :radio_buttons, collection_wrapper_tag: false

      assert_select 'form input[type=radio]', count: 2
      assert_no_select 'form ul'
    end
  end

  test 'input radio renders the wrapper tag with the configured wrapper class' do
    swap SimpleForm, collection_wrapper_tag: :ul, collection_wrapper_class: 'inputs-list' do
      with_input_for @user, :active, :radio_buttons

      assert_select 'form ul.inputs-list input[type=radio]', count: 2
    end
  end

  test 'input radio allows giving wrapper class at input level only' do
    swap SimpleForm, collection_wrapper_tag: :ul do
      with_input_for @user, :active, :radio_buttons, collection_wrapper_class: 'items-list'

      assert_select 'form ul.items-list input[type=radio]', count: 2
    end
  end

  test 'input radio uses both configured and given wrapper classes for wrapper tag' do
    swap SimpleForm, collection_wrapper_tag: :ul, collection_wrapper_class: 'inputs-list' do
      with_input_for @user, :active, :radio_buttons, collection_wrapper_class: 'items-list'

      assert_select 'form ul.inputs-list.items-list input[type=radio]', count: 2
    end
  end

  test 'input radio wraps each item in the configured item wrapper tag' do
    swap SimpleForm, item_wrapper_tag: :li do
      with_input_for @user, :active, :radio_buttons

      assert_select 'form li input[type=radio]', count: 2
    end
  end

  test 'input radio does not wrap items when configured with falsy values' do
    swap SimpleForm, item_wrapper_tag: false do
      with_input_for @user, :active, :radio_buttons

      assert_select 'form input[type=radio]', count: 2
      assert_no_select 'form li'
    end
  end

  test 'input radio allows overriding the item wrapper tag at input level' do
    swap SimpleForm, item_wrapper_tag: :li do
      with_input_for @user, :active, :radio_buttons, item_wrapper_tag: :dl

      assert_select 'form dl input[type=radio]', count: 2
      assert_no_select 'form li'
    end
  end

  test 'input radio allows disabling the item wrapper tag at input level' do
    swap SimpleForm, item_wrapper_tag: :ul do
      with_input_for @user, :active, :radio_buttons, item_wrapper_tag: false

      assert_select 'form input[type=radio]', count: 2
      assert_no_select 'form li'
    end
  end

  test 'input radio wraps items in a span tag by default' do
    with_input_for @user, :active, :radio_buttons

    assert_select 'form span input[type=radio]', count: 2
  end

  test 'input radio renders the item wrapper tag with a default class "radio"' do
    with_input_for @user, :active, :radio_buttons, item_wrapper_tag: :li

    assert_select 'form li.radio input[type=radio]', count: 2
  end

  test 'input radio renders the item wrapper tag with the configured item wrapper class' do
    swap SimpleForm, item_wrapper_tag: :li, item_wrapper_class: 'item' do
      with_input_for @user, :active, :radio_buttons

      assert_select 'form li.radio.item input[type=radio]', count: 2
    end
  end

  test 'input radio allows giving item wrapper class at input level only' do
    swap SimpleForm, item_wrapper_tag: :li do
      with_input_for @user, :active, :radio_buttons, item_wrapper_class: 'item'

      assert_select 'form li.radio.item input[type=radio]', count: 2
    end
  end

  test 'input radio uses both configured and given item wrapper classes for item wrapper tag' do
    swap SimpleForm, item_wrapper_tag: :li, item_wrapper_class: 'item' do
      with_input_for @user, :active, :radio_buttons, item_wrapper_class: 'inline'

      assert_select 'form li.radio.item.inline input[type=radio]', count: 2
    end
  end

  test 'input radio respects the nested boolean style config, generating nested label > input' do
    swap SimpleForm, boolean_style: :nested do
      with_input_for @user, :active, :radio_buttons

      assert_select 'span.radio > label > input#user_active_true[type=radio]'
      assert_select 'span.radio > label', 'Yes'
      assert_select 'span.radio > label > input#user_active_false[type=radio]'
      assert_select 'span.radio > label', 'No'
      assert_no_select 'label.collection_radio_buttons'
    end
  end

  test 'input radio with nested style does not overrides configured item wrapper tag' do
    swap SimpleForm, boolean_style: :nested, item_wrapper_tag: :li do
      with_input_for @user, :active, :radio_buttons

      assert_select 'li.radio > label > input'
    end
  end

  test 'input radio with nested style does not overrides given item wrapper tag' do
    swap SimpleForm, boolean_style: :nested do
      with_input_for @user, :active, :radio_buttons, item_wrapper_tag: :li

      assert_select 'li.radio > label > input'
    end
  end

  test 'input radio with nested style accepts giving extra wrapper classes' do
    swap SimpleForm, boolean_style: :nested do
      with_input_for @user, :active, :radio_buttons, item_wrapper_class: "inline"

      assert_select 'span.radio.inline > label > input'
    end
  end

  test 'input radio with nested style renders item labels with specified class' do
    swap SimpleForm, boolean_style: :nested do
      with_input_for @user, :active, :radio_buttons, item_label_class: "test"

      assert_select 'span.radio > label.test > input'
    end
  end

  test 'input radio with nested style and falsey input wrapper renders item labels with specified class' do
    swap SimpleForm, boolean_style: :nested, item_wrapper_tag: false do
      with_input_for @user, :active, :radio_buttons, item_label_class: "radio-inline"

      assert_select 'label.radio-inline > input'
      assert_no_select 'span.radio'
    end
  end

  test 'input radio wrapper class are not included when set to falsey' do
    swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do
      with_input_for @user, :gender, :radio_buttons, collection: %i[male female]

      assert_no_select 'label.radio'
    end
  end

  test 'input radio custom wrapper class is included when include input wrapper class is falsey' do
    swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do
      with_input_for @user, :gender, :radio_buttons, collection: %i[male female], item_wrapper_class: 'custom'

      assert_no_select 'label.radio'
      assert_select 'span.custom'
    end
  end

  test 'input radio with nested style and namespace uses the right for attribute' do
    swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do
      with_concat_form_for @user, namespace: :foo do |f|
        concat f.input :gender, as: :radio_buttons, collection: %i[male female]
      end

      assert_select 'label[for=foo_user_gender_male]'
      assert_select 'label[for=foo_user_gender_female]'
    end
  end

  test 'input radio with nested style and index uses the right for attribute' do
    swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do
      with_concat_form_for @user, index: 1 do |f|
        concat f.input :gender, as: :radio_buttons, collection: %i[male female]
      end

      assert_select 'label[for=user_1_gender_male]'
      assert_select 'label[for=user_1_gender_female]'
    end
  end

  test 'input radio with nested style accetps non-string attribute as label' do
    swap SimpleForm, boolean_style: :nested do
      with_input_for @user, :amount,
                            :radio_buttons,
                            collection: { 100 => 'hundred', 200 => 'two_hundred' },
                            label_method: :first,
                            value_method: :second

      assert_select 'input[type=radio][value=hundred]'
      assert_select 'input[type=radio][value=two_hundred]'
      assert_select 'span.radio > label', '100'
      assert_select 'span.radio > label', '200'
    end
  end

  test 'input check boxes with inline style support label custom classes' do
    swap SimpleForm, boolean_style: :inline do
      with_input_for @user, :gender, :radio_buttons, collection: %i[male female], item_label_class: 'beautiful-label'

      assert_select 'label.beautiful-label', count: 2
    end
  end
end