From 83f551c94d66b0eb93a41b40a9755ca15da2fc07 Mon Sep 17 00:00:00 2001 From: Anule Ndukwu Date: Tue, 1 Sep 2020 13:30:12 -0700 Subject: [PATCH] Add base Form Builder from CMR v2 Includes Form Builder and specs from https://github.com/codeforamerica/illinois_petition_service/blob/master/app/helpers/cmr_v2_form_builder.rb. Still to go: - Decide if we want to require label and legend text in method signatures - Add missing methods for Honeycrisp v1 FormBuilder (possibly: checkbox_set, checkbox_set_with_none, range_field, textarea, single_tap_button) - Bring over dense form styles - Bring over supporting files for new date input (validations, multipart form file) Co-authored-by: Christa Hartsock --- .../cfa/styleguide/cfa_v2_form_builder.rb | 261 ++++++++ spec/helpers/cfa_v2_form_builder_spec.rb | 562 ++++++++++++++++++ 2 files changed, 823 insertions(+) create mode 100644 app/helpers/cfa/styleguide/cfa_v2_form_builder.rb create mode 100644 spec/helpers/cfa_v2_form_builder_spec.rb diff --git a/app/helpers/cfa/styleguide/cfa_v2_form_builder.rb b/app/helpers/cfa/styleguide/cfa_v2_form_builder.rb new file mode 100644 index 00000000..83e9a7b5 --- /dev/null +++ b/app/helpers/cfa/styleguide/cfa_v2_form_builder.rb @@ -0,0 +1,261 @@ +module Cfa + module Styleguide + class CfaV2FormBuilder < ActionView::Helpers::FormBuilder + def cfa_text_input(method, + label_text = nil, + required: false, + help_text: nil, + wrapper_classes: [], + options: {}) + input_options = required ? options.merge({ 'aria-required': true }) : options + + if help_text.present? + help_text_id = help_text_id(method) + input_options = append_to_value(input_options, :'aria-describedby', help_text_id) + help_text_html = help_text_html(help_text, help_text_id) + end + + if object.errors[method].any? + wrapper_classes.push("form-group--error") + error_id = error_id(method) + input_options = append_to_value(input_options, :'aria-describedby', error_id) + error_html = errors_for(object, method, error_id) + end + + <<~HTML.html_safe +
+
+ #{label(method, label_text)} #{optional_html unless required} +
+ #{help_text_html} + #{text_field(method, input_options)} + #{error_html} +
+ HTML + end + + def cfa_button(label_text = nil, options: {}) + full_options = { + class: "cfa-button button button--primary", + }.merge(options) + + button(label_text, full_options) + end + + def cfa_radio(method, label_text, value, wrapper_classes: [], options: {}) + <<~HTML.html_safe + + HTML + end + + def cfa_radiogroup(method, legend_text = nil, wrapper_classes: [], options: {}, &block) + field_set_options = {} + if object.errors[method].any? + error_id = error_id(method) + field_set_options = append_to_value(field_set_options, :'aria-describedby', error_id) + end + + @template.tag.div({ class: "cfa-radiogroup #{wrapper_classes.join(' ')}" }) do + @template.field_set_tag(legend_text, field_set_options) do + @template.tag.radiogroup(options) do + output_html = "" + output_html.concat(@template.capture(&block)) + output_html.concat(errors_for(object, method, error_id)) if object.errors[method].any? + output_html.html_safe + end + end + end + end + + def cfa_select( + method, + label_text, + choices, + required: false, + wrapper_classes: [], + options: {}, + html_options: {}, + &block + ) + + if object.errors[method].any? + wrapper_classes.push("form-group--error") + error_id = error_id(method) + error_html = errors_for(object, method, error_id) + html_options = append_to_value(html_options, :'aria-describedby', error_id) + end + + if required + html_options[:'aria-required'] = true + end + + html_output = <<~HTML +
+
+ #{label(method, label_text)} #{optional_html unless required} +
+
+ #{select(method, choices, options, html_options, &block)} +
+ #{error_html} +
+ HTML + + html_output.html_safe + end + + def cfa_date_input(method, + label_text, + required: false, + help_text: nil, + wrapper_classes: [], + options: {}) + + base_options = append_to_value(options, :class, "text-input date-input").merge(type: "number") + base_options[:'aria-required'] = true if required + + helper_text_array = help_text ? help_text.split("/") : ["MM", "DD", "YYYY"] + help_text_id = help_text_id(method) + field_set_options = {} + + if object.errors[method].any? + wrapper_classes.push("form-group--error") + error_id = error_id(method) + error_html = errors_for(object, method, error_id) + base_options = append_to_value(base_options, :'aria-describedby', error_id) + field_set_options = append_to_value(field_set_options, :'aria-describedby', error_id) + end + + month_field = text_field(method, base_options.merge( + value: object.send(method) ? object.send(method).month : nil, + id: "#{object_name}_#{method}_2i", + name: "#{object_name}[#{method}(2i)]", + "aria-label": "Month #{helper_text_array[0]}", + size: 2, + placeholder: helper_text_array[0], + ).merge(append_to_value(base_options, :class, "form-width--month"))) + + day_field = text_field(method, base_options.merge( + value: object.send(method) ? object.send(method).day : nil, + id: "#{object_name}_#{method}_3i", + name: "#{object_name}[#{method}(3i)]", + "aria-label": "Day #{helper_text_array[1]}", + size: 2, + placeholder: helper_text_array[1], + ).merge(append_to_value(base_options, :class, "form-width--day"))) + + year_field = text_field(method, base_options.merge( + value: object.send(method) ? object.send(method).year : nil, + id: "#{object_name}_#{method}_1i", + name: "#{object_name}[#{method}(1i)]", + "aria-label": "Year #{helper_text_array[2]}", + size: 4, + placeholder: helper_text_array[2], + ).merge(append_to_value(base_options, :class, "form-width--year"))) + + @template.tag.div({ class: "cfa-date-input form-group #{wrapper_classes.join(' ')}" }) do + @template.tag.fieldset(field_set_options) do + <<~HTML.html_safe + #{@template.tag.legend(label_text, 'aria-describedby': help_text_id)} + #{help_text_html(helper_text_array.join('/'), help_text_id)} +
+
+ #{month_field} +
+
/
+
+ #{day_field} +
+
/
+
+ #{year_field} +
+
+ #{error_html} + HTML + end + end + end + + def cfa_checkbox(method, + label_text, + checked_value = "1", + unchecked_value = "0", + wrapper_classes: [], + options: {}) + + if object.errors[method].any? + wrapper_classes.push("form-group--error") + error_id = error_id(method) + options = append_to_value(options, :'aria-describedby', error_id) + error_html = errors_for(object, method, error_id) + end + + label_classes = ["checkbox"] + + if options[:disabled] + label_classes.push("is-disabled") + end + + @template.tag.div({ class: "cfa-checkbox form-group input-group #{wrapper_classes.join(' ')}" }) do + <<~HTML.html_safe + + #{error_html} + HTML + end + end + + private + + def help_text_html(help_text, help_text_id) + <<~HTML +
+ #{help_text} +
+ HTML + end + + def optional_html + <<~HTML +
+ (Optional) + HTML + end + + def errors_for(object, method, error_id) + errors = object.errors[method] + <<~HTML +
+ + #{errors.join(', ')} +
+ HTML + end + + def append_to_value(input_options, key, appending_value) + initial_value = input_options[key] + new_value = [initial_value, appending_value].compact.join(" ") + input_options.merge({ key => new_value }) + end + + def help_text_id(method) + "#{sanitized_id(method)}__help-text" + end + + def error_id(method) + "#{sanitized_id(method)}__errors" + end + + def sanitized_id(method, position = nil) + name = object_name.to_s.gsub(/([\[\(])|(\]\[)/, "_").gsub(/[\]\)]/, "") + + position ? "#{name}_#{method}_#{position}" : "#{name}_#{method}" + end + end + end +end diff --git a/spec/helpers/cfa_v2_form_builder_spec.rb b/spec/helpers/cfa_v2_form_builder_spec.rb new file mode 100644 index 00000000..0ae084f6 --- /dev/null +++ b/spec/helpers/cfa_v2_form_builder_spec.rb @@ -0,0 +1,562 @@ +require "spec_helper" +require "erb" + +describe Cfa::Styleguide::CfaV2FormBuilder, type: :view do + let(:template) do + template = OpenStruct.new(output_buffer: "") + template.extend ActionView::Helpers::FormHelper + template.extend ActionView::Helpers::FormTagHelper + template.extend ActionView::Helpers::FormOptionsHelper + template.extend ActionView::Helpers::DateHelper + end + + class FakeModel < Cfa::Styleguide::FormExample; end + + let(:fake_model) do + FakeModel.new + end + + let(:form_builder) { Cfa::Styleguide::CfaV2FormBuilder.new("fake_model", fake_model, template, {}) } + + describe ".cfa_button" do + let(:output) do + form_builder.cfa_button("my button") + end + + it "renders a button with valid HTML" do + expect(output).to be_html_safe + end + + it "includes an identifying class on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("cfa-button") + end + + context "when options provided" do + let(:output) do + form_builder.cfa_button("my button", options: { data: { "disable-with": "Searching..." } }) + end + + it "passes options to the button" do + html_component = Nokogiri::HTML.fragment(output).at_css(".cfa-button") + expect(html_component.text).to_not include("Searching...") + end + end + end + + describe ".cfa_text_input" do + let(:output) do + form_builder.cfa_text_input(:example_method_with_validation) + end + + it "renders a text input with valid HTML" do + expect(output).to be_html_safe + end + + it "includes an identifying class on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("cfa-text-input") + end + + it "falls back to the defaults used by the Rails form label" do + label = Nokogiri::HTML.fragment(output).at_css("label") + expect(label.text).to eq("Example method with validation") + end + + context "when options provided" do + let(:output) do + form_builder.cfa_text_input(:example_method_with_validation, options: { + placeholder: "my text", + disabled: true, + }) + end + + it "passes options to the input" do + input_html = Nokogiri::HTML.fragment(output).at_css("input") + expect(input_html.get_attribute("disabled")).to be_truthy + expect(input_html.get_attribute("placeholder")).to eq("my text") + end + end + + context "label_text is provided" do + it "uses the provided label text" do + output = form_builder.cfa_text_input(:example_method_with_validation, "My method name") + + label = Nokogiri::HTML.fragment(output).at_css("label") + expect(label.text).to eq("My method name") + end + end + + context "errors" do + let(:output) do + form_builder.cfa_text_input(:example_method_with_validation, options: { + 'aria-describedby': "another-id", + }) + end + + before do + fake_model.validate + end + + it "associates form errors with input and appends error id to existing aria-describedby attributes" do + input_html = Nokogiri::HTML.fragment(output).at_css("input") + error_text_html = Nokogiri::HTML.fragment(output).at_css(".text--error") + expect(input_html.get_attribute("aria-describedby")).to include("another-id") + expect(input_html.get_attribute("aria-describedby")).to include(error_text_html.get_attribute("id")) + end + end + + context "wrapper_classes provided" do + let(:output) do + form_builder.cfa_text_input( + :example_method_with_validation, + wrapper_classes: ["wrapper-class"], + ) + end + + it "assigns wrapper classes on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("wrapper-class") + end + end + + context "required is true" do + let(:output) do + form_builder.cfa_text_input( + :example_method_with_validation, + required: true, + ) + end + + it "does not append the optional text after the label" do + html_component = Nokogiri::HTML.fragment(output).at_css(".form-question") + expect(html_component.text).to_not include("(Optional)") + end + + it "sets the aria-required attribute on the select tag" do + input_html = Nokogiri::HTML.fragment(output).at_css("input") + expect(input_html.get_attribute("aria-required")).to be_truthy + end + end + + context "help text is provided" do + let(:output) do + form_builder.cfa_text_input(:example_method_with_validation, help_text: "Found on RAP sheet") + end + + it "displays the help text" do + help_text_html = Nokogiri::HTML.fragment(output).at_css(".text--help") + expect(help_text_html.text).to eq("\n Found on RAP sheet\n") + end + + it "associates the help text with the input" do + input_html = Nokogiri::HTML.fragment(output).at_css("input") + help_text_html = Nokogiri::HTML.fragment(output).at_css(".text--help") + help_id = help_text_html.get_attribute("id") + expect(input_html.get_attribute("aria-describedby")).to include(help_id) + end + end + end + + describe ".cfa_radio" do + let(:output) do + form_builder.cfa_radio(:example_method_with_validation, "Truthy value", "true") + end + + it "renders a radio buttons with valid HTML" do + expect(output).to be_html_safe + end + + it "includes an identifying class on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("cfa-radio") + end + + context "when options provided" do + let(:output) do + form_builder.cfa_radio(:example_method_with_validation, + "Truthy value", + "true", + options: { 'data-follow-up': "#follow-up-question" }) + end + + it "passes options to the radio button" do + input_html = Nokogiri::HTML.fragment(output).at_css("input") + expect(input_html.get_attribute("data-follow-up")).to eq("#follow-up-question") + end + end + + context "wrapper_classes provided" do + let(:output) do + form_builder.cfa_radio(:example_method_with_validation, + "Truthy value", + "true", + wrapper_classes: ["wrapper-class"]) + end + + it "assigns wrapper classes on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("wrapper-class") + end + end + end + + describe ".cfa_radiogroup" do + let(:output) do + form_builder.cfa_radiogroup(:example_method_with_validation, "Radio group") do + ERB.new( + "<%= form_builder.cfa_radio(:example_method_with_validation, 'First option', :first_option) %> + <%= form_builder.cfa_radio(:example_method_with_validation, 'Second option', :second_option) %>", + ).result(binding).html_safe + end + end + + it "renders a radio group with valid HTML" do + expect(output).to be_html_safe + end + + it "renders all items in passed block" do + html_component = Nokogiri::HTML.fragment(output).css(".cfa-radio") + expect(html_component.count).to eq 2 + end + + it "includes an identifying class on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("cfa-radiogroup") + end + + it "displays a legend" do + legend = Nokogiri::HTML.fragment(output).at_css("legend") + expect(legend.text).to include "Radio group" + end + + context "when options provided" do + let(:output) do + form_builder.cfa_radiogroup(:example_method_with_validation, "Radio group", options: { 'data-option': "some-value" }) do + ERB.new( + "<%= form_builder.cfa_radio(:example_method_with_validation, 'First option', :first_option) %> + <%= form_builder.cfa_radio(:example_method_with_validation, 'Second option', :second_option) %>", + ).result(binding).html_safe + end + end + + it "passes options to the radiogroup" do + radiogroup_html = Nokogiri::HTML.fragment(output).at_css("radiogroup") + expect(radiogroup_html.get_attribute("data-option")).to eq("some-value") + end + end + + context "errors" do + before do + fake_model.validate + end + + it "should associate form errors with fieldset" do + fieldset_html = Nokogiri::HTML.fragment(output).at_css("fieldset") + error_text_html = Nokogiri::HTML.fragment(output).at_css(".text--error") + expect(fieldset_html.get_attribute("aria-describedby")).to eq(error_text_html.get_attribute("id")) + end + end + + context "wrapper_classes provided" do + let(:output) do + form_builder.cfa_radiogroup(:example_method_with_validation, "Radio group", wrapper_classes: ["wrapper-class"]) do + ERB.new( + "<%= form_builder.cfa_radio(:example_method_with_validation, 'First option', :first_option) %> + <%= form_builder.cfa_radio(:example_method_with_validation, 'Second option', :second_option) %>", + ).result(binding).html_safe + end + end + + it "assigns wrapper classes on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("wrapper-class") + end + end + end + + describe ".cfa_select" do + let(:select_options) { ["thing one", "thing two"] } + + let(:output) do + form_builder.cfa_select(:example_method_with_validation, "My select value", select_options) + end + + it "renders a text input with valid HTML" do + expect(output).to be_html_safe + end + + it "includes an identifying class on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("cfa-select") + end + + it "by default appends optional text after the label" do + html_component = Nokogiri::HTML.fragment(output).at_css(".form-question") + expect(html_component.text).to include("(Optional)") + end + + it "includes label with provided text" do + label = Nokogiri::HTML.fragment(output).at_css("label") + expect(label.text).to eq("My select value") + end + + context "when options provided" do + let(:output) do + form_builder.cfa_select( + :example_method_with_validation, "My select value", select_options, options: { include_blank: "Choose an option" } + ) + end + + it "passes options to the select" do + first_option_html = Nokogiri::HTML.fragment(output).at_css("option") + expect(first_option_html.text).to eq("Choose an option") + expect(first_option_html.get_attribute("value")).to eq("") + end + end + + context "when html options provided" do + let(:output) do + form_builder.cfa_select(:example_method_with_validation, "My select value", select_options, html_options: { disabled: true }) + end + + it "passes html_options to the select" do + select_html = Nokogiri::HTML.fragment(output).at_css("select") + expect(select_html.get_attribute("disabled")).to be_truthy + end + end + + context "errors" do + before do + fake_model.validate + end + + let(:output) do + form_builder.cfa_select(:example_method_with_validation, "My select value", select_options, html_options: { 'aria-describedby': "another-id" }) + end + + it "should associate form errors with input and append error id to existing aria-describedby attributes" do + select_html = Nokogiri::HTML.fragment(output).at_css("select") + error_text_html = Nokogiri::HTML.fragment(output).at_css(".text--error") + expect(select_html.get_attribute("aria-describedby")).to include("another-id") + expect(select_html.get_attribute("aria-describedby")).to include(error_text_html.get_attribute("id")) + end + end + + context "wrapper_classes provided" do + let(:output) do + form_builder.cfa_select(:example_method_with_validation, "My select value", select_options, wrapper_classes: ["wrapper-class"]) + end + + it "assigns wrapper classes on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("wrapper-class") + end + end + + context "required is true" do + let(:output) do + form_builder.cfa_select(:example_method_with_validation, "My select value", select_options, required: true) + end + + it "does not append the optional text after the label" do + html_component = Nokogiri::HTML.fragment(output).at_css(".form-question") + expect(html_component.text).to_not include("(Optional)") + end + + it "sets the aria-required attribute on the select tag" do + select_html = Nokogiri::HTML.fragment(output).at_css("select") + expect(select_html.get_attribute("aria-required")).to be_truthy + end + end + end + + describe ".cfa_date_input" do + let(:output) do + form_builder.cfa_date_input(:example_method_with_validation, "Date case was filed") + end + + it "renders a text input with valid HTML" do + expect(output).to be_html_safe + end + + it "includes an identifying class on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("cfa-date-input") + end + + it "sets legend inside the fieldset" do + legend = Nokogiri::HTML.fragment(output).at_css("legend") + expect(legend.text).to eq("Date case was filed") + end + + it "uses default help text" do + month_input = Nokogiri::HTML.fragment(output).at_css(".form-width--month") + day_input = Nokogiri::HTML.fragment(output).at_css(".form-width--day") + year_input = Nokogiri::HTML.fragment(output).at_css(".form-width--year") + + expect(month_input.get_attribute("placeholder")).to eq("MM") + expect(day_input.get_attribute("placeholder")).to eq("DD") + expect(year_input.get_attribute("placeholder")).to eq("YYYY") + end + + context "when options provided" do + let(:output) do + form_builder.cfa_date_input(:example_method_with_validation, "Date case was filed", options: { class: "some-class" }) + end + + it "passes options to each of the inputs" do + month_input = Nokogiri::HTML.fragment(output).at_css(".form-width--month") + day_input = Nokogiri::HTML.fragment(output).at_css(".form-width--day") + year_input = Nokogiri::HTML.fragment(output).at_css(".form-width--year") + expect(month_input.classes).to include "some-class" + expect(day_input.classes).to include "some-class" + expect(year_input.classes).to include "some-class" + end + end + + context "errors" do + let(:output) do + form_builder.cfa_date_input(:example_method_with_validation, "Date case was filed", options: { 'aria-describedby': "another-id" }) + end + + before do + fake_model.validate + end + + it "associates form errors with each input and appends error id to existing aria-describedby attributes" do + month_input = Nokogiri::HTML.fragment(output).at_css(".form-width--month") + day_input = Nokogiri::HTML.fragment(output).at_css(".form-width--day") + year_input = Nokogiri::HTML.fragment(output).at_css(".form-width--year") + error_text_html = Nokogiri::HTML.fragment(output).at_css(".text--error") + error_id = error_text_html.get_attribute("id") + expect(month_input.get_attribute("aria-describedby")).to include(error_id) + expect(month_input.get_attribute("aria-describedby")).to include("another-id") + expect(day_input.get_attribute("aria-describedby")).to include(error_id) + expect(day_input.get_attribute("aria-describedby")).to include("another-id") + expect(year_input.get_attribute("aria-describedby")).to include(error_id) + expect(year_input.get_attribute("aria-describedby")).to include("another-id") + end + end + + context "wrapper_classes provided" do + let(:output) do + form_builder.cfa_date_input(:example_method_with_validation, "Date case was filed", wrapper_classes: ["wrapper-class"]) + end + + it "assigns wrapper classes on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("wrapper-class") + end + end + + context "required is true" do + let(:output) do + form_builder.cfa_date_input(:example_method_with_validation, "Date case was filed", required: true) + end + + it "sets the aria-required attribute on the select tag" do + month_input = Nokogiri::HTML.fragment(output).at_css(".form-width--month") + day_input = Nokogiri::HTML.fragment(output).at_css(".form-width--day") + year_input = Nokogiri::HTML.fragment(output).at_css(".form-width--year") + + expect(month_input.get_attribute("aria-required")).to be_truthy + expect(day_input.get_attribute("aria-required")).to be_truthy + expect(year_input.get_attribute("aria-required")).to be_truthy + end + end + + context "help text is provided" do + let(:output) do + form_builder.cfa_date_input(:example_method_with_validation, "Date case was filed", help_text: "month/day/year") + end + + it "splits the help text and displays it in the inputs as placeholder text" do + month_input = Nokogiri::HTML.fragment(output).at_css(".form-width--month") + day_input = Nokogiri::HTML.fragment(output).at_css(".form-width--day") + year_input = Nokogiri::HTML.fragment(output).at_css(".form-width--year") + + expect(month_input.get_attribute("placeholder")).to eq("month") + expect(day_input.get_attribute("placeholder")).to eq("day") + expect(year_input.get_attribute("placeholder")).to eq("year") + end + end + end + + describe ".cfa_checkbox" do + let(:output) { form_builder.cfa_checkbox(:example_method_with_validation, "Checkbox stuff") } + + it "renders a text input with valid HTML" do + expect(output).to be_html_safe + end + + it "includes an identifying class on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("cfa-checkbox") + end + + context "options are provided" do + let(:output) do + form_builder.cfa_checkbox(:example_method_with_validation, "Checkbox stuff", options: { disabled: true, 'data-some-attribute': "some-value" }) + end + + it "passes options to the checkbox" do + checkbox_html = Nokogiri::HTML.fragment(output).at_css("input[type='checkbox']") + expect(checkbox_html.get_attribute("disabled")).to be_truthy + expect(checkbox_html.get_attribute("data-some-attribute")).to eq("some-value") + end + end + + context "errors" do + let(:output) do + form_builder.cfa_checkbox(:example_method_with_validation, "Checkbox stuff", options: { 'aria-describedby': "another-id" }) + end + + before do + fake_model.validate + end + + it "associates form errors with input and appends error id to existing aria-describedby attributes" do + checkbox_html = Nokogiri::HTML.fragment(output).at_css("input[type='checkbox']") + error_text_html = Nokogiri::HTML.fragment(output).at_css(".text--error") + expect(checkbox_html.get_attribute("aria-describedby")).to include("another-id") + expect(checkbox_html.get_attribute("aria-describedby")).to include(error_text_html.get_attribute("id")) + end + end + + context "wrapper_classes provided" do + let(:output) do + form_builder.cfa_checkbox(:example_method_with_validation, "Checkbox stuff", wrapper_classes: ["wrapper-class"]) + end + + it "assigns wrapper classes on the containing element" do + html_component = Nokogiri::HTML.fragment(output).child + expect(html_component.classes).to include("wrapper-class") + end + end + + context "when disabled" do + let(:output) do + form_builder.cfa_checkbox(:example_method_with_validation, "Checkbox stuff", options: { disabled: true }) + end + + it "adds the correct class to the label" do + label_html = Nokogiri::HTML.fragment(output).at_css("label") + expect(label_html.classes).to include("is-disabled") + end + end + + context "checked and unchecked value" do + let(:output) do + form_builder.cfa_checkbox(:example_method_with_validation, "Checkbox stuff", "yes", "no") + end + + it "uses the values in the generated inputs" do + hidden_input = Nokogiri::HTML.fragment(output).at_css("input[type='hidden']") + visible_input = Nokogiri::HTML.fragment(output).at_css("input[type='checkbox']") + expect(hidden_input.get_attribute("value")).to eq "no" + expect(visible_input.get_attribute("value")).to eq "yes" + end + end + end +end