mirror of
https://github.com/we-promise/sure.git
synced 2026-04-20 04:24:06 +00:00
- Added server-side validation to Category model to enforce 6-digit hex format for colors. - Added HTML pattern attribute to category form for client-side validation. - Updated tests to cover validation and fixed existing tests using shorthand hex colors.
This commit is contained in:
@@ -9,6 +9,7 @@ class Category < ApplicationRecord
|
|||||||
belongs_to :parent, class_name: "Category", optional: true
|
belongs_to :parent, class_name: "Category", optional: true
|
||||||
|
|
||||||
validates :name, :color, :lucide_icon, :family, presence: true
|
validates :name, :color, :lucide_icon, :family, presence: true
|
||||||
|
validates :color, format: { with: /\A#[0-9A-Fa-f]{6}\z/ }
|
||||||
validates :name, uniqueness: { scope: :family_id }
|
validates :name, uniqueness: { scope: :family_id }
|
||||||
|
|
||||||
validate :category_level_limit
|
validate :category_level_limit
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<div class="flex gap-2 items-center hidden flex-col" data-category-target="paletteSection">
|
<div class="flex gap-2 items-center hidden flex-col" data-category-target="paletteSection">
|
||||||
<div class="flex gap-2 items-center w-full">
|
<div class="flex gap-2 items-center w-full">
|
||||||
<div class="w-6 h-6 p-4 rounded-full cursor-pointer" style="background-color: <%= category.color %>" data-category-target="colorPreview"></div>
|
<div class="w-6 h-6 p-4 rounded-full cursor-pointer" style="background-color: <%= category.color %>" data-category-target="colorPreview"></div>
|
||||||
<%= f.text_field :color , data: { category_target: "colorInput"}, inline: true %>
|
<%= f.text_field :color, data: { category_target: "colorInput" }, inline: true, pattern: "^#[0-9A-Fa-f]{6}$" %>
|
||||||
<%= icon "palette", size: "2xl", data: { action: "click->category#toggleSections" } %>
|
<%= icon "palette", size: "2xl", data: { action: "click->category#toggleSections" } %>
|
||||||
</div>
|
</div>
|
||||||
<div data-category-target="validationMessage" class="hidden self-start flex gap-1 items-center text-xs text-destructive ">
|
<div data-category-target="validationMessage" class="hidden self-start flex gap-1 items-center text-xs text-destructive ">
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ class BudgetTest < ActiveSupport::TestCase
|
|||||||
source_budget.update!(budgeted_spending: 4000, expected_income: 6000)
|
source_budget.update!(budgeted_spending: 4000, expected_income: 6000)
|
||||||
|
|
||||||
# Create a category only in the source budget
|
# Create a category only in the source budget
|
||||||
temp_category = Category.create!(name: "Temp #{Time.now.to_f}", family: family, color: "#aaa")
|
temp_category = Category.create!(name: "Temp #{Time.now.to_f}", family: family, color: "#aaaaaa")
|
||||||
source_budget.budget_categories.create!(category: temp_category, budgeted_spending: 100, currency: "USD")
|
source_budget.budget_categories.create!(category: temp_category, budgeted_spending: 100, currency: "USD")
|
||||||
|
|
||||||
target_budget = Budget.find_or_bootstrap(family, start_date: 1.month.ago)
|
target_budget = Budget.find_or_bootstrap(family, start_date: 1.month.ago)
|
||||||
@@ -283,7 +283,7 @@ class BudgetTest < ActiveSupport::TestCase
|
|||||||
target_budget = Budget.find_or_bootstrap(family, start_date: 1.month.ago)
|
target_budget = Budget.find_or_bootstrap(family, start_date: 1.month.ago)
|
||||||
|
|
||||||
# Add a new category only to the target
|
# Add a new category only to the target
|
||||||
new_category = Category.create!(name: "New #{Time.now.to_f}", family: family, color: "#bbb")
|
new_category = Category.create!(name: "New #{Time.now.to_f}", family: family, color: "#bbbbbb")
|
||||||
target_budget.budget_categories.create!(category: new_category, budgeted_spending: 0, currency: "USD")
|
target_budget.budget_categories.create!(category: new_category, budgeted_spending: 0, currency: "USD")
|
||||||
|
|
||||||
target_budget.copy_from!(source_budget)
|
target_budget.copy_from!(source_budget)
|
||||||
|
|||||||
@@ -40,4 +40,19 @@ class CategoryTest < ActiveSupport::TestCase
|
|||||||
assert names.all? { |name| name.is_a?(String) }
|
assert names.all? { |name| name.is_a?(String) }
|
||||||
assert_equal names, names.uniq # No duplicates
|
assert_equal names, names.uniq # No duplicates
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "should accept valid 6-digit hex colors" do
|
||||||
|
[ "#FFFFFF", "#000000", "#123456", "#ABCDEF", "#abcdef" ].each do |color|
|
||||||
|
category = Category.new(name: "Category #{color}", color: color, lucide_icon: "shapes", family: @family)
|
||||||
|
assert category.valid?, "#{color} should be valid"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should reject invalid colors" do
|
||||||
|
[ "invalid", "#123", "#1234567", "#GGGGGG", "red", "ffffff", "#ffff", "" ].each do |color|
|
||||||
|
category = Category.new(name: "Category #{color}", color: color, lucide_icon: "shapes", family: @family)
|
||||||
|
assert_not category.valid?, "#{color} should be invalid"
|
||||||
|
assert_includes category.errors[:color], "is invalid"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user