// useAdjustments — the categories an adjustment line can pick (#429, D2). // // React's hooks come from the shared harness (src/test/hookHarness.ts, #409): // the hook runs as a plain function, its reducer is applied, and `commit()` // runs its mount effect. The services are mocked; the base answers a raw // query with every active category, so a hook that read the base itself, // instead of the Transactions list, would show it. import { describe, it, expect, vi, beforeEach } from "vitest"; vi.mock("react", async (orig) => (await import("../test/hookHarness")).fakeReact(await orig())); const { getAllCategories, getAllAdjustments, select } = vi.hoisted(() => ({ getAllCategories: vi.fn(), getAllAdjustments: vi.fn(), select: vi.fn(), })); vi.mock("../services/transactionService", () => ({ getAllCategories })); vi.mock("../services/adjustmentService", () => ({ getAllAdjustments, getEntriesByAdjustmentId: vi.fn(), createAdjustment: vi.fn(), updateAdjustment: vi.fn(), deleteAdjustment: vi.fn(), createEntry: vi.fn(), updateEntry: vi.fn(), deleteEntry: vi.fn(), })); vi.mock("../services/db", () => ({ getDb: vi.fn(async () => ({ select })) })); import { hookHarness } from "../test/hookHarness"; import { useAdjustments } from "./useAdjustments"; import type { Category } from "../shared/types"; const harness = hookHarness(); const category = (id: number, name: string, isInputable: boolean): Category => ({ id, name, type: "expense", is_active: true, is_inputable: isInputable, sort_order: id, created_at: "", }); /** The Transactions list: active and open to input. */ const INPUTABLE = [category(1, "Épicerie", true), category(2, "Loyer", true)]; /** Every active category, a parent hidden from input included. */ const ACTIVE = [category(3, "Alimentation", false), ...INPUTABLE]; /** Lets the loaders' promises settle. */ const flush = async () => { for (let i = 0; i < 10; i++) await Promise.resolve(); }; beforeEach(() => { harness.clear(); getAllCategories.mockReset(); getAllCategories.mockResolvedValue(INPUTABLE); getAllAdjustments.mockReset(); getAllAdjustments.mockResolvedValue([]); select.mockReset(); select.mockResolvedValue(ACTIVE); }); describe("useAdjustments — categories of a line (#429, D2)", () => { it("offers the Transactions list, active and open to input, not every active category", async () => { harness.render(useAdjustments); harness.commit(); await flush(); const { state } = harness.render(useAdjustments); expect(state.categories).toBe(INPUTABLE); expect(getAllCategories).toHaveBeenCalledTimes(1); expect(select).not.toHaveBeenCalled(); }); it("reports a failed read as the page's error, with no category", async () => { getAllCategories.mockRejectedValue(new Error("database is locked")); harness.render(useAdjustments); harness.commit(); await flush(); const { state } = harness.render(useAdjustments); expect(state.categories).toEqual([]); expect(state.error).toBe("database is locked"); }); });