From ab3c153328c578ad98703a62abb9c1e27398dd1b Mon Sep 17 00:00:00 2001 From: Jakob Skjerning Date: Sat, 23 Aug 2025 22:18:43 +0200 Subject: [PATCH 1/2] Verify that we render error messages --- test/components/input_field/file_test.rb | 16 ++++++++++++++++ test/components/input_field/password_test.rb | 16 ++++++++++++++++ test/components/input_field/url_test.rb | 16 ++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/test/components/input_field/file_test.rb b/test/components/input_field/file_test.rb index e9751c7..aff895d 100644 --- a/test/components/input_field/file_test.rb +++ b/test/components/input_field/file_test.rb @@ -66,4 +66,20 @@ def test_renders_enabled_file_by_default assert_no_selector("input[disabled]") end + + def test_renders_error_messages_when_in_error_state + @user.errors.add(:avatar, "file is too large") + @user.errors.add(:avatar, "must be an image") + + render_inline(Flowbite::InputField::File.new(form: @form, attribute: :avatar)) + + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "File is too large") + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "Must be an image") + end + + def test_does_not_render_error_messages_when_no_errors + render_inline(Flowbite::InputField::File.new(form: @form, attribute: :avatar)) + + assert_no_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500") + end end diff --git a/test/components/input_field/password_test.rb b/test/components/input_field/password_test.rb index bd6aa31..1ab270f 100644 --- a/test/components/input_field/password_test.rb +++ b/test/components/input_field/password_test.rb @@ -72,4 +72,20 @@ def test_renders_enabled_password_by_default assert_no_selector("input[disabled]") end + + def test_renders_error_messages_when_in_error_state + @user.errors.add(:password, "is too short") + @user.errors.add(:password, "must contain special characters") + + render_inline(Flowbite::InputField::Password.new(form: @form, attribute: :password)) + + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "Is too short") + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "Must contain special characters") + end + + def test_does_not_render_error_messages_when_no_errors + render_inline(Flowbite::InputField::Password.new(form: @form, attribute: :password)) + + assert_no_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500") + end end diff --git a/test/components/input_field/url_test.rb b/test/components/input_field/url_test.rb index 36de4c6..1b8f42c 100644 --- a/test/components/input_field/url_test.rb +++ b/test/components/input_field/url_test.rb @@ -66,4 +66,20 @@ def test_renders_enabled_url_by_default assert_no_selector("input[disabled]") end + + def test_renders_error_messages_when_in_error_state + @user.errors.add(:website_url, "is not a valid URL") + @user.errors.add(:website_url, "must start with http or https") + + render_inline(Flowbite::InputField::Url.new(form: @form, attribute: :website_url)) + + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "Is not a valid URL") + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "Must start with http or https") + end + + def test_does_not_render_error_messages_when_no_errors + render_inline(Flowbite::InputField::Url.new(form: @form, attribute: :website_url)) + + assert_no_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500") + end end From 3e540b1c95a308702a92e825f2c9b0d9562ceb82 Mon Sep 17 00:00:00 2001 From: Jakob Skjerning Date: Sat, 23 Aug 2025 22:24:38 +0200 Subject: [PATCH 2/2] Add error states to checkbox and radio buttons Now, this is outside the examples in Flowbite but for completeness sake we need this. --- app/components/flowbite/input/checkbox.rb | 4 ++-- app/components/flowbite/input/radio_button.rb | 4 ++-- test/components/input_field/checkbox_test.rb | 16 ++++++++++++++++ test/components/input_field/radio_button_test.rb | 16 ++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/app/components/flowbite/input/checkbox.rb b/app/components/flowbite/input/checkbox.rb index 669e285..7a64b13 100644 --- a/app/components/flowbite/input/checkbox.rb +++ b/app/components/flowbite/input/checkbox.rb @@ -22,8 +22,8 @@ def styles { default: Flowbite::Style.new( default: ["text-blue-600", "bg-gray-100", "border-gray-300", "rounded-sm", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"], - disabled: ["text-blue-600", "bg-gray-100", "border-gray-300", "rounded-sm", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"] - # TODO: error: ["bg-red-50", "border", "border-red-500", "text-red-900", "placeholder-red-700", "rounded-lg", "focus:ring-red-500", "dark:bg-gray-700", "focus:border-red-500", "block", "w-full", "dark:text-red-500", "dark:placeholder-red-500", "dark:border-red-500"] + disabled: ["text-blue-600", "bg-gray-100", "border-gray-300", "rounded-sm", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"], + error: ["text-red-600", "bg-red-50", "border-red-500", "rounded-sm", "focus:ring-red-500", "dark:focus:ring-red-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-red-500"] ) }.freeze end diff --git a/app/components/flowbite/input/radio_button.rb b/app/components/flowbite/input/radio_button.rb index 6bc0b90..a14c06e 100644 --- a/app/components/flowbite/input/radio_button.rb +++ b/app/components/flowbite/input/radio_button.rb @@ -20,8 +20,8 @@ def styles { default: Flowbite::Style.new( default: ["text-blue-600", "bg-gray-100", "border-gray-300", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"], - disabled: ["text-blue-600", "bg-gray-100", "border-gray-300", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"] - # TODO: error: ["bg-red-50", "border", "border-red-500", "text-red-900", "placeholder-red-700", "rounded-lg", "focus:ring-red-500", "dark:bg-gray-700", "focus:border-red-500", "block", "w-full", "dark:text-red-500", "dark:placeholder-red-500", "dark:border-red-500"] + disabled: ["text-blue-600", "bg-gray-100", "border-gray-300", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"], + error: ["text-red-600", "bg-red-50", "border-red-500", "focus:ring-red-500", "dark:focus:ring-red-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-red-500"] ) }.freeze end diff --git a/test/components/input_field/checkbox_test.rb b/test/components/input_field/checkbox_test.rb index 26ce23d..e1ac5e9 100644 --- a/test/components/input_field/checkbox_test.rb +++ b/test/components/input_field/checkbox_test.rb @@ -73,4 +73,20 @@ def test_renders_enabled_checkbox_by_default assert_no_selector("input[disabled]") end + + def test_renders_error_messages_when_in_error_state + @user.errors.add(:subscribed, "must be accepted") + @user.errors.add(:subscribed, "is required for notifications") + + render_inline(Flowbite::InputField::Checkbox.new(form: @form, attribute: :subscribed)) + + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "Must be accepted") + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "Is required for notifications") + end + + def test_does_not_render_error_messages_when_no_errors + render_inline(Flowbite::InputField::Checkbox.new(form: @form, attribute: :subscribed)) + + assert_no_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500") + end end diff --git a/test/components/input_field/radio_button_test.rb b/test/components/input_field/radio_button_test.rb index b57c9cf..15885c6 100644 --- a/test/components/input_field/radio_button_test.rb +++ b/test/components/input_field/radio_button_test.rb @@ -80,4 +80,20 @@ def test_renders_enabled_radio_by_default assert_no_selector("input[disabled]") end + + def test_renders_error_messages_when_in_error_state + @article.errors.add(:state, "is not a valid option") + @article.errors.add(:state, "must be selected") + + render_inline(Flowbite::InputField::RadioButton.new(form: @form, attribute: :state, value: "visible")) + + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "Is not a valid option") + assert_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500", text: "Must be selected") + end + + def test_does_not_render_error_messages_when_no_errors + render_inline(Flowbite::InputField::RadioButton.new(form: @form, attribute: :state, value: "visible")) + + assert_no_selector("p.mt-2.text-sm.text-red-600.dark\\:text-red-500") + end end