- AccountForm: optional vehicle_type dropdown (account mode, 6 fiscal envelopes + none) wired into create/update; custom_label field (category mode) written to custom_label, never i18n_key. - AccountsPage rename: writes custom_label, leaves i18n_key intact (fixes bug I where renaming clobbered the translation key). - New shared renderCategoryLabel helper (+ shape adapters) applied at the 5 sites: AccountsPage, AccountForm, SnapshotEditor, BalanceAccountsTable, BalancePage. - Hide v13-deactivated seeds: useBalanceAccounts passes includeInactive=false (keeps #202 behavior-neutral default + tests green). - BALANCE_VEHICLE_TYPES exported from shared/types as single source of truth (service reuses it). - i18n FR+EN: vehicleType.*, category.form.customLabel*, errors.vehicle_type_invalid. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
renderCategoryLabel,
|
|
renderCategoryLabelFromCategory,
|
|
renderCategoryLabelFromAccount,
|
|
} from "./renderCategoryLabel";
|
|
|
|
// Fake `t`: echoes the key prefixed, but honours defaultValue for unknown keys
|
|
// the way react-i18next does. We model "known" keys explicitly.
|
|
const known: Record<string, string> = {
|
|
"balance.category.cash": "Liquidités",
|
|
};
|
|
const t = (key: string, options?: { defaultValue?: string }) =>
|
|
known[key] ?? options?.defaultValue ?? key;
|
|
|
|
describe("renderCategoryLabel", () => {
|
|
it("prefers a non-empty custom_label over the i18n translation", () => {
|
|
expect(
|
|
renderCategoryLabel("Mon CELI", "balance.category.cash", "cash", t)
|
|
).toBe("Mon CELI");
|
|
});
|
|
|
|
it("trims custom_label and treats whitespace-only as absent", () => {
|
|
expect(
|
|
renderCategoryLabel(" ", "balance.category.cash", "cash", t)
|
|
).toBe("Liquidités");
|
|
});
|
|
|
|
it("falls back to the i18n translation when custom_label is null", () => {
|
|
expect(
|
|
renderCategoryLabel(null, "balance.category.cash", "cash", t)
|
|
).toBe("Liquidités");
|
|
});
|
|
|
|
it("falls back to the i18n translation when custom_label is undefined", () => {
|
|
expect(
|
|
renderCategoryLabel(undefined, "balance.category.cash", "cash", t)
|
|
).toBe("Liquidités");
|
|
});
|
|
|
|
it("falls back to the raw key when no translation exists", () => {
|
|
expect(
|
|
renderCategoryLabel(null, "balance.category.unknown", "unknown", t)
|
|
).toBe("unknown");
|
|
});
|
|
|
|
it("returns a trimmed custom_label (leading/trailing spaces removed)", () => {
|
|
expect(
|
|
renderCategoryLabel(" Épargne ", "balance.category.cash", "cash", t)
|
|
).toBe("Épargne");
|
|
});
|
|
});
|
|
|
|
describe("renderCategoryLabelFromCategory", () => {
|
|
it("maps the BalanceCategory shape", () => {
|
|
expect(
|
|
renderCategoryLabelFromCategory(
|
|
{ custom_label: null, i18n_key: "balance.category.cash", key: "cash" },
|
|
t
|
|
)
|
|
).toBe("Liquidités");
|
|
expect(
|
|
renderCategoryLabelFromCategory(
|
|
{ custom_label: "X", i18n_key: "balance.category.cash", key: "cash" },
|
|
t
|
|
)
|
|
).toBe("X");
|
|
});
|
|
});
|
|
|
|
describe("renderCategoryLabelFromAccount", () => {
|
|
it("maps the JOIN-prefixed account shape", () => {
|
|
expect(
|
|
renderCategoryLabelFromAccount(
|
|
{
|
|
category_custom_label: null,
|
|
category_i18n_key: "balance.category.cash",
|
|
category_key: "cash",
|
|
},
|
|
t
|
|
)
|
|
).toBe("Liquidités");
|
|
expect(
|
|
renderCategoryLabelFromAccount(
|
|
{
|
|
category_custom_label: "Compte X",
|
|
category_i18n_key: "balance.category.cash",
|
|
category_key: "cash",
|
|
},
|
|
t
|
|
)
|
|
).toBe("Compte X");
|
|
});
|
|
});
|