DFE-Digital/govuk-formbuilder

View on GitHub
spec/support/shared/shared_text_field_examples.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
shared_examples 'a regular input' do |method_identifier, field_type|
  let(:attribute) { :name }
  let(:label_text) { 'Full name' }
  let(:hint_text) { 'It says it on your passport' }
  let(:method) { "govuk_#{method_identifier}_field".to_sym }
  let(:args) { [method, attribute] }
  subject { builder.send(*args, label: { text: label_text }) }

  specify "output should have the correct type of #{field_type}" do
    expect(subject).to have_tag('input', with: { type: field_type })
  end

  specify 'output should be form group containing a label and input' do
    expect(subject).to have_tag('div', with: { class: 'govuk-form-group' }) do
      with_tag('label', text: label_text)
      with_tag('input')
    end
  end

  let(:field_type) { 'input' }
  let(:aria_described_by_target) { 'input' }

  include_examples 'HTML formatting checks'

  it_behaves_like 'a field that supports labels'
  it_behaves_like 'a field that supports labels as procs'
  it_behaves_like 'a field that supports captions on the label'
  it_behaves_like 'a field that supports hints'
  it_behaves_like 'a field that supports custom branding'
  it_behaves_like 'a field that contains a customisable form group'

  it_behaves_like 'a field that accepts arbitrary blocks of HTML' do
    let(:described_element) { 'input' }
  end

  it_behaves_like 'a field that supports errors' do
    let(:object) { Person.new(name: nil) }

    let(:error_message) { /Enter a name/ }
    let(:error_class) { 'govuk-input--error' }
    let(:error_identifier) { 'person-name-error' }
  end

  it_behaves_like 'a field that supports setting the label via localisation'
  it_behaves_like 'a field that supports setting the label caption via localisation'
  it_behaves_like 'a field that supports setting the hint via localisation'

  it_behaves_like 'a field that accepts a plain ruby object' do
    let(:described_element) { 'input' }
  end

  it_behaves_like 'a field that allows extra HTML attributes to be set' do
    let(:described_element) { 'input' }
    let(:expected_class) { 'govuk-input' }
  end

  it_behaves_like 'a field that allows nested HTML attributes to be set' do
    let(:described_element) { 'input' }
    let(:expected_class) { 'govuk-input' }
  end

  describe 'width' do
    context 'custom widths' do
      {
        20               => 'govuk-input--width-20',
        10               => 'govuk-input--width-10',
        5                => 'govuk-input--width-5',
        4                => 'govuk-input--width-4',
        3                => 'govuk-input--width-3',
        2                => 'govuk-input--width-2',
        'full'           => 'govuk-!-width-full',
        'three-quarters' => 'govuk-!-width-three-quarters',
        'two-thirds'     => 'govuk-!-width-two-thirds',
        'one-half'       => 'govuk-!-width-one-half',
        'one-third'      => 'govuk-!-width-one-third',
        'one-quarter'    => 'govuk-!-width-one-quarter'
      }.each do |identifier, width_class|
        context "when the width is #{identifier}" do
          let(:identifier) { identifier }
          let(:width_class) { width_class }
          subject { builder.send(*args, width: identifier) }

          specify "should have the correct class of #{width_class}" do
            expect(parsed_subject.at_css('input')['class']).to include(width_class)
          end
        end
      end
    end

    context 'invalid widths' do
      let(:invalid_width) { 'extra-medium' }
      subject { builder.send(method, :name, width: invalid_width) }

      specify 'invalid widths should fail' do
        expect { subject }.to raise_error(ArgumentError, /invalid width/)
      end
    end
  end

  describe 'extra letter spacing' do
    subject { builder.send(method, :name, extra_letter_spacing: true) }

    specify 'has extra letter spacing class on the input element' do
      expect(subject).to have_tag('input', with: { class: 'govuk-input--extra-letter-spacing' })
    end

    context 'when false' do
      subject { builder.send(method, :name, extra_letter_spacing: false) }

      specify 'no element with the class is rendered' do
        expect(subject).not_to have_tag('.govuk-input--extra-letter-spacing')
      end
    end
  end

  describe 'affixes' do
    let(:prefix_text) { '£' }
    let(:suffix_text) { 'per item' }

    shared_examples 'prefixes' do
      specify 'the wrapper and prefix should be present' do
        expect(subject).to have_tag('div', with: { class: 'govuk-form-group' }) do
          with_tag('div', with: { class: 'govuk-input__wrapper' }) do
            with_tag('span', with: { class: 'govuk-input__prefix', 'aria-hidden': true }, text: prefix_text)
            with_tag('input')
          end
        end
      end
    end

    shared_examples 'suffixes' do
      specify 'the wrapper and suffix should be present' do
        expect(subject).to have_tag('div', with: { class: 'govuk-form-group' }) do
          with_tag('div', with: { class: 'govuk-input__wrapper' }) do
            with_tag('span', with: { class: 'govuk-input__suffix', 'aria-hidden': true }, text: suffix_text)
            with_tag('input')
          end
        end
      end
    end

    shared_examples 'no prefix' do
      specify 'prefix should not be present' do
        expect(subject).not_to have_tag('span', with: { class: 'govuk-input__prefix' })
        expect(subject).to have_tag('input')
      end
    end

    shared_examples 'no suffix' do
      specify 'suffix should not be present' do
        expect(subject).not_to have_tag('span', with: { class: 'govuk-input__suffix' })
        expect(subject).to have_tag('input')
      end
    end

    context 'when a prefix is supplied' do
      subject { builder.send(*args, prefix_text:) }

      include_examples 'prefixes'
      include_examples 'no suffix'
    end

    context 'when a suffix is supplied' do
      subject { builder.send(*args, suffix_text:) }

      include_examples 'suffixes'
      include_examples 'no prefix'
    end

    context 'when both a prefix and suffix are supplied' do
      subject { builder.send(*args, prefix_text:, suffix_text:) }

      include_examples 'prefixes'
      include_examples 'suffixes'
    end

    context 'when neither a prefix or suffix is supplied' do
      subject { builder.send(*args) }

      include_examples 'no prefix'
      include_examples 'no suffix'
    end
  end
end