diff --git a/lib/govuk_elements_form_builder/form_builder.rb b/lib/govuk_elements_form_builder/form_builder.rb
index 751bfaf..865f74b 100644
--- a/lib/govuk_elements_form_builder/form_builder.rb
+++ b/lib/govuk_elements_form_builder/form_builder.rb
@@ -192,9 +192,8 @@ def form_group_id attribute
end
def form_group_classes attributes
- attributes = [attributes] if !attributes.respond_to? :count
classes = 'form-group'
- classes += ' error' if attributes.find { |a| error_for? a }
+ classes += ' error' if Array(attributes).find { |a| error_for? a }
classes
end
diff --git a/spec/lib/govuk_elements_form_builder/form_builder_spec.rb b/spec/lib/govuk_elements_form_builder/form_builder_spec.rb
index 6a254bd..f03d43f 100644
--- a/spec/lib/govuk_elements_form_builder/form_builder_spec.rb
+++ b/spec/lib/govuk_elements_form_builder/form_builder_spec.rb
@@ -13,7 +13,7 @@ class TestHelper < ActionView::Base; end
let(:helper) { TestHelper.new }
let(:resource) { Person.new }
- let(:builder) { described_class.new :person, resource, helper, {} }
+ subject(:builder) { described_class.new :person, resource, helper, {} }
def expect_equal output, expected
split_output = output.gsub(">\n", ' />').split("<").join("\n<").split(">").join(">\n").squeeze("\n").strip + '>'
@@ -30,76 +30,42 @@ def type_for(method, type)
end
shared_examples_for 'input field' do |method, type|
-
- def size(method, size)
- method == :text_area ? '' : %'size="#{size}" '
- end
+ let(:default_builder_options) { { resource: 'person' } }
it 'outputs label and input wrapped in div' do
output = builder.send method, :name
- expect_equal output, [
- '
',
- '',
- 'Full name',
- ' ',
- %'<#{element_for(method)} class="form-control" #{type_for(method, type)}name="person[name]" id="person_name" />',
- '
'
- ]
+ expect(output).to match_form_group(default_builder_options.merge(field: :name, input_type: method))
+ end
+
+ it 'supports attributes defined as a string' do
+ output = builder.send method, 'name'
+
+ expect(output).to match_form_group(default_builder_options.merge(field: :name, input_type: method))
end
it 'adds custom class to input when passed class: "custom-class"' do
output = builder.send method, :name, class: 'custom-class'
- expect_equal output, [
- '',
- '',
- 'Full name',
- ' ',
- %'<#{element_for(method)} class="form-control custom-class" #{type_for(method, type)}name="person[name]" id="person_name" />',
- '
'
- ]
+ expect(output).to match_form_group(default_builder_options.merge(field: :name, input_type: method, class: 'custom-class'))
end
it 'adds custom classes to input when passed class: ["custom-class", "another-class"]' do
output = builder.send method, :name, class: ['custom-class', 'another-class']
- expect_equal output, [
- '',
- '',
- 'Full name',
- ' ',
- %'<#{element_for(method)} class="form-control custom-class another-class" #{type_for(method, type)}name="person[name]" id="person_name" />',
- '
'
- ]
+ expect(output).to match_form_group(default_builder_options.merge(field: :name, input_type: method, class: 'custom-class another-class'))
end
it 'passes options passed to text_field onto super text_field implementation' do
output = builder.send method, :name, size: 100
- expect_equal output, [
- '',
- '',
- 'Full name',
- ' ',
- %'<#{element_for(method)} #{size(method, 100)}class="form-control" #{type_for(method, type)}name="person[name]" id="person_name" />',
- '
'
- ]
+
+ expect(output).to match_form_group(default_builder_options.merge(field: :name, input_type: method, size: 100))
end
context 'when hint text provided' do
it 'outputs hint text in span inside label' do
output = builder.send method, :ni_number
- expect_equal output, [
- '',
- '',
- 'National Insurance number',
- '',
- 'It’ll be on your last payslip. For example, JH 21 90 0A.',
- ' ',
- ' ',
- %'<#{element_for(method)} class="form-control" #{type_for(method, type)}name="person[ni_number]" id="person_ni_number" />',
- '
'
- ]
+ expect(output).to match_form_group(default_builder_options.merge(field: :ni_number, input_type: method))
end
end
@@ -108,14 +74,7 @@ def size(method, size)
output = builder.fields_for(:address, Address.new) do |f|
f.send method, :postcode
end
- expect_equal output, [
- '',
- '',
- 'Postcode',
- ' ',
- %'<#{element_for(method)} class="form-control" #{type_for(method, type)}name="person[address_attributes][postcode]" id="person_address_attributes_postcode" />',
- '
'
- ]
+ expect(output).to match_form_group(default_builder_options.merge(field: :postcode, input_type: method, fields_for: :address))
end
end
@@ -224,7 +183,7 @@ def expected_error_html method, type, attribute, name_value, label, error
end
describe '#text_area' do
- include_examples 'input field', :text_area, nil
+ include_examples 'input field', :text_area
end
describe '#email_field' do
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index 241a969..f271a2b 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -21,6 +21,7 @@
#
# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
require_relative 'support/translation_helper.rb'
+require_relative 'support/matcher_helpers.rb'
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
@@ -49,4 +50,5 @@
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
+ config.include MatcherHelpers
end
diff --git a/spec/support/matcher_helpers.rb b/spec/support/matcher_helpers.rb
new file mode 100644
index 0000000..ba561d8
--- /dev/null
+++ b/spec/support/matcher_helpers.rb
@@ -0,0 +1,7 @@
+require_relative 'matchers/form_group_matcher_helpers'
+
+module MatcherHelpers
+ def self.included(base)
+ base.send(:include, FormGroupMatcherHelpers)
+ end
+end
diff --git a/spec/support/matchers/form_group_matcher_helpers.rb b/spec/support/matchers/form_group_matcher_helpers.rb
new file mode 100644
index 0000000..405a6a9
--- /dev/null
+++ b/spec/support/matchers/form_group_matcher_helpers.rb
@@ -0,0 +1,115 @@
+require 'rspec/expectations'
+
+module FormGroupMatcherHelpers
+ extend RSpec::Matchers::DSL
+
+ class FormGroupObject
+ attr_reader :options, :resource, :field,
+ :label, :input_type, :input_class, :input_size,
+ :fields_for
+
+ def initialize(options)
+ @options = options
+ @resource = options[:resource]
+ @field = options.fetch(:field)
+ @label = options.fetch(:label) { @field.to_s.humanize }
+ @input_type = options.fetch(:input_type)
+ @input_class = options[:class]
+ @input_size = options[:size]
+ @fields_for = options[:fields_for]
+ end
+
+ def field_id
+ [resource, fields_for_attributes, field].compact.join('_')
+ end
+
+ def field_name
+ return "#{resource}[#{fields_for_attributes}][#{field}]" if resource && fields_for_attributes
+ return "#{resource}[#{field}]" if resource
+ field
+ end
+
+ def to_s
+ ['', label_tag, field_tag, '
'].join("\n")
+ end
+
+ private
+
+ def fields_for_attributes
+ return unless fields_for
+ "#{fields_for}_attributes"
+ end
+
+ def text_area_input?
+ input_type.to_s == 'text_area'
+ end
+
+ def input_tag
+ return '", ' />').split("<").join("\n<").split(">").join(">\n").squeeze("\n").strip + '>'
+ end
+
+ match do |actual|
+ formatted_actual(actual) == formatted_expected
+ end
+
+ failure_message do |actual|
+ "expected\n#{formatted_actual(actual)}\nto match\n#{formatted_expected}"
+ end
+ end
+end