Simpl-Resultat/src/hooks/useCartes.test.ts
le king fu 3be05db41a
All checks were successful
PR Check / rust (push) Successful in 21m48s
PR Check / frontend (push) Successful in 2m15s
PR Check / rust (pull_request) Successful in 21m44s
PR Check / frontend (pull_request) Successful in 2m16s
feat(reports/cartes): Mensuel/YTD toggle on KPI cards + user guide section (#102)
Adds a segmented Monthly/YTD toggle next to the reference-month picker that
flips the four KPI cards (income, expenses, net, savings rate) between the
reference-month value (unchanged default) and a Year-to-Date cumulative view.

In YTD mode, the "current" value sums January to the reference month of the
reference year; MoM delta compares it to Jan to (refMonth - 1) of the same
year (null in January, since no prior YTD window exists); YoY delta compares
it to Jan to refMonth of the previous year; savings rate is recomputed from
YTD income and expenses, and stays null when YTD income is zero.

The 13-month sparkline, top movers, seasonality and budget adherence cards
remain monthly regardless of the toggle (by design). The savings-rate tooltip
is now dynamic and mirrors the active mode. The mode is persisted in
localStorage under `reports-cartes-period-mode`.

Also adds a dedicated Cartes section to `docs/guide-utilisateur.md` covering
the four KPI formulas, the Monthly/YTD toggle and its effect on deltas, the
sparkline, top movers, seasonality, budget adherence and the savings-rate
edge case. Mirrored in the in-app `docs.reports` i18n tree (features/steps/
tips extended) for both FR and EN.

No SQL migration: YTD sums are computed from the already-fetched
`flowByMonth` map, so no extra round trip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:49:21 -04:00

77 lines
2.2 KiB
TypeScript

import { describe, it, expect, beforeEach, vi } from "vitest";
import {
defaultCartesReferencePeriod,
readCartesPeriodMode,
CARTES_PERIOD_MODE_STORAGE_KEY,
} from "./useCartes";
describe("defaultCartesReferencePeriod", () => {
it("returns the month before the given date", () => {
expect(defaultCartesReferencePeriod(new Date(2026, 3, 15))).toEqual({
year: 2026,
month: 3,
});
});
it("wraps around January to December of the previous year", () => {
expect(defaultCartesReferencePeriod(new Date(2026, 0, 10))).toEqual({
year: 2025,
month: 12,
});
});
it("handles the last day of a month", () => {
expect(defaultCartesReferencePeriod(new Date(2026, 5, 30))).toEqual({
year: 2026,
month: 5,
});
});
});
describe("readCartesPeriodMode (localStorage round-trip)", () => {
const store = new Map<string, string>();
const mockLocalStorage = {
getItem: vi.fn((key: string) => store.get(key) ?? null),
setItem: vi.fn((key: string, value: string) => {
store.set(key, value);
}),
removeItem: vi.fn((key: string) => {
store.delete(key);
}),
clear: vi.fn(() => store.clear()),
key: vi.fn(),
length: 0,
};
beforeEach(() => {
store.clear();
vi.stubGlobal("localStorage", mockLocalStorage);
});
it("defaults to 'month' when nothing is persisted", () => {
expect(readCartesPeriodMode()).toBe("month");
});
it("reads back a previously persisted 'month' value (round-trip)", () => {
store.set(CARTES_PERIOD_MODE_STORAGE_KEY, "month");
expect(readCartesPeriodMode()).toBe("month");
});
it("reads back a previously persisted 'ytd' value (round-trip)", () => {
store.set(CARTES_PERIOD_MODE_STORAGE_KEY, "ytd");
expect(readCartesPeriodMode()).toBe("ytd");
});
it("falls back to default for unknown/corrupted values", () => {
store.set(CARTES_PERIOD_MODE_STORAGE_KEY, "bogus");
expect(readCartesPeriodMode()).toBe("month");
});
it("supports a custom fallback", () => {
expect(readCartesPeriodMode(CARTES_PERIOD_MODE_STORAGE_KEY, "ytd")).toBe("ytd");
});
it("uses the expected storage key", () => {
expect(CARTES_PERIOD_MODE_STORAGE_KEY).toBe("reports-cartes-period-mode");
});
});