51 lines
3.7 KiB
TypeScript
51 lines
3.7 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { GlobalRegistrator } from "@happy-dom/global-registrator";
|
|
if (!GlobalRegistrator.isRegistered) GlobalRegistrator.register();
|
|
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
|
import { act } from "react";
|
|
import { createRoot } from "react-dom/client";
|
|
import { MemoryRouter } from "react-router";
|
|
import { createSeedDataset } from "../../domain/seed.ts";
|
|
import { addBudgetFolder, addRecurringCost, confirmOccurrence } from "../../store/actions.ts";
|
|
import { monthView } from "../../domain/views.ts";
|
|
import { store } from "../../store/index.ts";
|
|
import { BudgetTree } from "./BudgetTree.tsx";
|
|
|
|
function setup(run: (container: HTMLDivElement, billId: string) => void, confirm = false) {
|
|
const data = createSeedDataset("2026-09");
|
|
const housing = addBudgetFolder(data, "Housing", null);
|
|
const utilities = addBudgetFolder(data, "Utilities", housing.id); utilities.order = 0;
|
|
const post = data.posts[0]!; post.name = "Rent post"; post.folderId = housing.id; post.order = 1;
|
|
const bill = addRecurringCost(data, { name: "Rent bill", folderId: housing.id, archived: false, amount: { amount: 8000, currency: "DKK" }, startDate: "2026-09", recurrence: { kind: "everyNMonths", n: 18 }, anchoring: "calendar", splitMode: "percent", splits: [{ postId: post.id, value: 100, absorbsRemainder: true }] }); bill.order = 2;
|
|
addRecurringCost(data, { ...bill, name: "Ended bill", folderId: null, endedFrom: "2026-08" });
|
|
if (confirm) confirmOccurrence(data, bill.id, "2026-09", { date: "2026-09-01" });
|
|
const original = { get: store.get, subscribe: store.subscribe }; store.get = () => data; store.subscribe = () => () => {};
|
|
const container = document.createElement("div"); document.body.append(container); const root = createRoot(container);
|
|
try { act(() => root.render(<MemoryRouter><BudgetTree monthId="2026-09" rows={monthView(data, "2026-09").rows} /></MemoryRouter>)); run(container, bill.id); }
|
|
finally { act(() => root.unmount()); container.remove(); Object.assign(store, original); }
|
|
}
|
|
function housing(container: HTMLDivElement) { return container.querySelector('button[aria-label="Housing"]') as HTMLButtonElement; }
|
|
test("collapsed folder keeps Bills due", () => setup(container => {
|
|
expect(housing(container).getAttribute("aria-expanded")).toBe("false");
|
|
expect(housing(container).parentElement!.textContent).toContain("8,000");
|
|
expect(housing(container).parentElement!.textContent).toContain("Bills due");
|
|
expect(container.querySelector('[data-budget-name="Rent post"]')).toBeNull();
|
|
}));
|
|
test("expanded tree preserves mixed order", () => setup(container => {
|
|
act(() => housing(container).click());
|
|
for (const scope of [container.querySelector("table")!, container.querySelector("ul")!]) {
|
|
const names = Array.from(scope.querySelectorAll("[data-budget-item]")).map(item => item.getAttribute("data-budget-name"));
|
|
expect(names.slice(0, 4)).toEqual(["Housing", "Utilities", "Rent post", "Rent bill"]);
|
|
}
|
|
expect((container.querySelector('table [data-budget-name="Rent post"] td') as HTMLElement).style.paddingInlineStart).toBe("16px");
|
|
expect((container.querySelector('ul [data-budget-name="Rent post"]') as HTMLElement).style.paddingInlineStart).toBe("16px");
|
|
expect(container.textContent).toContain("Unfiled"); expect(container.textContent).toContain("Social");
|
|
expect(container.querySelector("table > div")).toBeNull();
|
|
}));
|
|
test("bill edit reaches its settings row", () => setup((container, billId) => {
|
|
act(() => housing(container).click());
|
|
expect(container.querySelector(`[data-budget-item="${billId}"] a`)!.getAttribute("href")).toBe(`/settings#bill-${billId}`);
|
|
expect(container.textContent).toContain("Ended");
|
|
expect(container.textContent).toContain("Next 2028-03");
|
|
}, true));
|