Files
sure/test/models/category_test.rb
ghost 01d7361477 fix(categories): avoid index N+1 queries (#2089)
* fix(categories): avoid index N+1 queries

Precompute category hierarchy groups and transaction membership for the categories settings index so the view no longer checks subcategories and transaction existence per rendered row.

Add a regression test for the query shape and stabilize a date-sensitive account statement coverage test that blocked the full suite on month-end-adjacent dates.

* fix(categories): preserve partial transaction fallback

Keep category list rendering compatible with callers that omit precomputed transaction membership data. Passing nil now lets the category row partial use its existing transaction existence fallback instead of forcing direct delete actions.

Add a view regression test for the fallback path.

* test(categories): cover parent deletion child transactions

* Bad merge confilict fix

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
2026-06-01 21:59:46 +02:00

81 lines
2.7 KiB
Ruby

require "test_helper"
class CategoryTest < ActiveSupport::TestCase
def setup
@family = families(:dylan_family)
end
test "replacing and destroying" do
transactions = categories(:food_and_drink).transactions.to_a
categories(:food_and_drink).replace_and_destroy!(categories(:income))
assert_equal categories(:income), transactions.map { |t| t.reload.category }.uniq.first
end
test "replacing with nil should nullify the category" do
transactions = categories(:food_and_drink).transactions.to_a
categories(:food_and_drink).replace_and_destroy!(nil)
assert_nil transactions.map { |t| t.reload.category }.uniq.first
end
test "destroying parent category preserves subcategory transaction assignments" do
parent = @family.categories.create!(
name: "Parent With Child Transactions",
color: "#000000",
lucide_icon: "folder"
)
subcategory = @family.categories.create!(
name: "Child With Transactions",
color: "#111111",
lucide_icon: "folder",
parent: parent
)
transaction = Transaction.create!(category: subcategory)
assert_difference "Category.count", -1 do
parent.destroy!
end
assert_nil subcategory.reload.parent_id
assert_equal subcategory, transaction.reload.category
end
test "subcategory can only be one level deep" do
category = categories(:subcategory)
error = assert_raises(ActiveRecord::RecordInvalid) do
category.subcategories.create!(name: "Invalid category", family: @family)
end
assert_equal "Validation failed: Parent can't have more than 2 levels of subcategories", error.message
end
test "all_investment_contributions_names returns all locale variants" do
names = Category.all_investment_contributions_names
assert_includes names, "Investment Contributions" # English
assert_includes names, "Contributions aux investissements" # French
assert_includes names, "Investeringsbijdragen" # Dutch
assert names.all? { |name| name.is_a?(String) }
assert_equal names, names.uniq # No duplicates
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