mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 14:31:25 +00:00
* fix: locale-dependent category duplication bug * fix: use family locale for investment contributions category to prevent duplicates and handle legacy data * Remove v* tag trigger from flutter-build to fix double-runs publish.yml already calls flutter-build via workflow_call on v* tags, so the direct push trigger was causing duplicate workflow runs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Refactor mobile release asset flow * fix: category uniqueness and workflow issues * fix: fix test issue * fix: solve test issue * fix: resolve legacy problem * fix: solve lint test issue * fix: revert unrelated changes --------- Co-authored-by: Juan José Mata <juanjo.mata@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
210 lines
7.4 KiB
Ruby
210 lines
7.4 KiB
Ruby
require "test_helper"
|
|
|
|
class FamilyTest < ActiveSupport::TestCase
|
|
include SyncableInterfaceTest
|
|
|
|
def setup
|
|
@syncable = families(:dylan_family)
|
|
end
|
|
|
|
test "investment_contributions_category creates category when missing" do
|
|
family = families(:dylan_family)
|
|
family.categories.where(name: Category.investment_contributions_name).destroy_all
|
|
|
|
assert_nil family.categories.find_by(name: Category.investment_contributions_name)
|
|
|
|
category = family.investment_contributions_category
|
|
|
|
assert category.persisted?
|
|
assert_equal Category.investment_contributions_name, category.name
|
|
assert_equal "#0d9488", category.color
|
|
assert_equal "expense", category.classification
|
|
assert_equal "trending-up", category.lucide_icon
|
|
end
|
|
|
|
test "investment_contributions_category returns existing category" do
|
|
family = families(:dylan_family)
|
|
existing = family.categories.find_or_create_by!(name: Category.investment_contributions_name) do |c|
|
|
c.color = "#0d9488"
|
|
c.classification = "expense"
|
|
c.lucide_icon = "trending-up"
|
|
end
|
|
|
|
assert_no_difference "Category.count" do
|
|
result = family.investment_contributions_category
|
|
assert_equal existing, result
|
|
end
|
|
end
|
|
|
|
test "investment_contributions_category uses family locale consistently" do
|
|
family = families(:dylan_family)
|
|
family.update!(locale: "fr")
|
|
family.categories.where(name: [ "Investment Contributions", "Contributions aux investissements" ]).destroy_all
|
|
|
|
# Simulate different request locales (e.g., from Accept-Language header)
|
|
# The category should always be created with the family's locale (French)
|
|
category_from_english_request = I18n.with_locale(:en) do
|
|
family.investment_contributions_category
|
|
end
|
|
|
|
assert_equal "Contributions aux investissements", category_from_english_request.name
|
|
|
|
# Second request with different locale should find the same category
|
|
assert_no_difference "Category.count" do
|
|
category_from_dutch_request = I18n.with_locale(:nl) do
|
|
family.investment_contributions_category
|
|
end
|
|
|
|
assert_equal category_from_english_request.id, category_from_dutch_request.id
|
|
assert_equal "Contributions aux investissements", category_from_dutch_request.name
|
|
end
|
|
end
|
|
|
|
test "investment_contributions_category prevents duplicate categories across locales" do
|
|
family = families(:dylan_family)
|
|
family.update!(locale: "en")
|
|
family.categories.where(name: [ "Investment Contributions", "Contributions aux investissements" ]).destroy_all
|
|
|
|
# Create category under English family locale
|
|
english_category = family.investment_contributions_category
|
|
assert_equal "Investment Contributions", english_category.name
|
|
|
|
# Simulate a request with French locale (e.g., from browser Accept-Language)
|
|
# Should still return the English category, not create a French one
|
|
assert_no_difference "Category.count" do
|
|
I18n.with_locale(:fr) do
|
|
french_request_category = family.investment_contributions_category
|
|
assert_equal english_category.id, french_request_category.id
|
|
assert_equal "Investment Contributions", french_request_category.name
|
|
end
|
|
end
|
|
end
|
|
|
|
test "investment_contributions_category reuses legacy category with wrong locale" do
|
|
family = families(:dylan_family)
|
|
family.update!(locale: "fr")
|
|
family.categories.where(name: [ "Investment Contributions", "Contributions aux investissements" ]).destroy_all
|
|
|
|
# Simulate legacy: category was created with English name (old bug behavior)
|
|
legacy_category = family.categories.create!(
|
|
name: "Investment Contributions",
|
|
color: "#0d9488",
|
|
classification: "expense",
|
|
lucide_icon: "trending-up"
|
|
)
|
|
|
|
# Should find and reuse the legacy category, updating its name to French
|
|
assert_no_difference "Category.count" do
|
|
result = family.investment_contributions_category
|
|
assert_equal legacy_category.id, result.id
|
|
assert_equal "Contributions aux investissements", result.name
|
|
end
|
|
end
|
|
|
|
test "investment_contributions_category merges multiple locale variants" do
|
|
family = families(:dylan_family)
|
|
family.update!(locale: "en")
|
|
family.categories.where(name: [ "Investment Contributions", "Contributions aux investissements" ]).destroy_all
|
|
|
|
# Simulate legacy: multiple categories created under different locales
|
|
english_category = family.categories.create!(
|
|
name: "Investment Contributions",
|
|
color: "#0d9488",
|
|
classification: "expense",
|
|
lucide_icon: "trending-up"
|
|
)
|
|
|
|
french_category = family.categories.create!(
|
|
name: "Contributions aux investissements",
|
|
color: "#0d9488",
|
|
classification: "expense",
|
|
lucide_icon: "trending-up"
|
|
)
|
|
|
|
# Create transactions pointing to both categories
|
|
account = family.accounts.first
|
|
txn1 = Transaction.create!(category: english_category)
|
|
Entry.create!(
|
|
account: account,
|
|
entryable: txn1,
|
|
amount: 100,
|
|
currency: "USD",
|
|
date: Date.current,
|
|
name: "Test 1"
|
|
)
|
|
|
|
txn2 = Transaction.create!(category: french_category)
|
|
Entry.create!(
|
|
account: account,
|
|
entryable: txn2,
|
|
amount: 200,
|
|
currency: "USD",
|
|
date: Date.current,
|
|
name: "Test 2"
|
|
)
|
|
|
|
# Should merge both categories into one, keeping the oldest
|
|
assert_difference "Category.count", -1 do
|
|
result = family.investment_contributions_category
|
|
assert_equal english_category.id, result.id
|
|
assert_equal "Investment Contributions", result.name
|
|
|
|
# Both transactions should now point to the keeper
|
|
assert_equal english_category.id, txn1.reload.category_id
|
|
assert_equal english_category.id, txn2.reload.category_id
|
|
|
|
# French category should be deleted
|
|
assert_nil Category.find_by(id: french_category.id)
|
|
end
|
|
end
|
|
|
|
test "moniker helpers return expected singular and plural labels" do
|
|
family = families(:dylan_family)
|
|
|
|
family.update!(moniker: "Family")
|
|
assert_equal "Family", family.moniker_label
|
|
assert_equal "Families", family.moniker_label_plural
|
|
|
|
family.update!(moniker: "Group")
|
|
assert_equal "Group", family.moniker_label
|
|
assert_equal "Groups", family.moniker_label_plural
|
|
end
|
|
|
|
test "available_merchants includes family merchants without transactions" do
|
|
family = families(:dylan_family)
|
|
|
|
new_merchant = family.merchants.create!(name: "New Test Merchant")
|
|
|
|
assert_includes family.available_merchants, new_merchant
|
|
end
|
|
|
|
test "upload_document stores provided metadata on family document" do
|
|
family = families(:dylan_family)
|
|
family.update!(vector_store_id: nil)
|
|
|
|
adapter = mock("vector_store_adapter")
|
|
adapter.expects(:create_store).with(name: "Family #{family.id} Documents").returns(
|
|
VectorStore::Response.new(success?: true, data: { id: "vs_test123" }, error: nil)
|
|
)
|
|
adapter.expects(:upload_file).with(
|
|
store_id: "vs_test123",
|
|
file_content: "hello",
|
|
filename: "notes.txt"
|
|
).returns(
|
|
VectorStore::Response.new(success?: true, data: { file_id: "file-xyz" }, error: nil)
|
|
)
|
|
|
|
VectorStore::Registry.stubs(:adapter).returns(adapter)
|
|
|
|
document = family.upload_document(
|
|
file_content: "hello",
|
|
filename: "notes.txt",
|
|
metadata: { "type" => "financial_document" }
|
|
)
|
|
|
|
assert_not_nil document
|
|
assert_equal({ "type" => "financial_document" }, document.metadata)
|
|
assert_equal "vs_test123", family.reload.vector_store_id
|
|
end
|
|
end
|